Compare commits

...

1616 Commits

Author SHA1 Message Date
Roman Perepelitsa 2b7da93df0 docs: fixup for #2718 3 months ago
Roman Perepelitsa 821b25dc32 Merge branch 'eliwss0-patch-1' 3 months ago
Eli Weiss 4a2ef610ef
Add instructions on setting Conemu font
Add instructions on setting font to MesloLGS NF in Conemu
3 months ago
Roman Perepelitsa df8ed16343 wizard: prefer POWERLEVEL9K_MODE=nerdfont-v3 over nerdfont-complete"
The preference for nerdfont-complete was necessitated by a bug
in Windows Terminal that has since been fixed.

This reverts commit b474978b2e.

  wizard: prefer POWERLEVEL9K_MODE=nerdfont-complete over nerdfont-v3

See the reverted commit for details on the Windows Terminal bug.
3 months ago
Roman Perepelitsa bde5ca4c2a
docs: the project is on life support 4 months ago
Elan Ruusamäe 16e5848426
Doc: Use shorter readme link (#2671)
Since it links to readme on default branch (permalink), can just omit that all making links shorter.
5 months ago
Roman Perepelitsa 3395c828b2 docs: mention that vscode terminal does not respect foreground colors chosen by the user by default 5 months ago
Roman Perepelitsa b28d68f44b allow ~/.timewarrior to be a symbolic link (#2603) 5 months ago
Roman Perepelitsa 01e3f0b4ba bump version 5 months ago
Roman Perepelitsa 808ba80ab0 fail more gracefully on timewarrior v3.0.1 (#2648) 5 months ago
Alejandro Armas 178fcda348
Update README.md Fix Typo (#2637)
Removes the extra ')' in the yazi segment meaning
5 months ago
Alexander Blum bcef7cafdf
fixes taskwarrior init data for taskwarrior v3 (#2635) 6 months ago
Roman Perepelitsa aeff1153d4 handle unquoted `prompt` when parsing pyenv.cfg 6 months ago
Roman Perepelitsa 7c2ce29c3f Merge branch 'hodeinavarro-hodei-pyenv-prompt-2628' 6 months ago
Hodei Navarro d6a0fed1d9
Ease regex pattern when reading pyenv.cfg prompt value
This commit provides support for virtualenv-like pyenv.cfg configuration files, where the `prompt` value is a plain text rather than a quoted string.
Before the commit, `prompt = My custom prompt` would not match the regex, returning a fallback of the $VIRTUAL_ENV directory name.
After the commit, both venv-like `prompt = 'My custom prompt'` and virtualenv-like `prompt = My custom prompt` are supported.

Closes #2628
6 months ago
Mohammad Al Zouabi da9b03777c
remove duplicate POWERLEVEL9K_DIR_SHOW_WRITABLE from p10k-lean-8colors.zsh (#2610) 6 months ago
Roman Perepelitsa 3fe8706d24 Merge commit '45627c528b4e3d8949a1e5c72ee3fe7cac516d8d' 6 months ago
Roman Perepelitsa 45627c528b Squashed 'gitstatus/' changes from 215063d4..62177e89
62177e89 build: drop -Werror

git-subtree-dir: gitstatus
git-subtree-split: 62177e89b2b04baf242cd1526cc2661041dda0fb
6 months ago
Roman Perepelitsa a7f13e420e bump version 6 months ago
Roman Perepelitsa 55c8f74c38 Revert "remove `DISABLE_UPDATE_PROMPT=true` from instant prompt"
This reverts commit 07a971d310.
6 months ago
Roman Perepelitsa 50794faba4 Revert "add p10k-deactivate-instant-prompt"
This reverts commit 93d074a82b.
6 months ago
Roman Perepelitsa a3f7dabcae cleanup 6 months ago
Roman Perepelitsa 93d074a82b add p10k-deactivate-instant-prompt
Function p10k-deactivate-instant-prompt is defined when and only when
instant prompt is active. Invoking it erases and deactivates instant
prompt.
6 months ago
Roman Perepelitsa 07a971d310 remove `DISABLE_UPDATE_PROMPT=true` from instant prompt
If this breaks your shell, it means you are using an old version of
oh-my-zsh, which predates this commit:

fe0dd8226d

You need to upgrade oh-my-zsh by running the following command:

    omz update
6 months ago
Roman Perepelitsa 6836bfe2da
fix heads in the wizard (#2605)
fixed on the phone, hence the dumb diff
6 months ago
Roman Perepelitsa 0fdca5b1e6 always offer the flat heads option in the wizard (#2600) 6 months ago
Roman Perepelitsa d39e426835 docs: mention sessions in the font instructions for MobaXterm (#2599) 6 months ago
Roman Perepelitsa 0cc19ac2ed use nf-md-redhat as the RHEL logo when on nerdfont-v3 (#2583) 7 months ago
Roman Perepelitsa b973805f01 cleanup and bump version (#2576) 7 months ago
Roman Perepelitsa b379cf6225 Merge branch 'cybershoe-2575-raspberry-pi-os-logo' 7 months ago
Adam Schumacher bb16e366c3 Undelete ubuntu. I shouldn't code this tired. 7 months ago
Adam Schumacher 31d99b694c Fix in wizard.zsh 7 months ago
Adam Schumacher bfbc65e63d whitespace 7 months ago
Adam Schumacher 12e0592ac8 Still keep debian 7 months ago
Adam Schumacher 9e3418d319 Detect rpi os based on apt source 7 months ago
Roman Perepelitsa 17cd9e354a when looking for .fvm/flutter_sdk, require that the last segment is a symlink rather than .fvm (#2573) 7 months ago
Roman Perepelitsa 8e2a22d80b cleanup and bump version (#2572) 7 months ago
Roman Perepelitsa 5ef7487648 Merge branch 'weirdgiraffe-master' 7 months ago
weirdgiraffe f880e18769
update readme 7 months ago
weirdgiraffe 665257d059
add themes support 7 months ago
weirdgiraffe 67cedd3edc
add visual expansion to wizard 7 months ago
weirdgiraffe eb8f96f808
add prompt segment for yazi levels 7 months ago
weirdgiraffe 1aa91f0069
add icon for yazi level 7 months ago
Roman Perepelitsa 5bba4b849b skip batteries with "Unknown" status (#2562) 8 months ago
Roman Perepelitsa ce7c242337 bump versions 8 months ago
Ulices 34ee1c6bbb
fix: use correct sourcehut repository url (#2556)
sourcehut.org is the website of the organization but
sr.ht is the website were the repositories are hosted.
8 months ago
Roman Perepelitsa 62341054d8 set the default value of LINUX_NEON_ICON to a glyph that exists in the recommended font (#2553) 8 months ago
Roman Perepelitsa be39c4ea5a Merge branch 'And9815-master' 8 months ago
Andrea adc238fa1d neon support 8 months ago
Andrea 6f4520cc13 add neon support 8 months ago
Roman Perepelitsa 307bce24d1 docs: fix a link to zsh-theme-powerlevel10k archlinux package 8 months ago
Roman Perepelitsa 35833ea15f docs: document per_directory_history segment (#2384) 8 months ago
Roman Perepelitsa bd0fa8a08f docs: fix a link 8 months ago
Roman Perepelitsa a6fa4e4304 faq: [oh-my-zsh] theme 'powerlevel10k/powerlevel10k' not found 8 months ago
Roman Perepelitsa ab6a863e23 docs: mention truecolor 8 months ago
Roman Perepelitsa 8fefef2285 rewrite the handling of custom prompt in virtualenv (#2540) 8 months ago
Roman Perepelitsa ecf91710c0 Merge branch 'mickolka-feature/virtualenv-custom-prompt' 8 months ago
Roman Perepelitsa d774adcb85 Merge branch 'feature/virtualenv-custom-prompt' of https://github.com/mickolka/powerlevel10k into mickolka-feature/virtualenv-custom-prompt 8 months ago
Roman Perepelitsa 30ba16ecd8 font: update alacritty instructions (#2539)
Alacritty has switched from yaml to toml for its config file.
8 months ago
Mikalai Rahachou 4d7925c983
Add parsing of pyvenv.cfg 8 months ago
Roman Perepelitsa c180a5e040 font: fix foot instructions (#2536) 8 months ago
Roman Perepelitsa 75724ec65e Merge branch 'LlemonDuck-patch-1' 8 months ago
Rhea 9be438f862
add foot font instructions
This adds instructions to the README for users of [foot](https://codeberg.org/dnkl/foot) to enable the MesloLGS Nerd Font as the default in their terminal.
8 months ago
Roman Perepelitsa cda24b72b7 bump version 8 months ago
Roman Perepelitsa f5d5abfe1f fix a silly bug introduced in the last commit (#2534) 8 months ago
Roman Perepelitsa 651033c3df work around a bug in laravel that results in colorized output (#2534) 8 months ago
Roman Perepelitsa d804048efc fix a bug in DCS detection within instant prompt output (#2518) 9 months ago
Roman Perepelitsa cc6ed4be41 add `cdk` to POWERLEVEL9K_AWS_SHOW_ON_COMMAND (#1104) 9 months ago
Roman Perepelitsa dec881651c Squashed 'gitstatus/' changes from 38d35b959..215063d47
215063d47 update libgit2 ref (#414)

git-subtree-dir: gitstatus
git-subtree-split: 215063d4703b944f66cc7cc92543205586a35485
9 months ago
Roman Perepelitsa d70eedb345 Merge commit 'dec881651ccbd90f7f68b2a2012cf4870741d0dd' 9 months ago
Roman Perepelitsa 36cce9a088 wizard: replace rm with zf_rm (#2504) 10 months ago
Roman Perepelitsa 3cc18b5e08 Merge branch 'oe7drt-openbsd-wizard' 10 months ago
Dominic Reich 44f754d711
use "rm" instead of "unlink" to delete old config file 10 months ago
Roman Perepelitsa 47b0187a67 docs: add a note about `p10k reload` (#2006) 10 months ago
Roman Perepelitsa b9a2d846ef docs: clarify that powerlevel10k does not install new commands (#2498) 10 months ago
Roman Perepelitsa 7fd76370f5 be a lot more strict when matching the remote git URL (#2493)
When you choose "Many icons" option in the configuration wizard,
git repositories with a remote receive an icon that depends on
the remote's URL. In the past the matching of the URL was rather
lax: both https://foo.bar/github.com and https://github.com.foo.bar/
were recognized as belonging to github.com. This is no longer the
case.

If you start seeing the plain "git" icon where you were used to
seeing a github/gitlab/etc logo, please open an issue. Make sure
to mention the remote URL of your repo.

This change also allows you to specify the mapping from remote URLs
to icons. Here's an example:

    typeset -g POWERLEVEL9K_VCS_GIT_REMOTE_ICONS=(
      '*@my-company.com:*' VCS_GIT_MY_COMPANY_ICON
      '?*'                 VCS_GIT_ICON
      '*'                  ''
    )

    POWERLEVEL9K_VCS_GIT_MY_COMPANY_ICON='my-company-logo'

The matching is done in the specified order: the first match wins.
10 months ago
Roman Perepelitsa 9547f22822 s/VCS_GIT_ARCH_ICON/VCS_GIT_ARCHLINUX_ICON/ (#2493) 10 months ago
Roman Perepelitsa c39e5304a1 add VCS_GIT_GITEA_ICON and VCS_GIT_SOURCEHUT_ICON (#2493) 10 months ago
Roman Perepelitsa 096a731db3 define usable defaults for VCS_*_ICON (#2493) 10 months ago
Roman Perepelitsa 783588c17f Merge branch 'add_remotes' of https://github.com/hasecilu/powerlevel10k 10 months ago
Roman Perepelitsa 211c90343f wizard: recognize `source -- ~.p10k.zsh` in .zshrc 10 months ago
hasecilu 47d5397baa
Add various remote git server instances
Currently only icons for big providers of git hosting service are available.

Organizations of open source software usually manage their own instances.

Adding the remote addresses of some of this organizations will let us to
identify via a glyph icon the provider of the source code.
10 months ago
hasecilu 92bee79642
Add icons for VCS_GIT usage
The icons are from organizations that manage a git instance by themselves.
10 months ago
Roman Perepelitsa 174ce9bf01 recognize azure devops git remote HTTPS URLs (#2472) 11 months ago
Roman Perepelitsa 18f0bec1bb use newer icons for azure and azure devops (#2472) 11 months ago
Roman Perepelitsa 430616734a make terraform_version compatible with tfenv (#2049) 11 months ago
Roman Perepelitsa c7fa7d6748 make rust_version segment compatible with the new rustup toolchain file (#2413) 11 months ago
Roman Perepelitsa 862440ae11 add an icon for azure to vcs (#2447) 12 months ago
Roman Perepelitsa 873c4ff09c fix the path to powerlevel10k when installing with homebrew (#2429) 1 year ago
Roman Perepelitsa 215b20e087 bump version 1 year ago
Jussi Timperi be4c68fd0a
add Guix System icon (#2424) 1 year ago
Roman Perepelitsa f8595a35bf use powerlevel10k from homebrew/core when installing with brew 1 year ago
Nanda Lopes 011b8469ab
typo: s/.tool-version/.tool-versions/ in all configs 1 year ago
Roman Perepelitsa d8041e4700 Squashed 'gitstatus/' changes from bdaad2e8d..38d35b959
38d35b959 cleanup
7e7b5e807 bash prompt: set PROMPT_COMMAND in a nicer and more robust manner (#403)
7ee9227de Merge branch 'samiam-append_prompt'
198ed58ce Revert "Update README to append to PROMPT_COMMAND"
8b6a229fa Switch to using var assignment for backward compatibility
693f9efa0 Update README to append to PROMPT_COMMAND
a48175ce1 Append to PROMPT_COMMAND to play nice with other prompt programs

git-subtree-dir: gitstatus
git-subtree-split: 38d35b95926e09d07b8cf78edade7cee7a9a1dcf
1 year ago
Roman Perepelitsa f04ce05d92 Merge commit 'd8041e4700ace779aaf42e19c3de2d25a14dbae8' 1 year ago
Roman Perepelitsa 9401ed17c0 Squashed 'gitstatus/' changes from abb4f6a52..bdaad2e8d
bdaad2e8d Makefile: remove the explicit check for the existence of $(CXX)
6d32e0272 Merge branch 'criadoperez-fix/makefile'
c0e3c250e improved Makefile

git-subtree-dir: gitstatus
git-subtree-split: bdaad2e8d0e6e2f9928e067c85de8096b87e21fa
1 year ago
Roman Perepelitsa 69d726d9fb Merge commit '9401ed17c0a8c3d1654214a204b8d5b5f7ccf386' 1 year ago
Roman Perepelitsa 22cb2f79dd Squashed 'gitstatus/' changes from 4b47ca047..abb4f6a52
abb4f6a52 fix typos in docs and comments
958ae4e6d docs: explicitly mention that core.fsmonitor was disable in git benchmarks (#370)

git-subtree-dir: gitstatus
git-subtree-split: abb4f6a5225d12f51ffd8196060804b0c770482e
1 year ago
Roman Perepelitsa 2d9c1f271b Merge commit '22cb2f79ddb89a368dd823e815fa1b0587ff1b6a' 1 year ago
Alejandro Criado-Pérez 717f9a1881
fix typos in docs and comments 1 year ago
Roman Perepelitsa f851f41fc1 remove MULTIBYTE requirement from the configuration wizard (#2397) 1 year ago
Roman Perepelitsa 9bb15e9ffb docs: rephrase "Git status looks incorrect" section 1 year ago
Roman Perepelitsa ef401ad02a Merge branch 'fzakaria-skip-hash' 1 year ago
Farid Zakaria a8fa0e2a1b Add documentation explaining lack of support for skipHash
libgit2 does not support skipHash which causes the prompt to be
incorrect for repos that have it toggled.

Add the documentation for this gap.

fixes #2387
1 year ago
Roman Perepelitsa 68104494a7 bump version + cleanup (#2391) 1 year ago
Roman Perepelitsa baf03bf48e Merge branch 'mgkurtz-mgk/rocky' 1 year ago
Markus Kurtz 367c667de6 Add rocky icon to wizard 1 year ago
Markus Kurtz 12aa3fa3c4 Add rocky icon 1 year ago
Roman Perepelitsa 7e9a79f3f1 new segment: per_directory_history (#2384) 1 year ago
Roman Perepelitsa 1d96f5e066 unquote ID in /etc/os-release (#2388) 1 year ago
Roman Perepelitsa e8aa8cce7f unquote ID in /etc/os-release (#2388) 1 year ago
Roman Perepelitsa 646bae0dd6 docs: Terminus is now called Tabby 1 year ago
Roman Perepelitsa 4cc0ea0081 Merge branch 'hugivar-master' 1 year ago
hugo 2453fd27e2
Update README.md as Terminus is now known as Tabby 1 year ago
Roman Perepelitsa 932954a8b1 do not display an indicator when a git branch is up to date with a remote
https://github.com/romkatv/powerlevel10k/issues/2361 requested an indicator for
up to date branches, which was added in
20323d6f8c.

Since then, 3 users complained about the new indicator:

- https://github.com/romkatv/powerlevel10k/issues/2377
- https://github.com/romkatv/powerlevel10k/issues/2380
- https://github.com/romkatv/powerlevel10k/issues/2361#issuecomment-1630731045

On one hand we have one request to add a feature. On the other hand we have
three complaints about the feature's existence. The feature is going away.
1 year ago
Roman Perepelitsa 93d97b7eba better comments 1 year ago
Roman Perepelitsa 078497570f clean up the handling of POWERLEVEL9K_AZURE_CLASSES and put it in all configs (#2379)
This reverts commit 343d4f44e5, reversing
changes made to 4dca4bdfbb.
1 year ago
Roman Perepelitsa 343d4f44e5 Merge branch 'benm-stm-bug/sub-patterns-colors-for-azure' 1 year ago
BEN MANSOUR Mohamed Rafik 0c28fec137 fix pattern coloration for azure defined classes 1 year ago
Roman Perepelitsa 4dca4bdfbb bug fix: honor POWERLEVEL9K_LEFT_SEGMENT_END_SEPARATOR in instant prompt (#2376) 1 year ago
Roman Perepelitsa 20323d6f8c display `=` in git status if up to date with the remote (#2361) 1 year ago
Roman Perepelitsa 017395a266 release v1.19.0 1 year ago
Koen van Zuijlen ab8bac01e2
Add sparkctl to POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND (#2346) 1 year ago
Roman Perepelitsa 360dcd3907 respect XDG_DATA_HOME when looking for the timewarrior data directory (#2344)
The logic for finding the data directory is as follows:

1. Find the root directory:
  1.1 If TIMEWARRIORDB is set, use that.
  1.2 Else if ~/.timewarrior is an existing directory, use that.
  1.3 Else if XDG_DATA_HOME is set, use $XDG_DATA_HOME/timewarrior.
  1.4 Else use ~/.local/share/timewarrior.
2. Append "/data" to the root directory.
1 year ago
Roman Perepelitsa 944f52fc43 move chezmoi_shell in the docs closer to other shell indicator segments 1 year ago
Roman Perepelitsa cc4878aef2 fix chezmoi segment and rename it to chezmoi_shell (#2311)
- Link to the project's homepage rather than its source code.
- Move `chezmoi_shell` next to all the other *shell indicator* segments.
- Use a shade of blue that resembes the color on chezmoi.io.
- Don't go beyond 8 colors in 8-color configs.
- Remove the segment from the *pure* config.
- Fix whitespace padding on `CHEZMOI_ICON`.
- Use the appropriate icon with all fonts (the same as `HOME`).
- Add missing `CHEZMOI_ICON` definitions for "powerline" and "ascii" font modes.
- Remove the redundant literal "chezmoi" content from the segment.
- Fix instant prompt so that the segment is shown only when `$CHEZMOI` is non-empty.
1 year ago
Roman Perepelitsa c775a3ffd5 Merge branch 'Alkindi42-feat/add-chezmoi-prompt' 1 year ago
Roman Perepelitsa 416bdf1ca3 Merge branch 'feat/add-chezmoi-prompt' of https://github.com/Alkindi42/powerlevel10k into Alkindi42-feat/add-chezmoi-prompt 1 year ago
Alkindi42 3ecef8c6a5 feat(chezmoi): add instant_prompt_chezmoi 1 year ago
Alkindi42 7b19746580 feat: add color and custom icon 1 year ago
kvanzuijlen e4b8925478 Added cert manager cmctl to POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND 1 year ago
Roman Perepelitsa 79753faacb add a comment within .p10k.zsh explaining the use of "_joined" (#2332) 1 year ago
Roman Perepelitsa 3ce7bac4ff Merge branch 'warp' 1 year ago
Alkindi42 9ed51ec315 doc: add chezmoi prompt in the README 1 year ago
Alkindi42 6db5920bb9 feat: add chezmoi icon 1 year ago
Alkindi42 29c0b25850 feat: enable chezmoi prompt in configurations 1 year ago
Skyler 951d695789 Update README.md
Fixed a small bug in alpine linux hyperlink under Installation
1 year ago
Alkindi42 6740f08f61 chezmoi: add chezmoi prompt 1 year ago
Roman Perepelitsa 8cce84643f set P9K_VERSION (#2307) 1 year ago
Roman Perepelitsa a69aa22fa8 show the right cwd when some part of it gets renamed (#2304) 1 year ago
Roman Perepelitsa f4a7e6d0e0 force shell integration when running under warp (#2307) 1 year ago
Roman Perepelitsa 7bb3f05318 annotate right prompt for warp (#2307) 1 year ago
Arthur McLain 9b47a22f13 Update README.md 1 year ago
Roman Perepelitsa 1dcd882593 set P9K_STARTUP_CONSOLE_OUTPUT to assist in debugging startup console output problems 1 year ago
Roman Perepelitsa 064f4d2209 whitelist DCS in startup console output (#2299) 1 year ago
Roman Perepelitsa 0a9eb73e16 nvm: change the default value of POWERLEVEL9K_NVM_PROMPT_ALWAYS_SHOW back to false (#2296) 1 year ago
Roman Perepelitsa 016512f493 nvm: change the default value of POWERLEVEL9K_NVM_PROMPT_ALWAYS_SHOW to true and fix the way it is used (#2296) 1 year ago
Roman Perepelitsa 7039779c19 Merge branch 'zaidhaan-nvm-always-show' 1 year ago
Zaidhaan Hussain 4ed8aae324 nvm: implement POWERLEVEL9K_NVM_PROMPT_ALWAYS_SHOW and default to false 1 year ago
Zaidhaan Hussain 5d16c106ed nvm: implement POWERLEVEL9K_NVM_SHOW_SYSTEM and default to true 1 year ago
Roman Perepelitsa 0af598cbed wizard: add a screen for detecting faulty terminals that render glyphs such as U+F0001 as wide (e.g., Windows Terminal) 1 year ago
Roman Perepelitsa ce0bee979b wizard: check for unicode 9 support before asking about U+F0737 1 year ago
Roman Perepelitsa dff735c261 increase the default value of POWERLEVEL9K_GITSTATUS_INIT_TIMEOUT_SEC from 5 to 10 1 year ago
Roman Perepelitsa 630c1868df add POWERLEVEL9K_GITSTATUS_INIT_TIMEOUT_SEC 1 year ago
Roman Perepelitsa bbea8d2d06 use U+F327 (Kali Linux logo) only with POWERLEVEL9K_MODE=nerdfont-v3 (#2281) 1 year ago
Roman Perepelitsa 6f8dec7a76 Merge branch 'zerom0-master' 1 year ago
Martin Mosler 94c4428ddc added icon for kali linux 1 year ago
Roman Perepelitsa 045f006c50 correctly resolve node_version when using nodenv (#2268) 1 year ago
Roman Perepelitsa c1b5b2c8aa Merge branch 'LucasLarson-clock_mnemonic' 1 year ago
Lucas Larson 954f38d589
use less surprising input for clock option
for the three clock options (no clock, a 12-hour clock, or a 24-hour
clock), use the first character of the option as the input to
fix #2266.

This pull request is a reissue of – and supersession of – #2267,
which was pushed on a branch with non-ASCII characters in the name.

Signed-off-by: Lucas Larson <LucasLarson@riseup.net>
1 year ago
Roman Perepelitsa f27d192eb2 bump version 1 year ago
Roman Perepelitsa bab655fb1f do not infer nix_shell from PATH unless POWERLEVEL9K_NIX_SHELL_INFER_FROM_PATH is set to true (#2246) 1 year ago
Roman Perepelitsa fb1287fedb simplify _p9k_url_escape 1 year ago
Roman Perepelitsa 1cff22491b fix the kubernetes icon (#2217) 1 year ago
Roman Perepelitsa b474978b2e wizard: prefer POWERLEVEL9K_MODE=nerdfont-complete over nerdfont-v3
Apparently Windows Terminal has a bug. To reproduce:

    print -P '\UF0737%K{red} %k'

The expected output:

    x_

Here 'x' signifies any glyph of width 1, and '_' signifies a red
block.

The actual output:

    x _

Notice the space.

The output of the following two commands is as expected:

    print -P '\UFC35%K{red} %k'
    print -P '\UFC35x'
1 year ago
Roman Perepelitsa 8167383665 wizard bug fix: offer advanced powerline options when using nerdfont-v3 1 year ago
Roman Perepelitsa d031df752b wizard: detect POWERLEVEL9K_MODE=nerdfont-v3
This is Step 2 of https://github.com/romkatv/powerlevel10k/issues/2217#issuecomment-1493271666.
1 year ago
Roman Perepelitsa 6314edf35c wizard: rename capability "arrow" to "quotes" 1 year ago
Roman Perepelitsa 6c82236d6f nerdfonts-v3: add an icon for EndevourOS (#1933) 1 year ago
Roman Perepelitsa 6b50e0918b nerdfonts-v3: use the kubernetes logo as a kubernetes icon (#2184) 1 year ago
Roman Perepelitsa ec1702caf1 nerdfonts-v3: add icons for artix and void linux (#2033) 1 year ago
Roman Perepelitsa f02b8d365b add POWERLEVEL9K_MODE=nerdfont-v3 (#2217)
This is Step 1 of https://github.com/romkatv/powerlevel10k/issues/2217#issuecomment-1493271666.
1 year ago
Roman Perepelitsa 614a6ed1ca display nix_shell if path contains /nix/store/* (#2246) 1 year ago
Roman Perepelitsa cb9788b12a docs: fix zed font instructions 2 years ago
Roman Perepelitsa 7f30a32ee6 Merge branch 'lazarjov-master' 2 years ago
Lazar Jovanovic e2c4e6673f Add manual MesloLGS NF font installation for Zed 2 years ago
Roman Perepelitsa 2aa16c5431 docs: prune the list of kubecontext commands 2 years ago
NatureLR 373337123c Added kubecolor to KUBECONTEXT_SHOW_ON_COMMAND 2 years ago
Roman Perepelitsa a30145b0f8 add an optional parameter to _p9k_upglob to pass glob qualifiers and use it in most cases to restrict globbing to files/directories/links/etc (#2175) 2 years ago
Roman Perepelitsa e7b2bb2372 set POWERLEVEL9K_VPN_IP_INTERFACE to the same value as the default: this adds ZeroTier support 2 years ago
Mehyar e9e94a503a fix the default value of POWERLEVEL9K_VPN_IP_INTERFACE
It was broken by #1730.
2 years ago
Roman Perepelitsa 0adbc1415b fix a silly bug introduced in the last commit (#2170) 2 years ago
Roman Perepelitsa f03d917fb0 fix network interface detection on macos (#2170)
This was broken in #2088.
2 years ago
Roman Perepelitsa 21e89cb61d bust caches 2 years ago
Zoltán Reegn b165fec0ed Add AWS partitions support to EKS kubernetes cluster names
The AWS ARN in govcloud and china looks different to the currently supported
one:

https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/using-govcloud-arns.html
https://docs.amazonaws.cn/en_us/aws/latest/userguide/ARNs.html

This change introduces support for all possible AWS partitions.
2 years ago
James Winegar d1b89dd381 Update README.md
You run containers that are based on images. The container will be deleted, but not the image.
2 years ago
Roman Perepelitsa a066b55f85 don't trust P9K_SSH if it was set with a different TTY (#2154) 2 years ago
Roman Perepelitsa 1a4b01c232 work around a bug in ohmyzsh (#2152)
The bug was introduced here: 3dd83a22a1

This causes Oh My Zsh to print \r to the terminal.
2 years ago
kvanzuijlen 35165798a8 Added kubent to KUBECONTEXT_SHOW_ON_COMMAND 2 years ago
Roman Perepelitsa 33916e91a7 add a missing lf header to p10k-lean.zsh (#2126) 2 years ago
Roman Perepelitsa c08975d0f6 Merge branch 'UtkarshVerma-master' 2 years ago
Utkarsh Verma 07b5a607d4
Add lf segment 2 years ago
Leon Satoshi 7f2950f9cc Update README.md
change from China mainland to  China in Mandarin
2 years ago
Roman Perepelitsa a7bf4c83de docs: add cpu_arch 2 years ago
Roman Perepelitsa edafcb5a7d fix bugs in cpu_arch 2 years ago
Roman Perepelitsa 9f0751c2e3 Merge branch 'clarkcox3-master' 2 years ago
Clark S. Cox 45758d95fb Use "machine" where available for CPU arch
This allows shells on macOS to display more specific CPU arch (e.g. a 64-bit intel machine will display "x86_64" instead of "i386")
2 years ago
Roman Perepelitsa 6609767abd don't invoke mktemp if it doesn't exist 2 years ago
Roman Perepelitsa 8d47270e8c don't invoke mktemp if it doesn't exist 2 years ago
Roman Perepelitsa 176f781121 assume that dotnet version may depend on the content of global.json (#2103) 2 years ago
Roman Perepelitsa cf83ab21e4 fix a bug in zap install instructions and add uninstall instructions (#2093) 2 years ago
Roman Perepelitsa 54798e0c18 Merge branch 'shwcsmack-patch-1' 2 years ago
shwcsmack d5123401be
Add reference to Zap plugin manager
I added a reference in the Readme for my favorite ZSH package manager: Zap
2 years ago
Roman Perepelitsa bc5983543a Merge branch 'ebardie-ebardie/prefer_ip_over_ifconfig' 2 years ago
Jonathan Sambrook 5691a418e0 Prefer `ip` over `ifconfig` for i/f detection.
`ifconfig`'s formatting doesn't cope well with long interface names. In
these cases it will eat up the whitespace separating the name from the
text "Link" in the output, which makes parsing the output problematic.

e.g. `ifconfig`:

    wlp0s20f0u2Link encap:Ethernet  HWaddr 00:AA:BB:CC:DD:EE

v.s `ip`:

   21: wlp0s20f0u2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc \
       mq state UP group default qlen 1000

This commit swaps the order of detection inside
`_p9k_prompt_net_iface_async()`, so that `ip` will be preferred.

`ifconfig` is deprecated by distros in favour of `ip`, so this will
often be an incredibly marginal performance boost :)

NOTE: this commit does not address the problem with using `ifconfig`. I
don't understand the zsh regex, so have not touched it.
2 years ago
Roman Perepelitsa 8c55eb4fa3 wizad: add a hint pointing to the frame when asking for frame color 2 years ago
Roman Perepelitsa 5a3109e40d replace POWERLEVEL9K_CHRUBY_SHOW_ENGINE_IF_RUBY with POWERLEVEL9K_CHRUBY_SHOW_ENGINE_PATTERN (#2072)
POWERLEVEL9K_CHRUBY_SHOW_ENGINE_PATTERN defines a pattern that
RUBY_ENGINE should match for it to be shown. Matching is done
with extended_glob.

For example, to show all values of RUBY_ENGINE except "ruby":

    POWERLEVEL9K_CHRUBY_SHOW_ENGINE_PATTERN='^ruby'

If POWERLEVEL9K_CHRUBY_SHOW_ENGINE_PATTERN is unset and
POWERLEVEL9K_CHRUBY_SHOW_ENGINE is set to true,
the behavior is the same as if POWERLEVEL9K_CHRUBY_SHOW_ENGINE_PATTERN
was set to *.
2 years ago
Roman Perepelitsa f68197a3aa Merge branch 'skipkayhil-rm-ruby-engine-if-ruby' 2 years ago
Hartley McGuire b8c6c6f42f
Add chruby config to hide RUBY_ENGINE when "ruby"
Previously, the chruby segment looks like this for standard and
non-standard ruby implementations respectively:

```
Ruby ruby 3.1.2
Ruby truffleruby 3.0.3
```

While displaying the RUBY_ENGINE is helpful for non-standard
implementations, showing it for "ruby" results in "Ruby ruby" which
feels redundant.

This commit adds a new configuration option to disable showing the
RUBY_ENGINE when it is "ruby". Other values for RUBY_ENGINE will always
display as before:

```
Ruby 3.1.2
Ruby truffleruby 3.0.3
```

This also makes the formatting more similar to the asdf segment:

```
Ruby 3.1.2
Ruby truffleruby-22.3.0
```
2 years ago
Roman Perepelitsa 8091c8a3a8 Merge branch 'mmathys-patch-1' 2 years ago
Roman Perepelitsa e4a94a8ae0 Merge branch 'patch-1' of github.com:mmathys/powerlevel10k into mmathys-patch-1 2 years ago
Roman Perepelitsa ed1b02efd5 Squashed 'gitstatus/' changes from 6dc0738c0..4b47ca047
4b47ca047 docs: s/mainland China/China/
b74da1403 docs: fix grammar
fc27662b4 Merge branch 'andresrinivasan-patch-1'
ad739b2b0 Clarify that gitstatus is included with Powerlevel10k

git-subtree-dir: gitstatus
git-subtree-split: 4b47ca047be1d482dbebec7279386a9365b946c6
2 years ago
Roman Perepelitsa cd47894197 Merge commit 'ed1b02efd5f7691d72cf9b657d939e3adc31034c' 2 years ago
Roman Perepelitsa bd0c9f4ec7 rename arch to cpu_arch and rewrite it (#1752) 2 years ago
Roman Perepelitsa f89b54faf2 Merge branch 'brent-moffit-master' 2 years ago
Roman Perepelitsa 02290d1eb9 Merge branch 'master' of github.com:brent-moffit/powerlevel10k into brent-moffit-master 2 years ago
Max Mathys 3e952468aa
"mainland China" to "China" 2 years ago
Max Mathys efffc87cf5
Rename "mainland China" to "China" 2 years ago
Roman Perepelitsa 5ee784787f fix a bug introduced in cf1b586515 2 years ago
Roman Perepelitsa cf1b586515 fix bugs introduced in 843dcf0167 2 years ago
Roman Perepelitsa 843dcf0167 survive broken FPATH (#10 2 years ago
hayas1 957249a95c Fix gcloud config directory 2 years ago
Roman Perepelitsa 4bbb198a60 fix tables broken by the last commit 2 years ago
Roman Perepelitsa b4a5379be8 Merge branch 'andresrinivasan-patch-1' 2 years ago
Roman Perepelitsa 5ca97df8fe Merge branch 'patch-1' of github.com:andresrinivasan/powerlevel10k into andresrinivasan-patch-1 2 years ago
André Srinivasan 18f939d344 Add references to Antidote
Signed-off-by: André Srinivasan <andre.srinivasan@gmail.com>
2 years ago
Roman Perepelitsa 3bfbb8294f sync fonts.md with README.md 2 years ago
Roman Perepelitsa cbca1bd8c1 docs: set font in Windows Terminal through the Settings UI 2 years ago
Roman Perepelitsa 534ace8773 Merge branch 'phwt-patch-1' 2 years ago
phwt 5d223b8351
docs: update Windows Terminal font configuration 2 years ago
Roman Perepelitsa 0493886837 clarify that quotes are necessary when specifying font name in crostini (#1934) 2 years ago
Roman Perepelitsa f9fd384d8d make zi installation instructions consistent with the rest; fix table formatting 2 years ago
Roman Perepelitsa 4a60348e07 Merge branch '0xMRTT-patch-1' 2 years ago
0xMRTT abc318b608
Add Zi plugin manager to the install list
A more detailled procedure of the installation of powerlevel10k with zi is available at [wiki.zshell.dev](https://wiki.zshell.dev/community/gallery/collection/themes#thp-romkatvpowerlevel10k)
2 years ago
Roman Perepelitsa e72264e01c don't trust cnorm as it's incorrect in some combinations of terminals and terminfo (#1699) 2 years ago
Roman Perepelitsa fd5fa09504 fix toolbox segment (#1916) 2 years ago
Roman Perepelitsa 7704f6b877 Merge branch 'christian-schulze-use-HOST-for-distrobox-detection' 2 years ago
Roman Perepelitsa 64c5f10379 Merge branch 'use-HOST-for-distrobox-detection' of https://github.com/christian-schulze/powerlevel10k into christian-schulze-use-HOST-for-distrobox-detection 2 years ago
Roman Perepelitsa 2dd6a29e4d replace a hyperlink in crostini instructions with regular text (#1934) 2 years ago
Omeir Fawaz 71e4e3288d fix typo in README 2 years ago
Roman Perepelitsa be3724bc80 typo in comments 2 years ago
Roman Perepelitsa 487a388dbd make crostini font instructions stylistically similar to the rest and copy them over to font.md (#1934) 2 years ago
Roman Perepelitsa c1c827e21d Merge branch 'alkis-crostini' 2 years ago
Alkis Evlogimenos 9a3c2f48a4 add Crostini installation instructions 2 years ago
Christian Schulze cb82b1f5d9 use HOST for distrobox detection 2 years ago
Roman Perepelitsa cf67cad465 fix the UNICODE code point for powerline "branch" icon in comments (#1911) 2 years ago
Gerald Turner 0c197ed4a5 battery plugin: Support Linux on Librem5 phone 2 years ago
Roman Perepelitsa 0bef490cda replace fig ads with installation instructions 2 years ago
Roman Perepelitsa 3ed9c1bce1 Merge branch 'ibayramli2001-fig' 2 years ago
Ilkin Bayramli 19bcd37935
Add Fig as an installation method to the README 2 years ago
Roman Perepelitsa 6b128d48d6 update alpine linux installation instructions 2 years ago
Anupam Srivastava 89ecd6539a Fixed minor spelling mistakes 2 years ago
Roman Perepelitsa 5c7ad753a2 add installation instructions for alpine; related: #1828 2 years ago
Roman Perepelitsa a3f6859a8d cleanup 2 years ago
Lucas Larson cf9a1fd02d suppress `nounset` error if `DIRENV_DIR` isn’t defined (fix #1876)
Signed-off-by: Lucas Larson <LucasLarson@riseup.net>
2 years ago
Roman Perepelitsa 74ff02a819 work around a bug in zsh 5.4.1 (#1872)
Here's the bug:

  zsh -fc 'print "${#${x}}"'

This code should print "0" but it prints "1" in zsh 5.4.1.
2 years ago
AdalZanabria 406e6aa9e4 Added missing segments to README without auto-formatting. 2 years ago
AdalZanabria d03058819d Revert "Added missing segments to README." because of auto-formatting.
This reverts commit e65e508743.
2 years ago
AdalZanabria ff531e5f2c Added missing segments to README. 2 years ago
Curtis Vogt 0b02654269 Show kubecontext when using kubeseal or skaffold 2 years ago
Roman Perepelitsa 657e184e0d disable vscode integration; it doesn't work anyway but it makes shell slower
Context: https://github.com/microsoft/vscode/pull/145610#issuecomment-1076519194
2 years ago
Roman Perepelitsa 65599411ec ignore garbage printed by vscode 3 years ago
Roman Perepelitsa e13283ec7d bug fix: strip escape sequences in instant prompt output less aggressively 3 years ago
Roman Perepelitsa f07d7baea3 minor cleanup around perlbrew 3 years ago
Roman Perepelitsa 73698935b8 Merge branch 'lmburns-perlbrew' 3 years ago
Lucas Burns 40a5cdfa6c
chore: forgot to add global variables to main 3 years ago
Lucas Burns b898d1de15
feature: added perlbrew 3 years ago
brent-moffit 59e90bd8b0 Add instant prompt for arch 3 years ago
brent-moffit 01467fae4f Change arch prompt colors to better match default themes 3 years ago
Roman Perepelitsa c0a028351f Squashed 'gitstatus/' changes from f889c13d1..6dc0738c0
6dc0738c0 release v1.5.4
6b3e7cf2f update mbuild script for the new release infra
12b2457ae release v1.5.4

git-subtree-dir: gitstatus
git-subtree-split: 6dc0738c0e5199b0ae47d9693874e7d43c7f8f29
3 years ago
Roman Perepelitsa 123136c0e7 Merge commit 'c0a028351ff9a611c4061938ebd5ec4cafb900eb' 3 years ago
Roman Perepelitsa 5fe28f0a01 bug fix: correctly parse kubectl config when current-context has metacharacters (#1767) 3 years ago
Roman Perepelitsa 4b21cd06ff Squashed 'gitstatus/' changes from b226d8e06..f889c13d1
f889c13d1 build: clean up dragonfly support (#297)
2b6366fbd Merge branch 'msvetlik-dragonflybsd-support'
409c791eb Added detection of DragonflyBSD and tested compilation on v6.2.1

git-subtree-dir: gitstatus
git-subtree-split: f889c13d18fbf6f3109d6889be34d50af04d99b9
3 years ago
Roman Perepelitsa a83e53005f Merge commit '4b21cd06ffeb5706b017c78b13c2eaf40d7deac1' 3 years ago
brent-moffit c5203a3da2 Add `arch` prompt for displaying CPU architecture
Adds the `arch` prompt to `p10k.zsh`, `ARCH_ICON` to `icons.zsh`, and commented entries in the default configs
3 years ago
Roman Perepelitsa 8a676a9157 fix shell integration with kitty 3 years ago
Roman Perepelitsa bee6e09262 Squashed 'gitstatus/' changes from 6eb490ab..b226d8e0
b226d8e0 bug fix: don't crap out when TMPDIR is unset

git-subtree-dir: gitstatus
git-subtree-split: b226d8e060db82ac68f1b00c49d1fc85abdbe56e
3 years ago
Roman Perepelitsa 4f143b7b97 Merge commit 'bee6e09262a6145fc178ddc85c656da4bb83a9a9' 3 years ago
Roman Perepelitsa d6f8c47761 survive broken $TMPDIR 3 years ago
Roman Perepelitsa 5014de0541 Squashed 'gitstatus/' changes from e02d9eed..6eb490ab
6eb490ab survive broken $TMPDIR
94bf4fc2 add ppc64 support to the build script

git-subtree-dir: gitstatus
git-subtree-split: 6eb490ab86118ad063224e4d50b6b05bea7dd12c
3 years ago
Roman Perepelitsa cead0349c5 Merge commit '5014de0541201716dc4ee6f544321ac4e3d7431e' 3 years ago
Roman Perepelitsa 6c71862c5f don't set OS, DEFAULT_COLOR and DEFAULT_COLOR_INVERTED
See #1735.
3 years ago
Roman Perepelitsa 9e0ef918db fix ZeroTier network interface regex
From https://forwardingplane.net/configuration-archive/renaming-interfaces-under-linux/:

> ZeroTier has the inconsistency of using zt* on some platforms and ztublkahlah on others.

They mean zt[0-9]+ and zt[a-z0-9]+.
3 years ago
Roman Perepelitsa 02710eb568 Merge branch 'Mehyar-ALS-patch-1' 3 years ago
Mehyar e511c36ec6
Add ZeroTier to the list of VPNs
ZeroTier users can also see their VPN IP when enabling the vpn_ip option.
3 years ago
Roman Perepelitsa 3d994b033b work around bugs in WSL where it reports more swap being used than the total available (#1724) 3 years ago
Roman Perepelitsa 0f8a77d47d increase the minimum required zsh version from 5.1 to 5.3 (#1722) 3 years ago
Roman Perepelitsa 161f4c1f04 respect VIRTUAL_ENV_PROMPT if its value is different from the default (#1718) 3 years ago
Roman Perepelitsa b8ddcd4c17 docs: clean up font instructions for xterm and copy them to README.md 3 years ago
Roman Perepelitsa c4d3ab0ae0 Merge branch 'pstekl-master' 3 years ago
pstekl 69909a7a1f
Add xterm to font configuration section 3 years ago
Roman Perepelitsa fdbde52c20 docs: sort the table of segments 3 years ago
Roman Perepelitsa 6fae3a169b add toolbox segment to the docs (#1713) 3 years ago
MenkeTechnologies 683a485232 remove duplicate the 3 years ago
Roman Perepelitsa e1c52e08d4 add an icon for amazon linux (#1706) 3 years ago
Andrea Cervesato (TheKoma) fba50d9671 Added gsutil as is the main "other command" in GCP 3 years ago
Roman Perepelitsa 66c0181f76 doc: s/Kitty/kitty/ 3 years ago
Roman Perepelitsa 67ac98d515 doc: kitty v0.24.0 has been released (the first version with shell integration) 3 years ago
Roman Perepelitsa c8160f2954 Squashed 'gitstatus/' changes from f1cf61b24..e02d9eedd
e02d9eedd fix cwd detection when it has weird characters
78c171590 Loongarch support (#290)
be6396b1a fix pkg_add command on openbsd (#282)
f1c89585a avoid ksh if possible (it's broken; see #282)
22407d6fd bug fix: correctly resolve pwd when it contains control chars

git-subtree-dir: gitstatus
git-subtree-split: e02d9eedd9d8f3689e6a6cdccec70b55cf87dca6
3 years ago
Roman Perepelitsa 2079d8ecbe Merge commit 'c8160f29543a2f57ae7149103deefa029fd4e861' 3 years ago
Roman Perepelitsa 3d3b24c419 work around bugs in WSL where it /proc/pid/cwd reports an alias drive 3 years ago
Roman Perepelitsa 7354688123 fix cwd handling when the current dir is '/foo\bar' (#1697) 3 years ago
Roman Perepelitsa dd3dcfaf51 make `toolbox` segment work with distrobox (#1696) 3 years ago
Roman Perepelitsa ced7788012 docs: fix indentation 3 years ago
Roman Perepelitsa ab321a2a03 docs: clean up puTTY font instructions 3 years ago
Roman Perepelitsa d99df7d12d Merge branch 'ajanian-master' 3 years ago
Andrew Janian 0d6202c077 add puTTY to the install section including not about a bug in versions prior to 0.75 3 years ago
Roman Perepelitsa ed70c90c2d fix a bug with URL-escaping for directory links (#1687) 3 years ago
Roman Perepelitsa c9bc2f5a32 fix POWERLEVEL9K_TERM_SHELL_INTEGRATION 3 years ago
Roman Perepelitsa 2e58e3888e add POWERLEVEL9K_TERM_SHELL_INTEGRATION parameter that enables OSC 133 marks 3 years ago
Roman Perepelitsa cde05cfa7b add a link to romkatv/zsh-bench#instant-prompt (should really copy some of that content over to p10k; maybe later) 3 years ago
Roman Perepelitsa 00dd4ae009 docs: shrink "getting started" 3 years ago
Roman Perepelitsa 370535af45 explicitly set LC_ALL when starting docker 3 years ago
Roman Perepelitsa da5a4cdbec add high-level table of contents at the top and low-level table of contents in each section; remove the full table of contents from the bottom 3 years ago
Roman Perepelitsa 83f773caae doc: remove most content from "is it fast to load" section 3 years ago
Roman Perepelitsa 356ce68f69 doc: remove most content from "is it really fast" section 3 years ago
Roman Perepelitsa 6692245f3e hide all screen recordings under <details> in the hope that #anchors will work properly 3 years ago
Roman Perepelitsa 09ece9601f grammar in the instant prompt faq 3 years ago
Roman Perepelitsa 608bd2c88b expand instant prompt faq 3 years ago
Roman Perepelitsa 469baa6221 url-escape dir properly when POWERLEVEL9K_DIR_HYPERLINK is set 3 years ago
Roman Perepelitsa 57d0274b88 fix bugs in dir and several other segments when cwd contains control characters 3 years ago
Roman Perepelitsa 2e8a8f1d63 fix a bug that causes VISUAL_IDENTIFIER_COLOR to leak into content 3 years ago
Roman Perepelitsa a23c4314a1 doc: update "horrific mess when resizing terminal window" section
- Don't say it's a bug in Zsh. It's more complicated than that.
- Mention that the the issue can be avoided by using Kitty.
- Do not mention that the issue can also be avoided by using
  zsh4humans (even though it's true). If you, dear reader, see this,
  give zsh4humans a try.
3 years ago
Roman Perepelitsa 4543076483 when using tmux, write unwrapped OSC 133 in addition to wrapped; the new integrated tmux uses them when resizing 3 years ago
Roman Perepelitsa 3091ffbd86 bust caches 3 years ago
Roman Perepelitsa fde8bf62d4 fix prefix-based formatting of numbers that are slightly below the boundary (#1664) 3 years ago
Roman Perepelitsa abc5df446d attempt to fix asdf when some files have windows line endings (#1653) 3 years ago
Roman Perepelitsa e181bc0653 Squashed 'gitstatus/' changes from e26996460..f1cf61b24
f1cf61b24 work around a bug in IP-guard

git-subtree-dir: gitstatus
git-subtree-split: f1cf61b241a2a34514a8ff5f71dfb79a99d85c7c
3 years ago
Roman Perepelitsa 3380f7503e Merge commit 'e181bc0653ae15ba5730a65b253d499bf22a31bf' 3 years ago
Roman Perepelitsa a9f208c8fc don't auto-start configuration wizard if it's likely that zshrc is broken
This change is an attempt to automate this:
https://github.com/romkatv/powerlevel10k#configuration-wizard-runs-automatically-every-time-zsh-is-started
3 years ago
Zura Kurtanidze 6520323fdb Delete duplicate word "using using"
Hi, I removed duplicate word in the default configuration file
3 years ago
Roman Perepelitsa e2447322e0 Squashed 'gitstatus/' changes from eaf430112..e26996460
e26996460 survive broken shasum
b1825b29a make bash bindings work with nounset

git-subtree-dir: gitstatus
git-subtree-split: e269964607042ef0fdbda2d7af74ef9c8f618cf4
3 years ago
Roman Perepelitsa d281e595b3 Merge commit 'e2447322e0be4eddb84196f05952f91fa3c6f37e' 3 years ago
Roman Perepelitsa a55955c5cf enable bracketed paste when printing instant prompt 3 years ago
Roman Perepelitsa dce00cdb5d docs: typo 3 years ago
Roman Perepelitsa 85e31542dd wizard: underline paths instead of bolding in the success message 3 years ago
Roman Perepelitsa 99edd12e00 grammar 3 years ago
Roman Perepelitsa faddef4a22 add faq entries about enabling direnv and exporting GPG_TTY (#702) 3 years ago
Roman Perepelitsa b4615f5e00 add _p9k__raw_msg for direnv notifications in zsh4humans 3 years ago
Roman Perepelitsa ed0bd29416 Merge commit '1af638543631f2e7db64829c7412ed007047fa81' 3 years ago
Roman Perepelitsa 1af6385436 Squashed 'gitstatus/' changes from cd98a3c2..eaf43011
eaf43011 when downloading gitstatusd, try curl/wget with user configs before trying without (https://github.com/romkatv/powerlevel10k/issues/1606)

git-subtree-dir: gitstatus
git-subtree-split: eaf43011246e359881931647747e8756a73a143a
3 years ago
Roman Perepelitsa 6441a01dd3 survive non-writable $TTY 3 years ago
Roman Perepelitsa edd98053cc disable icanon on the tty after printing instant prompt; this way keys like Ctrl-R and Ctrl-D will get through to zle 3 years ago
Roman Perepelitsa 5acedce0b0 speed up pre-redraw hook 3 years ago
Roman Perepelitsa 3e515a75d2 remove obsolete nordvpn comments 3 years ago
Roman Perepelitsa ed45177e19 fix nordvpn; it was broken by the latest upstream update (#1590) 3 years ago
Charles Timko 0ce9df66d2
Add RHEL to the OS Icon lists (#1581)
* Add RHEL to the OS Icon lists
3 years ago
Roman Perepelitsa 7a72acf563 clean up font instructions for yakuake 3 years ago
Roman Perepelitsa fcfeebfb53 Merge branch 'ilsteiner-patch-1' 3 years ago
Isaac Lebwohl-Steiner 0122a63834
Add instructions to manually set font on Yakuake 3 years ago
Roman Perepelitsa 543e2d59cf change formatting in the font installation instructions to make it more obvious where each step begins and ends 3 years ago
Roman Perepelitsa 0745592886 fix a spello in comments in the generated .p10k.zsh 3 years ago
Roman Perepelitsa 20eb8c64bf Squashed 'gitstatus/' changes from edd92f621..cd98a3c28
cd98a3c28 rebuild gitstatusd-freebsd-amd64 on freebsd 13
b03580cb0 rebuild gitstatusd-freebsd-amd64 (now with proper version)
3c95a47dc update version to v1.5.3
e3a3cd122 rebuild gitstatusd-freebsd-amd64 with clang (#262)
6aed2ae95 compile with clang on freebsd by default (#262)

git-subtree-dir: gitstatus
git-subtree-split: cd98a3c2849600982aa1b7d03f66784710106291
3 years ago
Roman Perepelitsa d2f78d4b29 Merge commit '20eb8c64bf2520e20739610acb503c8729867a5e' 3 years ago
Roman Perepelitsa 4f3d2ffe72 new prompt segment: toolbox (https://github.com/containers/toolbox) #1560 3 years ago
Roman Perepelitsa c5c9178341 update a link to visual-studio-code-font-settings.jpg (now with annotations) 3 years ago
Roman Perepelitsa c2c3171927 extra verbose instructions for vscode font changes 3 years ago
Roman Perepelitsa b5f4d27c74 add a screenshot of vscode font settings 3 years ago
Roman Perepelitsa 2c7241c43d add an extra step to the uninstallation instructions to delete cache files (#1561) 3 years ago
Roman Perepelitsa b3b0efb69f work around bugs in terminals and window managers by essentially disabling prompt_sp (but keeping prompt_cr) in instant prompt for new TTYs 3 years ago
Roman Perepelitsa 10ad57cc6b Squashed 'gitstatus/' changes from 2ecd9907..edd92f62
edd92f62 build: more debug info in case wget fails
1cfcb46c build: add a workaround for systems with broken wget

git-subtree-dir: gitstatus
git-subtree-split: edd92f6210afb16411274e1d6060c6a68bd1e999
3 years ago
Roman Perepelitsa e362b69735 Merge commit '10ad57cc6b73b9ed51474edbd5235e6b5f2fd16b' 3 years ago
Roman Perepelitsa 0a1946b965 bug fix: display the intended battery icon when using legacy configs (#1530) 3 years ago
elProxy 379b97e4e7
Fix after #1544 (#1547)
Well, that's embarassing...
3 years ago
elProxy 277ff8b414
Add support for AWS_REGION with fallback to AWS_DEFAULT_REGION (#1544)
See https://fossies.org/linux/aws-cli/CHANGELOG.rst#section-133
3 years ago
Roman Perepelitsa 80ec734a95 Squashed 'gitstatus/' changes from 845f492f..2ecd9907
2ecd9907 add logging to debug https://github.com/romkatv/powerlevel10k/issues/1477
74010456 add a TODO to fix #254
864f1caf Trim '\w' part of bash prompt. (#253)

git-subtree-dir: gitstatus
git-subtree-split: 2ecd990706255d2000fedbde3b2d2353f63d69a1
3 years ago
Roman Perepelitsa ec44300155 Merge commit '80ec734a953d930838ea6839923c97c3da880a0d' 3 years ago
Roman Perepelitsa 25e5f5985f spello 3 years ago
Roman Perepelitsa 5669c12c66 Revert "add availability to display or not Terraform version"
This reverts commit 20b87731de.
3 years ago
Roman Perepelitsa e7629449c6 spello 3 years ago
Roman Perepelitsa ce7d4a4cd3 Merge branch 'ptavares-master' 3 years ago
Patrick Tavares 6aeb13b08a add terraform_version segment to the list of available segments 3 years ago
Patrick Tavares 20b87731de add availability to display or not Terraform version
Show Terraform version segment only when *.tf files are present in current directory
3 years ago
Eric Nielsen 32e76e7721
Update README.md (#1532)
with new changed from version 1.5.0 of Zim.
3 years ago
ahillio 46a3e51896
readme: make 2steps for oh-my-zsh installation explicit. (#1526) 3 years ago
Roman Perepelitsa 799c22f63b Squashed 'gitstatus/' changes from 1edd9e62..845f492f
845f492f build: target march armv8-a instead of armv8
cf21109b build: respect CXX environment variable

git-subtree-dir: gitstatus
git-subtree-split: 845f492f777af84e50b9a4820c7b08729c841f0c
3 years ago
Roman Perepelitsa 8f798f986a Merge commit '799c22f63b93e9d1ab8f01473bf9ebd2e9750f43' 3 years ago
Roman Perepelitsa e3c8529052 doc: typo 3 years ago
NickVeld c23f3c3c10
README: Windows Terminal "default"->"defaults" key (#1499) 3 years ago
Roman Perepelitsa 5e1c1caeb1 doc: spello 3 years ago
Roman Perepelitsa 70ae5810d8 Squashed 'gitstatus/' changes from 0440e38b..1edd9e62
1edd9e62 build: respect standard compiler/linker env vars and fortify by default

git-subtree-dir: gitstatus
git-subtree-split: 1edd9e621ec5c8bf038767e529194b5c53b36352
3 years ago
Roman Perepelitsa a38a1f5be1 Merge commit '70ae5810d81f941a93e2077a2aa080f341deb96e' 3 years ago
Roman Perepelitsa 83d80fa308 don't leak 'state' local parameter 3 years ago
Roman Perepelitsa 2c135dd631 make terraform_version consistent with other *_version segments (#1487) 3 years ago
Roman Perepelitsa 942c4cf640 Merge branch 'alexganwd-master' 3 years ago
Alejandro Gandara dae5f7f1c9 * Added cache to terraform --version 3 years ago
Alejandro Gandara 9f98915167 * Added new module for showing in prompt the active terraform version.
* Prompt shows, the terraform version in this format: Terraform v0.12.13 . If only if a valid terraform command is used, or an alias to it.

The use case: We have a need to constantly change between terraform versions depending on what project we are working on, it is easy to by mistake upgrade the wrong project to the latest terraform version. This is why the prompt is shown in red as soon as you type terraform, this is a good way to remind you to double check this is the terraform version you want to use.

Future improvements:
Detect current terraform version by checking the terraform workspace state version, and change the terraform color prompt from red to green if you're using the same version.
3 years ago
Alejandro Gandara f717a91f55 * Added new module for showing in prompt the active terraform version.
* Prompt shows, the terraform version in this format: Terraform v0.12.13 . If only if a valid terraform command is used, or an alias to it.

The use case: We have a need to constantly change between terraform versions depending on what project we are working on, it is easy to by mistake upgrade the wrong project to the latest terraform version. This is why the prompt is shown in red as soon as you type terraform, this is a good way to remind you to double check this is the terraform version you want to use.

Future improvements:
Detect current terraform version by checking the terraform workspace state version, and change the terraform color prompt from red to green if you're using the same version.
3 years ago
Chris Williams 1e7be00e04
show kubecontext show for 'flux' (#1480)
Support for flux v2 CLI

Co-authored-by: Chris Williams <chris.williams@amwell.com>
3 years ago
Roman Perepelitsa 4bcc519547 add 'minify' make target 3 years ago
Roman Perepelitsa 077abf95e0 Squashed 'gitstatus/' changes from 4b4226ca..0440e38b
0440e38b sort files lexicographically
1c3157e9 don't minify from pkg target

git-subtree-dir: gitstatus
git-subtree-split: 0440e38b336aaf992aabf3649bf4a7f65f396c0a
3 years ago
Roman Perepelitsa 05d71fe82c Merge commit '077abf95e0a3c6325a6cdd9761cab75b2f5468c6' 3 years ago
Roman Perepelitsa 63a009669a Squashed 'gitstatus/' changes from 68bf9e0d..4b4226ca
4b4226ca add 'minify' make target and invoke it from 'pkg'

git-subtree-dir: gitstatus
git-subtree-split: 4b4226ca86fef6d0491ab9e863c9df6864dc9642
3 years ago
Roman Perepelitsa 7f4a2741b5 Merge commit '63a009669a7ed6aa6040f0af008adfb62829188c' 3 years ago
Roman Perepelitsa 7759063b74 Squashed 'gitstatus/' changes from 76182238..68bf9e0d
68bf9e0d build: generate byte-for-byte identical gitstatusd if the compiler supports -ffile-prefix-map
d03e8edc add support for s390x architecture
b32bea51 add a few architectures to the build script
7001409e bash: escape non-printable ANSI sequences (#247)

git-subtree-dir: gitstatus
git-subtree-split: 68bf9e0da3695ae989d523527643bef3f88e86ea
3 years ago
Roman Perepelitsa f4668bc194 Merge commit '7759063b7485ca0701fc8ba1961d0e53568ddd59' 3 years ago
Roman Perepelitsa 3213e2e17f docs: grammar 3 years ago
Roman Perepelitsa fd7313a5e7 replace @{u} with @{upstream} in the docs (it's the same thing but clearer) 3 years ago
Roman Perepelitsa 0c862a1307 add zwc make target 3 years ago
Roman Perepelitsa f1ff680487 Squashed 'gitstatus/' changes from 260a5f4b..76182238
76182238 add zwc make target
ea398d90 update libgit2 ref (https://github.com/romkatv/powerlevel10k/issues/1428)

git-subtree-dir: gitstatus
git-subtree-split: 7618223859f614a76ed8019f1a60ee3df18984cf
3 years ago
Roman Perepelitsa 73eff3a033 Merge commit 'f1ff6804871d47381b9bd398a60f4c77174fd1d3' 3 years ago
Roman Perepelitsa c003c253e8 respect POWERLEVEL9K_INSTANT_PROMPT_COMMAND_LINES if it is explicitly set even when using z4h 3 years ago
Roman Perepelitsa 515422c727 fix a bug that can cause instant prompt to be duplicated in z4h 3 years ago
Roman Perepelitsa 67f494cf54 docs: cross-link two faq entries 3 years ago
Roman Perepelitsa 606d4a85a9 readme: update git commands for ahead/behind arrows 3 years ago
Roman Perepelitsa 717573d845 presume that `node --version` may depend on package.json (#1388) 3 years ago
Roman Perepelitsa a49f90d3ba cleanup 3 years ago
Roman Perepelitsa 4e4c14927f update windows terminal font instructions to accound for the fact that they've changed the default settings.json (#1443) 3 years ago
Roman Perepelitsa 2e0989c018 Merge commit '038de6f78b21171615d0b4628471e71efe10d77e' 3 years ago
Roman Perepelitsa 038de6f78b Squashed 'gitstatus/' changes from 96b520b2..260a5f4b
260a5f4b fix a bug in the build script that prevented it from working when using a newer git with init.defaultBranch override in the global config (#242)

git-subtree-dir: gitstatus
git-subtree-split: 260a5f4bc9776d41d500a51464249ce5e555a99e
3 years ago
Roman Perepelitsa f5d61840ae Merge commit '96f3ca173331c5dba505d2ef5106cb0d605ec3be' 3 years ago
Roman Perepelitsa 96f3ca1733 Squashed 'gitstatus/' changes from 113f1f69..96b520b2
96b520b2 build v1.5.1 binaries for all platforms
ffeb0507 bump version to v1.5.1
1bcbea07 mbuild: disable pacman upgrades on msys
39dbb92f log a warning if unable to parse packed-refs
a9d70ec0 add `-r` flag to gitstatus_start in bash bindings (#241)
abbf9a79 don't use static_assert with one argument as it's not available prior to c++17 (#239)
f8c396e4 drop all tags if packed-refs doesn't have a header line (https://github.com/romkatv/powerlevel10k/issues/1428)

git-subtree-dir: gitstatus
git-subtree-split: 96b520b248ca872646e27b3df4535898356e4637
3 years ago
Roman Perepelitsa 4ba3c010f6 display "wip" in git status if the latest commit's summary contains "wip" or "WIP" (#1425) 3 years ago
Roman Perepelitsa b9c62ca028 cleanup 3 years ago
Roman Perepelitsa ba83466e1d Squashed 'gitstatus/' changes from 6d00edd0..113f1f69
113f1f69 release gitstatusd-linux-x86_64 v1.5.0
e193be52 expose HEAD's commit message
815301f1 do not redefine `exec` and `builtin` in bash bindings (#235)
97c2aa17 Make `--version-glob` to receive an argument (#216)
95e549fd Support building on OpenBSD (#208)
b054ddf2 make homebrew instructions work on systems other than darwin-x86_64 (#205)
98f99ade fix brew formula check

git-subtree-dir: gitstatus
git-subtree-split: 113f1f698667d12906d97e3818aec5d760dc6e3d
3 years ago
Roman Perepelitsa f217e4a39a Merge commit 'ba83466e1da75d9260ebbb145215d9c46d6eadf6' 3 years ago
Roman Perepelitsa 77fa0e6dcc clarify that Windows Terminal is the one from Microsoft 3 years ago
Mark Adamson d87d557b0f
Correct name of Windows Terminal in README (#1424) 3 years ago
Roman Perepelitsa c7ad00b5a5 add P9K_AWS_PROFILE and P9K_AWS_REGION and use it in default configs 3 years ago
Roman Perepelitsa 10918387b3 Merge branch 'alexjurkiewicz-aws-region' 3 years ago
Alex Jurkiewicz aa4d366341 Add region support for aws element 3 years ago
Zachary Palumbo 35acee119d
Fix icon padding for VCS bookmark icon (#1414) (#1415) 3 years ago
Roman Perepelitsa c59720647a fix asdf, was broken by 1ad8e5759e (#1409) 3 years ago
Roman Perepelitsa a3494a52d7 don't leak 'token' local variable in parser (#1407) 3 years ago
Roman Perepelitsa f774df6c76 pyenv: skip lines that start with "#" (#1376) 3 years ago
Roman Perepelitsa 69d3650958 hide python version in pyenv in lean/classic/rainbow if the rest of the content starts with it (#1376) 3 years ago
Roman Perepelitsa 1ad8e5759e when searching for files in ancestor directories, do match in $HOME (#1376) 3 years ago
Roman Perepelitsa 4d2346da0a set P9K_PYENV_PYTHON_VERSION correctly when dealing with multiple pyenv versions (#1376) 3 years ago
Roman Perepelitsa 0ab7e1ccfd when resolving `python --version`, handle pyenv shims specially (#1378) 3 years ago
Maxim Baz 9c034101fe
Add xplr segment (#1396) 3 years ago
Roman Perepelitsa f924646194 add P9K_IP_{RX,TX}_BYTES_DELTA to the list of parameters available within POWERLEVEL9K_IP_CONTENT_EXPANSION (#1392) 3 years ago
Roman Perepelitsa 8d1daa4e63 disable colors in the output of taskwarrior; this time for real (#1365) 3 years ago
Roman Perepelitsa b69bb45ab1 disable colors in the output of taskwarrior (#1365) 3 years ago
Roman Perepelitsa 48ff2e8065 fix style in font instructions 3 years ago
alsoGAMER 836332f578
Font instructions for Asbrú Connection Manager (#1362) 3 years ago
Roman Perepelitsa 607befe822 bump version (#1361) 3 years ago
Roman Perepelitsa cd865da150 expand c-escapes in kubectl (#1361) 3 years ago
Roman Perepelitsa b55ad16bdf bug fix: segments whose state contains numbers could not be hidden (#1353) 3 years ago
Roman Perepelitsa 30bd9461b3 replace POWERLEVEL9K_LOAD_THRESHOLD with POWERLEVEL9K_LOAD_{WARNING,CRITICAL}_PCT (#1340) 3 years ago
Tim Ysewyn 8dc91004cb
Fix gcloud CLI (#1342)
This reverts #1324 (d3de2e5).
4 years ago
Klas Mellbourn 8b2aab74d4
Add CPU load threshold setting (#1340) 4 years ago
Éverton Arruda 4d15cf977e
Get active gcloud profile using `list` command (#1331)
`gcloud config configure describe` command does not have `--filter` option. To filter
the active profile using `--filter` it is necessary to use `gcloud config configure list`
command
4 years ago
Paweł Cembaluk af86b53047
Added urxvt to manual font installation section. (#1326) 4 years ago
Roman Perepelitsa eafd78c3e0 respect POWERLEVEL9K_SHORTEN_DIR_LENGTH when POWERLEVEL9K_SHORTEN_STRATEGY=truncate_to_last 4 years ago
Ramon Lucas d3de2e558c
Sets the filter for the current gcloud profile (#1324)
When you have multiple profiles set up, you should only search for what is currently active.
4 years ago
Daniel 58f5470cd9
Add font configuration instructions for WezTerm (#1313) 4 years ago
Roman Perepelitsa 7d786b9c50 remove all CR from prompt (#1304 and #1305) 4 years ago
Roman Perepelitsa d28e84ca70 don't display git tag when on a branch (#1294) 4 years ago
wzy 6d545d5dd0
Fix #1286 (#1288) 4 years ago
bcochofel 3920940ea8
add fluxctl and stern to show kubecontext (#1268) 4 years ago
bcochofel 6a7115b35b
add azure classes (#1274) 4 years ago
Roman Perepelitsa b816abfed0 work around bugs in add-zle-hook-widget (#1238) 4 years ago
Dhananjay Tanpure d26bdcd601
Added wlan(w) to regular expression of network interfaces. (#1224)
Name of network interface is generally wlan0 or wlp3s0.
4 years ago
Jaehee Hong 7b0698debf
README Homebrew installation script fix (#1222)
make homebrew installation instructions work on darwin-arm64 and linux
4 years ago
Thomas Lauf 68abcc86d4
Change icon for the timewarrior segment to '' (#1217)
Icon was changed in c65260aaab from '🛡️' to ''
4 years ago
Roman Perepelitsa 00232d1b6d doc cleanup 4 years ago
Roman Perepelitsa a2695675e6 Merge branch 'joxxperez-master' 4 years ago
Roman Perepelitsa a20dcd0284 Merge branch 'master' of https://github.com/joxxperez/powerlevel10k into joxxperez-master 4 years ago
Roman Perepelitsa 4fa8943960 doc cleanup 4 years ago
Roman Perepelitsa f0af094382 Merge branch 'YorkGrizzly-master' 4 years ago
Roman Perepelitsa eadc0d7653 Merge branch 'master' of https://github.com/YorkGrizzly/powerlevel10k into YorkGrizzly-master 4 years ago
Julio Carlos Barrera Juez 33f20f5eae
Add tailscale in VPN network interface regex. (#1208) 4 years ago
joxxperez a43748d427
Add font installation instructions for WSLtty 4 years ago
YorkGrizzly 8bafd1a2ee
Update font.md 4 years ago
YorkGrizzly ea97f031b4
Update font.md 4 years ago
YorkGrizzly 29f16b61e6
Update font.md 4 years ago
Roman Perepelitsa d524164020 scroll the screen before printing prompt 4 years ago
Roman Perepelitsa 0513e0fee4 simplify `uname -m` matching on Windows platforms 4 years ago
Roman Perepelitsa 59db4252bb uncomment BACKGROUND and FOREGROUND parameters in p10k-classic.zsh; comments confuse users (#1182) 4 years ago
Roman Perepelitsa dd62469cc7 fix ram segment on darwin-arm64 (#1181)
Darwin arm64 uses 16kB pages rather than 4kB.

Thanks, @johnalanwoods!
4 years ago
Osman Tas 61c63eea6b
Update os icon at zsh.exe on git for windows (#1180)
* Update os icon for windows

Windows icon is not shown on git for windows zsh.exe
Same update also added to wizards.zsh file.

* Update os icon for windows

Windows icon is not shown on git for windows zsh.exe
Same update also added to p10k.zsh file.
4 years ago
Roman Perepelitsa 5ea5d4bc19 disable re_match_pcre, otherwise we can get an error when users enable this option without having zsh/pcre module 4 years ago
Roman Perepelitsa 9609a835ca Squashed 'gitstatus/' changes from 630915cc..6d00edd0
6d00edd0 use a native binary on darwin-arm64
4994f160 add a build server for darwin-arm64
0e922813 invoke port with sudo
576571c7 support macports in addition to homebrew when building on macos
b476570a remove trailing whitespace

git-subtree-dir: gitstatus
git-subtree-split: 6d00edd0bfd1d65a3cbcebfc6e679e8c43726acc
4 years ago
Roman Perepelitsa 9c3ecab81e Merge commit '9609a835ca2eb3089e35269a05369833e9ec0ba2' 4 years ago
Roman Perepelitsa 033e01a272 docs: more info about greyed out vcs 4 years ago
Samuel Gräfenstein 38a5492b5f
Remove trailing whitespace (#1173) 4 years ago
Roman Perepelitsa a5d0525c6a refactor my_git_formatter to make it easier to change it so that tag is always displayed 4 years ago
Roman Perepelitsa 4807bd8da2 doc cleanup 4 years ago
Roman Perepelitsa 7a6eef4918 docs: make `p10k configure` method of installing MesloLGS NF for iTerm2 more prominent 4 years ago
Roman Perepelitsa b9b3399b35 nordvpn: pick up nordvpnd.sock from the new location (changed with the latest nordvpn update); remove MISSING state; (#1167) 4 years ago
Roman Perepelitsa fc854fa719 fix a comment above POWERLEVEL9K_OS_ICON_CONTENT_EXPANSION in lean style 4 years ago
Roman Perepelitsa e8afa806ce wizard: allow uppercase letters in choices 4 years ago
Josh Skidmore c14fe96b7c
remove accidental logging (#1161) 4 years ago
Roman Perepelitsa 439ce3ed4e dir: add _NON_EXISTENT similarly to _NON_WRITABLE (requires POWERLEVEL9K_DIR_SHOW_WRITABLE=v3)
See #1160.
4 years ago
Roman Perepelitsa 1d99a0bac3 wifi: recognize SSID with spaces (#1152) 4 years ago
Roman Perepelitsa b90b36251d fix iterm2 integration when not using zsh4humans v5 (#192 and #1138) 4 years ago
Roman Perepelitsa 2c3bcd8b5d use tmux bypass in iterm2 integration only if _z4h_iterm_cmd is defined 4 years ago
Roman Perepelitsa c7914c051d remove spurious slashes from tmux bypass sequences 4 years ago
Roman Perepelitsa 96646e8b9c enable iterm2 shell integration when running in tmux in zsh4humans 4 years ago
ratijas ecf1de25a4
Makefile: optimize recursive invocation (#1127) 4 years ago
Roman Perepelitsa ff79e502ad don't allow overriding the path to zsh 4 years ago
Roman Perepelitsa 29759b7b0a Squashed 'gitstatus/' changes from e2276e72..630915cc
630915cc don't allow overriding the path to zsh

git-subtree-dir: gitstatus
git-subtree-split: 630915ccb1700f1f880d25cb04da23bf68fc4293
4 years ago
Roman Perepelitsa bc3158cba5 Merge commit '29759b7b0a83e08ce52dd240c9463f2c8090c416' 4 years ago
Roman Perepelitsa a7f417245d Squashed 'gitstatus/' changes from 4211e33b..e2276e72
e2276e72 install: fix the check for rosetta on darwin-arm64

git-subtree-dir: gitstatus
git-subtree-split: e2276e729e0155391126ee4aa090aa38b345b9fd
4 years ago
Roman Perepelitsa 9d6444a557 Merge commit 'a7f417245dc21b666f5647c4a0d55a1f51fe6cac' 4 years ago
Roman Perepelitsa 622069e60f Squashed 'gitstatus/' changes from 1dcba393..4211e33b
4211e33b bug fix: make install work in standalone mode

git-subtree-dir: gitstatus
git-subtree-split: 4211e33b0b9ed9ad41898eb5a2b4f6a4a37b1db2
4 years ago
Roman Perepelitsa 381bd09e67 Merge commit '622069e60f9573c714f482dd6c76858229f4732a' 4 years ago
Roman Perepelitsa 4050729e48 wizard: after installing the font on iTerm2, ask for system reboot if iTerm2 session restoration is enabled 4 years ago
Roman Perepelitsa 7cb7ee07be docs: add missing colons 4 years ago
Roman Perepelitsa ade5b86226 docs: s/Windows Terminal/Microsoft Terminal/ 4 years ago
Roman Perepelitsa e1e50dc84c Merge branch 'ravinderpal-patch-1' 4 years ago
Ravinder Pal Singh 8db9836617
Added instructions for IntelliJ 4 years ago
Roman Perepelitsa 98a8ec6f31 prompt_length cleanup 4 years ago
Roman Perepelitsa 685682da90 Revert "docs: experiment with image dimensions"
This reverts commit 507018f079.
4 years ago
Roman Perepelitsa 507018f079 docs: experiment with image dimensions 4 years ago
Roman Perepelitsa fb89173a42 Squashed 'gitstatus/' changes from 313fa4f1..1dcba393
1dcba393 bash bindings: provide better diagnostic for the common errors in gitstatus_start
603fb2ce move the rosetta check to `install`
3829edac provide better diagnostic for the common errors in gitstatus_start
e8c9d9cd propagate error messages from install to gitstatus_start; add a special diagnostic for rosetta2

git-subtree-dir: gitstatus
git-subtree-split: 1dcba3930654c54976f112b96acf2ce23006d9e5
4 years ago
Roman Perepelitsa 7e363af9ed Merge commit 'fb89173a4257e0cfe3bfc772bc0cdbccd61e3be0' 4 years ago
Roman Perepelitsa 98b96e06cc Squashed 'gitstatus/' changes from ae213c54..313fa4f1
313fa4f1 make target pkg work with `make -C`

git-subtree-dir: gitstatus
git-subtree-split: 313fa4f1bfabe99a04027d0bdf6cbecff2e963c7
4 years ago
Roman Perepelitsa 6b254621e7 Merge commit '98b96e06cc98ef2578adbf83ac4bb35a74485e8f' 4 years ago
Roman Perepelitsa 139413f535 add Makefile 4 years ago
Roman Perepelitsa 39cf063480 Squashed 'gitstatus/' changes from 90cbb46b..ae213c54
ae213c54 add "pkg" target to makefile
a208375b comments
cdeb063d Give ListDir() the same semantics on BSD as on Linux

git-subtree-dir: gitstatus
git-subtree-split: ae213c540dd6924d3fb153a0860276897c9ba6c8
4 years ago
Roman Perepelitsa 21df7db2b2 Merge commit '39cf063480f6a378dadc802c174e96112c38c0c0' 4 years ago
Felix Yan 31ede3c1d3
Correct some typos in zsh conf (#1119) 4 years ago
Roman Perepelitsa 28301be914 Squashed 'gitstatus/' changes from cb363c77..90cbb46b
90cbb46b s/darwin-aarch64/darwin-arm64/ (#188)

git-subtree-dir: gitstatus
git-subtree-split: 90cbb46b7b185dc95ab96301ec49754f7e801395
4 years ago
Roman Perepelitsa 04f75a10a5 Merge commit '28301be914dec6da5d1bbd21cd8511cd71b419ee' 4 years ago
Roman Perepelitsa 790f4719ab Squashed 'gitstatus/' changes from f9acc15a..cb363c77
cb363c77 build: use zsh if possible when langued with bash < 4.0 (#188)
efb0fd1b make mbuild work with darwin-aarch64
c9e6e608 do not hardcode path to homebrew, retrieve it with `brew --prefix`
df4eba94 work around bugs in ancient versions of bash (#188)

git-subtree-dir: gitstatus
git-subtree-split: cb363c778a37575b0d5371d7e355d80ec7ae5498
4 years ago
Roman Perepelitsa ece7213a3d Merge commit '790f4719ab3db8d62f8dec6fbb89a91d87e81df0' 4 years ago
Roman Perepelitsa b7167a64c6 Squashed 'gitstatus/' changes from 4f9746fb..f9acc15a
f9acc15a use gitstatusd-darwin-x86_64 binary on darwin-aarch64 (#188)

git-subtree-dir: gitstatus
git-subtree-split: f9acc15a3aa224206c4eba0e4a26b5d3c00325be
4 years ago
Roman Perepelitsa bf830b5bf1 Merge commit 'b7167a64c60401b184346147d8297f3803f56e06' 4 years ago
Roman Perepelitsa 7969eb3f18 retain instant prompt and state dumps when TERM or TERM_PROGRAM change (#1098) 4 years ago
Roman Perepelitsa 09be56bb53 fix a bug introduced in 8488f7c (#1107) 4 years ago
Roman Perepelitsa f8ae544e6e properly restore prompt after SIGINT when transient prompt is disabled 4 years ago
Roman Perepelitsa 8488f7c75c set P9K_PROMPT=transient for the duration of zle-line-finish (#1105) 4 years ago
Roman Perepelitsa feaf120ddc replace `>>!` with `>>`; the former does not work in non-zsh shells; users who set noclobber presumably know how to deal with errors from this option 4 years ago
Roman Perepelitsa 8840fe550e correct install-without-internet instructions w.r.t. ZSH_THEME 4 years ago
Roman Perepelitsa 271836403d remove artificial term scrolling before instant prompt 4 years ago
Roman Perepelitsa e2db860745 print instant prompt only if TERM is the same 4 years ago
Roman Perepelitsa f6c24d2053 reset text attributes at the end of precmd 4 years ago
Roman Perepelitsa 2fc7257486 docs 4 years ago
Roman Perepelitsa d7861fcfa0 wrap z4h-clear-screen-{soft,hard}-top 4 years ago
Roman Perepelitsa 5e2422df50 fix old/new TTY detection 4 years ago
Roman Perepelitsa 76e5a69262 save/restore screen through z4h to make it work over ssh 4 years ago
Roman Perepelitsa 85f9e75918 drop __p9k_initial_screen_empty; rely on _Z4H_TMUX_CMD instead 4 years ago
Roman Perepelitsa aa6d40b733 fix a typo in docs 4 years ago
Stephen b9be4f968b
Updating README.md typo (#1077) 4 years ago
Roman Perepelitsa 2ea3356d66 add __p9k_initial_screen_empty for z4h integration 4 years ago
Roman Perepelitsa 8f0db0c95a expand the list of things powerlevel10k does not affect 4 years ago
Roman Perepelitsa 74c6e18363 check mtime of $TTY on startup if it points to a different tty than in the parent; see #930 4 years ago
Roman Perepelitsa 49d5617989 doc cleanup 4 years ago
Roman Perepelitsa 78301e82c7 clean up kitty font instructions and duplicate them in readme.md 4 years ago
Subhaditya Nath 98494aaf7b
Added font instructions for kitty (#1070) 4 years ago
Roman Perepelitsa d86bbe75de Squashed 'gitstatus/' changes from 6ba954a4..4f9746fb
4f9746fb rebuild all binaries
6a3d54a5 upgrade libgit2

git-subtree-dir: gitstatus
git-subtree-split: 4f9746fb6e949475ff37986883796adf937055da
4 years ago
Roman Perepelitsa 68c89ec2bc Merge commit 'd86bbe75dece6c4276bfa99246880b92f9e053aa' 4 years ago
Roman Perepelitsa de0e022177 typo 4 years ago
Roman Perepelitsa f0159ca642 better wizard intro when installing z4h 4 years ago
Roman Perepelitsa fdc0ee3708 add font.md 4 years ago
Roman Perepelitsa 2bcf38f554 add #font anchor to the readme 4 years ago
Roman Perepelitsa 47713ea2df recognize double-quoted strings when parsing kube configs; other types of quotes are still not supported; see #1061 4 years ago
Kid e43209409b
Correct Python version in README (#1065) 4 years ago
Roman Perepelitsa b1aeeda6a8 make it more difficult to incorrectly restart iTerm2 after installing Meslo 4 years ago
Roman Perepelitsa a124a71032 typo 4 years ago
Roman Perepelitsa fb2805e5ab wizard: suppress the into message if z4h would print its welcome 4 years ago
Roman Perepelitsa 967e845819 wizard: suppress the outro message if z4h would print its welcome 4 years ago
Roman Perepelitsa b770e6a3e5 fix a typo that was preventing zinit-specific diagnostic from being printed as part of an error message 4 years ago
Roman Perepelitsa 0da94e8ef1 Squashed 'gitstatus/' changes from a760bda8..6ba954a4
6ba954a4 make lowercasing work with Turkish locale

git-subtree-dir: gitstatus
git-subtree-split: 6ba954a4a6fb2b86e7d10b4b19db7757b4876525
4 years ago
Roman Perepelitsa 9b981b89c5 Merge commit '0da94e8ef1b84581ce8b4eb397c9e465640711ea' 4 years ago
Roman Perepelitsa 3aec0c6b36 make configuration options work when using Turkish locale (#1036) 4 years ago
Roman Perepelitsa 060af91a80 fix a TOC link 4 years ago
Roman Perepelitsa 2875595647 add offline installation instructions (#1033) 4 years ago
Roman Perepelitsa 42aa719e48 dir: ignore separator overrides if cwd is / and POWERLEVEL9K_DIR_OMIT_FIRST_CHARACTER is true 4 years ago
Roman Perepelitsa 3586cc8d7e expand c-escapes in POWERLEVEL9K_DIR_PATH_SEPARATOR 4 years ago
Roman Perepelitsa 71b39f0da9 mention that zsh-theme-powerlevel10k community package is to be avoided (#1018) 4 years ago
Roman Perepelitsa 80d9e57388 docs: remove -u from yay commands (#1018) 4 years ago
Roman Perepelitsa 3b772824c0 don't print instant prompt if it was generated with the different value of terminfo[colors] 4 years ago
Roman Perepelitsa f14b58e44f wizard: recognize `source $POWERLEVEL9K_CONFIG_FILE` in .zshrc 4 years ago
Roman Perepelitsa 4d1fba340f bug fix: superfluous dash in P9K_KUBECONTEXT_CLOUD_ZONE (#1013) 4 years ago
Roman Perepelitsa 760f7cb7a5 Squashed 'gitstatus/' changes from 3f874d9c..a760bda8
a760bda8 disable certificate checks in curl; we are checking sha256 anyway

git-subtree-dir: gitstatus
git-subtree-split: a760bda882be6e79a5ff0ab0ccc0e576781dca7a
4 years ago
Roman Perepelitsa afb854d279 Merge commit '760f7cb7a55203be03ddf789dd3c06e75377423f' 4 years ago
Roman Perepelitsa 54d40b924c support POWERLEVEL9K_VIRTUALENV_SHOW_WITH_PYENV=if-different; see #730 4 years ago
Lucas Larson 12cef82077
repair spelling of "occurrences" (#998) 4 years ago
Roman Perepelitsa 622130980c add scalaenv prompt segment; see #991 4 years ago
Roman Perepelitsa 6c8c6eea1b typo in comments 4 years ago
Roman Perepelitsa 3b2f474c9f support generic POWERLEVEL9K_* parameters for segments with dashes in their names 4 years ago
Roman Perepelitsa 47c842fe8e wifi: further cleanup 4 years ago
Roman Perepelitsa cababbeee2 wifi on linux: fix bugs and speed things up 4 years ago
Roman Perepelitsa dd5948e5e3 Merge branch 'master' of https://github.com/sys-lectern/powerlevel10k into sys-lectern-master 4 years ago
Roman Perepelitsa 536d90a335 support per-state POWERLEVEL9K_BATTERY_HIDE_ABOVE_THRESHOLD; see #988 4 years ago
Roman Perepelitsa a3727dcaef wizard: don't refuse to start if ZDOTDIR is not writable; see #987 4 years ago
Roman Perepelitsa c1db3926fe docs: explicitly mention that powerlevel10k doesn't affect key bindings 4 years ago
Roman Perepelitsa b673e6a7dd bug fix: trigger transient prompt on send-break 4 years ago
Roman Perepelitsa f2bf019758 wizard: simplify instant prompt screen; make sure all screens work with 47x14 terminal size 4 years ago
Roman Perepelitsa 2a4c962c21 add "gpd" to the list of default VPN network interfaces; see #979 4 years ago
Roman Perepelitsa 7eb501c0f5 suport hex flags in the output of ifconfig; see #979 4 years ago
sys-lectern 6853fcd8e5 minor fixes and syntax improvements 4 years ago
sys-lectern c464fd25e6 Merge branch 'master' of https://github.com/sys-lectern/powerlevel10k 4 years ago
sys-lectern 16cb58d15f minor fixes and syntax improvements 4 years ago
Roman Perepelitsa 6279aa57d7 add k9s, helmfile and terragrunt to some SHOW_ON_COMMAND params; #904 4 years ago
Roman Perepelitsa 2f4c3c4cec use portable sed syntax 4 years ago
David d62961131c
Delete log.txt 4 years ago
hal9000 8f90ed6d49 linux wifi widget 4 years ago
Roman Perepelitsa dca8774f1b add an empty line after the branch/tag truncation logic 4 years ago
Roman Perepelitsa 711490252e enable extended_glob in p10k-{pure,robbyrussell}.zsh to fix `unset -m` 4 years ago
Roman Perepelitsa 525e2545db wizard: when using z4h, automatically enable instant prompt in quiet mode 4 years ago
Roman Perepelitsa c425a5e635 bump version 4 years ago
Roman Perepelitsa 03ab8e9c7e don't expand _p9k_dir when dir is hidden via 'p10k display'; see #952 4 years ago
Roman Perepelitsa f63d6a31c1 Squashed 'gitstatus/' changes from fcebf0b0..3f874d9c
3f874d9c fix bash bindings when noclobber is set; see #171

git-subtree-dir: gitstatus
git-subtree-split: 3f874d9c5933d184b9b06472dcf25e8debb326a8
4 years ago
Roman Perepelitsa ebfaae2ab6 Merge commit 'f63d6a31c1348e304e40e4e0dcca750128ad2cfd' 4 years ago
Roman Perepelitsa 7a0bf995c7 formatting 4 years ago
Roman Perepelitsa b53b43533a fix wording in docs 4 years ago
Stephen d5d6ee11ff
Add MesloLGS font config steps for Alacritty (#929)
* Add MesloLGS font config steps for Alacritty

* Adding Alacritty font config changes

Shortened steps and included official doc.

* Simplified and updated Alacritty font config steps

Required YAML included in full. Quotes added to font family due to space in family name. Unnecessary detail has been removed.

* Reduced the required Alacritty font config YAML

Removed additional styles from the "MesloLGS NF" family, they are implied and not necessary to include.
4 years ago
Roman Perepelitsa c48b81ecb7 remove minimum screen size requirement for the wizard 4 years ago
Roman Perepelitsa 03e61879b5 add `p10k display -r` 4 years ago
Roman Perepelitsa cb59280c40 Squashed 'gitstatus/' changes from b157d02a..fcebf0b0
fcebf0b0 support armv8l; see #165; thanks, @ppoffice!
c2e03bc5 use fully-qualified remote ref name; see powerlevel10k/issues/915
dc827169 Merge branch 'master' of github.com:romkatv/gitstatus
4ad671ca build: set -march=armv8 when compiling for Apple's arm64 architecture

git-subtree-dir: gitstatus
git-subtree-split: fcebf0b0f7aff181f2ecc441458d8fc443125ad0
4 years ago
Roman Perepelitsa 422b7a94b9 Merge commit 'cb59280c407e60d6e993c24eaddb0feb5dd373a5' 4 years ago
Roman Perepelitsa 05ff662568 add more info about the resizing bug and patch 4 years ago
Roman Perepelitsa 598ff99f1b reduce the default value of POWERLEVEL9K_VCS_MAX_SYNC_LATENCY_SECONDS to 10ms 4 years ago
Roman Perepelitsa 2ba87f4d1f ksh_arrays compatibility 4 years ago
Roman Perepelitsa 15818346bf Squashed 'gitstatus/' changes from 7546f4de..b157d02a
b157d02a treat exit code 159 (SIGSYS) from gistatusd as terminal

git-subtree-dir: gitstatus
git-subtree-split: b157d02a9a89892f228064e06b5a817a24eea9ed
4 years ago
Roman Perepelitsa 88d5fb6145 Merge commit '15818346bf496c7e5f8cb21b2f273c47d386b7db' 4 years ago
Roman Perepelitsa 7a114ad6fb detect artix linux for the sake of displaying os logo; see #898 4 years ago
Roman Perepelitsa 86b747f434 bug fix: infinite loop when cwd doesn't exist; see #900 4 years ago
Roman Perepelitsa 24278ccd39 Merge commit 'bf2aa14becccd2b55180bc2aeff44d3a6015a580' 4 years ago
Roman Perepelitsa bf2aa14bec Squashed 'gitstatus/' changes from 89e9ebfd..7546f4de
7546f4de return norepo-sync when cwd does not exist
8ccd4d34 comments

git-subtree-dir: gitstatus
git-subtree-split: 7546f4def34558e44ee660a9970da80f760e99c8
4 years ago
Roman Perepelitsa 6dfd92f8c1 allow optional offset in POWERLEVEL9K_DIR_TRUNCATE_BEFORE_MARKER; see #896 4 years ago
Roman Perepelitsa 620e69fef1 replace NETWORK_ICON; the original (U+F877) triggers a bug on macOS; see #895 4 years ago
Roman Perepelitsa 4635fcacee don't fetch gitstatusd if there is no git 4 years ago
Roman Perepelitsa a28d45005e Merge branch 'master' of github.com:romkatv/powerlevel10k 4 years ago
Roman Perepelitsa cfc35853df start downloading gitstatusd while wizard is running 4 years ago
Kamlesh d0edcbc966
Add Instructions to make powerlevel10 work for Guake (#882)
Update instructions for the `Guake` terminal
4 years ago
Henry Bley-Vroman 34952e4a85
Fix POWERLEVEL9K_COMMAND_EXECUTION_TIME_THRESHOLD comments (#880) 4 years ago
Roman Perepelitsa 6c9d0977a6 make omz installation command work when executed from weird shells (no quoting though; that would be too much) 4 years ago
Roman Perepelitsa 0c341b6702 Merge branch 'ancarpan-terraform-show-default' 4 years ago
Roman Perepelitsa 06ed564092 Merge branch 'terraform-show-default' of https://github.com/ancarpan/powerlevel10k into ancarpan-terraform-show-default 4 years ago
Roman Perepelitsa 2d74ac9d06 prefix all `source` calls with `builtin` 4 years ago
Roman Perepelitsa ff8654ccd5 Squashed 'gitstatus/' changes from 0f5402c8..89e9ebfd
89e9ebfd survive zsh environments where `source` is a broken function

git-subtree-dir: gitstatus
git-subtree-split: 89e9ebfd59f5ddfea4d97ae1e510273415a57a51
4 years ago
Roman Perepelitsa 9486385824 Merge commit 'ff8654ccd5b4f22710a235e7f715913277612451' 4 years ago
Andrea Carpani 882cede0ae Add option to show terraform workspace even if it's default 4 years ago
Roman Perepelitsa e0ed693e6d add `CMB*` to battery directory patterns; see #858 4 years ago
Roman Perepelitsa be66f21f53 replace NETWORK_ICON
The original icon (U+FBF1) is in fact a ligature. Some terminals do
funky things when displaying it. For example:

    print '\uFBF1 42 abc'

When executed in a VTE-based terminal with Nerd Fonts, it'll print this:

    42 X abc

Here X stands for the glyph that Nerd Fonts uses for U+FBF1.
4 years ago
Roman Perepelitsa a88e11f54b disable background transparency in iTerm2 4 years ago
Roman Perepelitsa db6f909958 suppress the expected error message from PlistBuddy 4 years ago
Roman Perepelitsa ae32fd58b3 fix `fvm` styling that has been broken by the last commit; fixes #645 4 years ago
Roman Perepelitsa 6a1e993a05 make `fvm` segment work with fvm >= 1.0.0; see #842 4 years ago
Roman Perepelitsa eadfdba707 Squashed 'gitstatus/' changes from 0d23fbd1..0f5402c8
0f5402c8 bug fix: properly propagate switches to gitstatusd

git-subtree-dir: gitstatus
git-subtree-split: 0f5402c8686a593cd21b95ade28a154dd51749bb
4 years ago
Roman Perepelitsa 1be10ebcf7 Merge commit 'eadfdba7073e625562ae02841608ea37a46e0120' 4 years ago
mundry d394a4e038
Fix typo in config comment. (#836)
Co-authored-by: mundry <mundry@users.noreply.github.com>
4 years ago
mundry 178c3bccf0
Add font configuration instructions for Terminator. (#835)
Co-authored-by: mundry <mundry@users.noreply.github.com>
4 years ago
Roman Perepelitsa 8854cb6000 survive files with windows EOL (on linux, yes; people do that); see #827 4 years ago
Roman Perepelitsa eda706c8ff notes 4 years ago
Roman Perepelitsa 54bbe0a0a3 speed up pasting in terminals without bracketed paste 4 years ago
Roman Perepelitsa 0717e57ff4 Squashed 'gitstatus/' changes from 1c74c8db..0d23fbd1
0d23fbd1 comments
9c19c9c4 fix a typo in install that prevents the locally built gitstatusd from being used
92fd143f doc cleanup

git-subtree-dir: gitstatus
git-subtree-split: 0d23fbd117ad6afe52fdbd96d08cf38f941be4d3
4 years ago
Roman Perepelitsa 5e5d3f5aff Merge commit '0717e57ff46201ff04e7d62cda8677e174a83be6' 4 years ago
Roman Perepelitsa 4c15d633dd respect POWERLEVEL9K_PROMPT_CHAR_ERROR_VIINS_CONTENT_EXPANSION in simple transient prompt; see #820 4 years ago
Roman Perepelitsa 3e17260622 no need to call `zle -R` when using z4h 4 years ago
Roman Perepelitsa b015817892 Squashed 'gitstatus/' changes from 38d62a47..1c74c8db
1c74c8db add linux-ppc64le
968779b5 fix tar invocation
300f657c create anonymous tar archives
a5581d18 force C locale during build (perl complains)
2616cd47 support downloads to usrbin
1e6075dd enable static linking on linux
2975d25f update libgit2 ref
bea6f868 add ppc64le target

git-subtree-dir: gitstatus
git-subtree-split: 1c74c8db0f422aa6f95ced878351e0c6944a9bd6
4 years ago
Roman Perepelitsa 4d14f9e0ba Merge commit 'b0158178925484c058e6175e174b639237532c63' 4 years ago
Roman Perepelitsa faa510d54c explicitly mention that POWERLEVEL9K_ASDF_${TOOL}_FOREGROUND overrides POWERLEVEL9K_ASDF_FOREGROUND; see #817 4 years ago
Roman Perepelitsa a43b1b34d8 add an icon and asdf colors for julia; see #817 4 years ago
Roman Perepelitsa e2196ce32e match terminal escape sequences in instant prompt output more aggressively 4 years ago
Roman Perepelitsa 05eaf8162c tweak omz update pattern; maybe it'll help with #729 4 years ago
Roman Perepelitsa fb5a0a6cca make error message about incorrect powerlevel10k loading visible in more cases 4 years ago
Roman Perepelitsa fa2e337cbd Squashed 'gitstatus/' changes from 3050dfca8..38d62a475
38d62a475 fix gitstatus on older zsh versions

git-subtree-dir: gitstatus
git-subtree-split: 38d62a475fadf5f8d418fc772d680ba234ba8609
4 years ago
Roman Perepelitsa b7d90c8467 Merge commit 'fa2e337cbdd88ccd297d25fa9847225211801d3e' 4 years ago
Roman Perepelitsa e3f582f246 survive people explicitly disabling conda prompt and then expecting to see it 4 years ago
Roman Perepelitsa c6e599ddd5 fix a typo in remote-git-url => icon conversion (bitbucket was shows as github); see #808 4 years ago
Roman Perepelitsa a700031279 don't start gitstatusd from instant prompt if there is no git command 4 years ago
Roman Perepelitsa a3c1b7164b Squashed 'gitstatus/' changes from 830aaa999..3050dfca8
3050dfca8 add `command` in front of commands

git-subtree-dir: gitstatus
git-subtree-split: 3050dfca875a8070aaa0dc890afcc756574078c6
4 years ago
Roman Perepelitsa 00cf3b1167 Merge commit 'a3c1b7164be115f097682088c6feac283c40a1f2' 4 years ago
Roman Perepelitsa d75147503e remove git from POWERLEVEL9K_VCS_BACKENDS if there is no git command 4 years ago
Roman Perepelitsa 6e120b9eec don't initialize vcs if there is no git command 4 years ago
Roman Perepelitsa b93f9663c5 Squashed 'gitstatus/' changes from ec9c39499..830aaa999
830aaa999 try wget without --no-config if it fails with

git-subtree-dir: gitstatus
git-subtree-split: 830aaa99976c0f5addedf336414f9bf82e2699d6
4 years ago
Roman Perepelitsa bf88ce9120 Merge commit 'b93f9663c5e4e9d914c4389fc405bc7ec7382b57' 4 years ago
Roman Perepelitsa 54c9822834 Squashed 'gitstatus/' changes from 643091154..ec9c39499
ec9c39499 don't download gitstatusd if there is a bad version in usrbin

git-subtree-dir: gitstatus
git-subtree-split: ec9c39499a96ea8b181db15c76df5089959d3111
4 years ago
Roman Perepelitsa ed9d5a7088 Merge commit '54c98228342043612ea83eaaf13ac13659c26295' 4 years ago
Roman Perepelitsa 05dad31f3f add uninstall instructions for arch linux 4 years ago
Roman Perepelitsa b2be33d556 fix formatting 4 years ago
Roman Perepelitsa 04656da7c1 add install and update instructions for arch linux 4 years ago
Roman Perepelitsa 50dec9f9f5 default to POWERLEVEL9K_MODE=ascii if there is no UTF-8 locale 4 years ago
Roman Perepelitsa 7760aa66d7 don't unset POWERLEVEL9K_GITSTATUS_DIR in config templates 4 years ago
Roman Perepelitsa 9fd719c834 Squashed 'gitstatus/' changes from a827370d7..643091154
643091154 suppress rc files for curl and wget; see #146

git-subtree-dir: gitstatus
git-subtree-split: 6430911548516bd9bb0e4a5088993302d45cc499
4 years ago
Roman Perepelitsa 2ba6182373 Merge commit '9fd719c834910c9734b0def927cc079654943a8d' 4 years ago
Roman Perepelitsa f82d0de0d3 remove spurious error messages from _p9k_worker_stop 4 years ago
Roman Perepelitsa 2b1d0e599c make todo segment work if todo-cli is installed from apt; see #785 4 years ago
Roman Perepelitsa 62c0a12a10 Squashed 'gitstatus/' changes from ab1aea155..a827370d7
a827370d7 suppress error message from redirect

git-subtree-dir: gitstatus
git-subtree-split: a827370d7f11f6e6aac4a044efaef6a99ab1f1f4
4 years ago
Roman Perepelitsa 537c2b04e1 Merge commit '62c0a12a10518607814fa661905b3c8ec0f16590' 4 years ago
Roman Perepelitsa 55a9f366a8 typo in docs 4 years ago
Roman Perepelitsa 801bfbb294 jump straight to ascii if TERM is "dump" or "linux" 4 years ago
Roman Perepelitsa 285bf7ba60 ignore POWERLEVEL9K_GITSTATUS_DIR when deciding whether to auto-trigger the wizard 4 years ago
Roman Perepelitsa 189ecf8e16 remove traling ")" from conda even if it is not followed by space 4 years ago
Roman Perepelitsa 094d1b3a47 Squashed 'gitstatus/' changes from 45489634e..ab1aea155
ab1aea155 remove "this command failed" message; it makes users to post truncated messages that are useless for debugging

git-subtree-dir: gitstatus
git-subtree-split: ab1aea155f051ecab8b70154f136eef81976dd25
4 years ago
Roman Perepelitsa 127737816a Merge commit '094d1b3a47cf40746807820cababab3a829ac334' 4 years ago
Roman Perepelitsa a4a71cff9e speed up pasting in terminals without bracketed paste; see #568 4 years ago
Roman Perepelitsa a3d887cd43 add __p9k_root_dir and GITSTATUS_AUTO_INSTALL to param_pat 4 years ago
romkatv f3fb34dd99 more conservative instant prompt activation and cleanup on premature shell exit; see #770 4 years ago
romkatv d8d6efc4ec add more details to uninstall instructions 4 years ago
romkatv c9e3cfe5db add `rm -f ~/.p10k.zsh` to uninistall instructions 4 years ago
romkatv 937204640a add uninistall instructions 4 years ago
romkatv 86d980cdb5 Squashed 'gitstatus/' changes from be42ea1be..45489634e
45489634e check for cygwin via OSTYPE

git-subtree-dir: gitstatus
git-subtree-split: 45489634e1b9a2a11fc8dc94482516142d61a9c8
4 years ago
romkatv b38a7bf4af Merge commit '86d980cdb5d8eed683322f61db7c22c02640dd67' 4 years ago
romkatv 102aefadab Squashed 'gitstatus/' changes from 331e9ff65..be42ea1be
be42ea1be support split gitstatusd release binaries

git-subtree-dir: gitstatus
git-subtree-split: be42ea1be4a7938464aea568d719bf4c01e4b1f4
4 years ago
romkatv ee68d4db4b Merge commit '102aefadaba271a48a74f13953dd88067f9862c6' 4 years ago
romkatv b3875f5193 avoid spurious error (even if harmless and invisible) on worker cleanup 4 years ago
romkatv ad18cd78db call taskwarrior via `command task` 4 years ago
romkatv 4cd2700a85 bug fix: update taskwarrior when a pending task becomes overdue; see #763 4 years ago
romkatv 7d35c7ebb8 remove execute permission from wizard.zsh 4 years ago
romkatv 6696212dde Squashed 'gitstatus/' changes from cc956ca78..331e9ff65
331e9ff65 docs: remove packaging instructions and instead discourage it
c1fff558c install: add a link to #compiling docs if no gitstatusd is found
8632b85ab build: use extra optimization and hardening flags
c0a71c757 mbuild: don't stop on first failure
52e0359ec build: don't link statically when doing a local linux build

git-subtree-dir: gitstatus
git-subtree-split: 331e9ff65df96e7423c0b7a01e5e98d6c6b7d428
4 years ago
romkatv 90df734bf8 Merge commit '6696212ddecbb5ffae8d71467518cc5651c90b3f' 4 years ago
romkatv ba6c79e277 docs: remove packaging instructions and instead discourage it 4 years ago
romkatv 9a4bbcd930 Squashed 'gitstatus/' changes from 0127fd26a..cc956ca78
cc956ca78 interrupt p10k instant prompt before printing "gitstatus failed to initialize" error
db3603bc8 improve "gitstatus failed to initialize" error message
e164594ea work around bugs in cygwin
55af96ade cleanup + todo
0e70dbc56 add an empty line before the error message

git-subtree-dir: gitstatus
git-subtree-split: cc956ca7878ef6d00bb1f35861864d0a40ffac75
4 years ago
romkatv 619ddaf6f1 Merge commit '9a4bbcd930afa54bc605e3020fb38353161e5a84' 4 years ago
romkatv 2ade5d786b disable instant prompt when gitstatus fails to initialize 4 years ago
romkatv ed3287b737 Revert "mention that arch linux packages for powerlevel10k are broken and should not be used"
This reverts commit 6b69030bfb.
4 years ago
romkatv 5e9a4eb072 asdf: filter multiple versions the same way as upstream; see #764 4 years ago
romkatv 644488afcc change the default anaconda format in config templates
Also document how to configure it.

See #762.
4 years ago
romkatv 45eeb08fc3 add P9K_ANACONDA_PYTHON_VERSION 4 years ago
romkatv a963533cbd mention that powerlevel10k once again can be installed from AUR 4 years ago
romkatv be83ec430c replace Ⅴ (roman numeral 5) with V (ascii); see #754 4 years ago
romkatv 6b69030bfb mention that arch linux packages for powerlevel10k are broken and should not be used 4 years ago
romkatv ee44f9e112 Squashed 'gitstatus/' changes from 063ed450..0127fd26
0127fd26 set user.name in the test git repo
00564e95 Merge pull request #135 from Aloxaf/Aloxaf-patch-1
6003278c build: no gpg sign

git-subtree-dir: gitstatus
git-subtree-split: 0127fd26a0d102cc5d5b2b10e511fa99138d78e3
4 years ago
romkatv 936b0d6dea Merge commit 'ee44f9e112a71ef6fa5aacdf65a43862a5a89279' 4 years ago
romkatv c713ded9e7 set P9K_TTY=old in preexec 4 years ago
romkatv 499de79a2b remove instant prompt if it corresponds to a different config 4 years ago
romkatv 8cfe934f15 Squashed 'gitstatus/' changes from 78a2ec25..063ed450
063ed450 Revert "close p10k instant prompt descriptors in daemon"

git-subtree-dir: gitstatus
git-subtree-split: 063ed45083386c98ab4d10f08794bec2a0c534d1
4 years ago
romkatv fb0dc597fa Merge commit '8cfe934f157a69976f55a796b65d4ed0a0344719' 4 years ago
romkatv 519de2c569 Revert "close instant prompt descriptors in worker"
This reverts commit 646a826440.
4 years ago
romkatv 8e86b0c8d4 don't hide empty line when invoking zsh immediately after clear 4 years ago
romkatv 00cfdb48a8 Squashed 'gitstatus/' changes from c99d28aa..78a2ec25
78a2ec25 close p10k instant prompt descriptors in daemon

git-subtree-dir: gitstatus
git-subtree-split: 78a2ec251e99ffa48ea10bbb48ab54ba6401701c
4 years ago
romkatv 072fc38ebe Merge commit '00cfdb48a8c74150814792e4deccff2a1ce91ad0' 4 years ago
romkatv 646a826440 close instant prompt descriptors in worker 4 years ago
romkatv fb9bc2d3f5 Merge branch 'master' of github.com:romkatv/powerlevel10k 4 years ago
romkatv f3ae4032c1 Squashed 'gitstatus/' changes from 4c1b9564..c99d28aa
c99d28aa block SIGINT in zle callback when being used from p10k
f52fd5b5 wrap most of gitstatus_start code in `{..} always {...}` to handle SIGINT properly
e4e88a5a mention that gitstatus can be cloned from gitee.com

git-subtree-dir: gitstatus
git-subtree-split: c99d28aa6be9db6f78c99c3f56626f2afcc3a466
4 years ago
romkatv 1e2a0cc34a Merge commit 'f3ae4032c1923404afc9fd8b6af2bf28bc406d61' 4 years ago
xPMo debacbf530
Fix warning for parameter _p9k__preexec_cmd (#735)
With `setopt warn_create_global`, I get this warning:

    _p9k_preexec2:1: scalar parameter _p9k__preexec_cmd created globally in function _p9k_preexec2
4 years ago
romkatv e3beeea0ae block SIGINT in nested p10k calls; allow SIGINT in gitstatus_start 4 years ago
romkatv c0ff47bea5 don't print instant prompt warning when omz update fails 4 years ago
romkatv be5c067125 bug fix: vcs and vpn_ip weren't respecting hide/show state 4 years ago
romkatv 5d1bfe8ed7 cleanup 4 years ago
romkatv 5e932c225e bug fix: properly disable instant prompt when auto-wizard is aborted 4 years ago
romkatv c0091537a9 fix gcloud for the case when there are multiple configurations
Fixes #731
4 years ago
romkatv 6998d06a91 pyenv: display python version alongside environment name if unequal
See #730.
4 years ago
romkatv f96c1eb5e5 add POWERLEVEL9K_VIRTUALENV_SHOW_WITH_PYENV=false to config templates
See #730.
4 years ago
romkatv 00d2cc7237 add POWERLEVEL9K_VIRTUALENV_SHOW_WITH_PYENV 4 years ago
romkatv fdac99c57c notes 4 years ago
romkatv 48c6ff4701 expand dir color faq 4 years ago
romkatv 6c83ace41c uncomment POWERLEVEL9K_DIR_BACKGROUND 4 years ago
romkatv b62a164998 add chinese translation for the reference to gitee.com
See #124.

Thanks, @ayalhw.
4 years ago
romkatv af0b387182 mention that powerlevel10k can be cloned from gitee.com; see #124 4 years ago
romkatv ff18dbaf74 Squashed 'gitstatus/' changes from caf5bfd3..4c1b9564
4c1b9564 Merge pull request #128 from carlosedp/arch
1d2816f2 Add support to build on ppc64le and riscv64 archs
5614639c update version in packaging instructions
d728a1da add homebrew installation instructions; fixed #118

git-subtree-dir: gitstatus
git-subtree-split: 4c1b95643bc78dfe8e4d9566823b72881637c2ef
4 years ago
romkatv bf0255931b Merge commit 'ff18dbaf74beb38f9e0721558f2c66552b5862a4' 4 years ago
romkatv 9f33d6567b work around bugs in zsh that break vim shell; see #717 4 years ago
romkatv d9b90027ba disable tty echo for the whole duration of wizard 4 years ago
romkatv 2841cecaa9 fix ask_python screen in the wizard 4 years ago
romkatv 3ddb8025d5 fix POWERLEVEL9K_VCS_DISABLED_WORKDIR_PATTERN example 4 years ago
romkatv accbe293cb wizard: print a message when aborted with ctrl-c 4 years ago
romkatv 574754eaf6 abort instant prompt if wizard needs to run on startup 4 years ago
romkatv 7e6abbb891 maintain _p9k_dumped_instant_prompt_sigs invariant 4 years ago
romkatv 6f5e834b8e update version in packaging instructions 4 years ago
romkatv 46c76dd707 Squashed 'gitstatus/' changes from 1a80249d..caf5bfd3
caf5bfd3 update build instructions
8bbfd153 update build instructions

git-subtree-dir: gitstatus
git-subtree-split: caf5bfd3d4b6099aeed13604936976e610a08e18
4 years ago
romkatv 1f8bd78e3a Merge commit '46c76dd7071bedab192aa65756ba09024e29da0c' 4 years ago
romkatv d0f6cd0b50 update build instructions 4 years ago
romkatv a6009c74a9 Squashed 'gitstatus/' changes from f81313e2..1a80249d
1a80249d build: verify libgit2 tarball sha256
74c3d56f bash: call mktemp only once and avoid `mktemp -u`
b139dec4 install: use mktemp if available
9f594d24 bash: block SIGQUIT and SIGTSTP in daemon
73f47ea3 add sha256 verification for downloaded gitstatusd; enable gitee mirror

git-subtree-dir: gitstatus
git-subtree-split: 1a80249d2b6a53fd076ae846f8fcc501183ca5a5
4 years ago
romkatv e7f0bac67d Merge commit 'a6009c74a92f1c01d725364635aa38eba67bc15a' 4 years ago
romkatv d23b2c3792 Squashed 'gitstatus/' changes from 901c366b..f81313e2
f81313e2 move gitee disable higher
8cfb83f3 print [ok] after download when stderr is not tty
d185a2ab disable gitee mirror until there is sha256 verification in place
fb88a401 show progress when downloading gitstatusd
ae988158 add a mirror for gitstatusd release files
c673d327 disable aliases before calling zcompile

git-subtree-dir: gitstatus
git-subtree-split: f81313e27271ee1fb3fd22b8e72382e9516776ef
4 years ago
romkatv 71f5f42997 Merge commit 'd23b2c3792712662408c332a52547dc903cc5c43' 4 years ago
romkatv 16b44fd9da add `p10k clear-instant-prompt`; disable instant prompt when gitstatus is likely to download a new binary 4 years ago
romkatv d075b5a5cb disable aliases before calling zcompile 4 years ago
romkatv bda74564e3 Squashed 'gitstatus/' changes from d3bc3e34..901c366b
901c366b survive `cd` being a function that fails instead of doing its job; see #123

git-subtree-dir: gitstatus
git-subtree-split: 901c366b8ecb736e579784b132442ee51bcb0840
4 years ago
romkatv f43d8b9e0e Merge commit 'bda74564e3b1b9bbaa77f840215f7d99d0b77ed8' 4 years ago
romkatv 1db7094966 Squashed 'gitstatus/' changes from cd5673b4..d3bc3e34
d3bc3e34 work around bugs in curl on cygwin; see #706
61a67c66 print error message from curl/wget before the summary

git-subtree-dir: gitstatus
git-subtree-split: d3bc3e346cc71ee1a29d0c4316449feb3dcb3116
4 years ago
romkatv e27a8fbcbf Merge commit '1db7094966bc86658166709db26b7750d8fc2821' 4 years ago
romkatv d047ed87a1 Squashed 'gitstatus/' changes from 6a4f0fc0..cd5673b4
cd5673b4 increase default gitstatus_start timeout from 5s to 30s

git-subtree-dir: gitstatus
git-subtree-split: cd5673b4971bf1a6d9aa8d57963e954e619b950e
4 years ago
romkatv 1a976f989a Merge commit 'd047ed87a1093b27aff3324ba57860c9c42f7b65' 4 years ago
romkatv bc85e46f8b Squashed 'gitstatus/' changes from 32b7b674..6a4f0fc0
6a4f0fc0 add missing \n in error messages
d2fd0166 update build instructions

git-subtree-dir: gitstatus
git-subtree-split: 6a4f0fc0cadc214bbe4051bf87d87033558aeed8
4 years ago
romkatv 75bbc4439f Merge commit 'bc85e46f8b8a548379144732a3218bfe686f2f63' 4 years ago
romkatv b305649e53 docs 4 years ago
romkatv 1c39df6280 document how to package powerlevel10k for distribution 4 years ago
romkatv 0acaefe57f Squashed 'gitstatus/' changes from 6b9ba17..32b7b67
32b7b67 silly typo bug dammit!

git-subtree-dir: gitstatus
git-subtree-split: 32b7b674326b109bbe639d6dc662ede2d4df3ad2
4 years ago
romkatv ec81904184 Merge commit '0acaefe57f32e2afffab13a988d8b29d3f6eb1aa' 4 years ago
romkatv 1531d6e543 Squashed 'gitstatus/' content from commit 6b9ba17
git-subtree-dir: gitstatus
git-subtree-split: 6b9ba179c6655286c4c399e7926d5098dd6bd706
4 years ago
romkatv 97fac973af Merge commit '1531d6e5439daae01627b2645684876b75eaf5eb' as 'gitstatus' 4 years ago
romkatv c159f3aaef nuke gitstatus (going to replace with subtree) 4 years ago
romkatv 9fc454fc08 mangle gitstatus function names 4 years ago
romkatv 317a9896d8 bump version 4 years ago
romkatv a238426d97 bug fix: preserve empty array elements in _p9k_declare (see #678) 4 years ago
romkatv 22396b86f3 when shortening with truncate_to_unique, never produce just dots for a segment 4 years ago
Roman Perepelitsa 3de6154ee7
notes 4 years ago
romkatv f2cffc978c better `p10k help display` 4 years ago
romkatv ca114f2508 work around more zsh bugs w.r.t. SIGWINCH; see #694 4 years ago
Olivier MARY 541d573551
Fix _p9k_precmd:trap:17: undefined signal: return (#695)
Signed-off-by: Olivier MARY <olivier@omary.fr>
4 years ago
romkatv 94bbbc1ca8 ignore cursor shape escape sequence in the output when instant prompt is active 4 years ago
romkatv dc1f023344 work around more zsh bugs w.r.t. local traps 4 years ago
romkatv aceb1c5c77 fix a typo: ${x:-} => ${x:--} 4 years ago
romkatv 9a47e80ff9 dump state after every initialization but never synchronously 4 years ago
romkatv 5d41bf4703 block SIGINT while powerlevel10k is running 4 years ago
romkatv c7efd5badb always dump instant prompt whenever dumping state 4 years ago
romkatv fc1fd9beb5 delete instant prompt cache when config changes while instant prompt is active 4 years ago
romkatv 30457e2be6 allow patterns in POWERLEVEL9K_VIRTUALENV_GENERIC_NAMES; see #686 4 years ago
romkatv 3688d12857 `cd` => `cd -q` to survive weird chpwd hooks 4 years ago
romkatv 3f08f1392a pull upstream changes from gitstatus 4 years ago
romkatv 48a36ebc17 pull upstream changes from gitstatus 4 years ago
romkatv 2cc815deaf 'cd /' in the worker to avoid locking cwd 4 years ago
romkatv b2c77eb370 pull upstream changes from gitstatus 4 years ago
romkatv 9b1353f112 perform single word shell expansions on PROMPT_EOL_MARK (see #683) 4 years ago
romkatv 1b5ee70b3d pull upstream changes from gitstatus 4 years ago
romkatv 06603a2d62 work around bugs in kitty where it hangs on close
All terminals quit when the child process terminates. Except
kitty. Kitty doesn't quit until there are no open file
descriptors to the tty.

And the best thing? This is "better". Having the balls to
claim this nasty bug as feature is worthy of admiration.
4 years ago
romkatv fdb0bb6af7 set P9K_PYENV_PYTHON_VERSION in prompt_pyenv; see #679 4 years ago
romkatv 459af1f238 allow dir styling based on the pair: $PWD and whether it's writable
fixes #678
4 years ago
Roman Perepelitsa f14ffcff2c
typo 4 years ago
romkatv 7c4b0f36c0 support POWERLEVEL9K_DIR_TRUNCATE_BEFORE_MARKER=first; see #669 4 years ago
romkatv eb66d0e66a pull upstream changes from gitstatus 4 years ago
romkatv 10ba0e45be pull upstream changes from gitstatus 4 years ago
romkatv 1b6c24e99e wizard bug fixes: screen redraws, spurious errors, frame selection
fixes #668
4 years ago
romkatv d3e5aebd69 notes 4 years ago
romkatv 1e598907f1 Merge branch 'LeSeulArtichaut-patch-1' 4 years ago
romkatv 03654d956d Merge branch 'patch-1' of https://github.com/LeSeulArtichaut/powerlevel10k into LeSeulArtichaut-patch-1 4 years ago
romkatv 5baecd66db wizard now reacts to terminal size changes and can function at much smaller terminal dimensions; fixes #649 4 years ago
LeSeulArtichaut 78eb23f4f3
Add terminal instructions for Terminus 4 years ago
romkatv aca2f19fa3 define POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_GAP_BACKGROUND in rainbow and classic config templates (see #655) 4 years ago
romkatv 0ac58db9ec Merge branch 'Jemoka-master' 4 years ago
Houjun Liu c7abab6e01
Include font instruction for Blink 4 years ago
romkatv f7a3ec4172 work around bugs in zsh 5.3.1; fixes #651 4 years ago
779g 8c84041ec7
Documented a default $ZSH_CUSTOM to install with Oh My Zsh Install in a script (#648)
Co-authored-by: 779g <aztlan@779.mx>
4 years ago
cptpcrd 0bb331b55d
Fix Arch Linux installation instructions (#644)
`pacman -Sy` does a partial upgrade, which is specifically documented as
being unsupported.
4 years ago
romkatv 681f504d8a unset DEFAULT_USER in generated .p10k.zsh; see #640 4 years ago
romkatv 993203a308 mention that MesloLGS NF is released under Apache license 4 years ago
romkatv af027c9989 mention that fix-winchanged doesn't work on alacritty (#175) 5 years ago
romkatv 0087f6b631 pull upstream changes from gitstatus 5 years ago
romkatv 303417688e pull upstream changes from gitstatus 5 years ago
romkatv 7963a365d8 add java_version to docs 5 years ago
romkatv 1d8a9ecdc5 pull upstream changes from gitstatus 5 years ago
romkatv 9d462b0ba9 add a tip for disabling git branch truncation 5 years ago
romkatv e59723872c notes 5 years ago
romkatv e1323716fe zf_rm before zf_mv to work around NTFS bugs (see #610) 5 years ago
romkatv da58ccbbaf unfuckup md formatting 5 years ago
romkatv fb117b5f97 notes 5 years ago
romkatv 0cdb75b9d1 auto-start configuration wizard if no POWERLEVEL9K parameters are set; fixes #615 5 years ago
romkatv 5986b35032 notes 5 years ago
romkatv 5777e72d14 notes 5 years ago
romkatv 96c6fe9967 notes 5 years ago
romkatv e9f75cb047 rename notes.txt => notes.md 5 years ago
romkatv fda14e93d2 ignore POWERLEVEL9K_CONFIG_FILE when deciding whether to start wizard 5 years ago
romkatv ddc47993a2 add POWERLEVEL9K_CONFIG_FILE 5 years ago
romkatv 3ef4e68b5f suppress errors from zf_mv (fixes #610) 5 years ago
romkatv b2667b8270 don't compile sources if zsh is < 5.1 5 years ago
romkatv c71606cd83 assume no zshrc changes are required if using z4h 5 years ago
romkatv 9e5ab2ce95 fix an embarrassing typo that causes instant prompt to get slower over time (fixes #608) 5 years ago
romkatv dfc98adb5c use a more portable PROXY_ICON; fixes #596 5 years ago
romkatv 86f6f58279 pull upstream changes from gitstatus 5 years ago
romkatv eab09f8938 remove special error message for 32-bit arm and intel; these are now supported 5 years ago
romkatv 9dadc822e3 pull upstream changes from gitstatus 5 years ago
romkatv 8573855d39 replace debian with alpine in the docker demo (starts much faster) 5 years ago
romkatv 2648292323 remove capitalization in some links for consistency 5 years ago
romkatv 1f99af70bc bug fix: always succeed when reaching the end of ask_* function; fixes #591 5 years ago
Roman Perepelitsa b577175c53
Tweak readme intro (#590)
Co-authored-by: Cameron Steffen <cam.steffen94@gmail.com>
5 years ago
romkatv 1c888e7b64 move the link to the TOC a bit higher; some users want to see it but give up before they reach it 5 years ago
romkatv a380b8d51c add padding after slanted separators when using non-monospace font; count width savings to be able to show more styles on narrow terminals 5 years ago
romkatv 597b8051df bug fix: remove superfluous /bin from gitstatusd path; see #589 5 years ago
shiro d8eeef278d
Update GitHub issue link (#588) 5 years ago
romkatv b80a4254b7 disable vi_mode if prompt_char is enabled; see #584 5 years ago
romkatv 758affe574 pull upstream changes from gitstatus 5 years ago
romkatv 02488ee3fe notes 5 years ago
romkatv 1ca48bec93 recommend enabling builtin powerline glyphs in iterm2 5 years ago
romkatv 2fbbc2a776 link to font faq 5 years ago
romkatv 6a0e7523b2 use better looking flat and slanted separators in unicode mode 5 years ago
romkatv 5d0ae3adba document how MesloLGS NF was created 5 years ago
romkatv a7594e103e Merge branch 'gcloud' 5 years ago
romkatv b626f06e64 fix progress messages when installing fonts 5 years ago
romkatv 3f61e27b8c iTerm2: offer to install a new version of MesloLGS NF 5 years ago
romkatv 3848a4e14f Merge branch 'wizard' 5 years ago
romkatv 34158d5c30 make os_icon non-bold even in lean style 5 years ago
romkatv 15cf43c792 iTerm2: fetch fonts from powerlevel10k-media; avoid font size 12; enable builtin powerline glyphs 5 years ago
romkatv 90d19e6f97 enable the display of project name in gcloud segment
Details:
https://github.com/romkatv/powerlevel10k/issues/318#issuecomment-602037792
5 years ago
romkatv 2468ccdb5e refactoring: give segments more flexibility in precompute 5 years ago
romkatv 4c3c5487f9 Merge branch 'GCloud-Segment' of https://github.com/Jeklah/powerlevel10k into gcloud 5 years ago
romkatv e60aa8ad7d bug fix: java version depends on JAVA_HOME (fixes #572) 5 years ago
romkatv 505a77f02e add installation instructions for Arch Linux via Pacman 5 years ago
Marko Kaznovac af4f7a5890
fix typo: disk_usgae (#574) 5 years ago
Yaroslav Derman 3468715e63
Added installation via antibody (#573) 5 years ago
romkatv a240439f2f remove calendar from the list of icons on the ask_icon_padding screen 5 years ago
romkatv 6f9ae0fd17 make os_icon non-bold 5 years ago
romkatv a52cff3024 don't resolve symbolic links when calling external commands; see #566 5 years ago
romkatv 04fd51b511 fix icon padding changes 5 years ago
romkatv 2b59d947e4 add 12-hour time format option to the wizard 5 years ago
Jeklah ba26a1a076
GCloud Segment shows proj name not proj ID.
Logic behind change: gcloud project IDs are semi randomly generated and can not be changed by the user. The project name can be changed and is much easier on the eyes, and easier for the user the identify the project, as it will be what they typed in when naming the project, as opposed to the ID which they won't have typed in.
5 years ago
romkatv 48a61471a7 parser bug fix: quote array elements after parameter expansion 5 years ago
romkatv d53355cd30 pull upstream changes from gitstatus 5 years ago
romkatv 95252aa7b3 pull upstream changes from gitstatus 5 years ago
romkatv f7f38dafe0 pull upstream changes from gitstatus 5 years ago
romkatv 2f0e193b7b s/and and/and/ 5 years ago
romkatv c0a84bf2ca FAQ: teminal cannot display wide glyphs; konsole cuts off icons; arch linux logo with a dot 5 years ago
romkatv e4e165f6d7 simplify configs
- use POWERLEVEL9K_ICON_PADDING instead of
  POWERLEVEL9K_VISUAL_IDENTIFIER_EXPANSION to customize padding after
  icons
- remove reliance on UTF-8 locale when the config is being sourced
5 years ago
romkatv 0d662be14c fix POWERLEVEL9K_ICON_PADDING with POWERLEVEL9K_MODE=ascii 5 years ago
romkatv 13523b117d Revert "terminate links with ST instead of BEL"
This reverts commit a2af168eb4.

Reason: Konsole has a bug that triggers when using \e\ instead of \a.
5 years ago
romkatv 65065ab658 add POWERLEVEL9K_ICON_PADDING; the only value that has effect is "none" 5 years ago
romkatv cf8f7f49fe add P9K_OS_ICON 5 years ago
Roman Perepelitsa c3ddca85ff
notes 5 years ago
Roman Perepelitsa 608872f117
notes 5 years ago
romkatv 6d57d00f32 pull upstream changes from gitstatus 5 years ago
romkatv 29cac7bdfb cleanup 5 years ago
romkatv 0467762964 add kube-toggle to FAQ 5 years ago
romkatv 3eaa7acb50 spello 5 years ago
romkatv fd283aa9e5 comment 5 years ago
romkatv ca8ec45f7a display only the version (without name) in `package` by default 5 years ago
romkatv 3308f18863 FAQ: greyed out Git status; see #558 5 years ago
romkatv db1e12bce3 add `package` prompt segment 5 years ago
romkatv 95008fc871 notes 5 years ago
romkatv 2db72dad1f speed up detect_virt segment by 50% (now takes 2 ms instead of 3 ms) 5 years ago
romkatv a082a04624 notes 5 years ago
romkatv 541a167b43 mention that gitstatusd needs to be rebuilt after updating p10k 5 years ago
romkatv 42ccb64c61 better instructions for building gistatusd; see https://github.com/romkatv/gitstatus/issues/110 5 years ago
romkatv 853253434d fix a typo: s/arm7l/armv7l/ 5 years ago
romkatv 3b985dde30 mention that powerlevel10k does not affect completions or non-prompt-related options 5 years ago
romkatv e0e426a61b link to the TOC at the top 5 years ago
romkatv ba1237beb9 add a screenshot showing what prompt is 5 years ago
romkatv 1cd33e5445 better color selection one-liners (see #554) 5 years ago
Cameron Steffen 054d9a6cd4
Improve colors preview one-liner (#554)
* Improve colors preview one-liner

* Show colored numbers next to background
5 years ago
romkatv 7306efb94b s/terraform/tf/ in ascii icons 5 years ago
romkatv c9c607369c add POWERLEVEL9K_*ENV_SHOW_SYSTEM to config templates 5 years ago
romkatv 6ccf26ff8e don't use href when the terminal is known to print garbage on it 5 years ago
romkatv a2af168eb4 terminate links with ST instead of BEL
See https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda.

  The sequence is terminated with ST (string terminator) which is
  typically ESC \. (Although ST is the standard sequence according to
  ECMA-48 §8.3.89, often the BEL (\a) character is used instead. This
  nonstandard choice originates from XTerm, and was later adopted by
  probably all terminal emulators to terminate OSC sequences. Nevertheless,
  we encourage the use of the standard ST.)
5 years ago
romkatv e7d167bdb5 formatting 5 years ago
romkatv 38d717db26 several fixes for #550
- remove $fg where it has no effect (minor optimization)
- add $style after $subsep if the latter has embedded styling (bug fix)
- bump version to invalidated cached styles
5 years ago
romkatv d7d3df8753 Merge branch 'ahaasler-change-supseparator-color' 5 years ago
Adrian Haasler García 366fc52200
Change subseparator color to match with segment 5 years ago
romkatv dfa377b1b9 more robust detection of clear and reset commands; see #545 5 years ago
romkatv 3f470b2d7d more robust detection of clear and reset commands; see #545 5 years ago
romkatv e302a9693e bug fix: restore special handling of `clear` and `reset`; see #545 5 years ago
romkatv 33a72faf5f if P9K_TTY is new, flip it to old only when precmd is called not from zle 5 years ago
romkatv d4854bfb30 don't print an empty line after `clear`, `reset` and `clear-screen`; see #545 5 years ago
romkatv 0205c01ba9 change the semantics of POWERLEVEL9K_DIR_OMIT_FIRST_CHARACTER to something useful
If POWERLEVEL9K_DIR_OMIT_FIRST_CHARACTER is set to true, it'll remove the leading
slash from the current directory if it's absolute. It will no longer do anything
if the directory is not absolute or if the leading character has been removed
or changed by the shortener.
5 years ago
romkatv cdb856e374 add POWERLEVEL9K_NODENV_SOURCES to config templates 5 years ago
romkatv cff3575c15 improve *env segments
- add POWERLEVEL9K_NODENV_SOURCES (fixes #542)
- handle *_DIR parameters the same way as upstream does it (fixes #541)
- add POWERLEVEL9K_*ENV_SHOW_SYSTEM parameter to enable hiding of "system"
5 years ago
romkatv c8c74ec29f pull upstream changes from gitstatus 5 years ago
Roman Perepelitsa a8cdc46a15
Add 'kogito' to POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND (#546)
Signed-off-by: David Ward <dward@redhat.com>
5 years ago
romkatv 945643bcab add istioctl to POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND in all config templates 5 years ago
romkatv 2a4538e25e simplify brew installation instructions; update toc 5 years ago
romkatv 5c1cf2cbcb add instructions for installation and update with homebrew; see #539 5 years ago
romkatv 04d19d031a add stack.yaml to the list of folder markers 5 years ago
romkatv dc8070219f add styling for asdf/haskell 5 years ago
romkatv 18701f4e49 add haskell_stack prompt segment (#535) 5 years ago
romkatv 1c5358e0d5 fix visual mode indicator on zsh >= 5.3 and disable completely on < 5.3; fixes #536 5 years ago
romkatv 769e47a5cd remove done items from notes 5 years ago
romkatv 4499e2069b add java_version to config templates (disabled by default) 5 years ago
romkatv 155485a996 add POWERLEVEL9K_JAVA_VERSION_FULL parameter
The file pattern is based on https://github.com/starship/starship/pull/966.
5 years ago
romkatv b207dd8e99 remove done items from notes 5 years ago
romkatv 526b1b543b add precommands: chronic and ifne 5 years ago
romkatv b0c051cdfd save and restore screen in the wizard 5 years ago
romkatv c5732cc810 expand "some prompt styles are missing from the configuration wizard" 5 years ago
romkatv cb0b91fc92 add "env" to the default value of POWERLEVEL9K_VIRTUALENV_GENERIC_NAMES; see #532 5 years ago
romkatv cfef402dab mention ASCII charset option 5 years ago
romkatv 56060f0bc1 don't assume that zero size of a file in /sys actually means it's empty 5 years ago
romkatv bd921485fc add ascii mode to configuration wizard 5 years ago
romkatv be16ab255d s/error/err/ (too verbose) 5 years ago
romkatv d96fbde6c5 don't enable battery segment if there is no battery 5 years ago
romkatv 92757e5a8d replace color 232 with 0 in lean-8colors 5 years ago
romkatv 112648acb1 more robust locale workaround in configs 5 years ago
romkatv 1fd5087e91 docs 5 years ago
romkatv 91023a1d8a wizard: if cannot display powerline glyphs, use flat heads by default and offer to change to blurred 5 years ago
romkatv 0f406f088d use NORDVPN_ICON instead of LOCK_ICON in nordvpn prompt segment 5 years ago
romkatv 47990df0b8 add POWERLEVEL9K_MODE=ascii 5 years ago
romkatv 84cb153746 make p10k.zsh work when there is no UTF-8 locale on the machine 5 years ago
romkatv dd0294e9bf add a link to https://aur.archlinux.org/packages/zsh-theme-powerlevel10k/ 5 years ago
romkatv e84b20901c s/ASDF_GO/ASDF_GOLANG/
Fixes #529.
5 years ago
romkatv cb3f58d21f add 'sleep 3' after changing iTerm2 settings; just trying random shit 5 years ago
romkatv ffbf86903d try to fix font instllation problems on mac 5 years ago
romkatv ff496ab2ba exit with an error when unable to delete old fonts 5 years ago
romkatv ea6607e701 better spelling when there is just one font file 5 years ago
romkatv 5567ab3850 before installing a font, check if it already exists; try to remove if so 5 years ago
romkatv 3077929e18 simplify code a little bit 5 years ago
romkatv e7b036418b notes 5 years ago
romkatv 3870196a65 notes 5 years ago
romkatv 27d018bc20 add POWERLEVEL9K_VPN_IP_SHOW_ALL; see #518 5 years ago
romkatv 4a4c43aa9a don't compute git status if POWERLEVEL9K_VCS_DISABLED_DIR_PATTERN matches 5 years ago
romkatv 7e262fb912 notes 5 years ago
romkatv 1885d15da2 set P9K_IP_TX_RATE and P9K_IP_RX_RATE to empty instead of 0 when unable to get the real values 5 years ago
romkatv cfc76c8856 pull upstream changes from gitstatus 5 years ago
romkatv 0d8e001f27 bug fixes in the gitstatus fastpath 5 years ago
romkatv 298169f042 Merge branch 'master' into zsh-api 5 years ago
romkatv 7c0cd05e9a if there is only one vcs segment and its expansion is not empty, assemble prompt while gitstatus is processing our request 5 years ago
romkatv a2689e757d don't reset prompt when precmd is called from zle 5 years ago
Roman Perepelitsa 4b4f514c15
add ⇠42⇢42 to the git status prompt example 5 years ago
romkatv 73a59bee65 always let gitstatus infer GITSTATUS_DAEMON and GITSTATUS_NUM_THREADS; fix android-arm7l error message 5 years ago
romkatv f4a0da0e4e pull upstream changes from gitstatus 5 years ago
romkatv 0105d760d6 bug fix: check _GITSTATUS_STATE_POWERLEVEL9K instead of the old GITSTATUS_DAEMON_PID_POWERLEVEL9K 5 years ago
romkatv aa90e7e148 pull upstream changes from gitstatus 5 years ago
romkatv 68257a197c pull upstream changes from gitstatus 5 years ago
romkatv f1be283dbc pull upstream changes from gitstatus 5 years ago
romkatv d53a0440d0 Merge branch 'master' into zsh-api 5 years ago
romkatv d70cc3a24b backport changes to 5.1: procsubstpid doesn't exist there 5 years ago
romkatv a0abdc6344 pull upstream changes from gitstatus 5 years ago
romkatv b4deda53a3 pull upstream changes from gitstatus 5 years ago
romkatv 7aab4d7ac5 notes 5 years ago
romkatv 491e630bcb don't send worker pid -- master can get it on its own 5 years ago
romkatv 0a28653355 optimize worker i/o 5 years ago
romkatv 0c606eb9e9 use the same cygwin binary on all versions of windows 5 years ago
romkatv ed16e4e481 save and restore all VCS_STATUS params 5 years ago
romkatv cab4489678 notes 5 years ago
romkatv 6f6c9b457e bug fix: add a space before arrows in pure style; fixes #517 5 years ago
romkatv 678733c68f pure style: move context to the left; upstream: https://github.com/sindresorhus/pure/pull/530 5 years ago
romkatv 126d0175f0 fix another typo in taskwarrior link 5 years ago
romkatv c0f8f9aacf fix a typo in taskwarrior link; thanks @cridemichel! 5 years ago
romkatv 8cf22480c0 add taskwarrior prompt segment; see #511 5 years ago
romkatv 4fdd02db26 don't call zstat without arguments 5 years ago
romkatv be7735ebf8 doc cleanup 5 years ago
romkatv 891090acc4 make locale workarounds more robust 5 years ago
romkatv 9ce0a0551e attempt to make locale workarounds more robust 5 years ago
romkatv 8a845210b5 notes 5 years ago
romkatv 060103f63f recognize void linux; use the generic linux icon for now; fixes #509 5 years ago
romkatv 07d86d93ce pull upstream changes from gitstatus 5 years ago
romkatv dc470dba4b recognize a few more patterns of "source .p10k.zsh" 5 years ago
romkatv a6a2d9a481 stop loading icons.zsh lazily; print boundaries in get_icon_names 5 years ago
romkatv d9da275e9e more robust zcompile 5 years ago
romkatv e5f2d39a16 drop cache when path to uname changes
Fixes https://github.com/romkatv/gitstatus/issues/102.
5 years ago
romkatv 31757b3f6c punctuation 5 years ago
romkatv a1c964b49d bug fix: don't chmod inexisting file 5 years ago
romkatv e750c26266 don't crap out when using more than one prompt_char 5 years ago
romkatv f02997a8f0 notes 5 years ago
romkatv 829744654a docs 5 years ago
romkatv 65c4ae4abf grey Git status in robbyrussell while loading 5 years ago
romkatv 7cbaed976d unset WIDGET when calling p10k-on-post-widget from _p9k_on_expand 5 years ago
romkatv 7c1cc0c487 call p10k-on-pre-prompt on every precmd; call widget hooks right after when in zle 5 years ago
romkatv 3fe66ba74a Revert "call _p9k_on_expand and subsequenty p10k-on-pre-prompt on every precmd, even when called from zle"
This reverts commit a6363401bb.
5 years ago
romkatv a6363401bb call _p9k_on_expand and subsequenty p10k-on-pre-prompt on every precmd, even when called from zle 5 years ago
romkatv ac39345713 notes 5 years ago
romkatv 1a9f317650 wizard: gracefully handle non-writable ~/.zshrc 5 years ago
romkatv ffb6bf8fd7 Merge branch 'Brettm12345-readonly-fix' 5 years ago
romkatv 1061d1c516 Merge branch 'readonly-fix' of https://github.com/Brettm12345/powerlevel10k into Brettm12345-readonly-fix 5 years ago
brettm12345 cc796d9cda
Oop 5 years ago
brettm12345 fdef2c08d4
Remove extra line 5 years ago
brettm12345 ea95789078
Return an error 5 years ago
brettm12345 9017e5815c
Remove the extra variable and inline the test 5 years ago
brettm12345 ae4650b40d
Use `[[ ]]` instead of `test` 5 years ago
brettm12345 cb6351436a
Change variable name and fix warning 5 years ago
brettm12345 9cd3bfdea1
Warn user if they try to modify their `.zshrc` 5 years ago
brettm12345 fe27e57de6
Added the `__p9k_readonly_zsh` variable 5 years ago
romkatv 53c63c9dfc add robbyrussell theme emulation config 5 years ago
romkatv 944ea827d2 notes 5 years ago
romkatv efa7b4a51d notes 5 years ago
romkatv a3282100f0 bug fix: truncate_to_last didn't behave like %1~ in / and /foo 5 years ago
romkatv cee4a16e7d expand on minimalist prompt advice 5 years ago
romkatv 27af39ffe8 notes 5 years ago
romkatv ae42177fa4 bump version 5 years ago
romkatv a7ef4a7403 add php prompt segments to docs: phpenv, php_version, laravel_version 5 years ago
romkatv 0e04538c38 add laravel_version to config templates 5 years ago
romkatv 4386b5a6e7 remove "PHP" from php_version 5 years ago
romkatv 84097d9073 speed up laravel_version 5 years ago
romkatv b8a949498f add php configuration for asdf 5 years ago
romkatv d34f3dd983 comments 5 years ago
romkatv 9a3263fbe5 add php_version to config templates; see #499 5 years ago
romkatv 04e0cfa670 add POWERLEVEL9K_PHP_VERSION_PROJECT_ONLY; use PHP_ICON in php_version 5 years ago
romkatv 245a420499 add phpenv prompt segment; see #499 5 years ago
romkatv e4e7ccec81 pull upstream changes from gitstatus 5 years ago
romkatv 6e9fbbcae4 stop unsetting local_options in powerlevel10k.zsh-theme; see #496 5 years ago
romkatv e7bf217ed5 more robust prompt options management 5 years ago
Roman Perepelitsa 1489727c38
typo in docs 5 years ago
romkatv c4ffe42f7d notes 5 years ago
romkatv 69fce3e1fc speed up worker chatter 5 years ago
romkatv 4f7efdcc8b bug fix: detect gcloud config changes when using non-default configs 5 years ago
romkatv 63183dea4b pull upstream changes from gitstatus 5 years ago
romkatv 9a0e093e0e disable mmap when loading powerlevel10k; maybe it'll help with #490 5 years ago
romkatv 3fff07357d bump version 5 years ago
romkatv 24507b9744 asdf bug fix: call list-legacy-filenames only when legacy_version_file = yes
Fixes #492.
5 years ago
romkatv 1588693400 notes 5 years ago
romkatv e1ff1a7fdf notes 5 years ago
romkatv 37c88f4347 notes 5 years ago
romkatv c5782e9dab add SHOW_ON_UPGLOB parameters for asdf to config templates; see #485 5 years ago
romkatv 6987a7e8a8 add POWERLEVEL9K_${SEGMENT}_${STATE}_SHOW_ON_UPGLOB with regular fallback; see #485 5 years ago
romkatv 3ca90731b0 make SHOW_ON_COMMAND work with legacy custom prompts; see #488 5 years ago
romkatv d71d1409c4 fix `p10k display -a` 5 years ago
romkatv f06be72977 notes 5 years ago
romkatv 1cab51ae9f notes 5 years ago
romkatv aef4ad39f2 fix link 5 years ago
romkatv eb3ddadc6c add POWERLEVEL9K_VCS_DISABLED_WORKDIR_PATTERN='~' to config templates 5 years ago
romkatv 747b78ed47 document "─" in Git status 5 years ago
romkatv c7ca5453e2 notes 5 years ago
romkatv 2969546bbf don't use POWERLEVEL9K_* params after init; simplify asdf 5 years ago
romkatv cdbf25a5e6 notes 5 years ago
romkatv 7c8e7d960c add POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY to config templates and display "─" if worktree scan was skipped 5 years ago
romkatv 6f4840b463 minor bug fix in nordvpn plus cleanup of the same 5 years ago
romkatv b86eb6a037 cleanup 5 years ago
romkatv 924dfe6889 comments 5 years ago
romkatv 9fcc380cac make fewer sysread calls 5 years ago
romkatv 47400657ec don't persist fprint cache 5 years ago
romkatv 30a54b1d5e dump state and instant prompt from zle (no more forking) 5 years ago
romkatv f01c200e98 rename many _p9k_ vars to _p9k__; trigger state dump when timewarrior and asdf caches change 5 years ago
romkatv b6cf0cf9ec bug fix: persist _p9k_dumped_instant_prompt_sigs changes 5 years ago
romkatv 54360ed430 use the high contrast image at the top 5 years ago
romkatv 36b7eaba42 faq: error status is shifted 5 years ago
romkatv d1ed61c972 docs: add ahead/behind the push remote to the legend 5 years ago
Gibson Fahnestock d37cf22a9c show VCS_STATUS_PUSH_COMMITS_{AHEAD,BEHIND} in vcs by default
Fixes #395.
5 years ago
romkatv 63d09812f9 pull upstream changes from gitstatus 5 years ago
romkatv 43a6269008 s/ip/IP/ in docs 5 years ago
romkatv 6fb0e8d7f5 doc cleanup 5 years ago
romkatv 925f18936e add "extensible" section to docs 5 years ago
romkatv 0cb64f6474 bump version 5 years ago
romkatv 540f895669 bug fix: handle empty versions in legacy asdf files correctly 5 years ago
romkatv 160fb52f47 bug fix: don't crap out when file names contain colon
See #477.
5 years ago
romkatv 6a79008aec notes 5 years ago
romkatv a0f4447b60 add hide-related asdf parameters to config templates 5 years ago
romkatv 59f8d186b6 add POWERLEVEL9K_ASDF_${plugin}_SHOW_SYSTEM with fallback to POWERLEVEL9K_ASDF_SHOW_SYSTEM 5 years ago
romkatv 8be5750ccc add POWERLEVEL9K_ASDF_${plugin}_{SOURCES,PROMPT_ALWAYS_SHOW} with fallback to POWERLEVEL9K_ASDF_{SOURCES,PROMPT_ALWAYS_SHOW} 5 years ago
romkatv abbe7f361c add faq: transient prompt stops working after some time 5 years ago
romkatv af42857637 add custom colors for several asdf tools: erlang, elixir, postgres 5 years ago
romkatv fd30ed1560 add icons (for asdf): ERLANG_ICON, ELIXIR_ICON, POSTGRES_ICON 5 years ago
romkatv f9f3aa594a add spaces after a few icons that tend to be very wide in non-monospace fonts 5 years ago
romkatv 50318c0250 add POWERLEVEL9K_DIR_TRUNCATE_BEFORE_MARKER to config templates 5 years ago
romkatv 71708336a9 add asdf to docs 5 years ago
romkatv 730ef08dfb Merge branch 'master' into asdf 5 years ago
romkatv 80139d8949 add NODEJS_ICON and DOTNET_CORE_ICON (for asdf) 5 years ago
romkatv f509a16bbb add asdf to config templates (enabled by default) 5 years ago
romkatv f788f6b4bd asdf: replace "-" with "_" when converting to upper case 5 years ago
romkatv 44c479a819 add asdf prompt segment 5 years ago
romkatv d17c7278a5 spello 5 years ago
romkatv 17d3dc78fe pick up `ifconfig` and `ip` from PATH
Apparently there are systems on which these tools are not in /sbin.
Fixes #472.
5 years ago
romkatv a5b5945792 Merge branch 'master' into asdf 5 years ago
romkatv d716875918 replace terraform icon; several terminals have bugs that prevent them from rendering the current icon correctly 5 years ago
David Ward a06bbdc196
respect TIMEWARRIORDB environment variable (#471)
Signed-off-by: David Ward <dward@redhat.com>
5 years ago
romkatv be7e7b3b15 add `ip` to docs 5 years ago
romkatv 73e24180a0 add `ip` to config templates 5 years ago
romkatv 75e5712cd0 slightly shorter bandwidth display 5 years ago
romkatv 01cce2c4eb fix netstat parsing on macos 5 years ago
romkatv 80015c7c71 fix netstat parsing on macos 5 years ago
romkatv d9b9aa4383 add network bandwidth stats to `ip` segment 5 years ago
romkatv 7354eeaa96 workaround for a bug in sysread
There is a bug in sysread from zsh/system. It triggers in the
following case:

1. zsh has been compiled with HAVE_SELECT and without HAVE_POLL.
2. sysread is called with timeout (-t).
3. the input file descriptor is valid but there is no data to read.
4. errno happens to be EINTR prior to the call to sysread.

This results in an infinite loop in sysread:

  while ((ret = select(infd+1, (SELECT_ARG_2_T) &fds,
                       NULL, NULL,&select_tv)) < 1) {
    if (errno != EINTR || errflag || retflag || breaks || contflag)
      break;
  }

Here select() keeps returning 0, indicating timeout. This is not an
error, so errno doesn't get set. If it was EINTR prior to the call,
it stays EINTR, and the loop keeps spinning.

As a workaround, powerlevel10k sets errno to ENOTTY (any value other
than EINTR will do) prior to calling sysread with timeout.
5 years ago
romkatv a12f7ac8ee when the user's locale is misconfigured, set it to utf8 at the top level
fixes #469
5 years ago
romkatv e2571dc95a comments 5 years ago
romkatv 27b25196d8 comments 5 years ago
romkatv f7645af7e3 add wifi prompt segment to docs 5 years ago
romkatv b95c75921a Merge branch 'master' into asdf 5 years ago
Roman Perepelitsa 47e8c1b38c
remove debug messages; fixes #466 5 years ago
romkatv 507e647e63 Merge branch 'master' into asdf 5 years ago
romkatv afb7a59fbe add contacts to docs 5 years ago
romkatv 1ac3624463 progress on asdf design 5 years ago
romkatv ce37ae5426 Merge branch 'master' into asdf 5 years ago
romkatv 5e5ff583a3 extend the ZLE_RPROMPT_INDENT=0 workaround to a few more cases
If the last right prompt line can be proven to always have
zero length after prompt expansion, we can unset RPROMPT
thus avoiding triggering zsh bugs related to ZLE_RPROMPT_INDENT=0.

Fixes #458.
5 years ago
romkatv 4095a018dc basic asdf design 5 years ago
romkatv fab13389f1 remove profiling instrumentation 5 years ago
romkatv 3b2fa36cd6 comments 5 years ago
romkatv 637752ef7b comments 5 years ago
romkatv 71f4eade9f add wifi prompt segment 5 years ago
romkatv 4b62cd7380 bug fix: make reset=2 sticky 5 years ago
romkatv a0535ffcd6 replace all wide glyphs with narrow in nerdfont configuration; many terminals have bugs that prevents them from properly rendering wide glyphs 5 years ago
romkatv 1a9c8d126c typo 5 years ago
romkatv c321e50f38 remove redundant expansion of C-escapes 5 years ago
romkatv 6db57923b1 add POWERLEVEL9K_BATTERY_${state}_{STAGES,LEVEL_BACKGROUND,LEVEL_FOREGROUND} 5 years ago
romkatv 45a71cbc05 "restart your terminal" should help iTerm users who fail to restart iTerm when asked to 5 years ago
romkatv 4de584652c rm p9k-vs-p10k.cast 5 years ago
romkatv 84a7ad7cc2 add "some prompt styles missing from the wizard" 5 years ago
romkatv 9d9c50611d s/hight/height/ 5 years ago
romkatv 4599ad9f2c add extra options to pure style
- non-permanent content location (left or right)
- show current time
- prompt height (one or two lines)
- prompt spacing (with empty line between prompts or without)
5 years ago
romkatv eb9da89ad9 quote $foo when running with unknown options; fixes #453 5 years ago
romkatv c08d1e846b link to zsh building instructions 5 years ago
romkatv b71a19c92e more precise mitigation for the resizing bug 5 years ago
romkatv c983ff6a41 typo 5 years ago
romkatv 0b9829d409 add "mess when resizing" to troubleshooting 5 years ago
romkatv cea51ee866 formatting 5 years ago
romkatv 04767278bd formatting 5 years ago
romkatv 994a1e1371 remove antibody, add "how to update"
The instructions for installation with Antibody are likely
wrong anyway. Dunno how to fix them, so Antibody goes.
5 years ago
romkatv 8bad59ef13 s/zsh/Zsh/ in docs 5 years ago
romkatv d54f6f50ca more links 5 years ago
romkatv 1b0ab85f87 link to installation 5 years ago
romkatv aea3e1393e cleanup 5 years ago
romkatv 828a776a7b fix links 5 years ago
romkatv c34c567be2 update toc 5 years ago
romkatv b6cb9618a8 spelling and cleanup 5 years ago
romkatv 0d6859cae8 add configuration wizard tips 5 years ago
romkatv 44bf61ac2c doc: describe how p9k and p10k are related 5 years ago
romkatv 6ca69df39f doc: sub-pixel imperfections 5 years ago
romkatv b0a08e0ae5 Merge branch 'master' into tour 5 years ago
romkatv f91597fe7b speed up terraform, add classes to configs, bump version 5 years ago
romkatv ecc0157d94 Merge branch 'Meroje-terraform-classes' 5 years ago
romkatv 4b99ca847c doc cleanup 5 years ago
Jérôme Foray ae12802bbe Add support for classes to terraform segment 5 years ago
romkatv 2c65a0c1c4 add nix_shell to the list of segments 5 years ago
romkatv 808ccfc7bd cleanup 5 years ago
romkatv adfbbb741a cleanup 5 years ago
romkatv f562a837d8 expand on commitment 5 years ago
romkatv ea2b2f1e02 split troubleshooting out of faq; expand on spacing differences between 9k and 10k 5 years ago
romkatv 1bdee256e5 add POWERLEVEL9K_LEGACY_ICON_SPACING 5 years ago
romkatv 2913765868 update 'try it in docker' section 5 years ago
romkatv d800fd5f41 rewrite the color faq; move omz p9k migration instructions to faq 5 years ago
romkatv c65260aaab change the default timewarrior icon (shield => watch); see #295 5 years ago
romkatv 23e241bf67 update color scheme 5 years ago
romkatv 3354789278 Merge branch 'master' into tour 5 years ago
romkatv 788ee7df4d bug fix: remove spurious "entry=" from instant prompt 5 years ago
romkatv 1f2251b799 bug fix: don't cache range and nnn segments as their content is not static 5 years ago
romkatv 73878f398a add nix_shell prompt segment; see #448 5 years ago
romkatv 6c507767b8 minor style fixes 5 years ago
romkatv 7ae901212c update toc; explain how the screenshots and gifs were produced; clean things up 5 years ago
romkatv e916104c1c add a table with all supported segments; reword the intro and font sections 5 years ago
romkatv 084b0203c7 spelling and cleanup 5 years ago
romkatv b3e02f54d5 feature: customizable 5 years ago
romkatv 6686f3ba17 expand features section 5 years ago
romkatv 3b281aba49 pure config template cleanup 5 years ago
romkatv e07a91c1a2 some progress on docs 5 years ago
romkatv 2564afb48d fix gif urls 5 years ago
romkatv 2a78889243 start doc overhaul 5 years ago
romkatv 0a4b832b25 add `tabbed` to the list of precommands 5 years ago
romkatv 453907bbbc pull upstream changes from gitstatus 5 years ago
romkatv 0a7f7c85c4 minor fixes 5 years ago
romkatv 674e5fd029 bump version 5 years ago
romkatv 5ce620436d quote override dirs form rustup 5 years ago
romkatv 5f6d73c5ac don't call stat in prompt_dir; use _p9k__parent_mtimes instead 5 years ago
romkatv 43fe2c30d1 cleanup 5 years ago
romkatv 589c679045 add POWERLEVEL9K_GOENV_SOURCES to config templates 5 years ago
romkatv 4d4c2658b3 migrate remaining segments to the new globbing api 5 years ago
romkatv 3c64f43f2d make __p9k_byte_suffix readonly 5 years ago
romkatv 286ba2a84b s/_p9k_upsearch/_p9k_upglob/g 5 years ago
romkatv 34d34eb112 finish fast globbing and start migrating stuff 5 years ago
romkatv 262ce24905 Merge branch 'master' into glob 5 years ago
romkatv 5de4142517 set prompt_subst when printing ruler; see #444 5 years ago
romkatv c7405e4678 start working on faster globbing 5 years ago
romkatv 14868da64a move buffer parser to internal/parser.zsh 5 years ago
romkatv 37f6b67dc9 better text flowing when nudging to restart iTerm2 5 years ago
romkatv 3bca7e845f detect source code corruption done by antigen and suggest resetting cache 5 years ago
romkatv b7777bb86e attempt to work around antigen bugs 5 years ago
romkatv a5cafefa40 truncate timewarrior task names 5 years ago
romkatv 12e0d2e7e8 notes 5 years ago
romkatv 164100899e drop support for no-icons mode from all config templates 5 years ago
romkatv bfa70fa86d add timewarrior prompt segment; see #295 5 years ago
romkatv a9715367d4 fix prompt_char (never showed error); unify options 5 years ago
romkatv 98c614b851 move notes.txt to internal to avoid confusing people 5 years ago
romkatv 8d2ab89627 remove debugging junk 5 years ago
romkatv b7f03790e2 bump version 5 years ago
romkatv 5d460d7b99 remove trailing zeros from _p9k_human_readable_bytes 5 years ago
romkatv fa4d151f94 cleanup 5 years ago
romkatv b9cfa4e7ff bug fixes:
- don't use typeset -p on zsh 5.4 as it's broken there
- remove redundant local declarations from _p9k_prompt_net_iface_async
- change the default value of POWERLEVEL9K_PUBLIC_IP_HOST as the old is broken
5 years ago
romkatv 57dc301d6e bug fix: declare worker global vars in _p9k_init_vars 5 years ago
romkatv 5e42c4c930 add P9K_KUBECONTEXT_USER 5 years ago
romkatv 9c21f4b273 Merge branch 'master' into worker 5 years ago
Max Rydahl Andersen 774701432e Add `oc` to `POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND` (#436) 5 years ago
romkatv 08f326a457 add _p9k__segment_{cond,va}_{left,right} and migrate swap to worker 5 years ago
romkatv 8fe1521d21 add swap segment to config templates 5 years ago
romkatv f1bb5601fe process ready replies from worker synchornously in precmd 5 years ago
romkatv e97a6c6701 delete fifo before killing worker from watchdog 5 years ago
romkatv 2dc56d0afe trap PIPE 5 years ago
romkatv 565492b10e migrate over from the old worker api; use worker in battery on macOS 5 years ago
romkatv 148ecf7fc3 use ascii ENQ (0x05) for watchdog pings 5 years ago
romkatv 45d14cbcf5 add watchdog to worker 5 years ago
romkatv bdf55b7318 notes 5 years ago
romkatv 2aa1d07b4a massive worker simplification (figure out during massive hangover) 5 years ago
romkatv f1314f9072 Merge branch 'master' into worker 5 years ago
romkatv 833cc73f73 add a link to gitter 5 years ago
romkatv 1fb30a62e7 add disk_usage to config templates 5 years ago
romkatv 08f73b27fd cherry pick disk_usage fix from 0d33157b12; see #435 5 years ago
romkatv cf886d0baf notes 5 years ago
romkatv 186d1539b9 add POWERLEVEL9K_DIR_TRUNCATE_BEFORE_MARKER; see #430 5 years ago
romkatv e4349e0c9b fix option names in the color selection screen; fixes #432 5 years ago
romkatv f069f787ba notes 5 years ago
romkatv ed2b83275b Merge branch 'master' into worker 5 years ago
romkatv 0f9cee9dc2 display lean with 8 colors right away if the terminal does not support 256 colors 5 years ago
romkatv fc7178ad92 check for truecolor before offering snazzy 5 years ago
romkatv 7144ebb465 add snazzy color scheme option to pure style 5 years ago
romkatv 0f6b7953be synthesize common prompt functions 5 years ago
Roman Perepelitsa e74e0d38c8
update notes 5 years ago
romkatv 80e8e46fe5 Merge branch 'master' into worker 5 years ago
romkatv e01b5d9529 refactor worker code 5 years ago
romkatv 9586e24dfb add color selection dialog for lean-8colors; remove space before prompt char in lean-* when it's the first segment on the line 5 years ago
romkatv 2feac7f121 survive SIGINT during preexec; see #427 5 years ago
romkatv f1e9d9ade7 fix ram segment on wsl 5 years ago
romkatv c79108ff0a work around wsl bugs 5 years ago
romkatv 6a9cc19741 add notes 5 years ago
romkatv 430c2b0178 explicit exec in worker 5 years ago
romkatv 0d8a51bcf3 Merge branch 'master' into worker 5 years ago
romkatv e374395746 follow ~/.zshrc and ~/.p10k.zsh symlinks
When the user tells the configuration wizard to apply
changes to ~/.zshrc and ~/.p10k.zsh and these files
are symlinks, apply changes to the targets.

see #426
5 years ago
romkatv b35a814828 migrate ram to worker 5 years ago
romkatv 635ffb0e21 load the same modules and functions in worker as in master 5 years ago
romkatv 61df3d1cfb even further simplify worker bootstrap 5 years ago
romkatv 23e8921b8d further simplify worker bootstrap 5 years ago
romkatv 1208fd10ef simplify worker bootstrap 5 years ago
romkatv 0ae338dde1 make sure pwd and IFS are initialized when running *_compute 5 years ago
romkatv e65f05d7be bump versions 5 years ago
romkatv 5ae34b98fe skip worker hooks for 'time' if POWERLEVEL9K_EXPERIMENTAL_TIME_REALTIME is not set 5 years ago
romkatv 8513fa63d9 add disk_usage to config templates 5 years ago
romkatv 831b8da62e add a comment explaining how to display VPN ip 5 years ago
romkatv a36b0cba24 migrate load, ip and vpn_ip to worker 5 years ago
romkatv 573f2549cc add back POWERLEVEL9K_EXPERIMENTAL_TIME_REALTIME support 5 years ago
romkatv 0d33157b12 migrate disk_usage and public_ip to worker 5 years ago
romkatv a6e0b01dc1 remove explicit timeout support from worker 5 years ago
romkatv da498aef57 support parallelism in worker 5 years ago
romkatv a652d49bd9 Merge branch 'master' into worker 5 years ago
romkatv 0a484d1d99 print the same error message for 32-bit android as for 32-bit linux
see https://github.com/romkatv/gitstatus/pull/96
5 years ago
romkatv 145b1a1103 cleanup 5 years ago
romkatv e0e6a4bf49 cleanup 5 years ago
romkatv aa0f435d75 add worker.zsh 5 years ago
romkatv f1da8c41ac prepare for worker migration 5 years ago
romkatv c21961b53c pull upstream changes from gitstatus 5 years ago
romkatv a0f3d94dd6 fix POWERLEVEL9K_DIR_HYPERLINK=true with POWERLEVEL9K_SHORTEN_STRATEGY=truncate_from_right
fixes #420
5 years ago
romkatv 8a9e879164 cleanup 5 years ago
romkatv f85a3a5652 fix 1-liner mode 5 years ago
romkatv eeabcbfa80 remove notes.txt 5 years ago
romkatv b241f2ce25 add ssh-agent to precommands 5 years ago
romkatv cf2b97e389 spello 5 years ago
romkatv 3391739b55 make the default glcoud format less verbose 5 years ago
romkatv 525e3257d8 port latest changes from p10k-lean.zsh to other styles 5 years ago
romkatv 74116e206b cleanup 5 years ago
romkatv 5544777c01 enable midnight_commander and aws_eb_env by default 5 years ago
romkatv ece366ba68 update SHOW_ON_COMMAND parameters based on suggestions from #318; enable google_app_cred, gcloud and azure by default 5 years ago
romkatv 124723fdd2 add faq entry about SHOW_ON_COMMAND 5 years ago
romkatv e2813c5db5 Merge branch 'master' into reactive 5 years ago
romkatv bd9e4ee35b add 8-color version of lean style 5 years ago
romkatv f3cdf7d9ba Merge branch 'master' into reactive 5 years ago
romkatv 8394e6338e switch to debian in the docker demo
archlinux fails to install packages half the time

  error: key "Christian Hesse (Arch Linux Package Signing) <arch@eworm.de>" could not be imported

This seems to be a long-standing bug in arch that hasn't been acknowledged.
Users suffering from it are offered to to repeatedly wipe their keyring,
reinitialize, and retry.
5 years ago
romkatv ad22ff1ffa speed up 5 years ago
romkatv 057533460f use more precise pattern for process substitutions 5 years ago
romkatv bbc6f8638e add a bunch of SHOW_ON_COMMAND paramters to p10k-lean.zsh; still in flux 5 years ago
romkatv f15af7b2c2 Merge branch 'master' into reactive 5 years ago
romkatv 437b624532 rustup is just wow 5 years ago
romkatv 5ccec88673 Merge branch 'master' into reactive 5 years ago
romkatv 1cf99b34e5 give content expansion for rust_version access to full version through $P9K_RUST_VERSION; see #418 5 years ago
romkatv ddecb91a0f rust_version: support rustup; see #418 5 years ago
romkatv 4218cc5106 optimize `p10k display`, POWERLEVEL9K_*_SHOW_ON_COMMAND, and startup 5 years ago
romkatv e9335145b3 add all p10k-* hooks to parameter signature 5 years ago
romkatv 1efade9962 don't replace show with print if p10k-on-post-prompt is defined 5 years ago
romkatv 32c3ad75cc Merge branch 'master' into reactive 5 years ago
romkatv 2b307eefd8 clear to eol when printing empty_line and ruler 5 years ago
romkatv 5ecde25fea delete trash 5 years ago
romkatv 35d2432326 parse process substitutions 5 years ago
romkatv cbb3f2bc41 add `p10k display -a` 5 years ago
romkatv 7b37e475d3 remove parse.zsh 5 years ago
romkatv 1eb83b081e add POWERLEVEL9K_COMMANDS_MAX_TOKEN_COUNT 5 years ago
romkatv 14623f0626 add POWERLEVEL9K_${segment}_SHOW_ON_COMMAND; bug fixes in parsing 5 years ago
romkatv be359b6e76 group precommands with commands 5 years ago
romkatv b8981328bb minor opitimization 5 years ago
romkatv 02a5d21f12 incorporate latest parser fixes 5 years ago
romkatv bc0429f3bb comments 5 years ago
romkatv 856baeb610 Merge branch 'master' into reactive 5 years ago
romkatv 974529b642 add faq about changing colors 5 years ago
romkatv 60d00e9e75 fix 'always' 5 years ago
romkatv b59f74a7bd fix heredocs 5 years ago
romkatv 770bf93444 get rid of captures 5 years ago
romkatv 6e3711759f rename _p9k names for easier testing 5 years ago
romkatv 940e6dc118 write all p10k-on-* hooks to instant prompt 5 years ago
romkatv 849e9519de back to 32 token limit 5 years ago
romkatv 84f01d5cb3 don't array-expand unnecessarily 5 years ago
romkatv efe0e79436 don't array-expand unnecessarily 5 years ago
romkatv 8380cee319 run widget hooks only from PS1 5 years ago
romkatv db9913984d integrate the new command buffer parser intp p10k 5 years ago
romkatv fc9cc6f82a typo 5 years ago
romkatv 4fa3f2cd6a cleanup 5 years ago
romkatv dd437267cd cleanup 5 years ago
romkatv df4b33c699 handle early precommand termination 5 years ago
romkatv 347392daab support precommands and fix a few bugs 5 years ago
romkatv 9a6eb616d9 add precommand specs 5 years ago
romkatv 251ec93396 limit the number of looked-at tokens to 32 5 years ago
romkatv 2db236fc69 speedup 5 years ago
romkatv 1779555402 filter and dedup commands 5 years ago
romkatv 461e1acb98 comments 5 years ago
romkatv 68d9aeb559 handle `<<<` 5 years ago
romkatv dfc5382c0d handle `for x (y) z` 5 years ago
romkatv b8c9e83661 fix a few bugs in parsing 5 years ago
romkatv 57b500d083 speedup 5 years ago
romkatv 90ac9c9e20 remove function decls from the list of commands 5 years ago
romkatv c4f68bd609 speed up parsing 5 years ago
romkatv 07ee25a147 add parse.zsh 5 years ago
romkatv bbd5791aac pass fd to _p9k_restore_prompt 5 years ago
romkatv 9da0365dfb make sure the next hook called after p10k-on-post-prompt is always either p10k-on-pre-prompt or p10k-on-init 5 years ago
romkatv 5deed4d459 fix bugs in widget hooks and improve performance 5 years ago
romkatv ed78375a2e work around bugs in zsh-syntax-highlighting 5 years ago
romkatv 1173119d55 wrap all widgets; call p10k-on-post-widget hook if defined 5 years ago
romkatv c79d0c0478 call p10k-on-init hook if defined 5 years ago
romkatv 597767e3fc describe hooks and parameters accessible from them 5 years ago
Eric Nielsen a50a336b64 Add Zim installation instructions to README.md (#411)
add zim installation instructions
5 years ago
romkatv 9f83e5e1dc Merge branch 'master' into reactive 5 years ago
romkatv d77bc5fa46 set DISABLE_UPDATE_PROMPT=true when activating instant prompt
This is an Oh My Zsh option that makes it update without asking for
confirmation. In practice, when instant prompt is active, OMZ doesn't
wait for the user confirmation and automatically updates.

By setting DISABLE_UPDATE_PROMPT=true we get rid of the spurious
question from the console output without changing the behavior of OMZ
updater.
5 years ago
romkatv 784fea72b5 fix omz update detection 5 years ago
romkatv e371319f49 don't print concole output warning if oh-my-zsh updates during instant prompt 5 years ago
romkatv 0be72e33f1 add notes 5 years ago
romkatv 7b77d63e7e add "todo" prompt segment to default configs 5 years ago
romkatv 2291458a5a show the number of filtered toto tasks if not the same as total and add options to hide todo when filtered and/or total is zero 5 years ago
romkatv 197e542a84 use a more portable icon for todo in portable font mode 5 years ago
romkatv 970f4fb8ff bug fix: set $0 to =todo.sh when sourcing the user config; fixes #403 5 years ago
romkatv acb6b68a37 add nnn prompt segment; see #342 5 years ago
romkatv a9620d7dca add plenv prompt segment; see #342 5 years ago
romkatv d8b847c67f add jenv prompt segment; see #342 5 years ago
romkatv 20a17daf15 add luaenv prompt segment; see #342 5 years ago
romkatv e45af961da BREAKING CHANGE: add classes to google_app_cred and change its default content 5 years ago
romkatv e2c46f0dfc bug fix: don't trigger transint prompt behavior on Ctrl-C when it wouldn't terminate the top-level zle; fixes #321 5 years ago
romkatv f220106baa bug fix: escape backquote; fixes #404 5 years ago
romkatv 8baa6d3a35 pull upstream changes from gitstatus 5 years ago
romkatv 8ef2b737d1 rename gcloud_app to google_app_cred and change its api 5 years ago
romkatv 61c268f7ae Merge branch 'rsotnychenko-update-gcloud' 5 years ago
romkatv 1086f747ba Merge branch 'update-gcloud' of https://github.com/rsotnychenko/powerlevel10k into rsotnychenko-update-gcloud 5 years ago
romkatv fa665ae4a7 bug fix: don't print an empty line after the ruler
If the visibility of ruler is 'print', there is an extra
empty line printed after it. With 'show' there is no
extra empty line (as expected).

With this commit there is no empty line in either case.

Fixes #383.
5 years ago
romkatv e72c6b9338 bump versions 5 years ago
romkatv 78da8d1b5a docs 5 years ago
romkatv c440fc79c5 docs: add faq about configuration wizard running all the time 5 years ago
Rajiv Ranjan Singh d0ff879744 corrected docs of README.md (#384)
Fix typos in readme.
5 years ago
romkatv 53a3fa92f1 more empty lines 5 years ago
romkatv 16bb3104ca typo 5 years ago
romkatv 553bf08a74 nag users to restart iTerm2 after installing fonts 5 years ago
Rostyslav Sotnychenko 0d0425c1ba
Fix typos 5 years ago
Rostyslav Sotnychenko caea2c5b2a
Add prompt for Google Cloud application credentials 5 years ago
romkatv 541646c12e hide cursor when rewrawing prompt 5 years ago
romkatv 5591ad2290 add POWERLEVEL9K_RBENV_SOURCES; fixes #372 5 years ago
Adam Stroud 82aba01ea8 Fix typo 5 years ago
romkatv 14fc4d838c unbreak Git commit formatting 5 years ago
romkatv 90238d8df8 Merge branch 'alexjurkiewicz-git-commit' 5 years ago
Alex Jurkiewicz 3c54e091f0 Add example for showing the current Git commit 5 years ago
romkatv 345d0644a9 pull upstream changes from gitstatus 5 years ago
romkatv d5cff592c6 display the new rustc version when rustc is upgraded; fixes #365 5 years ago
romkatv 339703e2b1 better commends for POWERLEVEL9K_GCLOUD_CONTENT_EXPANSION 5 years ago
romkatv c971c2a619 use simpler patterns in POWERLEVEL9K_DIR_CLASSES examples that don't require extended_glob 5 years ago
romkatv a8f9527079 add gcloud prompt segment; fixes #366 5 years ago
romkatv 5fc38b0586 pull upstream changes from gitstatus 5 years ago
romkatv 22f0d6a82a add fvm 5 years ago
romkatv 196dce2d72 ensure vim_shell and midnight_commander icons are always shown; apply narrow_icons to them 5 years ago
romkatv 11b8979c61 s/macOS Terminal/Apple Terminal 5 years ago
romkatv 3e52e38b5b spello 5 years ago
romkatv 5044c61902 spelling 5 years ago
romkatv 8395e6cd68 add faq about context 5 years ago
romkatv fb527ad091 remove unnecessary my_git_formatter argument 5 years ago
romkatv 113f290826 add vim_shell prompt segment; see #359 5 years ago
romkatv e0697c200f add Git status description to FAQ 5 years ago
romkatv ac2f387dfd new prompt segment: goenv (see #342) 5 years ago
romkatv 3340dc7269 new prompt segment: midnignt_commander (see #342) 5 years ago
romkatv 6a928c6500 comments 5 years ago
romkatv 37fa37c039 make it easier to edit context segment settings in generated configs 5 years ago
romkatv dc4ca30600 pull upstream changes from gitstatus 5 years ago
Jacek Musial 5c11690612 Correct typo in word starting 5 years ago
romkatv 9c62b8931f pull upstream changes from gitstatus 5 years ago
romkatv a9af1e86b1 survive ancient zsh in PATH 5 years ago
romkatv d55923be87 survive ancient zsh 5 years ago
romkatv 41eebccdc4 roll back accidental change 5 years ago
romkatv 1e7cd82e03 don't unset prompt_sp when bailing early 5 years ago
romkatv 84be5266ec survive ancient zsh in PATH 5 years ago
romkatv 183ec8ff6e survive ancient zsh in PATH (run wizard.zsh from a fork) 5 years ago
romkatv e67ad0fe38 pull upstream changes from gitstatus 5 years ago
romkatv 213ef3e426 add POWERLEVEL9K_VIRTUALENV_GENERIC_NAMES; closes #350 5 years ago
romkatv 2d32241c20 pull upstream changes from gitstatus 5 years ago
romkatv fdb90994c9 add `p10k reload` and call it from all standard configs 5 years ago
romkatv 8a759305dd extend faq 5 years ago
romkatv d4a0255b30 iterm2: add settings that don't exist 5 years ago
romkatv df74c32cdc don't try to fix Minimum Contrast for iTerm2 users; it fails for at least one person 5 years ago
romkatv 611dd73ca2 wizard: record instant_prompt and transient_prompt options 5 years ago
romkatv 4b451fbc8a replace ↵ with ✘ in config templates
Some terminals are unable to display ↵ even when using fonts that
have this ghyph. See #326.
5 years ago
romkatv 0f2573e8ba clarify what "ornaments" refers to; see #329 5 years ago
romkatv 1be144aed3 add POWERLEVEL9K_RBENV_SOURCES; see #333 5 years ago
romkatv 700910cd04 remove redundant extra icons question 5 years ago
romkatv a6531a6586 black os_ison on white background in rainbow style. otherwise it sucks on both MS terminals as they cannot differentiate between black and no background 5 years ago
romkatv 1777bd41a6 docs 5 years ago
Rostyslav Sotnychenko 1e009cf43a Add support for classes for AWS profile prompt 5 years ago
romkatv 707d7d6671 bug fix: %k was printed instead of %f 5 years ago
romkatv 2fa5480b0c move iterm mark above ruler and empty_line; otherwise transient prompt is broken and Select Output of Last Command includes more than it should 5 years ago
romkatv 1dee8902ab don't empty PROMPT in preexec; it makes it harder to debug stuff 5 years ago
romkatv 40c0fea5f7 Revert "try to fix prompt marks on apple terminal"
This reverts commit c3afd891c7.
5 years ago
romkatv c3afd891c7 try to fix prompt marks on apple terminal 5 years ago
romkatv a1127fa3a7 typo 5 years ago
romkatv cce9cf08e3 add iterm2 marks to transient prompt 5 years ago
romkatv c3685015e6 attempt to fix iterm2 intergration 5 years ago
romkatv c9b36cd32e suppress errors from `zmodload zsh/parameter`; there are bugs in msys that cause garbage output 5 years ago
romkatv 5aee36e4da match msys and mingw `uname -s` output more aggressively; there is no rhyme or reason to all the formats they employ 5 years ago
romkatv d9c3fce012 pull upstream changes from gitstatus 5 years ago
romkatv 3cc231ea9c bump versions 5 years ago
romkatv d92c45c6bd move _p9k_do_nothing to the front of precmd_functions 5 years ago
romkatv 1387763f27 comments 5 years ago
romkatv d93f3960ba add VIOWN color params 5 years ago
romkatv e753f4152c remove debug logs that were added for #315 5 years ago
romkatv 1ab91283dc detect \e*\e\ escape sequences in addition to \e*\a; fixes #315 5 years ago
romkatv 3d6a899338 reduce POWERLEVEL9K_VCS_MAX_SYNC_LATENCY_SECONDS from 50 to 20 ms 5 years ago
romkatv a1d2c96605 fix caching and slow repo detection when GIT_DIR is set 5 years ago
romkatv 376c77712b pull upstream changes from gitstatus 5 years ago
romkatv 37221b7720 parenthesize regex 5 years ago
romkatv 39b2064a97 when ifconfig is not available, use ip; fixes #305 5 years ago
romkatv ff305e3d45 bug fix: missing \r in sp emulation 5 years ago
romkatv 6294e59268 font docs 5 years ago
romkatv e4aa4588dd work around a bug in zsh that skips precmd hooks after trapped SIGINT if there is just one of them 5 years ago
romkatv 1382fa7e81 revert most changes from 5605799 5 years ago
romkatv 97ba93a43d Merge branch 'Nobody912-master' 5 years ago
romkatv 5f9dd5a619 Merge branch 'master' of https://github.com/Nobody912/powerlevel10k into Nobody912-master 5 years ago
romkatv 6fff441e76 add more debug logging for #315 5 years ago
romkatv 49f63e224c add more debug logging for #315 5 years ago
romkatv 517db99244 add more debug logging for #315 5 years ago
romkatv 184c217c47 add debug logging for #315 5 years ago
romkatv dfa7b1578f wizard: frame for lean prompt 5 years ago
romkatv fa995cf0eb don't embed prefixes and suffixes if they are empty; save some bytes 5 years ago
romkatv 583bbdace5 docs 5 years ago
romkatv d6173b97b1 add POWERLEVEL9K_VCS_DISABLED_WORKDIR_PATTERN; fixes #311 5 years ago
romkatv e10c4c70f6 pull upstream changes from gitstatus 5 years ago
romkatv 274c50883a drop windows version number from the output of uname on mingw 5 years ago
romkatv e67c2fa9f7 fix prompt char color in transient prompt preview for Pure 5 years ago
romkatv 5bf5121c7e bump versions 5 years ago
romkatv 108208a2bf wizard: apply options to Pure style 5 years ago
romkatv d0bd6f4e21 remove scratch notes 5 years ago
romkatv fc70afc6bf remove second declration of POWERLEVEL9K_NEW_TTY_MAX_AGE_SECONDS 5 years ago
romkatv 2ba8df9ddc wizard: TRANSIENT_PROMPT same-dir => always 5 years ago
romkatv ba5c6dd12d always print LF at the end of full lines 5 years ago
romkatv 845aefd746 s/_p9k_last_prompt_pwd/_p9k__last_prompt_pwd/ 5 years ago
romkatv 702439f386 deinit after `p10k configure` to trigger initialization even if POWERLEVEL9K_DISABLE_HOT_RELOAD=true 5 years ago
romkatv 6767e271cd wizard: add transient prompt (optional); disable hot reload 5 years ago
romkatv c3a678740f suppress POWERLEVEL9K_DISABLE_HOT_RELOAD after `p10k configure` 5 years ago
romkatv ba751e13db add POWERLEVEL9K_DISABLE_HOT_RELOAD 5 years ago
romkatv 10d03863c4 snapshot all POWERLEVEL9K params 5 years ago
romkatv 123cf5f676 Merge branch 'master' into dynamic 5 years ago
romkatv 2aca13130a add --depth=1 5 years ago
romkatv 4bd5ec75ae iTerm2: set minimum contrast to 0; enable anti-aliasing 5 years ago
romkatv 8203b6a218 don't reset PS2 prompt 5 years ago
romkatv 00c69d6bda add POWERLEVEL9K_TRANSIENT_PROMPT 5 years ago
romkatv 4b34a6ed51 POWERLEVEL9K_INSTANT_PROMPT_COMMAND_LINES => 1 by default 5 years ago
romkatv b1450284e9 bug fix (incorrect height in instant prompt); embed LF in the line overflow workaround 5 years ago
romkatv 8231995ed5 Merge branch 'master' into dynamic 5 years ago
romkatv 4586e8d54c pull upstream changes from gitstatus 5 years ago
romkatv 3691b75216 survive broken user-defined gitattributes 5 years ago
romkatv 9cd922af31 pull upstream changes from gitstatus 5 years ago
romkatv 9519c5fa03 pull upstream changes from gitstatus 5 years ago
romkatv ce2e142443 use msys gitstatusd binary on mingw 5 years ago
romkatv 6df7802295 pull upstream changes from gitstatus 5 years ago
Roman Perepelitsa fc0274de2c
Don't choke on empty zshrc. 5 years ago
romkatv 50c8214038 pull upstream changes from gitstatus 5 years ago
romkatv 5d74fa39c8 support msys 5 years ago
romkatv d4265ab279 replace TRAPINT function with trap statement; the former triggers memory corruption bug in zsh 5 years ago
romkatv 47017e948e pull upstream changes from gitstatus 5 years ago
romkatv 551dd0c277 remove eval 5 years ago
romkatv adb6f92f59 fix empty_line and ruler in instant prompt; speed up regular prompt 5 years ago
romkatv 35fd701b45 set POWERLEVEL9K_NEW_TTY_MAX_AGE_SECONDS to 5 by default 5 years ago
romkatv 5d729b635d speed up p10k display 5 years ago
romkatv d0ff9df8d0 return => return 0 5 years ago
romkatv e3a2716afa call p10k-on-pre-prompt from instant prompt 5 years ago
romkatv 561f3734a9 trap sigint 5 years ago
romkatv 1d0ee7cbdd add p10k-on-post-prompt 5 years ago
romkatv 232e312b4d add p10k-on-pre-prompt 5 years ago
romkatv a2657e339a make frame hidable 5 years ago
romkatv 5262ddc07e don't use _p9k__{ruler,empty_line}_idx in p10k display 5 years ago
romkatv b6df93d250 allow unset _p9k__{ruler,empty_line}_i 5 years ago
romkatv 93b90d8029 remove one todo item 5 years ago
romkatv e1687af750 faster p10k display 5 years ago
romkatv d3fd5940cc support negative line numbers 5 years ago
romkatv 0e95c532ea wip: some more churn on dynamic stuff 5 years ago
romkatv 7b3532de44 enable vi_mode in configs that don't have prompt_char 5 years ago
romkatv d9c587a8d7 wip: some churn on dynamic stuff 5 years ago
romkatv a7db19ec7e pull upstream changes from gitstatus 5 years ago
romkatv 99e632f97d add POWERLEVEL9K_<segment>_DISABLED_DIR_PATTERN
This parameter allows you to disable a given prompt segment in
any directory that matches the specified pattern.

For example, if you have a Git repository in /foo/bar for which
you don't want to see Git status in prompt, define the following
parameter:

    POWERLEVEL9K_VCS_DISABLED_DIR_PATTERN='/foo/bar(|/*)'

See #300.
5 years ago
Nobody912 56057992b9 Update README.md 5 years ago
romkatv 1b2990ecb3 fix an error message printed for 32-bit intel users; see https://github.com/romkatv/gitstatus/issues/73 5 years ago
romkatv 2057080ec2 fix an error message printed for 32-bit intel users; see https://github.com/romkatv/gitstatus/issues/73 5 years ago
Roman Perepelitsa ff29cd3d89
Add line1 5 years ago
romkatv c28d4bf3e4 design doc for dynamic stuff 5 years ago
romkatv 3377990a6f wip: dynamic shit 5 years ago
romkatv 37fbc8c7ea transient_rprompt hides gap 5 years ago
romkatv 806ec183ff add `p10k display` command 5 years ago
romkatv af703932b3 highlight the default suggestion when asking about instant prompt 5 years ago
romkatv 4e3953566f speed up truncate_to_unique 5 years ago
romkatv dc7cfc78a4 remove debug logs 5 years ago
romkatv 8cb81ecd90 cheaper cache key in dir 5 years ago
romkatv c6c0ee59d7 speed up dotnet 5 years ago
romkatv daee88bc01 don't stat unnecessary dirs 5 years ago
romkatv 6914a23b44 work around bugs in Hyper
The bug in Hyper (https://github.com/zeit/hyper/issues/3586) is
similar to the one in VTE but it takes Hyper at least 100 times
longer to report correct TTY (Hyper is slow in general, so this
isn't surprising.)
5 years ago
romkatv 826d8adf44 speed up direnv and improve its rendering in instant prompt 5 years ago
romkatv d7f2667676 allow individual segments to be hidden or shown with low latency 5 years ago
romkatv 6c8b24760c speed up prompt by 2ms when there are many POWERLEVEL9K parameters 5 years ago
romkatv f9e548dde9 docs 5 years ago
romkatv f722f3d1ce add direnv segment; fixes 291 5 years ago
romkatv 6096321f61 move _p9k_precmd to the end of precmd_functions 5 years ago
romkatv d40f54f30d define instant_prompt_example to demonstrate how to add segments to instant prompt 5 years ago
romkatv e7520409d1 use more conservative glyphs in 'compatible' and 'powerline' mode
See #265.
5 years ago
romkatv dfe6a86eb3 don't display ruler in instant prompt when the terminal size is unknown 5 years ago
romkatv d443fccddb better warnings 5 years ago
romkatv 28795b43ce reset style before percent-expanding PROMPT_EOL_MARK 5 years ago
romkatv bdb18cbe2f pick the correct default for PROMPT_EOL_MARK 5 years ago
romkatv 01640fccba doc cleanup 5 years ago
romkatv de3d1f128b comments 5 years ago
romkatv 16d526377d doc cleanup 5 years ago
romkatv e8cf0f6d7e doc cleanup 5 years ago
romkatv 627d471fca improve instant prompt usability, update docs and add an option to the wizard to enable it 5 years ago
romkatv f17081ca98 when unable to get tty size for instant prompt, don't emulate prompt_sp and don't print right prompt or gap 5 years ago
romkatv a42b58a93a make right prompt hidable even on the last line 5 years ago
romkatv 5a75b1bfc9 bug fix: unset _p9k__* 5 years ago
romkatv 61bba0f6ee use _p9k__* naming pattern for variables that must not be dumped but must be unset 5 years ago
romkatv 8a2c9430f3 make right prompt hidable 5 years ago
romkatv b46a251b93 mention that prompt can be customized by editing ~/.p10k.zsh 5 years ago
romkatv 863cf50703 fix handling of transient_rprompt 5 years ago
romkatv 88cc59a08a add ${+VTE_VERSION} to param_sig; fix locale-related parts 5 years ago
romkatv a14d8e92dd short-circuit double sourcing of the theme 5 years ago
romkatv 7ab85fbfc3 bug fix: unset _p9k_preinit when tearing down 5 years ago
romkatv b91cba49aa add POWERLEVEL9K_VCS_RECURSE_UNTRACKED_DIRS 5 years ago
romkatv ebf19dfeee add todo 5 years ago
romkatv de63bb8ab2 survive old 'awesome' mapped fonts that miss glyphs 5 years ago
romkatv 23b20b5d8e pull upstream changes from gitstatus 5 years ago
romkatv 7fbba216b0 no_bg_nice to avoid spam on wsl 5 years ago
romkatv e92da0e322 Merge branch 'instant-prompt' 5 years ago
romkatv 0249484302 bump version 5 years ago
romkatv a410349090 redirect stdin to /dev/null while instant prompt is active 5 years ago
romkatv cf01e98ef0 define P9K_TODO_FILTERED_TASK_COUNT and P9K_TODO_TOTAL_TASK_COUNT
These new parameters can be used to customize the content of `todo` prompt.

Example:

    POWERLEVEL9K_TODO_CONTENT_EXPANSION='$P9K_TODO_FILTERED_TASK_COUNT / $P9K_TODO_TOTAL_TASK_COUNT'

The default format is '$P9K_TODO_TOTAL_TASK_COUNT', just like before.

Fixes #283.
5 years ago
romkatv d2361d4dda typo 5 years ago
romkatv 56a7d6c245 apply the `stty size` workaround only when using VTE 5 years ago
romkatv 2b860eea53 add no_aliases to a bunch of places 5 years ago
romkatv 97dbf1d1fb add a note saying that users should NOT enable instant prompt 5 years ago
romkatv 981774f178 better workaround for the lying `stty size`
See https://github.com/gnunn1/tilix/issues/1777.
5 years ago
romkatv 6dbe2c860c temporarily disable instant prompt in the configuration wizard. there are issues that I need to deal with 5 years ago
romkatv 2a0c31f0eb call `/bin/stty size` to obtain correct COLUMNS 5 years ago
romkatv 7a2bd8ffa8 workaround for a bug in tilix: $COLUMNS is incorrect in the new shell immediately after splitting; it becomes correct after forking 5 years ago
romkatv bb7b755c25 git clone --depth=1 in docker 5 years ago
romkatv 8e8385b700 doc formatting 5 years ago
romkatv c675fc8cce better instant prompt docs 5 years ago
romkatv 4d561553e5 document minimum version requirements for instant prompt 5 years ago
romkatv de98e89d72 fix links 5 years ago
romkatv b2d1f832e9 new docs: instant prompt and broken unicode glyph debugging 5 years ago
romkatv b4e1f1f029 revert testing changes 5 years ago
romkatv 4f02ad912f enable instant prompt when configuration wizard runs 5 years ago
romkatv 32f363a1b1 move p10k-instant-prompt-finalize to the static source file 5 years ago
romkatv cf2eef5556 add p10k-instant-prompt-finalize 5 years ago
romkatv d17f22e5b0 better handling of XDG_CACHE_HOME changes 5 years ago
romkatv cb2473751e add diagnostics when prompt_cr is set after sourcing p10k with instant prompt; improve diagnostics for delayed loading of p10k with instant prompt 5 years ago
romkatv f11f76ec5b slightly better handling of options and disabling of instant prompt 5 years ago
romkatv ad16896b9d bump instant prompt version 5 years ago
romkatv fde23891a4 unsetopt prompt_cr prompt_sp from p10k-instant-prompt for good measure 5 years ago
romkatv 461d1ca43d clear instant prompt a little bit later 5 years ago
romkatv a1bab30690 don't use prompt segments with non-hermetic expansions in instant prompt 5 years ago
romkatv 148a8500c1 fix bugs in instant prompt 5 years ago
romkatv 3cf30a25e4 fix bugs in instant prompt 5 years ago
romkatv 41c0a87918 wip: instant prompt (part 4) 5 years ago
romkatv 68d6ffd844 wip: instant prompt (part 3) 5 years ago
romkatv 4536dc2a27 Merge branch 'master' into instant-prompt 5 years ago
romkatv aa53902281 pull upstream changes from gitstatus 5 years ago
romkatv f2cd89ed70 work around a bug in zsh that percent-expands `%1F{2}` as if it was `%F{2}`; fixes #270 5 years ago
romkatv 41084c089e wip: instant prompt (part 2) 5 years ago
romkatv 164fcad558 save git prompt in ephemeral cache 5 years ago
romkatv 727b483810 wip: instant prompt 5 years ago
romkatv 94de8519b4 cleanup 5 years ago
Melvyn de Kort abf1e3b0af Also show the default profile when set 5 years ago
Melvyn de Kort 9fdbd4a3e7 Add support for awsume 5 years ago
romkatv f21a2e3c46 add ITERM_SHELL_INTEGRATION_INSTALLED to param sig; inline iterm2_prompt_mark 5 years ago
romkatv fc404a2d8a bug fix: display the right OS icon on Android 5 years ago
romkatv 3775ec7175 pull upstream changes from gitstatus 5 years ago
Benedikt Stemmildt af2b394eb3 Fix EXC_BAD_ACCESS on MacOS Catalina
Fix #259
5 years ago
romkatv 13fdf0a426 update screenshot, now with rainbow style 5 years ago

5
.gitattributes vendored

@ -0,0 +1,5 @@
* text=auto
*.zsh text eol=lf
*.zsh-theme text eol=lf
/prompt_powerlevel9k_setup text eol=lf
/prompt_powerlevel10k_setup text eol=lf

@ -0,0 +1,14 @@
ZSH := $(shell command -v zsh 2> /dev/null)
all:
zwc:
$(MAKE) -C gitstatus zwc
$(or $(ZSH),:) -fc 'for f in *.zsh-theme internal/*.zsh; do zcompile -R -- $$f.zwc $$f || exit; done'
minify:
$(MAKE) -C gitstatus minify
rm -rf -- .git .gitattributes .gitignore LICENSE Makefile README.md font.md powerlevel10k.png
pkg: zwc
$(MAKE) -C gitstatus pkg

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -12,7 +12,8 @@
# doesn't fit on one line, it wraps around with no attempt to shorten it.
#
# If you like the general style of Pure but not particularly attached to all its quirks, type
# `p10k configure` while having Powerlevel10k theme active and pick "Lean" style.
# `p10k configure` and pick "Lean" style. This will give you slick minimalist prompt while taking
# advantage of Powerlevel10k features that aren't present in Pure.
# Temporarily change options.
'builtin' 'local' '-a' 'p10k_config_opts'
@ -22,25 +23,46 @@
'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand'
() {
emulate -L zsh
setopt no_unset
emulate -L zsh -o extended_glob
# Unset all configuration options.
unset -m 'POWERLEVEL9K_*'
unset -m '(POWERLEVEL9K_*|DEFAULT_USER)~POWERLEVEL9K_GITSTATUS_DIR'
# Zsh >= 5.1 is required.
[[ $ZSH_VERSION == (5.<1->*|<6->.*) ]] || return
# Prompt colors.
local grey=242
local red=1
local yellow=3
local blue=4
local magenta=5
local cyan=6
local white=7
# Left prompt segments.
typeset -g POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(
dir # current directory
vcs # git status
context # user@host
command_execution_time # previous command duration
newline # \n
virtualenv # python virtual environment
prompt_char # prompt symbol
# =========================[ Line #1 ]=========================
context # user@host
dir # current directory
vcs # git status
command_execution_time # previous command duration
# =========================[ Line #2 ]=========================
newline # \n
virtualenv # python virtual environment
prompt_char # prompt symbol
)
# Right prompt segments.
typeset -g POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=()
typeset -g POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=(
# =========================[ Line #1 ]=========================
# command_execution_time # previous command duration
# virtualenv # python virtual environment
# context # user@host
# time # current time
# =========================[ Line #2 ]=========================
newline # \n
)
# Basic style options that define the overall prompt look.
typeset -g POWERLEVEL9K_BACKGROUND= # transparent background
@ -50,37 +72,35 @@
typeset -g POWERLEVEL9K_VISUAL_IDENTIFIER_EXPANSION= # no segment icons
# Add an empty line before each prompt except the first. This doesn't emulate the bug
# in Pure that makes prompt drift down whenever you use the ALT-C binding from fzf or similar.
# in Pure that makes prompt drift down whenever you use the Alt-C binding from fzf or similar.
typeset -g POWERLEVEL9K_PROMPT_ADD_NEWLINE=true
# Magenta prompt symbol if the last command succeeded.
typeset -g POWERLEVEL9K_PROMPT_CHAR_OK_{VIINS,VICMD,VIVIS}_FOREGROUND=magenta
typeset -g POWERLEVEL9K_PROMPT_CHAR_OK_{VIINS,VICMD,VIVIS}_FOREGROUND=$magenta
# Red prompt symbol if the last command failed.
typeset -g POWERLEVEL9K_PROMPT_CHAR_ERROR_{VIINS,VICMD,VIVIS}_FOREGROUND=red
typeset -g POWERLEVEL9K_PROMPT_CHAR_ERROR_{VIINS,VICMD,VIVIS}_FOREGROUND=$red
# Default prompt symbol.
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIINS_CONTENT_EXPANSION=''
# Prompt symbol in command vi mode.
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VICMD_CONTENT_EXPANSION=''
# Prompt symbol in visual vi mode is the same as in command mode. This is unlikely
# to be desired by anyone but that's how Pure does it.
# Prompt symbol in visual vi mode is the same as in command mode.
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIVIS_CONTENT_EXPANSION=''
# Prompt symbol in overwrite vi mode is the same as in command mode. This is unlikely
# to be desired by anyone but that's how Pure does it.
# Prompt symbol in overwrite vi mode is the same as in command mode.
typeset -g POWERLEVEL9K_PROMPT_CHAR_OVERWRITE_STATE=false
# Grey Python Virtual Environment.
typeset -g POWERLEVEL9K_VIRTUALENV_FOREGROUND=242
typeset -g POWERLEVEL9K_VIRTUALENV_FOREGROUND=$grey
# Don't show Python version.
typeset -g POWERLEVEL9K_VIRTUALENV_SHOW_PYTHON_VERSION=false
typeset -g POWERLEVEL9K_VIRTUALENV_{LEFT,RIGHT}_DELIMITER=
# Blue current directory.
typeset -g POWERLEVEL9K_DIR_FOREGROUND=blue
typeset -g POWERLEVEL9K_DIR_FOREGROUND=$blue
# Context format when root: user@host. The first part white, the rest grey.
typeset -g POWERLEVEL9K_CONTEXT_ROOT_TEMPLATE='%7F%n%f%242F@%m%f'
typeset -g POWERLEVEL9K_CONTEXT_ROOT_TEMPLATE="%F{$white}%n%f%F{$grey}@%m%f"
# Context format when not root: user@host. The whole thing grey.
typeset -g POWERLEVEL9K_CONTEXT_TEMPLATE='%242F%n@%m%f'
typeset -g POWERLEVEL9K_CONTEXT_TEMPLATE="%F{$grey}%n@%m%f"
# Don't show context unless root or in SSH.
typeset -g POWERLEVEL9K_CONTEXT_{DEFAULT,SUDO}_CONTENT_EXPANSION=
@ -91,10 +111,10 @@
# Duration format: 1d 2h 3m 4s.
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FORMAT='d h m s'
# Yellow previous command duration.
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FOREGROUND=yellow
typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FOREGROUND=$yellow
# Grey Git prompt. This makes stale prompts indistinguishable from up-to-date ones.
typeset -g POWERLEVEL9K_VCS_FOREGROUND=242
typeset -g POWERLEVEL9K_VCS_FOREGROUND=$grey
# Disable async loading indicator to make directories that aren't Git repositories
# indistinguishable from large Git repositories without known state.
@ -105,26 +125,69 @@
typeset -g POWERLEVEL9K_VCS_MAX_SYNC_LATENCY_SECONDS=0
# Cyan ahead/behind arrows.
typeset -g POWERLEVEL9K_VCS_{INCOMING,OUTGOING}_CHANGESFORMAT_FOREGROUND=cyan
typeset -g POWERLEVEL9K_VCS_{INCOMING,OUTGOING}_CHANGESFORMAT_FOREGROUND=$cyan
# Don't show remote branch, current tag or stashes.
typeset -g POWERLEVEL9K_VCS_GIT_HOOKS=(vcs-detect-changes git-untracked git-aheadbehind)
# Don't show the branh icon.
# Don't show the branch icon.
typeset -g POWERLEVEL9K_VCS_BRANCH_ICON=
# When in detached HEAD state, show @commit where branch normally goes.
typeset -g POWERLEVEL9K_VCS_COMMIT_ICON='@'
# Don't show staged, unstaged, untracked indicators.
typeset -g POWERLEVEL9K_VCS_{STAGED,UNSTAGED,UNTRACKED}_ICON=$'\b'
typeset -g POWERLEVEL9K_VCS_{STAGED,UNSTAGED,UNTRACKED}_ICON=
# Show '*' when there are staged, unstaged or untracked files.
typeset -g POWERLEVEL9K_VCS_DIRTY_ICON='*'
# Show '⇣' if local branch is behind remote.
typeset -g POWERLEVEL9K_VCS_INCOMING_CHANGES_ICON='⇣'
typeset -g POWERLEVEL9K_VCS_INCOMING_CHANGES_ICON=':⇣'
# Show '⇡' if local branch is ahead of remote.
typeset -g POWERLEVEL9K_VCS_OUTGOING_CHANGES_ICON='⇡'
typeset -g POWERLEVEL9K_VCS_OUTGOING_CHANGES_ICON=':⇡'
# Don't show the number of commits next to the ahead/behind arrows.
typeset -g POWERLEVEL9K_VCS_{COMMITS_AHEAD,COMMITS_BEHIND}_MAX_NUM=1
# Remove space between '⇣' and '⇡', and get rid of $' \b'.
typeset -g POWERLEVEL9K_VCS_CONTENT_EXPANSION=$'${${P9K_CONTENT/⇣* ⇡/⇣⇡}// \b}'
# Remove space between '⇣' and '⇡' and all trailing spaces.
typeset -g POWERLEVEL9K_VCS_CONTENT_EXPANSION='${${${P9K_CONTENT/⇣* :⇡/⇣⇡}// }//:/ }'
# Grey current time.
typeset -g POWERLEVEL9K_TIME_FOREGROUND=$grey
# Format for the current time: 09:51:02. See `man 3 strftime`.
typeset -g POWERLEVEL9K_TIME_FORMAT='%D{%H:%M:%S}'
# If set to true, time will update when you hit enter. This way prompts for the past
# commands will contain the start times of their commands rather than the end times of
# their preceding commands.
typeset -g POWERLEVEL9K_TIME_UPDATE_ON_COMMAND=false
# Transient prompt works similarly to the builtin transient_rprompt option. It trims down prompt
# when accepting a command line. Supported values:
#
# - off: Don't change prompt when accepting a command line.
# - always: Trim down prompt when accepting a command line.
# - same-dir: Trim down prompt when accepting a command line unless this is the first command
# typed after changing current working directory.
typeset -g POWERLEVEL9K_TRANSIENT_PROMPT=off
# Instant prompt mode.
#
# - off: Disable instant prompt. Choose this if you've tried instant prompt and found
# it incompatible with your zsh configuration files.
# - quiet: Enable instant prompt and don't print warnings when detecting console output
# during zsh initialization. Choose this if you've read and understood
# https://github.com/romkatv/powerlevel10k#instant-prompt.
# - verbose: Enable instant prompt and print a warning when detecting console output during
# zsh initialization. Choose this if you've never tried instant prompt, haven't
# seen the warning, or if you are unsure what this all means.
typeset -g POWERLEVEL9K_INSTANT_PROMPT=verbose
# Hot reload allows you to change POWERLEVEL9K options after Powerlevel10k has been initialized.
# For example, you can type POWERLEVEL9K_BACKGROUND=red and see your prompt turn red. Hot reload
# can slow down prompt by 1-2 milliseconds, so it's better to keep it turned off unless you
# really need it.
typeset -g POWERLEVEL9K_DISABLE_HOT_RELOAD=true
# If p10k is already loaded, reload configuration.
# This works even with POWERLEVEL9K_DISABLE_HOT_RELOAD=true.
(( ! $+functions[p10k] )) || p10k reload
}
# Tell `p10k configure` which file it should overwrite.
typeset -g POWERLEVEL9K_CONFIG_FILE=${${(%):-%x}:a}
(( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]}
'builtin' 'unset' 'p10k_config_opts'

File diff suppressed because it is too large Load Diff

@ -0,0 +1,111 @@
# Config file for Powerlevel10k with the style of robbyrussell theme from Oh My Zsh.
#
# Original: https://github.com/ohmyzsh/ohmyzsh/wiki/Themes#robbyrussell.
#
# Replication of robbyrussell theme is exact. The only observable difference is in
# performance. Powerlevel10k prompt is very fast everywhere, even in large Git repositories.
#
# Usage: Source this file either before or after loading Powerlevel10k.
#
# source ~/powerlevel10k/config/p10k-robbyrussell.zsh
# source ~/powerlevel10k/powerlevel10k.zsh-theme
# Temporarily change options.
'builtin' 'local' '-a' 'p10k_config_opts'
[[ ! -o 'aliases' ]] || p10k_config_opts+=('aliases')
[[ ! -o 'sh_glob' ]] || p10k_config_opts+=('sh_glob')
[[ ! -o 'no_brace_expand' ]] || p10k_config_opts+=('no_brace_expand')
'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand'
() {
emulate -L zsh -o extended_glob
# Unset all configuration options.
unset -m '(POWERLEVEL9K_*|DEFAULT_USER)~POWERLEVEL9K_GITSTATUS_DIR'
# Zsh >= 5.1 is required.
[[ $ZSH_VERSION == (5.<1->*|<6->.*) ]] || return
# Left prompt segments.
typeset -g POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(prompt_char dir vcs)
# Right prompt segments.
typeset -g POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=()
# Basic style options that define the overall prompt look.
typeset -g POWERLEVEL9K_BACKGROUND= # transparent background
typeset -g POWERLEVEL9K_{LEFT,RIGHT}_{LEFT,RIGHT}_WHITESPACE= # no surrounding whitespace
typeset -g POWERLEVEL9K_{LEFT,RIGHT}_SUBSEGMENT_SEPARATOR=' ' # separate segments with a space
typeset -g POWERLEVEL9K_{LEFT,RIGHT}_SEGMENT_SEPARATOR= # no end-of-line symbol
typeset -g POWERLEVEL9K_VISUAL_IDENTIFIER_EXPANSION= # no segment icons
# Green prompt symbol if the last command succeeded.
typeset -g POWERLEVEL9K_PROMPT_CHAR_OK_{VIINS,VICMD,VIVIS}_FOREGROUND=green
# Red prompt symbol if the last command failed.
typeset -g POWERLEVEL9K_PROMPT_CHAR_ERROR_{VIINS,VICMD,VIVIS}_FOREGROUND=red
# Prompt symbol: bold arrow.
typeset -g POWERLEVEL9K_PROMPT_CHAR_CONTENT_EXPANSION='%B➜ '
# Cyan current directory.
typeset -g POWERLEVEL9K_DIR_FOREGROUND=cyan
# Show only the last segment of the current directory.
typeset -g POWERLEVEL9K_SHORTEN_STRATEGY=truncate_to_last
# Bold directory.
typeset -g POWERLEVEL9K_DIR_CONTENT_EXPANSION='%B$P9K_CONTENT'
# Git status formatter.
function my_git_formatter() {
emulate -L zsh
if [[ -n $P9K_CONTENT ]]; then
# If P9K_CONTENT is not empty, it's either "loading" or from vcs_info (not from
# gitstatus plugin). VCS_STATUS_* parameters are not available in this case.
typeset -g my_git_format=$P9K_CONTENT
else
# Use VCS_STATUS_* parameters to assemble Git status. See reference:
# https://github.com/romkatv/gitstatus/blob/master/gitstatus.plugin.zsh.
typeset -g my_git_format="${1+%B%4F}git:(${1+%1F}"
my_git_format+=${${VCS_STATUS_LOCAL_BRANCH:-${VCS_STATUS_COMMIT[1,8]}}//\%/%%}
my_git_format+="${1+%4F})"
if (( VCS_STATUS_NUM_CONFLICTED || VCS_STATUS_NUM_STAGED ||
VCS_STATUS_NUM_UNSTAGED || VCS_STATUS_NUM_UNTRACKED )); then
my_git_format+=" ${1+%3F}"
fi
fi
}
functions -M my_git_formatter 2>/dev/null
# Disable the default Git status formatting.
typeset -g POWERLEVEL9K_VCS_DISABLE_GITSTATUS_FORMATTING=true
# Install our own Git status formatter.
typeset -g POWERLEVEL9K_VCS_CONTENT_EXPANSION='${$((my_git_formatter(1)))+${my_git_format}}'
typeset -g POWERLEVEL9K_VCS_LOADING_CONTENT_EXPANSION='${$((my_git_formatter()))+${my_git_format}}'
# Grey Git status when loading.
typeset -g POWERLEVEL9K_VCS_LOADING_FOREGROUND=246
# Instant prompt mode.
#
# - off: Disable instant prompt. Choose this if you've tried instant prompt and found
# it incompatible with your zsh configuration files.
# - quiet: Enable instant prompt and don't print warnings when detecting console output
# during zsh initialization. Choose this if you've read and understood
# https://github.com/romkatv/powerlevel10k#instant-prompt.
# - verbose: Enable instant prompt and print a warning when detecting console output during
# zsh initialization. Choose this if you've never tried instant prompt, haven't
# seen the warning, or if you are unsure what this all means.
typeset -g POWERLEVEL9K_INSTANT_PROMPT=verbose
# Hot reload allows you to change POWERLEVEL9K options after Powerlevel10k has been initialized.
# For example, you can type POWERLEVEL9K_BACKGROUND=red and see your prompt turn red. Hot reload
# can slow down prompt by 1-2 milliseconds, so it's better to keep it turned off unless you
# really need it.
typeset -g POWERLEVEL9K_DISABLE_HOT_RELOAD=true
# If p10k is already loaded, reload configuration.
# This works even with POWERLEVEL9K_DISABLE_HOT_RELOAD=true.
(( ! $+functions[p10k] )) || p10k reload
}
# Tell `p10k configure` which file it should overwrite.
typeset -g POWERLEVEL9K_CONFIG_FILE=${${(%):-%x}:a}
(( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]}
'builtin' 'unset' 'p10k_config_opts'

@ -0,0 +1,167 @@
# Recommended font: Meslo Nerd Font patched for Powerlevel10k
Gorgeous monospace font designed by Jim Lyles for Bitstream, customized by the same for Apple,
further customized by André Berg, and finally patched by yours truly with customized scripts
originally developed by Ryan L McIntyre of Nerd Fonts. Contains all glyphs and symbols that
Powerlevel10k may need. Battle-tested in dozens of different terminals on all major operating
systems.
*FAQ*: [How was the recommended font created?](README.md#how-was-the-recommended-font-created)
## Automatic font installation
If you are using iTerm2 or Termux, `p10k configure` can install the recommended font for you.
Simply answer `Yes` when asked whether to install *Meslo Nerd Font*.
If you are using a different terminal, proceed with manual font installation. 👇
## Manual font installation
1. Download these four ttf files:
- [MesloLGS NF Regular.ttf](
https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Regular.ttf)
- [MesloLGS NF Bold.ttf](
https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold.ttf)
- [MesloLGS NF Italic.ttf](
https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Italic.ttf)
- [MesloLGS NF Bold Italic.ttf](
https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold%20Italic.ttf)
1. Double-click on each file and click "Install". This will make `MesloLGS NF` font available to all
applications on your system.
1. Configure your terminal to use this font:
- **iTerm2**: Type `p10k configure` and answer `Yes` when asked whether to install
*Meslo Nerd Font*. Alternatively, open *iTerm2 → Preferences → Profiles → Text* and set *Font* to
`MesloLGS NF`.
- **Apple Terminal**: Open *Terminal → Preferences → Profiles → Text*, click *Change* under *Font*
and select `MesloLGS NF` family.
- **Hyper**: Open *Hyper → Edit → Preferences* and change the value of `fontFamily` under
`module.exports.config` to `MesloLGS NF`.
- **Visual Studio Code**: Open *File → Preferences → Settings* (PC) or
*Code → Preferences → Settings* (Mac), enter `terminal.integrated.fontFamily` in the search box at
the top of *Settings* tab and set the value below to `MesloLGS NF`.
Consult [this screenshot](
https://raw.githubusercontent.com/romkatv/powerlevel10k-media/389133fb8c9a2347929a23702ce3039aacc46c3d/visual-studio-code-font-settings.jpg)
to see how it should look like or see [this issue](
https://github.com/romkatv/powerlevel10k/issues/671) for extra information.
- **GNOME Terminal** (the default Ubuntu terminal): Open *Terminal → Preferences* and click on the
selected profile under *Profiles*. Check *Custom font* under *Text Appearance* and select
`MesloLGS NF Regular`.
- **Konsole**: Open *Settings → Edit Current Profile → Appearance*, click *Select Font* and select
`MesloLGS NF Regular`.
- **Tilix**: Open *Tilix → Preferences* and click on the selected profile under *Profiles*. Check
*Custom font* under *Text Appearance* and select `MesloLGS NF Regular`.
- **Windows Console Host** (the old thing): Click the icon in the top left corner, then
*Properties → Font* and set *Font* to `MesloLGS NF`.
- **Windows Terminal** by Microsoft (the new thing): Open *Settings* (<kbd>Ctrl+,</kbd>), click
either on the selected profile under *Profiles* or on *Defaults*, click *Appearance* and set
*Font face* to `MesloLGS NF`.
- **Conemu**: Open *Setup → General → Fonts* and set *Main console font* to `MesloLGS NF`.
- **IntelliJ** (and other IDEs by Jet Brains): Open *IDE → Edit → Preferences → Editor →
Color Scheme → Console Font*. Select *Use console font instead of the default* and set the font
name to `MesloLGS NF`.
- **Termux**: Type `p10k configure` and answer `Yes` when asked whether to install
*Meslo Nerd Font*.
- **Blink**: Type `config`, go to *Appearance*, tap *Add a new font*, tap *Open Gallery*, select
*MesloLGS NF.css*, tap *import* and type `exit` in the home view to reload the font.
- **Tabby** (formerly **Terminus**): Open *Settings → Appearance* and set *Font* to `MesloLGS NF`.
- **Terminator**: Open *Preferences* using the context menu. Under *Profiles* select the *General*
tab (should be selected already), uncheck *Use the system fixed width font* (if not already)
and select `MesloLGS NF Regular`. Exit the Preferences dialog by clicking *Close*.
- **Guake**: Right Click on an open terminal and open *Preferences*. Under *Appearance*
tab, uncheck *Use the system fixed width font* (if not already) and select `MesloLGS NF Regular`.
Exit the Preferences dialog by clicking *Close*.
- **MobaXterm**: Open *Settings**Configuration**Terminal* → (under *Terminal look and feel*)
and change *Font* to `MesloLGS NF`. If you have *sessions*, you need to change the font in each
of them through *Settings* → right click on an individual session → *Edit Session* → *Terminal
Settings* → *Font settings*.
- **Asbrú Connection Manager**: Open *Preferences → Local Shell Options → Look and Feel*, enable
*Use these personal options* and change *Font:* under *Terminal UI* to `MesloLGS NF Regular`.
To change the font for the remote host connections, go to *Preferences → Terminal Options →
Look and Feel* and change *Font:* under *Terminal UI* to `MesloLGS NF Regular`.
- **WSLtty**: Right click on an open terminal and then on *Options*. In the *Text* section, under
*Font*, click *"Select..."* and set Font to `MesloLGS NF Regular`.
- **Yakuake**: Click *≡**Manage Profiles**New**Appearance*. Click *Choose* next to the
*Font* dropdown, select `MesloLGS NF` and click *OK*. Click *OK* to save the profile. Select the
new profile and click *Set as Default*.
- **Alacritty**: Create or open `~/.config/alacritty/alacritty.toml` and add the following
section to it:
```toml
[font.normal]
family = "MesloLGS NF"
```
- **foot**: Create or open `~/.config/foot/foot.ini` and add the following section to it:
```ini
font=MesloLGS NF:size=12
```
- **kitty**: Create or open `~/.config/kitty/kitty.conf` and add the following line to it:
```text
font_family MesloLGS NF
```
Restart kitty by closing all sessions and opening a new session.
- **puTTY**: Set *Window**Appearance**Font* to `MesloLGS NF`. Requires puTTY
version >= 0.75.
- **WezTerm**: Create or open `$HOME/.config/wezterm/wezterm.lua` and add the following:
```lua
local wezterm = require 'wezterm';
return {
font = wezterm.font("MesloLGS NF"),
}
```
If the file already exists, only add the line with the font to the existing return.
Also add the first line if it is not already present.
- **urxvt**: Create or open `~/.Xresources` and add the following line to it:
```text
URxvt.font: xft:MesloLGS NF:size=11
```
You can adjust the font size to your preference. After changing the config run
`xrdb ~/.Xresources` to reload it. The new config is applied to all new terminals.
- **xterm**: Create or open `~/.Xresources` and add the following line to it:
```text
xterm*faceName: MesloLGS NF
```
After changing the config run `xrdb ~/.Xresources` to reload it. The new config is applied to
all new terminals.
- **Zed**: Open `~/.config/zed/settings.json` and set `terminal.font_family` to `"MesloLGS NF"`.
```jsonc
{
"terminal": {
"font_family": "MesloLGS NF"
},
// Other settings.
}
```
- Crostini (Linux on Chrome OS): Open
chrome-untrusted://terminal/html/nassh_preferences_editor.html, set *Text font family* to
`'MesloLGS NF'` (including the quotes) and *Custom CSS (inline text)* to the following:
```css
@font-face {
font-family: "MesloLGS NF";
src: url("https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/MesloLGS%20NF%20Regular.ttf");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "MesloLGS NF";
src: url("https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/MesloLGS%20NF%20Bold.ttf");
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: "MesloLGS NF";
src: url("https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/MesloLGS%20NF%20Italic.ttf");
font-weight: normal;
font-style: italic;
}
@font-face {
font-family: "MesloLGS NF";
src: url("https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/MesloLGS%20NF%20Bold%20Italic.ttf");
font-weight: bold;
font-style: italic;
}
```
**_CAVEAT_**: If you open the normal terminal preferences these settings will be overwritten.
1. Run `p10k configure` to generate a new `~/.p10k.zsh`. The old config may work
incorrectly with the new font.
_Using a different terminal and know how to set the font for it? Share your knowledge by sending a
PR to expand the list!_

@ -0,0 +1,4 @@
BasedOnStyle: Google
ColumnLimit: 100
DerivePointerAlignment: false
PointerAlignment: Left

@ -0,0 +1,16 @@
* text=auto
*.cc text eol=lf
*.h text eol=lf
*.info text eol=lf
*.json text eol=lf
*.md text eol=lf
*.sh text eol=lf
*.zsh text eol=lf
/.clang-format text eol=lf
/LICENSE text eol=lf
/Makefile text eol=lf
/build text eol=lf
/install text eol=lf
/mbuild text eol=lf

@ -0,0 +1,8 @@
*.zwc
/core
/deps/libgit2-*.tar.gz
/locks
/logs
/obj
/usrbin/gitstatusd*
/.vscode/ipch

@ -0,0 +1,17 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/src"
],
"defines": [
],
"compilerPath": "/usr/bin/g++",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "gcc-x64"
}
],
"version": 4
}

@ -0,0 +1,72 @@
{
"files.exclude": {
"*.zwc": true,
"core": true,
"locks/": true,
"logs/": true,
"obj/": true,
"usrbin/": true,
},
"files.associations": {
"array": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"complex": "cpp",
"condition_variable": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"fstream": "cpp",
"functional": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"memory": "cpp",
"mutex": "cpp",
"new": "cpp",
"numeric": "cpp",
"optional": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"thread": "cpp",
"type_traits": "cpp",
"tuple": "cpp",
"typeinfo": "cpp",
"utility": "cpp",
"variant": "cpp",
"cstdarg": "cpp",
"charconv": "cpp",
"algorithm": "cpp",
"cinttypes": "cpp",
"iterator": "cpp",
"map": "cpp",
"memory_resource": "cpp",
"random": "cpp",
"string": "cpp",
"bit": "cpp",
"netfwd": "cpp"
}
}

@ -0,0 +1,57 @@
APPNAME ?= gitstatusd
OBJDIR ?= obj
CXX ?= g++
ZSH := $(shell command -v zsh 2> /dev/null)
VERSION ?= $(shell . ./build.info && printf "%s" "$$gitstatus_version")
# Note: -fsized-deallocation is not used to avoid binary compatibility issues on macOS.
#
# Sized delete is implemented as __ZdlPvm in /usr/lib/libc++.1.dylib but this symbol is
# missing in macOS prior to 10.13.
CXXFLAGS += -std=c++14 -funsigned-char -O3 -DNDEBUG -DGITSTATUS_VERSION=$(VERSION) -Wall # -g -fsanitize=thread
LDFLAGS += -pthread # -fsanitize=thread
LDLIBS += -lgit2 # -lprofiler -lunwind
SRCS := $(shell find src -name "*.cc")
OBJS := $(patsubst src/%.cc, $(OBJDIR)/%.o, $(SRCS))
all: $(APPNAME)
$(APPNAME): usrbin/$(APPNAME)
usrbin/$(APPNAME): $(OBJS)
$(CXX) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@
$(OBJDIR):
mkdir -p -- $(OBJDIR)
$(OBJDIR)/%.o: src/%.cc Makefile build.info | $(OBJDIR)
$(CXX) $(CXXFLAGS) -MM -MT $@ src/$*.cc >$(OBJDIR)/$*.dep
$(CXX) $(CXXFLAGS) -Wall -c -o $@ src/$*.cc
clean:
rm -rf -- $(OBJDIR)
zwc:
$(or $(ZSH),:) -fc 'for f in *.zsh install; do zcompile -R -- $$f.zwc $$f || exit; done'
minify:
rm -rf -- .clang-format .git .gitattributes .gitignore .vscode deps docs src usrbin/.gitkeep LICENSE Makefile README.md build mbuild
pkg: zwc
GITSTATUS_DAEMON= GITSTATUS_CACHE_DIR=$(shell pwd)/usrbin ./install -f
-include $(OBJS:.o=.dep)
.PHONY: help
help:
@echo "Usage: make [TARGET]"
@echo "Available targets:"
@echo " all Build $(APPNAME) (default target)"
@echo " clean Remove generated files and directories"
@echo " zwc Compile Zsh files"
@echo " minify Remove unnecessary files and folders"
@echo " pkg Create a package"

@ -1 +1,530 @@
This is a bundled copy of [gitstatus](https://github.com/romkatv/gitstatus) ZSH plugin.
# gitstatus
**gitstatus** is a 10x faster alternative to `git status` and `git describe`. Its primary use
case is to enable fast git prompt in interactive shells.
Heavy lifting is done by **gitstatusd** -- a custom binary written in C++. It comes with Zsh and
Bash bindings for integration with shell.
## Table of Contents
1. [Using from Zsh](#using-from-zsh)
1. [Using from Bash](#using-from-bash)
2. [Using from other shells](#using-from-other-shells)
1. [How it works](#how-it-works)
1. [Benchmarks](#benchmarks)
1. [Why fast](#why-fast)
1. [Requirements](#requirements)
1. [Compiling](#compiling)
1. [License](#license)
## Using from Zsh
The easiest way to take advantage of gitstatus from Zsh is to use a theme that's already integrated
with it. For example, [Powerlevel10k](https://github.com/romkatv/powerlevel10k) is a flexible and
fast theme with first-class gitstatus integration. If you install Powerlevel10k, you don't need to
install gitstatus.
![Powerlevel10k Zsh Theme](
https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/prompt-styles-high-contrast.png)
For those who wish to use gitstatus without a theme, there is
[gitstatus.prompt.zsh](gitstatus.prompt.zsh). Install it as follows:
```zsh
git clone --depth=1 https://github.com/romkatv/gitstatus.git ~/gitstatus
echo 'source ~/gitstatus/gitstatus.prompt.zsh' >>! ~/.zshrc
```
Users in China can use the official mirror on gitee.com for faster download.<br>
中国大陆用户可以使用 gitee.com 上的官方镜像加速下载.
```zsh
git clone --depth=1 https://gitee.com/romkatv/gitstatus.git ~/gitstatus
echo 'source ~/gitstatus/gitstatus.prompt.zsh' >>! ~/.zshrc
```
Alternatively, if you have Homebrew installed:
```zsh
brew install romkatv/gitstatus/gitstatus
echo "source $(brew --prefix)/opt/gitstatus/gitstatus.prompt.zsh" >>! ~/.zshrc
```
(If you choose this option, replace `~/gitstatus` with `$(brew --prefix)/opt/gitstatus/gitstatus`
in all code snippets below.)
_Make sure to disable your current theme if you have one._
This will give you a basic yet functional prompt with git status in it. It's
[over 10x faster](#benchmarks) than any alternative that can give you comparable prompt. In order
to customize it, set `PROMPT` and/or `RPROMPT` at the end of `~/.zshrc` after sourcing
`gitstatus.prompt.zsh`. Insert `${GITSTATUS_PROMPT}` where you want git status to go. For example:
```zsh
source ~/gitstatus/gitstatus.prompt.zsh
PROMPT='%~%# ' # left prompt: directory followed by %/# (normal/root)
RPROMPT='$GITSTATUS_PROMPT' # right prompt: git status
```
The expansion of `${GITSTATUS_PROMPT}` can contain the following bits:
| segment | meaning |
|-------------|-------------------------------------------------------|
| `master` | current branch |
| `#v1` | HEAD is tagged with `v1`; not shown when on a branch |
| `@5fc6fca4` | current commit; not shown when on a branch or tag |
| `⇣1` | local branch is behind the remote by 1 commit |
| `⇡2` | local branch is ahead of the remote by 2 commits |
| `⇠3` | local branch is behind the push remote by 3 commits |
| `⇢4` | local branch is ahead of the push remote by 4 commits |
| `*5` | there are 5 stashes |
| `merge` | merge is in progress (could be some other action) |
| `~6` | there are 6 merge conflicts |
| `+7` | there are 7 staged changes |
| `!8` | there are 8 unstaged changes |
| `?9` | there are 9 untracked files |
`$GITSTATUS_PROMPT_LEN` tells you how long `$GITSTATUS_PROMPT` is when printed to the console.
[gitstatus.prompt.zsh](gitstatus.prompt.zsh) has an example of using it to truncate the current
directory.
If you'd like to change the format of git status, or want to have greater control over the
process of assembling `PROMPT`, you can copy and modify parts of
[gitstatus.prompt.zsh](gitstatus.prompt.zsh) instead of sourcing the script. Your `~/.zshrc`
might look something like this:
```zsh
source ~/gitstatus/gitstatus.plugin.zsh
function my_set_prompt() {
PROMPT='%~%# '
RPROMPT=''
if gitstatus_query MY && [[ $VCS_STATUS_RESULT == ok-sync ]]; then
RPROMPT=${${VCS_STATUS_LOCAL_BRANCH:-@${VCS_STATUS_COMMIT}}//\%/%%} # escape %
(( VCS_STATUS_NUM_STAGED )) && RPROMPT+='+'
(( VCS_STATUS_NUM_UNSTAGED )) && RPROMPT+='!'
(( VCS_STATUS_NUM_UNTRACKED )) && RPROMPT+='?'
fi
setopt no_prompt_{bang,subst} prompt_percent # enable/disable correct prompt expansions
}
gitstatus_stop 'MY' && gitstatus_start -s -1 -u -1 -c -1 -d -1 'MY'
autoload -Uz add-zsh-hook
add-zsh-hook precmd my_set_prompt
```
This snippet is sourcing `gitstatus.plugin.zsh` rather than `gitstatus.prompt.zsh`. The former
defines low-level bindings that communicate with gitstatusd over pipes. The latter is a simple
script that uses these bindings to assemble git prompt.
Unlike [Powerlevel10k](https://github.com/romkatv/powerlevel10k), code based on
[gitstatus.prompt.zsh](gitstatus.prompt.zsh) is communicating with gitstatusd synchronously. This
can make your prompt slow when working in a large git repository or on a slow machine. To avoid
this problem, call `gitstatus_query` asynchronously as documented in
[gitstatus.plugin.zsh](gitstatus.plugin.zsh). This can be quite challenging.
## Using from Bash
The easiest way to take advantage of gitstatus from Bash is via
[gitstatus.prompt.sh](gitstatus.prompt.sh). Install it as follows:
```bash
git clone --depth=1 https://github.com/romkatv/gitstatus.git ~/gitstatus
echo 'source ~/gitstatus/gitstatus.prompt.sh' >> ~/.bashrc
```
Users in China can use the official mirror on gitee.com for faster download.<br>
中国大陆用户可以使用 gitee.com 上的官方镜像加速下载.
```bash
git clone --depth=1 https://gitee.com/romkatv/gitstatus.git ~/gitstatus
echo 'source ~/gitstatus/gitstatus.prompt.sh' >> ~/.bashrc
```
Alternatively, if you have Homebrew installed:
```zsh
brew install romkatv/gitstatus/gitstatus
echo "source $(brew --prefix)/opt/gitstatus/gitstatus.prompt.sh" >> ~/.bashrc
```
(If you choose this option, replace `~/gitstatus` with `$(brew --prefix)/opt/gitstatus/gitstatus`
in all code snippets below.)
This will give you a basic yet functional prompt with git status in it. It's
[over 10x faster](#benchmarks) than any alternative that can give you comparable prompt.
![Bash Prompt with GitStatus](
https://raw.githubusercontent.com/romkatv/gitstatus/1ac366952366d89980b3f3484f270b4fa5ae4293/bash-prompt.png)
In order to customize your prompt, set `PS1` at the end of `~/.bashrc` after sourcing
`gitstatus.prompt.sh`. Insert `${GITSTATUS_PROMPT}` where you want git status to go. For example:
```bash
source ~/gitstatus/gitstatus.prompt.sh
PS1='\w ${GITSTATUS_PROMPT}\n\$ ' # directory followed by git status and $/# (normal/root)
```
The expansion of `${GITSTATUS_PROMPT}` can contain the following bits:
| segment | meaning |
|-------------|-------------------------------------------------------|
| `master` | current branch |
| `#v1` | HEAD is tagged with `v1`; not shown when on a branch |
| `@5fc6fca4` | current commit; not shown when on a branch or tag |
| `⇣1` | local branch is behind the remote by 1 commit |
| `⇡2` | local branch is ahead of the remote by 2 commits |
| `⇠3` | local branch is behind the push remote by 3 commits |
| `⇢4` | local branch is ahead of the push remote by 4 commits |
| `*5` | there are 5 stashes |
| `merge` | merge is in progress (could be some other action) |
| `~6` | there are 6 merge conflicts |
| `+7` | there are 7 staged changes |
| `!8` | there are 8 unstaged changes |
| `?9` | there are 9 untracked files |
If you'd like to change the format of git status, or want to have greater control over the
process of assembling `PS1`, you can copy and modify parts of
[gitstatus.prompt.sh](gitstatus.prompt.sh) instead of sourcing the script. Your `~/.bashrc` might
look something like this:
```bash
source ~/gitstatus/gitstatus.plugin.sh
function my_set_prompt() {
PS1='\w'
if gitstatus_query && [[ "$VCS_STATUS_RESULT" == ok-sync ]]; then
if [[ -n "$VCS_STATUS_LOCAL_BRANCH" ]]; then
PS1+=" ${VCS_STATUS_LOCAL_BRANCH//\\/\\\\}" # escape backslash
else
PS1+=" @${VCS_STATUS_COMMIT//\\/\\\\}" # escape backslash
fi
(( VCS_STATUS_HAS_STAGED" )) && PS1+='+'
(( VCS_STATUS_HAS_UNSTAGED" )) && PS1+='!'
(( VCS_STATUS_HAS_UNTRACKED" )) && PS1+='?'
fi
PS1+='\n\$ '
shopt -u promptvars # disable expansion of '$(...)' and the like
}
gitstatus_stop && gitstatus_start
PROMPT_COMMAND=my_set_prompt
```
This snippet is sourcing `gitstatus.plugin.sh` rather than `gitstatus.prompt.sh`. The former
defines low-level bindings that communicate with gitstatusd over pipes. The latter is a simple
script that uses these bindings to assemble git prompt.
Note: Bash bindings, unlike Zsh bindings, don't support asynchronous calls.
## Using from other shells
If there are no gitstatusd bindings for your shell, you'll need to get your hands dirty.
Use the existing bindings for inspiration; run `gitstatusd --help` or read the same thing in
[options.cc](src/options.cc).
## How it works
gitstatusd reads requests from stdin and prints responses to stdout. Requests contain an ID and
a directory. Responses contain the same ID and machine-readable git status for the directory.
gitstatusd keeps some state in memory for the directories it has seen in order to serve future
requests faster.
[Zsh bindings](gitstatus.plugin.zsh) and [Bash bindings](gitstatus.plugin.sh) start gitstatusd in
the background and communicate with it via pipes. Themes such as
[Powerlevel10k](https://github.com/romkatv/powerlevel10k) use these bindings to put git status in
`PROMPT`.
Note that gitstatus cannot be used as a drop-in replacement for `git status` command as it doesn't
produce output in the same format. It does perform the same computation though.
## Benchmarks
The following benchmark results were obtained on Intel i9-7900X running Ubuntu 18.04 in
a clean [chromium](https://github.com/chromium/chromium) repository synced to `9394e49a`. The
repository was checked out to an ext4 filesystem on M.2 SSD.
Three functionally equivalent tools for computing git status were benchmarked:
* `gitstatusd`
* `git` with `core.untrackedcache` enabled and `core.fsmonitor` disabled
* `lg2` -- a demo/example executable from [libgit2](https://github.com/romkatv/libgit2) that
implements a subset of `git` functionality on top of libgit2 API; for the purposes of this
benchmark the subset is sufficient to generate the same data as the other tools
Every tool was benchmark in cold and hot conditions. For `git` the first run in a repository was
considered cold, with the following runs considered hot. `lg2` was patched to compute results twice
in a single invocation without freeing the repository in between; the second run was considered hot.
The same patching was not done for `git` because `git` cannot be easily modified to refresh inmemory
index state between invocations; in fact, this limitation is one of the primary reasons developers
use libgit2. `gitstatusd` was benchmarked similarly to `lg2` with two result computations in the
same invocation.
Two commands were benchmarked: `status` and `describe`.
### Status
In this benchmark all tools were computing the equivalent of `git status`. Lower numbers are better.
| Tool | Cold | Hot |
|---------------|-----------:|------------:|
| **gitstatus** | **291 ms** | **30.9 ms** |
| git | 876 ms | 295 ms |
| lg2 | 1730 ms | 1310 ms |
gitstatusd is substantially faster than the alternatives, especially on hot runs. Note that hot runs
are of primary importance to the main use case of gitstatus in interactive shells.
The performance of `git status` fluctuated wildly in this benchmarks for reasons unknown to the
author. Moreover, performance is sticky -- once `git status` settles around a number, it stays
there for a long time. Numbers as diverse as 295, 352, 663 and 730 had been observed on hot runs on
the same repository. The number in the table is the lowest (fastest or best) that `git status` had
shown.
### Describe
In this benchmark all tools were computing the equivalent of `git describe --tags --exact-match`
to find tags that resolve to the same commit as `HEAD`. Lower numbers are better.
| Tool | Cold | Hot |
|---------------|------------:|--------------:|
| **gitstatus** | **4.04 ms** | **0.0345 ms** |
| git | 18.0 ms | 14.5 ms |
| lg2 | 185 ms | 45.2 ms |
gitstatusd is once again faster than the alternatives, more so on hot runs.
## Why fast
Since gitstatusd doesn't have to print all staged/unstaged/untracked files but only report
whether there are any, it can terminate repository scan early. It can also remember which files
were dirty on the previous run and check them first on the next run to avoid the scan entirely if
the files are still dirty. However, the benchmarks above were performed in a clean repository where
these shortcuts do not trigger. All benchmarked tools had to do the same work -- check the status
of every file in the index to see if it has changed, check every directory for newly created files,
etc. And yet, gitstatusd came ahead by a large margin. This section describes what it does that
makes it so fast.
Most of the following comparisons are done against libgit2 rather than git because of the author's
familiarity with the former but not the with latter. libgit2 has clean, well-documented APIs and an
elegant implementation, which makes it so much easier to work with and to analyze performance
bottlenecks.
### Summary for the impatient
Under the benchmark conditions described above, the equivalent of libgit2's
`git_diff_index_to_workdir` (the most expensive part of `status` command) is 46.3 times faster in
gitstatusd. The speedup comes from the following sources.
* gitstatusd uses more efficient data structures and algorithms and employs performance-conscious
coding style throughout the codebase. This reduces CPU time in userspace by 32x compared to libgit2.
* gitstatusd uses less expensive system calls and makes fewer of them. This reduces CPU time spent
in kernel by 1.9x.
* gitstatusd can utilize multiple cores to scan index and workdir in parallel with almost perfect
scaling. This reduces total run time by 12.4x while having virtually no effect on total CPU time.
### Problem statement
The most resource-intensive part of the `status` command is finding the difference between _index_
and _workdir_ (`git_diff_index_to_workdir` in libgit2). Index is a list of all files in the git
repository with their last modification times. This is an obvious simplification but it suffices for
this exposition. On disk, index is stored sorted by file path. Here's an example of git index:
| File | Last modification time |
|-------------|-----------------------:|
| Makefile | 2019-04-01T14:12:32Z |
| src/hello.c | 2019-04-01T14:12:00Z |
| src/hello.h | 2019-04-01T14:12:32Z |
This list needs to be compared to the list of files in the working directory. If any of the files
listed in the index are missing from the workdir or have different last modification time, they are
"unstaged" in gitstatusd parlance. If you run `git status`, they'll be shown as "changes not staged
for commit". Thus, any implementation of `status` command has to call `stat()` or one of its
variants on every file in the index.
In addition, all files in the working directory for which there is no entry in the index at all are
"untracked". `git status` will show them as "untracked files". Finding untracked files requires some
form of work directory traversal.
### Single-threaded scan
Let's see how `git_diff_index_to_workdir` from libgit2 accomplishes these tasks. Here's its CPU
profile from 200 hot runs over chromium repository.
![libgit2 CPU profile (hot)](
https://raw.githubusercontent.com/romkatv/gitstatus/1ac366952366d89980b3f3484f270b4fa5ae4293/cpu-profile-libgit2.png)
(The CPU profile was created with [gperftools](https://github.com/gperftools/gperftools) and
rendered with [pprof](https://github.com/google/pprof)).
We can see `__GI__lxstat` taking a lot of time. This is the `stat()` call for every file in the
index. We can also identify `__opendir`, `__readdir` and `__GI___close_nocancel` -- glibc wrappers
for reading the contents of a directory. This is for finding untracked files. Out of the total 232
seconds, 111 seconds -- or 47.7% -- was spent on these calls. The rest is computation -- comparing
strings, sorting arrays, etc.
Now let's take a look at the CPU profile of gitstatusd on the same task.
![gitstatusd CPU profile (hot)](
https://raw.githubusercontent.com/romkatv/gitstatus/1ac366952366d89980b3f3484f270b4fa5ae4293/cpu-profile-gitstatusd-hot.png)
The first impression is that this profile looks pruned. This isn't an artifact. The profile was
generated with the same tools and the same flags as the profile of libgit2.
Since both profiles were generated from the same workload, absolute numbers can be compared. We can
see that gitstatusd took 62 seconds in total compared to libgit2's 232 seconds. System calls at the
core of the algorithm are clearly visible. `__GI___fxstatat` is a flavor of `stat()`, and the other
three calls -- `__libc_openat64`, `__libc_close` and `__GI___fxstat` are responsible for opening
directories and finding untracked files. Notice that there is almost nothing else in the profile
apart from these calls. The rest of the code accounts for 3.77 seconds of CPU time -- 32 times less
than in libgit2.
So, one reason gitstatusd is fast is that it has efficient diffing code -- very little time is spent
outside of kernel. However, if we look closely, we can notice that system calls in gitstatusd are
_also_ faster than in libgit2. For example, libgit2 spent 72.07 seconds in `__GI__lxstat` while
gitstatusd spent only 48.82 seconds in `__GI___fxstatat`. There are two reasons for this difference.
First, libgit2 makes more `stat()` calls than is strictly required. It's not necessary to stat
directories because index only has files. There are 25k directories in chromium repository (and 300k
files) -- that's 25k `stat()` calls that could be avoided. The second reason is that libgit2 and
gitstatusd use different flavors of `stat()`. libgit2 uses `lstat()`, which takes a path to the file
as input. Its performance is linear in the number of subdirectories in the path because it needs to
perform a lookup for every one of them and to check permissions. gitstatusd uses `fstatat()`, which
takes a file descriptor to the parent directory and a name of the file. Just a single lookup, less
CPU time.
Similarly to `lstat()` vs `fstatat()`, it's faster to open files and directories with `openat()`
from the parent directory file descriptor than with regular `open()` that accepts full file path.
gitstatusd takes advantage of `openat()` to open directories as fast as possible. It opens about 90%
of the directories (this depends on the actual directory structure of the repository) from the
immediate parent -- the most efficient way -- and the remaining 10% it opens from the repository's
root directory. The reason it's done this way is to keep the maximum number of simultaneously open
file descriptors bounded. libgit2 can have O(repository depth) simultaneously open file descriptors,
which may be OK for a single-threaded application but can balloon to a large number when scans are
done by many threads simultaneously, like in gitstatusd.
There is no equivalent to `__opendir` or `__readdir` in the gitstatusd profile because it uses the
equivalent of [untracked cache](https://git-scm.com/docs/git-update-index#_untracked_cache) from
git. On the first scan of the workdir gitstatusd lists all files just like libgit2. But, unlike
libgit2, it remembers the last modification time of every directory along with the list of
untracked files under it. On the next scan, gitstatusd can skip listing files in directories whose
last modification time hasn't changed.
To summarize, here's what gitstatusd was doing when the CPU profile was captured:
1. `__libc_openat64`: Open every directory for which there are files in the index.
2. `__GI___fxstat`: Check last modification time of the directory. Since it's the same as on the
last scan, this directory has the same list of untracked files as before, which is empty (the
repository is clean).
3. `__GI___fxstatat`: Check last modification time for every file in the index that belongs to this
directory.
4. `__libc_close`: Close the file descriptor to the directory.
Here's how the very first scan of a repository looks like in gitstatusd:
![gitstatusd CPU profile (cold)](
https://raw.githubusercontent.com/romkatv/gitstatus/1ac366952366d89980b3f3484f270b4fa5ae4293/cpu-profile-gitstatusd-cold.png)
(Some glibc functions are mislabel on this profile. `explicit_bzero` and `__nss_passwd_lookup` are
in reality `strcmp` and `memcmp`.)
This is a superset of the previous -- hot -- profile, with an extra `syscall` and string sorting for
directory listing. gitstatusd uses `getdents64` Linux system call directly, bypassing the glibc
wrapper that libgit2 uses. This is 23% faster. The details of this optimization can be found in a
[separate document](docs/listdir.md).
### Multithreading
The diffing algorithm in gitstatusd was designed from the ground up with the intention of using it
concurrently from multiple threads. With a fast SSD, `status` is CPU bound, so taking advantage of
all available CPU cores is an obvious way to yield results faster.
gitstatusd exhibits almost perfect scaling from multithreading. Engaging all cores allows it to
produce results 12.4 times faster than in single-threaded execution. This is on Intel i9-7900X with
10 cores (20 with hyperthreading) with single-core frequency of 4.3GHz and all-core frequency of
4.0GHz.
Note: `git status` also uses all available cores in some parts of its algorithm while `lg2` does
everything in a single thread.
### Postprocessing
Once the difference between the index and the workdir is found, we have a list of _candidates_ --
files that may be unstaged or untracked. To make the final judgement, these files need to be checked
against `.gitignore` rules and a few other things.
gitstatusd uses [patched libgit2](https://github.com/romkatv/libgit2) for this step. This fork
adds several optimizations that make libgit2 faster. The patched libgit2 performs more than twice
as fast in the benchmark as the original even without changes in the user code (that is, in the
code that uses the libgit2 APIs). The fork also adds several API extensions, most notable of which
is the support for multi-threaded scans. If `lg2 status` is modified to take advantage of these
extensions, it outperforms the original libgit2 by a factor of 18. Lastly, the fork fixes a score of
bugs, most of which become apparent only when using libgit2 from multiple threads.
_WARNING: Changes to libgit2 are extensive but the testing they underwent isn't. It is
**not recommended** to use the patched libgit2 in production._
## Requirements
* To compile: binutils, cmake, gcc, g++, git and GNU make.
* To run: Linux, macOS, FreeBSD, Android, WSL, Cygwin or MSYS2.
## Compiling
There are prebuilt `gitstatusd` binaries in [releases](
https://github.com/romkatv/gitstatus/releases). When using the official shell bindings
provided by gitstatus, the right binary for your architecture gets downloaded automatically.
If prebuilt binaries don't work for you, you'll need to get your hands dirty.
### Compiling for personal use
```zsh
git clone --depth=1 https://github.com/romkatv/gitstatus.git
cd gitstatus
./build -w -s -d docker
```
Users in China can use the official mirror on gitee.com for faster download.<br>
中国大陆用户可以使用 gitee.com 上的官方镜像加速下载.
```zsh
git clone --depth=1 https://gitee.com/romkatv/gitstatus.git
cd gitstatus
./build -w -s -d docker
```
- If it says that `-d docker` is not supported on your OS, remove this flag.
- If it says that `-s` is not supported on your OS, remove this flag.
- If it tell you to install docker but you cannot or don't want to, remove `-d docker`.
- If it says that some command is missing, install it.
If everything goes well, the newly built binary will appear in `./usrbin`. It'll be picked up
by shell bindings automatically.
When you update shell bindings, they may refuse to work with the binary you've built earlier. In
this case you'll need to rebuild.
If you are using gitstatus through [Powerlevel10k](https://github.com/romkatv/powerlevel10k), the
instructions are the same except that you don't need to clone gitstatus. Instead, change your
current directory to `/path/to/powerlevel10k/gitstatus` (`/path/to/powerlevel10k` is the directory
where you've installed Powerlevel10k) and run `./build -w -s -d docker` from there as described
above.
### Compiling for distribution
It's currently neither easy nor recommended to package and distribute gitstatus. There are no
instructions you can follow that would allow you to easily update your package when new versions of
gitstatus are released. This may change in the future but not soon.
## License
GNU General Public License v3.0. See [LICENSE](LICENSE). Contributions are covered by the same
license.

@ -1 +0,0 @@
gitstatusd-cygwin_nt-10.0-x86_64

@ -1 +0,0 @@
gitstatusd-freebsd-amd64

@ -1 +0,0 @@
gitstatusd-linux-armv7l

@ -0,0 +1,656 @@
#!/bin/sh
#
# Type `build -h` for help and see https://github.com/romkatv/gitstatus
# for full documentation.
set -ue
if [ -n "${ZSH_VERSION:-}" ]; then
emulate sh -o err_exit -o no_unset
fi
export LC_ALL=C
if [ -z "${ZSH_VERSION-}" ] && command -v zsh >/dev/null 2>&1; then
# Avoid bash 3.*.
case "${BASH_VERSION-}" in
[0-3].*) exec zsh "$0" "$@";;
esac
fi
# Avoid ksh: https://github.com/romkatv/gitstatus/issues/282.
if [ -n "${KSH_VERSION-}" ]; then
if [ -z "${ZSH_VERSION-}" ] && command -v zsh >/dev/null 2>&1; then
exec zsh "$0" "$@"
elif [ -z "${BASH_VERSION-}" ] && command -v bash >/dev/null 2>&1 &&
bash_version="$(bash --version 2>&1)"; then
case "$bash_version" in
*version\ [4-9]*|*version\ [1-9][0-9]*) exec bash "$0" "$@";;
esac
fi
fi
usage="$(command cat <<\END
Usage: build [-m ARCH] [-c CPU] [-d CMD] [-i IMAGE] [-s] [-w]
Options:
-m ARCH `uname -m` from the target machine; defaults to `uname -m`
from the local machine
-c CPU generate machine instructions for CPU of this type; this
value gets passed as `-march` (or `-mcpu` for ppc64le) to gcc;
inferred from ARCH if not set explicitly
-d CMD build in a Docker container and use CMD as the `docker`
command; e.g., `-d docker` or `-d podman`
-i IMAGE build in this Docker image; inferred from ARCH if not set
explicitly
-s install whatever software is necessary for build to
succeed; on some operating systems this option is not
supported; on others it can have partial effect
-w automatically download tarballs for dependencies if they
do not already exist in ./deps; dependencies are described
in ./build.info
END
)"
build="$(command cat <<\END
outdir="$(command pwd)"
if command -v mktemp >/dev/null 2>&1; then
workdir="$(command mktemp -d "${TMPDIR:-/tmp}"/gitstatus-build.XXXXXXXXXX)"
else
workdir="${TMPDIR:-/tmp}/gitstatus-build.tmp.$$"
command mkdir -- "$workdir"
fi
cd -- "$workdir"
workdir="$(command pwd)"
narg() { echo $#; }
if [ "$(narg $workdir)" != 1 -o -z "${workdir##*:*}" -o -z "${workdir##*=*}" ]; then
>&2 echo "[error] cannot build in this directory: $workdir"
exit 1
fi
appname=gitstatusd
libgit2_tmp="$outdir"/deps/"$appname".libgit2.tmp
cleanup() {
trap - INT QUIT TERM ILL PIPE
cd /
if ! command rm -rf -- "$workdir" "$outdir"/usrbin/"$appname".tmp "$libgit2_tmp"; then
command sleep 5
command rm -rf -- "$workdir" "$outdir"/usrbin/"$appname".tmp "$libgit2_tmp"
fi
}
trap cleanup INT QUIT TERM ILL PIPE
if [ -n "$gitstatus_install_tools" ]; then
case "$gitstatus_kernel" in
linux)
if command -v apk >/dev/null 2>&1; then
command apk update
command apk add binutils cmake gcc g++ git make musl-dev perl-utils
elif command -v apt-get >/dev/null 2>&1; then
apt-get update
apt-get install -y binutils cmake gcc g++ make wget
else
>&2 echo "[error] -s is not supported on this system"
exit 1
fi
;;
freebsd|dragonfly)
command pkg install -y cmake gmake binutils git perl5 wget
;;
openbsd)
command pkg_add cmake gmake gcc g++ git wget
;;
netbsd)
command pkgin -y install cmake gmake binutils git
;;
darwin)
if ! command -v make >/dev/null 2>&1 || ! command -v gcc >/dev/null 2>&1; then
>&2 echo "[error] please run 'xcode-select --install' and retry"
exit 1
fi
if command -v port >/dev/null 2>&1; then
sudo port -N install libiconv cmake wget
elif command -v brew >/dev/null 2>&1; then
for formula in libiconv cmake git wget; do
if command brew ls --version "$formula" &>/dev/null; then
command brew upgrade "$formula"
else
command brew install "$formula"
fi
done
else
>&2 echo "[error] please install MacPorts or Homebrew and retry"
exit 1
fi
;;
msys*|mingw*)
command pacman -Syu --noconfirm
command pacman -S --needed --noconfirm binutils cmake gcc git make perl
;;
*)
>&2 echo "[internal error] unhandled kernel: $gitstatus_kernel"
exit 1
;;
esac
fi
cpus="$(command getconf _NPROCESSORS_ONLN 2>/dev/null)" ||
cpus="$(command sysctl -n hw.ncpu 2>/dev/null)" ||
cpus=8
case "$gitstatus_cpu" in
powerpc64|powerpc64le)
archflag="-mcpu"
;;
*)
archflag="-march"
;;
esac
cflags="$archflag=$gitstatus_cpu -fno-plt -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fpie"
ldflags=
static_pie=
if [ -z "${CC-}" ]; then
case "$gitstatus_kernel" in
freebsd) export CC=clang;;
*) export CC=cc;;
esac
fi
printf 'int main() {}\n' >"$workdir"/cc-test.c
if 2>/dev/null "$CC" \
-ffile-prefix-map=x=y \
-Werror \
-c "$workdir"/cc-test.c \
-o "$workdir"/cc-test.o; then
cflags="$cflags -ffile-prefix-map=$workdir/="
fi
command rm -f -- "$workdir"/cc-test "$workdir"/cc-test.o
if 2>/dev/null "$CC" \
-fstack-clash-protection \
-Werror \
-c "$workdir"/cc-test.c \
-o "$workdir"/cc-test.o; then
cflags="$cflags -fstack-clash-protection"
fi
command rm -f -- "$workdir"/cc-test "$workdir"/cc-test.o
if 2>/dev/null "$CC" \
-fcf-protection \
-Werror \
-c "$workdir"/cc-test.c \
-o "$workdir"/cc-test.o; then
cflags="$cflags -fcf-protection"
fi
command rm -f -- "$workdir"/cc-test "$workdir"/cc-test.o
if 2>/dev/null "$CC" \
-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now \
-Werror \
"$workdir"/cc-test.c \
-o "$workdir"/cc-test; then
ldflags="$ldflags -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"
fi
command rm -f -- "$workdir"/cc-test "$workdir"/cc-test.o
if 2>/dev/null "$CC" \
-fpie -static-pie \
-Werror \
"$workdir"/cc-test.c \
-o "$workdir"/cc-test; then
static_pie='-static-pie'
fi
if [ "$gitstatus_cpu" = x86-64 ]; then
cflags="$cflags -mtune=generic"
fi
libgit2_cmake_flags=
libgit2_cflags="${CFLAGS-} $cflags -O3 -DNDEBUG"
gitstatus_cxx=g++
gitstatus_cxxflags="${CXXFLAGS-} $cflags -I${workdir}/libgit2/include -DGITSTATUS_ZERO_NSEC -D_GNU_SOURCE -D_GLIBCXX_ASSERTIONS"
gitstatus_ldflags="${LDFLAGS-} $ldflags -L${workdir}/libgit2/build"
gitstatus_ldlibs=
gitstatus_make=make
case "$gitstatus_kernel" in
linux)
gitstatus_ldflags="$gitstatus_ldflags ${static_pie:--static}"
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=ON"
;;
freebsd)
gitstatus_cxx=clang++
gitstatus_make=gmake
gitstatus_ldflags="$gitstatus_ldflags ${static_pie:--static}"
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=ON"
;;
dragonfly)
gitstatus_cxx=clang++12
gitstatus_make=gmake
gitstatus_ldflags="$gitstatus_ldflags ${static_pie:--static}"
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=ON"
;;
openbsd)
gitstatus_cxx=eg++
gitstatus_make=gmake
gitstatus_ldflags="$gitstatus_ldflags ${static_pie:--static}"
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=ON"
;;
netbsd)
gitstatus_make=gmake
gitstatus_ldflags="$gitstatus_ldflags ${static_pie:--static}"
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=ON"
;;
darwin)
command mkdir -- "$workdir"/lib
if [ -e /opt/local/lib/libiconv.a ]; then
command ln -s -- /opt/local/lib/libiconv.a "$workdir"/lib
libgit2_cflags="$libgit2_cflags -I/opt/local/include"
gitstatus_cxxflags="$gitstatus_cxxflags -I/opt/local/include"
else
brew_prefix="$(command brew --prefix)"
command ln -s -- "$brew_prefix"/opt/libiconv/lib/libiconv.a "$workdir"/lib
libgit2_cflags="$libgit2_cflags -I"$brew_prefix"/opt/libiconv/include"
gitstatus_cxxflags="$gitstatus_cxxflags -I"$brew_prefix"/opt/libiconv/include"
fi
libgit2_cmake_flags="$libgit2_cmake_flags -DUSE_ICONV=ON"
gitstatus_ldlibs="$gitstatus_ldlibs -liconv"
gitstatus_ldflags="$gitstatus_ldflags -L${workdir}/lib"
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=OFF"
;;
msys*|mingw*)
gitstatus_ldflags="$gitstatus_ldflags ${static_pie:--static}"
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=ON"
;;
cygwin*)
gitstatus_ldflags="$gitstatus_ldflags ${static_pie:--static}"
libgit2_cmake_flags="$libgit2_cmake_flags -DENABLE_REPRODUCIBLE_BUILDS=ON"
;;
*)
>&2 echo "[internal error] unhandled kernel: $gitstatus_kernel"
exit 1
;;
esac
for cmd in cat cmake git ld ln mkdir rm strip tar "$gitstatus_make"; do
if ! command -v "$cmd" >/dev/null 2>&1; then
if [ -n "$gitstatus_install_tools" ]; then
>&2 echo "[internal error] $cmd not found"
exit 1
else
>&2 echo "[error] command not found: $cmd"
exit 1
fi
fi
done
. "$outdir"/build.info
if [ -z "${libgit2_version:-}" ]; then
>&2 echo "[internal error] libgit2_version not set"
exit 1
fi
if [ -z "${libgit2_sha256:-}" ]; then
>&2 echo "[internal error] libgit2_sha256 not set"
exit 1
fi
libgit2_tarball="$outdir"/deps/libgit2-"$libgit2_version".tar.gz
if [ ! -e "$libgit2_tarball" ]; then
if [ -n "$gitstatus_download_deps" ]; then
if ! command -v wget >/dev/null 2>&1; then
if [ -n "$gitstatus_install_tools" ]; then
>&2 echo "[internal error] wget not found"
exit 1
else
>&2 echo "[error] command not found: wget"
exit 1
fi
fi
libgit2_url=https://github.com/romkatv/libgit2/archive/"$libgit2_version".tar.gz
if ! >"$libgit2_tmp" command wget --no-config -qO- -- "$libgit2_url" &&
! >"$libgit2_tmp" command wget -qO- -- "$libgit2_url"; then
set -x
>&2 command which wget
>&2 command ls -lAd -- "$(command which wget)"
>&2 command ls -lAd -- "$outdir"
>&2 command ls -lA -- "$outdir"
>&2 command ls -lAd -- "$outdir"/deps
>&2 command ls -lA -- "$outdir"/deps
set +x
exit 1
fi
command mv -f -- "$libgit2_tmp" "$libgit2_tarball"
else
>&2 echo "[error] file not found: deps/libgit2-"$libgit2_version".tar.gz"
exit 1
fi
fi
libgit2_actual_sha256=
if command -v shasum >/dev/null 2>/dev/null; then
libgit2_actual_sha256="$(command shasum -b -a 256 -- "$libgit2_tarball")"
libgit2_actual_sha256="${libgit2_actual_sha256%% *}"
elif command -v sha256sum >/dev/null 2>/dev/null; then
libgit2_actual_sha256="$(command sha256sum -b -- "$libgit2_tarball")"
libgit2_actual_sha256="${libgit2_actual_sha256%% *}"
elif command -v sha256 >/dev/null 2>/dev/null; then
libgit2_actual_sha256="$(command sha256 -- "$libgit2_tarball" </dev/null)"
# Ignore sha256 output if it's from hashalot. It's incompatible.
if [ ${#libgit2_actual_sha256} -lt 64 ]; then
libgit2_actual_sha256=
else
libgit2_actual_sha256="${libgit2_actual_sha256##* }"
fi
fi
if [ -z "$libgit2_actual_sha256" ]; then
>&2 echo "[error] command not found: shasum or sha256sum"
exit 1
fi
if [ "$libgit2_actual_sha256" != "$libgit2_sha256" ]; then
>&2 echo "[error] sha256 mismatch"
>&2 echo ""
>&2 echo " file : deps/libgit2-$libgit2_version.tar.gz"
>&2 echo " expected: $libgit2_sha256"
>&2 echo " actual : $libgit2_actual_sha256"
exit 1
fi
cd -- "$workdir"
command tar -xzf "$libgit2_tarball"
command mv -- libgit2-"$libgit2_version" libgit2
command mkdir libgit2/build
cd libgit2/build
CFLAGS="$libgit2_cflags" command cmake \
-DCMAKE_BUILD_TYPE=None \
-DZERO_NSEC=ON \
-DTHREADSAFE=ON \
-DUSE_BUNDLED_ZLIB=ON \
-DREGEX_BACKEND=builtin \
-DUSE_HTTP_PARSER=builtin \
-DUSE_SSH=OFF \
-DUSE_HTTPS=OFF \
-DBUILD_CLAR=OFF \
-DUSE_GSSAPI=OFF \
-DUSE_NTLMCLIENT=OFF \
-DBUILD_SHARED_LIBS=OFF \
$libgit2_cmake_flags \
..
command make -j "$cpus" VERBOSE=1
APPNAME="$appname".tmp \
OBJDIR="$workdir"/gitstatus \
CXX="${CXX:-$gitstatus_cxx}" \
CXXFLAGS="$gitstatus_cxxflags" \
LDFLAGS="$gitstatus_ldflags" \
LDLIBS="$gitstatus_ldlibs" \
command "$gitstatus_make" -C "$outdir" -j "$cpus"
app="$outdir"/usrbin/"$appname"
command strip "$app".tmp
command mkdir -- "$workdir"/repo
printf '[init]\n defaultBranch = master\n' >"$workdir"/.gitconfig
(
cd -- "$workdir"/repo
GIT_CONFIG_NOSYSTEM=1 HOME="$workdir" command git init
GIT_CONFIG_NOSYSTEM=1 HOME="$workdir" command git config user.name "Your Name"
GIT_CONFIG_NOSYSTEM=1 HOME="$workdir" command git config user.email "you@example.com"
GIT_CONFIG_NOSYSTEM=1 HOME="$workdir" command git commit \
--allow-empty --allow-empty-message --no-gpg-sign -m ''
)
resp="$(printf "hello\037$workdir/repo\036" | "$app".tmp)"
case "$resp" in
hello*1*/repo*master*);;
*)
>&2 echo 'error: invalid gitstatusd response for a git repo'
exit 1
;;
esac
resp="$(printf 'hello\037\036' | "$app".tmp)"
case "$resp" in
hello*0*);;
*)
>&2 echo 'error: invalid gitstatusd response for a non-repo'
exit 1
;;
esac
command mv -f -- "$app".tmp "$app"
cleanup
command cat >&2 <<-END
-------------------------------------------------
SUCCESS: created usrbin/$appname
END
END
)"
docker_image=
docker_cmd=
gitstatus_arch=
gitstatus_cpu=
gitstatus_install_tools=
gitstatus_download_deps=
while getopts ':m:c:i:d:swh' opt "$@"; do
case "$opt" in
h)
printf '%s\n' "$usage"
exit
;;
m)
if [ -n "$gitstatus_arch" ]; then
>&2 echo "[error] duplicate option: -$opt"
exit 1
fi
if [ -z "$OPTARG" ]; then
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
exit 1
fi
gitstatus_arch="$OPTARG"
;;
c)
if [ -n "$gitstatus_cpu" ]; then
>&2 echo "[error] duplicate option: -$opt"
exit 1
fi
if [ -z "$OPTARG" ]; then
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
exit 1
fi
gitstatus_cpu="$OPTARG"
;;
i)
if [ -n "$docker_image" ]; then
>&2 echo "[error] duplicate option: -$opt"
exit 1
fi
if [ -z "$OPTARG" ]; then
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
exit 1
fi
docker_image="$OPTARG"
;;
d)
if [ -n "$docker_cmd" ]; then
>&2 echo "[error] duplicate option: -$opt"
exit 1
fi
if [ -z "$OPTARG" ]; then
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
exit 1
fi
docker_cmd="$OPTARG"
;;
s)
if [ -n "$gitstatus_install_tools" ]; then
>&2 echo "[error] duplicate option: -$opt"
exit 1
fi
gitstatus_install_tools=1
;;
w)
if [ -n "$gitstatus_download_deps" ]; then
>&2 echo "[error] duplicate option: -$opt"
exit 1
fi
gitstatus_download_deps=1
;;
\?) >&2 echo "[error] invalid option: -$OPTARG" ; exit 1;;
:) >&2 echo "[error] missing required argument: -$OPTARG"; exit 1;;
*) >&2 echo "[internal error] unhandled option: -$opt" ; exit 1;;
esac
done
if [ "$OPTIND" -le $# ]; then
>&2 echo "[error] unexpected positional argument"
exit 1
fi
if [ -n "$docker_image" -a -z "$docker_cmd" ]; then
>&2 echo "[error] cannot use -i without -d"
exit 1
fi
if [ -z "$gitstatus_arch" ]; then
gitstatus_arch="$(uname -m)"
gitstatus_arch="$(printf '%s' "$gitstatus_arch" | tr '[A-Z]' '[a-z]')"
fi
if [ -z "$gitstatus_cpu" ]; then
case "$gitstatus_arch" in
armel) gitstatus_cpu=armv5;;
armv6l|armhf) gitstatus_cpu=armv6;;
armv7l) gitstatus_cpu=armv7;;
arm64|aarch64) gitstatus_cpu=armv8-a;;
ppc64|ppc64le) gitstatus_cpu=powerpc64le;;
riscv64) gitstatus_cpu=rv64imafdc;;
loongarch64) gitstatus_cpu=loongarch64;;
x86_64|amd64) gitstatus_cpu=x86-64;;
x86) gitstatus_cpu=i586;;
s390x) gitstatus_cpu=z900;;
i386|i586|i686) gitstatus_cpu="$gitstatus_arch";;
*)
>&2 echo '[error] unable to infer target CPU architecture'
>&2 echo 'Please specify explicitly with `-c CPU`.'
exit 1
;;
esac
fi
gitstatus_kernel="$(uname -s)"
gitstatus_kernel="$(printf '%s' "$gitstatus_kernel" | tr '[A-Z]' '[a-z]')"
case "$gitstatus_kernel" in
linux)
if [ -n "$docker_cmd" ]; then
if [ -z "${docker_cmd##*/*}" ]; then
if [ ! -x "$docker_cmd" ]; then
>&2 echo "[error] not an executable file: $docker_cmd"
exit 1
fi
else
if ! command -v "$docker_cmd" >/dev/null 2>&1; then
>&2 echo "[error] command not found: $docker_cmd"
exit 1
fi
fi
if [ -z "$docker_image" ]; then
case "$gitstatus_arch" in
x86_64) docker_image=alpine:3.11.6;;
x86|i386|i586|i686) docker_image=i386/alpine:3.11.6;;
armv6l|armhf) docker_image=arm32v6/alpine:3.11.6;;
armv7l) docker_image=arm32v7/alpine:3.11.6;;
aarch64) docker_image=arm64v8/alpine:3.11.6;;
ppc64|ppc64le) docker_image=ppc64le/alpine:3.11.6;;
s390x) docker_image=s390x/alpine:3.11.6;;
*)
>&2 echo '[error] unable to infer docker image'
>&2 echo 'Please specify explicitly with `-i IMAGE`.'
exit 1
;;
esac
fi
fi
;;
freebsd|openbsd|netbsd|darwin|dragonfly)
if [ -n "$docker_cmd" ]; then
>&2 echo "[error] docker (-d) is not supported on $gitstatus_kernel"
exit 1
fi
;;
msys_nt-*|mingw32_nt-*|mingw64_nt-*|cygwin_nt-*)
if ! printf '%s' "$gitstatus_kernel" | grep -Eqx '[^-]+-[0-9]+\.[0-9]+(-.*)?'; then
>&2 echo '[error] unsupported kernel, sorry!'
exit 1
fi
gitstatus_kernel="$(printf '%s' "$gitstatus_kernel" | sed 's/^\([^-]*-[0-9]*\.[0-9]*\).*/\1/')"
if [ -n "$docker_cmd" ]; then
>&2 echo '[error] docker (-d) is not supported on windows'
exit 1
fi
if [ -n "$gitstatus_install_tools" -a -z "${gitstatus_kernel##cygwin_nt-*}" ]; then
>&2 echo '[error] -s is not supported on cygwin'
exit 1
fi
;;
*)
>&2 echo '[error] unsupported kernel, sorry!'
exit 1
;;
esac
dir="$(dirname -- "$0")"
cd -- "$dir"
dir="$(pwd)"
>&2 echo "Building gitstatusd..."
>&2 echo ""
>&2 echo " kernel := $gitstatus_kernel"
>&2 echo " arch := $gitstatus_arch"
>&2 echo " cpu := $gitstatus_cpu"
[ -z "$docker_cmd" ] || >&2 echo " docker command := $docker_cmd"
[ -z "$docker_image" ] || >&2 echo " docker image := $docker_image"
if [ -n "$gitstatus_install_tools" ]; then
>&2 echo " install tools := yes"
else
>&2 echo " install tools := no"
fi
if [ -n "$gitstatus_download_deps" ]; then
>&2 echo " download deps := yes"
else
>&2 echo " download deps := no"
fi
if [ -n "$docker_cmd" ]; then
"$docker_cmd" run \
-e docker_cmd="$docker_cmd" \
-e docker_image="$docker_image" \
-e gitstatus_kernel="$gitstatus_kernel" \
-e gitstatus_arch="$gitstatus_arch" \
-e gitstatus_cpu="$gitstatus_cpu" \
-e gitstatus_install_tools="$gitstatus_install_tools" \
-e gitstatus_download_deps="$gitstatus_download_deps" \
-v "$dir":/out \
-w /out \
--rm \
-- "$docker_image" /bin/sh -uexc "$build"
else
eval "$build"
fi

@ -0,0 +1,22 @@
# This value gets embedded in gitstatusd at build time. It is
# read by ./Makefile. `gitstatusd --version` reports it back.
#
# This value is also read by shell bindings (indirectly, through
# ./install) when using GITSTATUS_DAEMON or usrbin/gitstatusd.
gitstatus_version="v1.5.4"
# libgit2 is a build time dependency of gitstatusd. The values of
# libgit2_version and libgit2_sha256 are read by ./build.
#
# If ./deps/libgit2-${libgit2_version}.tar.gz doesn't exist, build
# downloads it from the following location:
#
# https://github.com/romkatv/libgit2/archive/${libgit2_version}.tar.gz
#
# Once downloaded, the tarball is stored at the path indicated
# above so that repeated builds don't consume network bandwidth.
#
# If sha256 of ./deps/libgit2-${libgit2_version}.tar.gz doesn't match,
# build gets aborted.
libgit2_version="tag-2ecf33948a4df9ef45a66c68b8ef24a5e60eaac6"
libgit2_sha256="4ce11d71ee576dbbc410b9fa33a9642809cc1fa687b315f7c23eeb825b251e93"

@ -0,0 +1,330 @@
# Fast directory listing
In order to find untracked files in a git repository, [gitstatusd](../README.md) needs to list the
contents of every directory. gitstatusd does it 27% faster than a reasonable implementation that a
seasoned C/C++ practitioner might write. This document explains the optimizations that went into it.
As directory listing is a common operation, many other projects can benefit from applying these
optimizations.
## v1
Given a path to a directory, `ListDir()` must produce the list of files in that directory. Moreover,
the list must be sorted lexicographically to enable fast comparison with Git index.
The following C++ implementation gets the job done. For simplicity, it returns an empty list on
error.
```c++
vector<string> ListDir(const char* dirname) {
vector<string> entries;
if (DIR* dir = opendir(dirname)) {
while (struct dirent* ent = (errno = 0, readdir(dir))) {
if (!Dots(ent->d_name)) entries.push_back(ent->d_name);
}
if (errno) entries.clear();
sort(entries.begin(), entries.end());
closedir(dir);
}
return entries;
}
```
Every directory has entries `"."` and `".."`, which we aren't interested in. We filter them out with
a helper function `Dots()`.
```c++
bool Dots(const char* s) { return s[0] == '.' && (!s[1] || (s[1] == '.' && !s[2])); }
```
To check how fast `ListDir()` performs, we can run it many times on a typical directory. One million
runs on a directory with 32 files with 16-character names takes 12.7 seconds.
## v2
Experienced C++ practitioners will scoff at our implementation of `ListDir()`. If it's meant to be
efficient, returning `vector<string>` is an unaffordable convenience. To avoid heap allocations we
can use a simple arena that will allow us to reuse memory between different `ListDir()` calls.
(Changed and added lines are marked with comments.)
```c++
void ListDir(const char* dirname, string& arena, vector<char*>& entries) { // +
entries.clear(); // +
if (DIR* dir = opendir(dirname)) {
arena.clear(); // +
while (struct dirent* ent = (errno = 0, readdir(dir))) {
if (!Dots(ent->d_name)) {
entries.push_back(reinterpret_cast<char*>(arena.size())); // +
arena.append(ent->d_name, strlen(ent->d_name) + 1); // +
}
}
if (errno) entries.clear();
for (char*& p : entries) p = &arena[reinterpret_cast<size_t>(p)]; // +
sort(entries.begin(), entries.end(), // +
[](const char* a, const char* b) { return strcmp(a, b) < 0; }); // +
closedir(dir);
}
}
```
To make performance comparison easier, we can normalize them relative to the baseline. v1 will get
performance score of 100. A twice-as-fast alternative will be 200.
| version | optimization | score |
|---------|----------------------------|----------:|
| v1 | baseline | 100.0 |
| **v2** | **avoid heap allocations** | **112.7** |
Avoiding heap allocations makes `ListDir()` 12.7% faster. Not bad. As an added bonus, those casts
will fend off the occasional frontend developer who accidentally wanders into the codebase.
## v3
`opendir()` is an expensive call whose performance is linear in the number of subdirectories in the
path because it needs to perform a lookup for every one of them. We can replace it with `openat()`,
which takes a file descriptor to the parent directory and a name of the subdirectory. Just a single
lookup, less CPU time. This optimization assumes that callers already have a descriptor to the
parent directory, which is indeed the case for gitstatusd, and is often the case in other
applications that traverse filesystem.
```c++
void ListDir(int parent_fd, const char* dirname, string& arena, vector<char*>& entries) { // +
entries.clear();
int dir_fd = openat(parent_fd, dirname, O_NOATIME | O_RDONLY | O_DIRECTORY | O_CLOEXEC); // +
if (dir_fd < 0) return; // +
if (DIR* dir = fdopendir(dir_fd)) {
arena.clear();
while (struct dirent* ent = (errno = 0, readdir(dir))) {
if (!Dots(ent->d_name)) {
entries.push_back(reinterpret_cast<char*>(arena.size()));
arena.append(ent->d_name, strlen(ent->d_name) + 1);
}
}
if (errno) entries.clear();
for (char*& p : entries) p = &arena[reinterpret_cast<size_t>(p)];
sort(entries.begin(), entries.end(),
[](const char* a, const char* b) { return strcmp(a, b) < 0; });
closedir(dir);
} else { // +
close(dir_fd); // +
} // +
}
```
This is worth about 3.5% in speed.
| version | optimization | score |
|---------|--------------------------------------|----------:|
| v1 | baseline | 100.0 |
| v2 | avoid heap allocations | 112.7 |
| **v3** | **open directories with `openat()`** | **116.2** |
## v4
Copying file names to the arena isn't free but it doesn't seem like we can avoid it. Poking around
we can see that the POSIX API we are using is implemented on Linux on top of `getdents64` system
call. Its documentation isn't very encouraging:
```text
These are not the interfaces you are interested in. Look at
readdir(3) for the POSIX-conforming C library interface. This page
documents the bare kernel system call interfaces.
Note: There are no glibc wrappers for these system calls.
```
Hmm... The API looks like something we can take advantage of, so let's try it anyway.
First, we'll need a simple `Arena` class that can allocate 8KB blocks of memory.
```c++
class Arena {
public:
enum { kBlockSize = 8 << 10 };
char* Alloc() {
if (cur_ == blocks_.size()) blocks_.emplace_back(kBlockSize, 0);
return blocks_[cur_++].data();
}
void Clear() { cur_ = 0; }
private:
size_t cur_ = 0;
vector<string> blocks_;
};
```
Next, we need to define `struct dirent64_t` ourselves because there is no wrapper for the system
call we are about to use.
```c++
struct dirent64_t {
ino64_t d_ino;
off64_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[];
};
```
Finally we can get to the implementation of `ListDir()`.
```c++
void ListDir(int parent_fd, Arena& arena, vector<char*>& entries) { // +
entries.clear();
int dir_fd = openat(parent_fd, dirname, O_NOATIME | O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if (dir_fd < 0) return;
arena.Clear(); // +
while (true) { // +
char* buf = arena.Alloc(); // +
int n = syscall(SYS_getdents64, dir_fd, buf, Arena::kBlockSize); // +
if (n <= 0) { // +
if (n) entries.clear(); // +
break; // +
} // +
for (int pos = 0; pos < n;) { // +
auto* ent = reinterpret_cast<dirent64_t*>(buf + pos); // +
if (!Dots(ent->d_name)) entries.push_back(ent->d_name); // +
pos += ent->d_reclen; // +
} // +
} // +
sort(entries.begin(), entries.end(),
[](const char* a, const char* b) { return strcmp(a, b) < 0; });
close(dir_fd);
}
```
How are we doing with this one?
| version | optimization | score |
|---------|----------------------------------|----------:|
| v1 | baseline | 100.0 |
| v2 | avoid heap allocations | 112.7 |
| v3 | open directories with `openat()` | 116.2 |
| **v4** | **call `getdents64()` directly** | **137.8** |
Solid 20% speedup. Worth the trouble. Unfortunately, we now have just one `reinterpret_cast` instead
of two, and it's not nearly as scary-looking. Hopefully with the next iteration we can get back some
of that evil vibe of low-level code.
As a bonus, every element in `entries` has `d_type` at offset -1. This can be useful to the callers
that need to distinguish between regular files and directories (gitstatusd, in fact, needs this).
Note how `ListDir()` implements this feature at zero cost, as a lucky accident of `dirent64_t`
memory layout.
## v5
The CPU profile of `ListDir()` reveals that almost all userspace CPU time is spent in `strcmp()`.
Digging into the source code of `std::sort()` we can see that it uses Insertion Sort for short
collections. Our 32-element vector falls under the threshold. Insertion Sort makes `O(N^2)`
comparisons, hence a lot of CPU time in `strcmp()`. Switching to `qsort()` or
[Timsort](https://en.wikipedia.org/wiki/Timsort) is of no use as all good sorting algorithms fall
back to Insertion Sort.
If we cannot make fewer comparisons, perhaps we can make each of them faster? `strcmp()` compares
characters one at a time. It cannot read ahead as it can be illegal to touch memory past the first
null byte. But _we_ know that it's safe to read a few extra bytes past the end of `d_name` for every
entry except the last in the buffer. And since we own the buffer, we can overallocate it so that
reading past the end of the last entry is also safe.
Combining these ideas with the fact that file names on Linux are at most 255 bytes long, we can
invoke `getdents64()` like this:
```c++
int n = syscall(SYS_getdents64, dir_fd, buf, Arena::kBlockSize - 256);
```
And then compare entries like this:
```c++
[](const char* a, const char* b) { return memcmp(a, b, 255) < 0; }
```
This version doesn't give any speedup compared to the previous but it opens an avenue for another
optimization. The pointers we pass to `memcmp()` aren't aligned. To be more specific, their
numerical values are `N * 8 + 3` for some `N`. When given such a pointer, `memcmp()` will check the
first 5 bytes one by one, and only then switch to comparing 8 bytes at a time. If we can handle the
first 5 bytes ourselves, we can pass aligned memory to `memcmp()` and take full advantage of its
vectorized loop.
Here's the implementation:
```c++
uint64_t Read64(const void* p) { // +
uint64_t x; // +
memcpy(&x, p, sizeof(x)); // +
return x; // +
} // +
void ByteSwap64(void* p) { // +
uint64_t x = __builtin_bswap64(Read64(p)); // +
memcpy(p, &x, sizeof(x)); // +
} // +
void ListDir(int parent_fd, Arena& arena, vector<char*>& entries) {
entries.clear();
int dir_fd = openat(parent_fd, dirname, O_NOATIME | O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if (dir_fd < 0) return;
arena.Clear();
while (true) {
char* buf = arena.Alloc();
int n = syscall(SYS_getdents64, dir_fd, buf, Arena::kBlockSize - 256); // +
if (n <= 0) {
if (n) entries.clear();
break;
}
for (int pos = 0; pos < n;) {
auto* ent = reinterpret_cast<dirent64_t*>(buf + pos);
if (!Dots(ent->d_name)) {
ByteSwap64(ent->d_name); // +
entries.push_back(ent->d_name);
}
pos += ent->d_reclen;
}
}
sort(entries.begin(), entries.end(), [](const char* a, const char* b) {
uint64_t x = Read64(a); // +
uint64_t y = Read64(b); // +
return x < y || (x == y && a != b && memcmp(a + 5, b + 5, 256) < 0); // +
});
for (char* p : entries) ByteSwap64(p); // +
close(dir_fd);
}
```
This is for Little Endian architecture. Big Endian doesn't need `ByteSwap64()`, so it'll be a bit
faster.
| version | optimization | score |
|---------|----------------------------------|----------:|
| v1 | baseline | 100.0 |
| v2 | avoid heap allocations | 112.7 |
| v3 | open directories with `openat()` | 116.2 |
| v4 | call `getdents64()` directly | 137.8 |
| **v5** | **hand-optimize `strcmp()`** | **143.3** |
Fast and respectably arcane.
## Conclusion
Through a series of incremental improvements we've sped up directory listing by 43.3% compared to a
naive implementation (v1) and 27.2% compared to a reasonable implementation that a seasoned C/C++
practitioner might write (v2).
However, these numbers are based on an artificial benchmark while the real judge is always the real
code. Our goal was to speed up gitstatusd. Benchmark was just a tool. Thankfully, the different
versions of `ListDir()` have the same comparative performance within gitstatusd as in the benchmark.
In truth, the directory chosen for the benchmark wasn't arbitrary. It was picked by sampling
gitstatusd when it runs on [chromium](https://github.com/chromium/chromium) git repository.
The final version of `ListDir()` spends 97% of its CPU time in the kernel. If we assume that it
makes the minimum possible number of system calls and these calls are optimal (true to the best
of my knowledge), it puts the upper bound on possible future performance improvements at just 3%.
There is almost nothing left in `ListDir()` to optimize.
![ListDir() CPU profile](
https://raw.githubusercontent.com/romkatv/gitstatus/1ac366952366d89980b3f3484f270b4fa5ae4293/cpu-profile-listdir.png)
(The CPU profile was created with [gperftools](https://github.com/gperftools/gperftools) and
rendered with [pprof](https://github.com/google/pprof)).

@ -0,0 +1,474 @@
# Bash bindings for gitstatus.
[[ $- == *i* ]] || return # non-interactive shell
# Starts gitstatusd in the background. Does nothing and succeeds if gitstatusd
# is already running.
#
# Usage: gitstatus_start [OPTION]...
#
# -t FLOAT Fail the self-check on initialization if not getting a response from
# gitstatusd for this this many seconds. Defaults to 5.
#
# -s INT Report at most this many staged changes; negative value means infinity.
# Defaults to 1.
#
# -u INT Report at most this many unstaged changes; negative value means infinity.
# Defaults to 1.
#
# -c INT Report at most this many conflicted changes; negative value means infinity.
# Defaults to 1.
#
# -d INT Report at most this many untracked files; negative value means infinity.
# Defaults to 1.
#
# -m INT Report -1 unstaged, untracked and conflicted if there are more than this many
# files in the index. Negative value means infinity. Defaults to -1.
#
# -e Count files within untracked directories like `git status --untracked-files`.
#
# -U Unless this option is specified, report zero untracked files for repositories
# with status.showUntrackedFiles = false.
#
# -W Unless this option is specified, report zero untracked files for repositories
# with bash.showUntrackedFiles = false.
#
# -D Unless this option is specified, report zero staged, unstaged and conflicted
# changes for repositories with bash.showDirtyState = false.
#
# -r INT Close git repositories that haven't been used for this many seconds. This is
# meant to release resources such as memory and file descriptors. The next request
# for a repo that's been closed is much slower than for a repo that hasn't been.
# Negative value means infinity. The default is 3600 (one hour).
function gitstatus_start() {
if [[ "$BASH_VERSION" < 4 ]]; then
>&2 printf 'gitstatus_start: need bash version >= 4.0, found %s\n' "$BASH_VERSION"
>&2 printf '\n'
>&2 printf 'To see the version of the current shell, type:\n'
>&2 printf '\n'
>&2 printf ' \033[32mecho\033[0m \033[33m"$BASH_VERSION"\033[0m\n'
>&2 printf '\n'
>&2 printf 'The output of `\033[32mbash\033[0m --version` may be different and is not relevant.\n'
return 1
fi
unset OPTIND
local opt timeout=5 max_dirty=-1 ttl=3600 extra_flags=
local max_num_staged=1 max_num_unstaged=1 max_num_conflicted=1 max_num_untracked=1
while getopts "t:s:u:c:d:m:r:eUWD" opt; do
case "$opt" in
t) timeout=$OPTARG;;
s) max_num_staged=$OPTARG;;
u) max_num_unstaged=$OPTARG;;
c) max_num_conflicted=$OPTARG;;
d) max_num_untracked=$OPTARG;;
m) max_dirty=$OPTARG;;
r) ttl=$OPTARG;;
e) extra_flags+='--recurse-untracked-dirs ';;
U) extra_flags+='--ignore-status-show-untracked-files ';;
W) extra_flags+='--ignore-bash-show-untracked-files ';;
D) extra_flags+='--ignore-bash-show-dirty-state ';;
*) return 1;;
esac
done
(( OPTIND == $# + 1 )) || { echo "usage: gitstatus_start [OPTION]..." >&2; return 1; }
[[ -z "${GITSTATUS_DAEMON_PID:-}" ]] || return 0 # already started
if [[ "${BASH_SOURCE[0]}" == */* ]]; then
local gitstatus_plugin_dir="${BASH_SOURCE[0]%/*}"
if [[ "$gitstatus_plugin_dir" != /* ]]; then
gitstatus_plugin_dir="$PWD"/"$gitstatus_plugin_dir"
fi
else
local gitstatus_plugin_dir="$PWD"
fi
local tmpdir req_fifo resp_fifo culprit
function gitstatus_start_impl() {
local log_level="${GITSTATUS_LOG_LEVEL:-}"
[[ -n "$log_level" || "${GITSTATUS_ENABLE_LOGGING:-0}" != 1 ]] || log_level=INFO
local uname_sm
uname_sm="$(command uname -sm)" || return
uname_sm="${uname_sm,,}"
local uname_s="${uname_sm% *}"
local uname_m="${uname_sm#* }"
if [[ "${GITSTATUS_NUM_THREADS:-0}" -gt 0 ]]; then
local threads="$GITSTATUS_NUM_THREADS"
else
local cpus
if ! command -v sysctl &>/dev/null || [[ "$uname_s" == linux ]] ||
! cpus="$(command sysctl -n hw.ncpu)"; then
if ! command -v getconf &>/dev/null || ! cpus="$(command getconf _NPROCESSORS_ONLN)"; then
cpus=8
fi
fi
local threads=$((cpus > 16 ? 32 : cpus > 0 ? 2 * cpus : 16))
fi
local daemon_args=(
--parent-pid="$$"
--num-threads="$threads"
--max-num-staged="$max_num_staged"
--max-num-unstaged="$max_num_unstaged"
--max-num-conflicted="$max_num_conflicted"
--max-num-untracked="$max_num_untracked"
--dirty-max-index-size="$max_dirty"
--repo-ttl-seconds="$ttl"
$extra_flags)
if [[ -n "$TMPDIR" && ( ( -d "$TMPDIR" && -w "$TMPDIR" ) || ! ( -d /tmp && -w /tmp ) ) ]]; then
local tmpdir=$TMPDIR
else
local tmpdir=/tmp
fi
tmpdir="$(command mktemp -d "$tmpdir"/gitstatus.bash.$$.XXXXXXXXXX)" || return
if [[ -n "$log_level" ]]; then
GITSTATUS_DAEMON_LOG="$tmpdir"/daemon.log
[[ "$log_level" == INFO ]] || daemon_args+=(--log-level="$log_level")
else
GITSTATUS_DAEMON_LOG=/dev/null
fi
req_fifo="$tmpdir"/req.fifo
resp_fifo="$tmpdir"/resp.fifo
command mkfifo -- "$req_fifo" "$resp_fifo" || return
{
(
trap '' INT QUIT TSTP
[[ "$GITSTATUS_DAEMON_LOG" == /dev/null ]] || set -x
builtin cd /
(
local fd_in fd_out
exec {fd_in}<"$req_fifo" {fd_out}>>"$resp_fifo" || exit
echo "$BASHPID" >&"$fd_out"
local _gitstatus_bash_daemon _gitstatus_bash_version _gitstatus_bash_downloaded
function _gitstatus_set_daemon() {
_gitstatus_bash_daemon="$1"
_gitstatus_bash_version="$2"
_gitstatus_bash_downloaded="$3"
}
set -- -d "$gitstatus_plugin_dir" -s "$uname_s" -m "$uname_m" \
-p "printf '.\036' >&$fd_out" -e "$fd_out" -- _gitstatus_set_daemon
[[ "${GITSTATUS_AUTO_INSTALL:-1}" -ne 0 ]] || set -- -n "$@"
source "$gitstatus_plugin_dir"/install || return
[[ -n "$_gitstatus_bash_daemon" ]] || return
[[ -n "$_gitstatus_bash_version" ]] || return
[[ "$_gitstatus_bash_downloaded" == [01] ]] || return
local sig=(TERM ILL PIPE)
if (( UID == EUID )); then
local home=~
else
local user
user="$(command id -un)" || return
[[ "$user" =~ ^[a-zA-Z0-9_,.-]+$ ]] || return
eval "local home=~$user"
[[ -n "$home" ]] || return
fi
if [[ -x "$_gitstatus_bash_daemon" ]]; then
HOME="$home" "$_gitstatus_bash_daemon" \
-G "$_gitstatus_bash_version" "${daemon_args[@]}" <&"$fd_in" >&"$fd_out" &
local pid=$!
trap "trap - ${sig[*]}; kill $pid &>/dev/null" ${sig[@]}
wait "$pid"
local ret=$?
trap - ${sig[@]}
case "$ret" in
0|129|130|131|137|141|143|159)
echo -nE $'}bye\x1f0\x1e' >&"$fd_out"
exit "$ret"
;;
esac
fi
(( ! _gitstatus_bash_downloaded )) || return
[[ "${GITSTATUS_AUTO_INSTALL:-1}" -ne 0 ]] || return
[[ "$_gitstatus_bash_daemon" == \
"${GITSTATUS_CACHE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/gitstatus}"/* ]] || return
set -- -f "$@"
_gitstatus_bash_daemon=
_gitstatus_bash_version=
_gitstatus_bash_downloaded=
source "$gitstatus_plugin_dir"/install || return
[[ -n "$_gitstatus_bash_daemon" ]] || return
[[ -n "$_gitstatus_bash_version" ]] || return
[[ "$_gitstatus_bash_downloaded" == 1 ]] || return
HOME="$home" "$_gitstatus_bash_daemon" \
-G "$_gitstatus_bash_version" "${daemon_args[@]}" <&"$fd_in" >&"$fd_out" &
local pid=$!
trap "trap - ${sig[*]}; kill $pid &>/dev/null" ${sig[@]}
wait "$pid"
trap - ${sig[@]}
echo -nE $'}bye\x1f0\x1e' >&"$fd_out"
) & disown
) & disown
} 0</dev/null &>"$GITSTATUS_DAEMON_LOG"
exec {_GITSTATUS_REQ_FD}>>"$req_fifo" {_GITSTATUS_RESP_FD}<"$resp_fifo" || return
command rm -f -- "$req_fifo" "$resp_fifo" || return
[[ "$GITSTATUS_DAEMON_LOG" != /dev/null ]] || command rmdir -- "$tmpdir" 2>/dev/null
IFS='' read -r -u $_GITSTATUS_RESP_FD GITSTATUS_DAEMON_PID || return
[[ "$GITSTATUS_DAEMON_PID" == [1-9]* ]] || return
local reply
echo -nE $'}hello\x1f\x1e' >&$_GITSTATUS_REQ_FD || return
local dl=
while true; do
reply=
if ! IFS='' read -rd $'\x1e' -u $_GITSTATUS_RESP_FD -t "$timeout" reply; then
culprit="$reply"
return 1
fi
[[ "$reply" == $'}hello\x1f0' ]] && break
if [[ -z "$dl" ]]; then
dl=1
if [[ -t 2 ]]; then
local spinner=('\b\033[33m-\033[0m' '\b\033[33m\\\033[0m' '\b\033[33m|\033[0m' '\b\033[33m/\033[0m')
>&2 printf '[\033[33mgitstatus\033[0m] fetching \033[32mgitstatusd\033[0m .. '
else
local spinner=('.')
>&2 printf '[gitstatus] fetching gitstatusd ..'
fi
fi
>&2 printf "${spinner[0]}"
spinner=("${spinner[@]:1}" "${spinner[0]}")
done
if [[ -n "$dl" ]]; then
if [[ -t 2 ]]; then
>&2 printf '\b[\033[32mok\033[0m]\n'
else
>&2 echo ' [ok]'
fi
fi
_GITSTATUS_DIRTY_MAX_INDEX_SIZE=$max_dirty
_GITSTATUS_CLIENT_PID="$BASHPID"
}
if ! gitstatus_start_impl; then
>&2 printf '\n'
>&2 printf '[\033[31mERROR\033[0m]: gitstatus failed to initialize.\n'
if [[ -n "${culprit-}" ]]; then
>&2 printf '\n%s\n' "$culprit"
fi
[[ -z "${req_fifo:-}" ]] || command rm -f "$req_fifo"
[[ -z "${resp_fifo:-}" ]] || command rm -f "$resp_fifo"
unset -f gitstatus_start_impl
gitstatus_stop
return 1
fi
export _GITSTATUS_CLIENT_PID _GITSTATUS_REQ_FD _GITSTATUS_RESP_FD GITSTATUS_DAEMON_PID
unset -f gitstatus_start_impl
}
# Stops gitstatusd if it's running.
function gitstatus_stop() {
if [[ "${_GITSTATUS_CLIENT_PID:-$BASHPID}" == "$BASHPID" ]]; then
[[ -z "${_GITSTATUS_REQ_FD:-}" ]] || exec {_GITSTATUS_REQ_FD}>&- || true
[[ -z "${_GITSTATUS_RESP_FD:-}" ]] || exec {_GITSTATUS_RESP_FD}>&- || true
[[ -z "${GITSTATUS_DAEMON_PID:-}" ]] || kill "$GITSTATUS_DAEMON_PID" &>/dev/null || true
fi
unset _GITSTATUS_REQ_FD _GITSTATUS_RESP_FD GITSTATUS_DAEMON_PID
unset _GITSTATUS_DIRTY_MAX_INDEX_SIZE _GITSTATUS_CLIENT_PID
}
# Retrieves status of a git repository from a directory under its working tree.
#
# Usage: gitstatus_query [OPTION]...
#
# -d STR Directory to query. Defaults to $PWD. Has no effect if GIT_DIR is set.
# -t FLOAT Timeout in seconds. Will block for at most this long. If no results
# are available by then, will return error.
# -p Don't compute anything that requires reading Git index. If this option is used,
# the following parameters will be 0: VCS_STATUS_INDEX_SIZE,
# VCS_STATUS_{NUM,HAS}_{STAGED,UNSTAGED,UNTRACKED,CONFLICTED}.
#
# On success sets VCS_STATUS_RESULT to one of the following values:
#
# norepo-sync The directory doesn't belong to a git repository.
# ok-sync The directory belongs to a git repository.
#
# If VCS_STATUS_RESULT is ok-sync, additional variables are set:
#
# VCS_STATUS_WORKDIR Git repo working directory. Not empty.
# VCS_STATUS_COMMIT Commit hash that HEAD is pointing to. Either 40 hex digits or
# empty if there is no HEAD (empty repo).
# VCS_STATUS_COMMIT_ENCODING Encoding of the HEAD's commit message. Empty value means UTF-8.
# VCS_STATUS_COMMIT_SUMMARY The first paragraph of the HEAD's commit message as one line.
# VCS_STATUS_LOCAL_BRANCH Local branch name or empty if not on a branch.
# VCS_STATUS_REMOTE_NAME The remote name, e.g. "upstream" or "origin".
# VCS_STATUS_REMOTE_BRANCH Upstream branch name. Can be empty.
# VCS_STATUS_REMOTE_URL Remote URL. Can be empty.
# VCS_STATUS_ACTION Repository state, A.K.A. action. Can be empty.
# VCS_STATUS_INDEX_SIZE The number of files in the index.
# VCS_STATUS_NUM_STAGED The number of staged changes.
# VCS_STATUS_NUM_CONFLICTED The number of conflicted changes.
# VCS_STATUS_NUM_UNSTAGED The number of unstaged changes.
# VCS_STATUS_NUM_UNTRACKED The number of untracked files.
# VCS_STATUS_HAS_STAGED 1 if there are staged changes, 0 otherwise.
# VCS_STATUS_HAS_CONFLICTED 1 if there are conflicted changes, 0 otherwise.
# VCS_STATUS_HAS_UNSTAGED 1 if there are unstaged changes, 0 if there aren't, -1 if
# unknown.
# VCS_STATUS_NUM_STAGED_NEW The number of staged new files. Note that renamed files
# are reported as deleted plus new.
# VCS_STATUS_NUM_STAGED_DELETED The number of staged deleted files. Note that renamed files
# are reported as deleted plus new.
# VCS_STATUS_NUM_UNSTAGED_DELETED The number of unstaged deleted files. Note that renamed files
# are reported as deleted plus new.
# VCS_STATUS_HAS_UNTRACKED 1 if there are untracked files, 0 if there aren't, -1 if
# unknown.
# VCS_STATUS_COMMITS_AHEAD Number of commits the current branch is ahead of upstream.
# Non-negative integer.
# VCS_STATUS_COMMITS_BEHIND Number of commits the current branch is behind upstream.
# Non-negative integer.
# VCS_STATUS_STASHES Number of stashes. Non-negative integer.
# VCS_STATUS_TAG The last tag (in lexicographical order) that points to the same
# commit as HEAD.
# VCS_STATUS_PUSH_REMOTE_NAME The push remote name, e.g. "upstream" or "origin".
# VCS_STATUS_PUSH_REMOTE_URL Push remote URL. Can be empty.
# VCS_STATUS_PUSH_COMMITS_AHEAD Number of commits the current branch is ahead of push remote.
# Non-negative integer.
# VCS_STATUS_PUSH_COMMITS_BEHIND Number of commits the current branch is behind push remote.
# Non-negative integer.
# VCS_STATUS_NUM_SKIP_WORKTREE The number of files in the index with skip-worktree bit set.
# Non-negative integer.
# VCS_STATUS_NUM_ASSUME_UNCHANGED The number of files in the index with assume-unchanged bit set.
# Non-negative integer.
#
# The point of reporting -1 via VCS_STATUS_HAS_* is to allow the command to skip scanning files in
# large repos. See -m flag of gitstatus_start.
#
# gitstatus_query returns an error if gitstatus_start hasn't been called in the same
# shell or the call had failed.
function gitstatus_query() {
unset OPTIND
local opt dir= timeout=() no_diff=0
while getopts "d:c:t:p" opt "$@"; do
case "$opt" in
d) dir=$OPTARG;;
t) timeout=(-t "$OPTARG");;
p) no_diff=1;;
*) return 1;;
esac
done
(( OPTIND == $# + 1 )) || { echo "usage: gitstatus_query [OPTION]..." >&2; return 1; }
[[ -n "${GITSTATUS_DAEMON_PID-}" ]] || return # not started
local req_id="$RANDOM.$RANDOM.$RANDOM.$RANDOM"
if [[ -z "${GIT_DIR:-}" ]]; then
[[ "$dir" == /* ]] || dir="$(pwd -P)/$dir" || return
elif [[ "$GIT_DIR" == /* ]]; then
dir=:"$GIT_DIR"
else
dir=:"$(pwd -P)/$GIT_DIR" || return
fi
echo -nE "$req_id"$'\x1f'"$dir"$'\x1f'"$no_diff"$'\x1e' >&$_GITSTATUS_REQ_FD || return
local -a resp
while true; do
IFS=$'\x1f' read -rd $'\x1e' -a resp -u $_GITSTATUS_RESP_FD "${timeout[@]}" || return
[[ "${resp[0]}" == "$req_id" ]] && break
done
if [[ "${resp[1]}" == 1 ]]; then
VCS_STATUS_RESULT=ok-sync
VCS_STATUS_WORKDIR="${resp[2]}"
VCS_STATUS_COMMIT="${resp[3]}"
VCS_STATUS_LOCAL_BRANCH="${resp[4]}"
VCS_STATUS_REMOTE_BRANCH="${resp[5]}"
VCS_STATUS_REMOTE_NAME="${resp[6]}"
VCS_STATUS_REMOTE_URL="${resp[7]}"
VCS_STATUS_ACTION="${resp[8]}"
VCS_STATUS_INDEX_SIZE="${resp[9]}"
VCS_STATUS_NUM_STAGED="${resp[10]}"
VCS_STATUS_NUM_UNSTAGED="${resp[11]}"
VCS_STATUS_NUM_CONFLICTED="${resp[12]}"
VCS_STATUS_NUM_UNTRACKED="${resp[13]}"
VCS_STATUS_COMMITS_AHEAD="${resp[14]}"
VCS_STATUS_COMMITS_BEHIND="${resp[15]}"
VCS_STATUS_STASHES="${resp[16]}"
VCS_STATUS_TAG="${resp[17]}"
VCS_STATUS_NUM_UNSTAGED_DELETED="${resp[18]}"
VCS_STATUS_NUM_STAGED_NEW="${resp[19]:-0}"
VCS_STATUS_NUM_STAGED_DELETED="${resp[20]:-0}"
VCS_STATUS_PUSH_REMOTE_NAME="${resp[21]:-}"
VCS_STATUS_PUSH_REMOTE_URL="${resp[22]:-}"
VCS_STATUS_PUSH_COMMITS_AHEAD="${resp[23]:-0}"
VCS_STATUS_PUSH_COMMITS_BEHIND="${resp[24]:-0}"
VCS_STATUS_NUM_SKIP_WORKTREE="${resp[25]:-0}"
VCS_STATUS_NUM_ASSUME_UNCHANGED="${resp[26]:-0}"
VCS_STATUS_COMMIT_ENCODING="${resp[27]-}"
VCS_STATUS_COMMIT_SUMMARY="${resp[28]-}"
VCS_STATUS_HAS_STAGED=$((VCS_STATUS_NUM_STAGED > 0))
if (( _GITSTATUS_DIRTY_MAX_INDEX_SIZE >= 0 &&
VCS_STATUS_INDEX_SIZE > _GITSTATUS_DIRTY_MAX_INDEX_SIZE_ )); then
VCS_STATUS_HAS_UNSTAGED=-1
VCS_STATUS_HAS_CONFLICTED=-1
VCS_STATUS_HAS_UNTRACKED=-1
else
VCS_STATUS_HAS_UNSTAGED=$((VCS_STATUS_NUM_UNSTAGED > 0))
VCS_STATUS_HAS_CONFLICTED=$((VCS_STATUS_NUM_CONFLICTED > 0))
VCS_STATUS_HAS_UNTRACKED=$((VCS_STATUS_NUM_UNTRACKED > 0))
fi
else
VCS_STATUS_RESULT=norepo-sync
unset VCS_STATUS_WORKDIR
unset VCS_STATUS_COMMIT
unset VCS_STATUS_LOCAL_BRANCH
unset VCS_STATUS_REMOTE_BRANCH
unset VCS_STATUS_REMOTE_NAME
unset VCS_STATUS_REMOTE_URL
unset VCS_STATUS_ACTION
unset VCS_STATUS_INDEX_SIZE
unset VCS_STATUS_NUM_STAGED
unset VCS_STATUS_NUM_UNSTAGED
unset VCS_STATUS_NUM_CONFLICTED
unset VCS_STATUS_NUM_UNTRACKED
unset VCS_STATUS_HAS_STAGED
unset VCS_STATUS_HAS_UNSTAGED
unset VCS_STATUS_HAS_CONFLICTED
unset VCS_STATUS_HAS_UNTRACKED
unset VCS_STATUS_COMMITS_AHEAD
unset VCS_STATUS_COMMITS_BEHIND
unset VCS_STATUS_STASHES
unset VCS_STATUS_TAG
unset VCS_STATUS_NUM_UNSTAGED_DELETED
unset VCS_STATUS_NUM_STAGED_NEW
unset VCS_STATUS_NUM_STAGED_DELETED
unset VCS_STATUS_PUSH_REMOTE_NAME
unset VCS_STATUS_PUSH_REMOTE_URL
unset VCS_STATUS_PUSH_COMMITS_AHEAD
unset VCS_STATUS_PUSH_COMMITS_BEHIND
unset VCS_STATUS_NUM_SKIP_WORKTREE
unset VCS_STATUS_NUM_ASSUME_UNCHANGED
unset VCS_STATUS_COMMIT_ENCODING
unset VCS_STATUS_COMMIT_SUMMARY
fi
}
# Usage: gitstatus_check.
#
# Returns 0 if and only if gitstatus_start has succeeded previously.
# If it returns non-zero, gitstatus_query is guaranteed to return non-zero.
function gitstatus_check() {
[[ -n "$GITSTATUS_DAEMON_PID" ]]
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,111 @@
# Simple Bash prompt with Git status.
# Source gitstatus.plugin.sh from $GITSTATUS_DIR or from the same directory
# in which the current script resides if the variable isn't set.
if [[ -n "${GITSTATUS_DIR-}" ]]; then
source "$GITSTATUS_DIR" || return
elif [[ "${BASH_SOURCE[0]}" == */* ]]; then
source "${BASH_SOURCE[0]%/*}/gitstatus.plugin.sh" || return
else
source gitstatus.plugin.sh || return
fi
# Sets GITSTATUS_PROMPT to reflect the state of the current git repository.
# The value is empty if not in a git repository. Forwards all arguments to
# gitstatus_query.
#
# Example value of GITSTATUS_PROMPT: master ⇣42⇡42 ⇠42⇢42 *42 merge ~42 +42 !42 ?42
#
# master current branch
# ⇣42 local branch is 42 commits behind the remote
# ⇡42 local branch is 42 commits ahead of the remote
# ⇠42 local branch is 42 commits behind the push remote
# ⇢42 local branch is 42 commits ahead of the push remote
# *42 42 stashes
# merge merge in progress
# ~42 42 merge conflicts
# +42 42 staged changes
# !42 42 unstaged changes
# ?42 42 untracked files
function gitstatus_prompt_update() {
GITSTATUS_PROMPT=""
gitstatus_query "$@" || return 1 # error
[[ "$VCS_STATUS_RESULT" == ok-sync ]] || return 0 # not a git repo
local reset=$'\001\e[0m\002' # no color
local clean=$'\001\e[38;5;076m\002' # green foreground
local untracked=$'\001\e[38;5;014m\002' # teal foreground
local modified=$'\001\e[38;5;011m\002' # yellow foreground
local conflicted=$'\001\e[38;5;196m\002' # red foreground
local p
local where # branch name, tag or commit
if [[ -n "$VCS_STATUS_LOCAL_BRANCH" ]]; then
where="$VCS_STATUS_LOCAL_BRANCH"
elif [[ -n "$VCS_STATUS_TAG" ]]; then
p+="${reset}#"
where="$VCS_STATUS_TAG"
else
p+="${reset}@"
where="${VCS_STATUS_COMMIT:0:8}"
fi
(( ${#where} > 32 )) && where="${where:0:12}${where: -12}" # truncate long branch names and tags
p+="${clean}${where}"
# ⇣42 if behind the remote.
(( VCS_STATUS_COMMITS_BEHIND )) && p+=" ${clean}${VCS_STATUS_COMMITS_BEHIND}"
# ⇡42 if ahead of the remote; no leading space if also behind the remote: ⇣42⇡42.
(( VCS_STATUS_COMMITS_AHEAD && !VCS_STATUS_COMMITS_BEHIND )) && p+=" "
(( VCS_STATUS_COMMITS_AHEAD )) && p+="${clean}${VCS_STATUS_COMMITS_AHEAD}"
# ⇠42 if behind the push remote.
(( VCS_STATUS_PUSH_COMMITS_BEHIND )) && p+=" ${clean}${VCS_STATUS_PUSH_COMMITS_BEHIND}"
(( VCS_STATUS_PUSH_COMMITS_AHEAD && !VCS_STATUS_PUSH_COMMITS_BEHIND )) && p+=" "
# ⇢42 if ahead of the push remote; no leading space if also behind: ⇠42⇢42.
(( VCS_STATUS_PUSH_COMMITS_AHEAD )) && p+="${clean}${VCS_STATUS_PUSH_COMMITS_AHEAD}"
# *42 if have stashes.
(( VCS_STATUS_STASHES )) && p+=" ${clean}*${VCS_STATUS_STASHES}"
# 'merge' if the repo is in an unusual state.
[[ -n "$VCS_STATUS_ACTION" ]] && p+=" ${conflicted}${VCS_STATUS_ACTION}"
# ~42 if have merge conflicts.
(( VCS_STATUS_NUM_CONFLICTED )) && p+=" ${conflicted}~${VCS_STATUS_NUM_CONFLICTED}"
# +42 if have staged changes.
(( VCS_STATUS_NUM_STAGED )) && p+=" ${modified}+${VCS_STATUS_NUM_STAGED}"
# !42 if have unstaged changes.
(( VCS_STATUS_NUM_UNSTAGED )) && p+=" ${modified}!${VCS_STATUS_NUM_UNSTAGED}"
# ?42 if have untracked files. It's really a question mark, your font isn't broken.
(( VCS_STATUS_NUM_UNTRACKED )) && p+=" ${untracked}?${VCS_STATUS_NUM_UNTRACKED}"
GITSTATUS_PROMPT="${p}${reset}"
}
# Start gitstatusd in the background.
gitstatus_stop && gitstatus_start -s -1 -u -1 -c -1 -d -1
# On every prompt, fetch git status and set GITSTATUS_PROMPT.
if [[ -z "${PROMPT_COMMAND[*]}" ]]; then
PROMPT_COMMAND=gitstatus_prompt_update
elif [[ ! "${PROMPT_COMMAND[*]}" =~ [[:space:]\;]?gitstatus_prompt_update[[:space:]\;]? ]]; then
# Note: If PROMPT_COMMAND is an array, this will modify its first element.
PROMPT_COMMAND=$'gitstatus_prompt_update\n'"$PROMPT_COMMAND"
fi
# Retain 3 trailing components of the current directory.
PROMPT_DIRTRIM=3
# Enable promptvars so that ${GITSTATUS_PROMPT} in PS1 is expanded.
shopt -s promptvars
# Customize prompt. Put $GITSTATUS_PROMPT in it reflect git status.
#
# Example:
#
# user@host ~/projects/skynet master ⇡42
# $ █
PS1='\[\033[01;32m\]\u@\h\[\033[00m\] ' # green user@host
PS1+='\[\033[01;34m\]\w\[\033[00m\]' # blue current working directory
PS1+='${GITSTATUS_PROMPT:+ $GITSTATUS_PROMPT}' # git status (requires promptvars option)
PS1+='\n\[\033[01;$((31+!$?))m\]\$\[\033[00m\] ' # green/red (success/error) $/# (normal/root)
PS1+='\[\e]0;\u@\h: \w\a\]' # terminal title: user@host: dir

@ -0,0 +1,111 @@
# Simple Zsh prompt with Git status.
# Source gitstatus.plugin.zsh from $GITSTATUS_DIR or from the same directory
# in which the current script resides if the variable isn't set.
source "${GITSTATUS_DIR:-${${(%):-%x}:h}}/gitstatus.plugin.zsh" || return
# Sets GITSTATUS_PROMPT to reflect the state of the current git repository. Empty if not
# in a git repository. In addition, sets GITSTATUS_PROMPT_LEN to the number of columns
# $GITSTATUS_PROMPT will occupy when printed.
#
# Example:
#
# GITSTATUS_PROMPT='master ⇣42⇡42 ⇠42⇢42 *42 merge ~42 +42 !42 ?42'
# GITSTATUS_PROMPT_LEN=39
#
# master current branch
# ⇣42 local branch is 42 commits behind the remote
# ⇡42 local branch is 42 commits ahead of the remote
# ⇠42 local branch is 42 commits behind the push remote
# ⇢42 local branch is 42 commits ahead of the push remote
# *42 42 stashes
# merge merge in progress
# ~42 42 merge conflicts
# +42 42 staged changes
# !42 42 unstaged changes
# ?42 42 untracked files
function gitstatus_prompt_update() {
emulate -L zsh
typeset -g GITSTATUS_PROMPT=''
typeset -gi GITSTATUS_PROMPT_LEN=0
# Call gitstatus_query synchronously. Note that gitstatus_query can also be called
# asynchronously; see documentation in gitstatus.plugin.zsh.
gitstatus_query 'MY' || return 1 # error
[[ $VCS_STATUS_RESULT == 'ok-sync' ]] || return 0 # not a git repo
local clean='%76F' # green foreground
local modified='%178F' # yellow foreground
local untracked='%39F' # blue foreground
local conflicted='%196F' # red foreground
local p
local where # branch name, tag or commit
if [[ -n $VCS_STATUS_LOCAL_BRANCH ]]; then
where=$VCS_STATUS_LOCAL_BRANCH
elif [[ -n $VCS_STATUS_TAG ]]; then
p+='%f#'
where=$VCS_STATUS_TAG
else
p+='%f@'
where=${VCS_STATUS_COMMIT[1,8]}
fi
(( $#where > 32 )) && where[13,-13]="…" # truncate long branch names and tags
p+="${clean}${where//\%/%%}" # escape %
# ⇣42 if behind the remote.
(( VCS_STATUS_COMMITS_BEHIND )) && p+=" ${clean}${VCS_STATUS_COMMITS_BEHIND}"
# ⇡42 if ahead of the remote; no leading space if also behind the remote: ⇣42⇡42.
(( VCS_STATUS_COMMITS_AHEAD && !VCS_STATUS_COMMITS_BEHIND )) && p+=" "
(( VCS_STATUS_COMMITS_AHEAD )) && p+="${clean}${VCS_STATUS_COMMITS_AHEAD}"
# ⇠42 if behind the push remote.
(( VCS_STATUS_PUSH_COMMITS_BEHIND )) && p+=" ${clean}${VCS_STATUS_PUSH_COMMITS_BEHIND}"
(( VCS_STATUS_PUSH_COMMITS_AHEAD && !VCS_STATUS_PUSH_COMMITS_BEHIND )) && p+=" "
# ⇢42 if ahead of the push remote; no leading space if also behind: ⇠42⇢42.
(( VCS_STATUS_PUSH_COMMITS_AHEAD )) && p+="${clean}${VCS_STATUS_PUSH_COMMITS_AHEAD}"
# *42 if have stashes.
(( VCS_STATUS_STASHES )) && p+=" ${clean}*${VCS_STATUS_STASHES}"
# 'merge' if the repo is in an unusual state.
[[ -n $VCS_STATUS_ACTION ]] && p+=" ${conflicted}${VCS_STATUS_ACTION}"
# ~42 if have merge conflicts.
(( VCS_STATUS_NUM_CONFLICTED )) && p+=" ${conflicted}~${VCS_STATUS_NUM_CONFLICTED}"
# +42 if have staged changes.
(( VCS_STATUS_NUM_STAGED )) && p+=" ${modified}+${VCS_STATUS_NUM_STAGED}"
# !42 if have unstaged changes.
(( VCS_STATUS_NUM_UNSTAGED )) && p+=" ${modified}!${VCS_STATUS_NUM_UNSTAGED}"
# ?42 if have untracked files. It's really a question mark, your font isn't broken.
(( VCS_STATUS_NUM_UNTRACKED )) && p+=" ${untracked}?${VCS_STATUS_NUM_UNTRACKED}"
GITSTATUS_PROMPT="${p}%f"
# The length of GITSTATUS_PROMPT after removing %f and %F.
GITSTATUS_PROMPT_LEN="${(m)#${${GITSTATUS_PROMPT//\%\%/x}//\%(f|<->F)}}"
}
# Start gitstatusd instance with name "MY". The same name is passed to
# gitstatus_query in gitstatus_prompt_update. The flags with -1 as values
# enable staged, unstaged, conflicted and untracked counters.
gitstatus_stop 'MY' && gitstatus_start -s -1 -u -1 -c -1 -d -1 'MY'
# On every prompt, fetch git status and set GITSTATUS_PROMPT.
autoload -Uz add-zsh-hook
add-zsh-hook precmd gitstatus_prompt_update
# Enable/disable the right prompt options.
setopt no_prompt_bang prompt_percent prompt_subst
# Customize prompt. Put $GITSTATUS_PROMPT in it to reflect git status.
#
# Example:
#
# user@host ~/projects/skynet master ⇡42
# % █
#
# The current directory gets truncated from the left if the whole prompt doesn't fit on the line.
PROMPT='%70F%n@%m%f ' # green user@host
PROMPT+='%39F%$((-GITSTATUS_PROMPT_LEN-1))<…<%~%<<%f' # blue current working directory
PROMPT+='${GITSTATUS_PROMPT:+ $GITSTATUS_PROMPT}' # git status
PROMPT+=$'\n' # new line
PROMPT+='%F{%(?.76.196)}%#%f ' # %/# (normal/root); green/red (ok/error)

@ -0,0 +1,476 @@
#!/bin/sh
#
# This script does not have a stable API.
_gitstatus_install_daemon_found() {
local installed="$1"
shift
[ $# = 0 ] || "$@" "$daemon" "$version" "$installed"
}
_gitstatus_install_main() {
if [ -n "${ZSH_VERSION:-}" ]; then
emulate -L sh -o no_unset
else
set -u
fi
local argv1="$1"
shift
local no_check= no_install= uname_s= uname_m= gitstatus_dir= dl_status= e=
local opt= OPTARG= OPTIND=1
while getopts ':s:m:d:p:e:fnh' opt "$@"; do
case "$opt" in
h)
command cat <<\END
Usage: install [-s KERNEL] [-m ARCH] [-d DIR] [-p CMD] [-e ERRFD] [-f|-n] [-- CMD [ARG]...]
If positional arguments are specified, call this on success:
CMD [ARG]... DAEMON VERSION INSTALLED
DAEMON is path to gitstatusd. VERSION is a glob pattern for the
version this daemon should support; it's supposed to be passed as
-G to gitstatusd. INSTALLED is 1 if gitstatusd has just been
downloaded and 0 otherwise.
Options:
-s KERNEL use this instead of lowercase `uname -s`
-m ARCH use this instead of lowercase `uname -m`
-d DIR use this instead of `dirname "$0"`
-p CMD eval this every second while downloading gitstatusd
-e ERRFD write error messages to this file descriptor
-f download gitstatusd even if there is one locally
-n do not download gitstatusd (fail instead)
END
return
;;
n)
if [ -n "$no_install" ]; then
>&2 echo "[gitstatus] error: duplicate option: -$opt"
return 1
fi
no_install=1
;;
f)
if [ -n "$no_check" ]; then
>&2 echo "[gitstatus] error: duplicate option: -$opt"
return 1
fi
no_check=1
;;
d)
if [ -n "$gitstatus_dir" ]; then
>&2 echo "[gitstatus] error: duplicate option: -$opt"
return 1
fi
if [ -z "$OPTARG" ]; then
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
return 1
fi
gitstatus_dir="$OPTARG"
;;
p)
if [ -n "$dl_status" ]; then
>&2 echo "[gitstatus] error: duplicate option: -$opt"
return 1
fi
if [ -z "$OPTARG" ]; then
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
return 1
fi
dl_status="$OPTARG"
;;
e)
if [ -n "$e" ]; then
>&2 echo "[gitstatus] error: duplicate option: -$opt"
return 1
fi
if [ -z "$OPTARG" ]; then
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
return 1
fi
e="$OPTARG"
;;
m)
if [ -n "$uname_m" ]; then
>&2 echo "[gitstatus] error: duplicate option: -$opt"
return 1
fi
if [ -z "$OPTARG" ]; then
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
return 1
fi
uname_m="$OPTARG"
;;
s)
if [ -n "$uname_s" ]; then
>&2 echo "[gitstatus] error: duplicate option: -$opt"
return 1
fi
if [ -z "$OPTARG" ]; then
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
return 1
fi
uname_s="$OPTARG"
;;
\?) >&2 echo "[gitstatus] error: invalid option: -$OPTARG" ; return 1;;
:) >&2 echo "[gitstatus] error: missing required argument: -$OPTARG"; return 1;;
*) >&2 echo "[gitstatus] internal error: unhandled option: -$opt" ; return 1;;
esac
done
shift "$((OPTIND - 1))"
: "${e:=2}"
: "${gitstatus_dir:=$argv1}"
if [ -n "$no_check" -a -n "$no_install" ]; then
>&2 echo "[gitstatus] error: incompatible options: -f, -n"
return 1
fi
if [ -z "$uname_s" ]; then
uname_s="$(command uname -s)" || return
uname_s="$(printf '%s' "$uname_s" | command tr '[A-Z]' '[a-z]')" || return
fi
if [ -z "$uname_m" ]; then
uname_m="$(command uname -m)" || return
uname_m="$(printf '%s' "$uname_m" | command tr '[A-Z]' '[a-z]')" || return
fi
local daemon="${GITSTATUS_DAEMON:-}"
local cache_dir="${GITSTATUS_CACHE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/gitstatus}"
if [ -z "$no_check" ]; then
if [ -n "${daemon##/*}" ]; then
>&2 echo "[gitstatus] error: GITSTATUS_DAEMON is not absolute path: $daemon"
return 1
fi
if [ -z "$daemon" -a -e "$gitstatus_dir"/usrbin/gitstatusd ]; then
daemon="$gitstatus_dir"/usrbin/gitstatusd
fi
if [ -n "$daemon" ]; then
local gitstatus_version= libgit2_version=
if ! . "$gitstatus_dir"/build.info; then
>&2 echo "[gitstatus] internal error: failed to source build.info"
return 1
fi
if [ -z "$gitstatus_version" ]; then
>&2 echo "[gitstatus] internal error: empty gitstatus_version in build.info"
return 1
fi
local version="$gitstatus_version"
_gitstatus_install_daemon_found 0 "$@"
return
fi
fi
while IFS= read -r line; do
line="${line###*}"
[ -n "$line" ] || continue
local uname_s_glob= uname_m_glob= file= version= sha256=
eval "$line" || return
if [ -z "$uname_s_glob" -o \
-z "$uname_m_glob" -o \
-z "$file" -o \
-z "$version" -o \
-z "$sha256" ]; then
>&2 echo "[gitstatus] internal error: invalid install.info line: $line"
return 1
fi
case "$uname_s" in
$uname_s_glob) ;;
*) continue;;
esac
case "$uname_m" in
$uname_m_glob) ;;
*) continue;;
esac
# Found a match. The while loop will terminate during this iteration.
if [ -z "$no_check" ]; then
# Check if a suitable gitstatusd already exists.
local daemon="$gitstatus_dir"/usrbin/"$file"
if [ ! -e "$daemon" ]; then
daemon="$cache_dir"/"$file"
[ -e "$daemon" ] || daemon=
fi
if [ -n "$daemon" ]; then
_gitstatus_install_daemon_found 0 "$@"
return
fi
fi
# No suitable gitstatusd exists. Need to download.
if [ -n "$no_install" ]; then
>&2 echo "[gitstatus] error: no gitstatusd found and installation is disabled"
return 1
fi
local daemon="$cache_dir"/"$file"
if [ -n "${cache_dir##/*}" ]; then
>&2 echo "[gitstatus] error: GITSTATUS_CACHE_DIR is not absolute: $cache_dir"
return 1
fi
if [ ! -d "$cache_dir" ] && ! mkdir -p -- "$cache_dir" || [ ! -w "$cache_dir" ]; then
local dir="$cache_dir"
while true; do
if [ -e "$dir" ]; then
if [ ! -d "$dir" ]; then
>&"$e" printf 'Not a directory: \033[4;31m%s\033[0m\n' "$dir"
>&"$e" printf '\n'
>&"$e" printf 'Delete it, then restart your shell.\n'
elif [ ! -w "$dir" ]; then
>&"$e" printf 'Directory is not writable: \033[4;31m%s\033[0m\n' "$dir"
>&"$e" printf '\n'
>&"$e" printf 'Make it writable, then restart your shell.\n'
fi
break
fi
if [ "$dir" = / ] || [ "$dir" = . ]; then
break
fi
dir="$(dirname -- "$dir")"
done
return 1
fi
if [ -n "${TMPDIR-}" -a '(' '(' -d "${TMPDIR-}" -a -w "${TMPDIR-}" ')' -o '!' '(' -d /tmp -a -w /tmp ')' ')' ]; then
local tmp="$TMPDIR"
else
local tmp=/tmp
fi
if ! command -v mktemp >/dev/null 2>&1 ||
! tmpdir="$(command mktemp -d "$tmp"/gitstatus-install.XXXXXXXXXX)"; then
tmpdir="$tmp/gitstatus-install.tmp.$$"
if ! mkdir -p -- "$tmpdir"; then
if [ "$tmp" = /tmp ]; then
local label='directory'
else
local label='directory (\033[1mTMPDIR\033[m)'
fi
if [ ! -e "$tmp" ]; then
>&"$e" printf 'Temporary '"$label"' does not exist: \033[4;31m%s\033[0m\n' "$tmp"
>&"$e" printf '\n'
>&"$e" printf 'Create it, then restart your shell.\n'
elif [ ! -d "$tmp" ]; then
>&"$e" printf 'Not a '"$label"': \033[4;31m%s\033[0m\n' "$tmp"
>&"$e" printf '\n'
>&"$e" printf 'Make it a directory, then restart your shell.\n'
elif [ ! -w "$tmp" ]; then
>&"$e" printf 'Temporary '"$label"' is not writable: \033[4;31m%s\033[0m\n' "$tmp"
>&"$e" printf '\n'
>&"$e" printf 'Make it writable, then restart your shell.\n'
fi
return 1
fi
fi
if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then
>&"$e" printf 'Please install \033[32mcurl\033[0m or \033[32mwget\033[0m, then restart your shell.\n'
return 1
fi
(
run_cmd() {
command -v "$1" >/dev/null 2>/dev/null || return 127
local trapped= pid die ret
trap 'trapped=1' $sig
# The only reason for suppressing stderr is that `curl -f` cannot be silenced:
# `-s` doesn't work despite what the docs say.
command "$@" 2>/dev/null &
ret="$?"
if [ "$ret" = 0 ]; then
pid="$!"
die="trap - $sig; kill -- $pid 2>/dev/null; wait -- $pid 2>/dev/null; exit 1"
trap "$die" $sig
[ -z "$trapped" ] || eval "$die"
wait -- "$pid" 2>/dev/null
ret="$?"
fi
trap - $sig
[ -z "$trapped" ] || exit
return "$ret"
}
check_sha256() {
local data_file="$tmpdir"/"$1".tar.gz
local hash_file="$tmpdir"/"$1".tar.gz.sha256
local hash=
{
command -v shasum >/dev/null 2>/dev/null &&
run_cmd shasum -b -a 256 -- "$data_file" >"$hash_file" </dev/null &&
IFS= read -r hash <"$hash_file" &&
hash="${hash%% *}" &&
[ ${#hash} -eq 64 ]
} || {
command -v sha256sum >/dev/null 2>/dev/null &&
run_cmd sha256sum -b -- "$data_file" >"$hash_file" </dev/null &&
IFS= read -r hash <"$hash_file" &&
hash="${hash%% *}" &&
[ ${#hash} -eq 64 ]
} || {
# Note: sha256 can be from hashalot. It's incompatible.
# Thankfully, it produces shorter output.
command -v sha256 >/dev/null 2>/dev/null &&
run_cmd sha256 -- "$data_file" >"$hash_file" </dev/null &&
IFS= read -r hash <"$hash_file" &&
hash="${hash##* }" &&
[ ${#hash} -eq 64 ]
} || {
hash=
}
[ "$1" = 1 -a -z "$hash" -o "$hash" = "$sha256" ]
}
local url1="https://github.com/romkatv/gitstatus/releases/download/$version/$file.tar.gz"
local url2="https://gitee.com/romkatv/gitstatus/raw/release-$version/release/$file.tar.gz"
local sig='INT QUIT TERM ILL PIPE'
fetch() {
if [ "$1" != 1 ] && command -v sleep >/dev/null 2>/dev/null; then
if ! run_cmd sleep "$1"; then
echo -n >"$tmpdir"/"$1".status
return 1
fi
fi
local cmd part url ret
for cmd in 'curl -kfsSL' 'wget -qO-' 'curl -q -kfsSL' 'wget --no-config -qO-'; do
part=0
while true; do
if [ "$part" = 2 ]; then
ret=1
break
elif [ "$part" = 0 ]; then
url="$2"
else
url="$2"."$part"
fi
run_cmd $cmd -- "$url" >>"$tmpdir"/"$1".tar.gz
ret="$?"
[ "$ret" = 0 ] || break
check_sha256 "$1" && break
part=$((part+1))
done
[ "$ret" = 0 ] && break
run_cmd rm -f -- "$tmpdir"/"$1".tar.gz && continue
ret="$?"
break
done
echo -n >"$tmpdir"/"$1".status
return "$ret"
}
local trapped=
trap 'trapped=1' $sig
fetch 1 "$url1" &
local pid1="$!"
fetch 2 "$url2" &
local pid2="$!"
local die="trap - $sig; kill -- $pid1 $pid2 2>/dev/null; wait -- $pid1 $pid2 2>/dev/null; exit 1"
trap "$die" $sig
[ -z "$trapped" ] || eval "$die"
local n=
while true; do
[ -z "$dl_status" ] || eval "$dl_status" || eval "$die"
if command -v sleep >/dev/null 2>/dev/null; then
command sleep 1
elif command -v true >/dev/null 2>/dev/null; then
command true
fi
if [ -n "$pid1" -a -e "$tmpdir"/1.status ]; then
wait -- "$pid1" 2>/dev/null
local ret="$?"
pid1=
if [ "$ret" = 0 ]; then
if [ -n "$pid2" ]; then
kill -- "$pid2" 2>/dev/null
wait -- "$pid2" 2>/dev/null
fi
n=1
break
elif [ -z "$pid2" ]; then
break
else
die="trap - $sig; kill -- $pid2 2>/dev/null; wait -- $pid2 2>/dev/null; exit 1"
trap "$die" $sig
fi
elif [ -n "$pid2" -a -e "$tmpdir"/2.status ]; then
wait -- "$pid2" 2>/dev/null
local ret="$?"
pid2=
if [ "$ret" = 0 ]; then
if [ -n "$pid1" ]; then
kill -- "$pid1" 2>/dev/null
wait -- "$pid1" 2>/dev/null
fi
n=2
break
elif [ -z "$pid1" ]; then
break
else
die="trap - $sig; kill -- $pid1 2>/dev/null; wait -- $pid1 2>/dev/null; exit 1"
trap "$die" $sig
fi
fi
done
trap - $sig
if [ -z "$n" ]; then
>&"$e" printf 'Failed to download \033[32m%s\033[0m from any mirror:\n' "$file"
>&"$e" printf '\n'
>&"$e" printf ' 1. \033[4m%s\033[0m\n' "$url1"
>&"$e" printf ' 2. \033[4m%s\033[0m\n' "$url2"
>&"$e" printf '\n'
>&"$e" printf 'Check your internet connection, then restart your shell.\n'
exit 1
fi
command tar -C "$tmpdir" -xzf "$tmpdir"/"$n".tar.gz || exit
local tmpfile
if ! command -v mktemp >/dev/null 2>&1 ||
! tmpfile="$(command mktemp "$cache_dir"/gitstatusd.XXXXXXXXXX)"; then
tmpfile="$cache_dir"/gitstatusd.tmp.$$
fi
command mv -f -- "$tmpdir"/"$file" "$tmpfile" || exit
command mv -f -- "$tmpfile" "$cache_dir"/"$file" && exit
command rm -f -- "$cache_dir"/"$file"
command mv -f -- "$tmpfile" "$cache_dir"/"$file" && exit
command rm -f -- "$tmpfile"
exit 1
)
local ret="$?"
command rm -rf -- "$tmpdir"
[ "$ret" = 0 ] || return
_gitstatus_install_daemon_found 1 "$@"
return
done <"$gitstatus_dir"/install.info
>&"$e" printf 'There is no prebuilt \033[32mgitstatusd\033[0m for \033[1m%s\033[0m.\n' "$uname_s $uname_m"
>&"$e" printf '\n'
>&"$e" printf 'See: \033[4mhttps://github.com/romkatv/gitstatus#compiling\033[0m\n'
return 1
}
if [ -z "${0##*/*}" ]; then
_gitstatus_install_main "${0%/*}" "$@"
else
_gitstatus_install_main . "$@"
fi

@ -0,0 +1,34 @@
# 3
#
# This file is used by ./install and indirectly by shell bindings.
#
# The first line is read by powerlevel10k instant prompt. It must
# be updated whenever the content of this file changes. The actual
# value doesn't matter as long as it's unique. Consecutive integers
# work fine.
# Official gitstatusd binaries.
uname_s_glob="cygwin_nt-10.0"; uname_m_glob="i686"; file="gitstatusd-${uname_s}-${uname_m}"; version="v1.5.4"; sha256="5a8a809dcebdb6aa9b47d37e086c0485424a9d9c136770eec3c26cedf5bb75e3";
uname_s_glob="cygwin_nt-10.0"; uname_m_glob="x86_64"; file="gitstatusd-${uname_s}-${uname_m}"; version="v1.5.1"; sha256="c84cade0d6b86e04c27a6055f45851f6b46d6b88ba58772f7ca8ef4d295c800f";
uname_s_glob="darwin"; uname_m_glob="arm64"; file="gitstatusd-${uname_s}-${uname_m}"; version="v1.5.4"; sha256="eae979e990ca37c56ee39fadd0c3f392cbbd0c6bdfb9a603010be60d9e48910a";
uname_s_glob="darwin"; uname_m_glob="x86_64"; file="gitstatusd-${uname_s}-${uname_m}"; version="v1.5.4"; sha256="9fd3913ec1b6b856ab6e08a99a2343f0e8e809eb6b62ca4b0963163656c668e6";
uname_s_glob="freebsd"; uname_m_glob="amd64"; file="gitstatusd-${uname_s}-${uname_m}"; version="v1.5.4"; sha256="8e57ad642251e5acfa430aed82cd4ffe103db0bfadae4a15ccaf462c455d0442";
uname_s_glob="linux"; uname_m_glob="aarch64"; file="gitstatusd-${uname_s}-${uname_m}"; version="v1.5.4"; sha256="32b57eb28bf6d80b280e4020a0045184f8ca897b20b570c12948aa6838673225";
uname_s_glob="linux"; uname_m_glob="armv6l"; file="gitstatusd-${uname_s}-${uname_m}"; version="v1.5.1"; sha256="4bf5a0d0a082f544a48536ad3675930d5d2cc6a8cf906710045e0788f51192b3";
uname_s_glob="linux"; uname_m_glob="armv7l"; file="gitstatusd-${uname_s}-${uname_m}"; version="v1.5.1"; sha256="2b9deb29f86c8209114b71b94fc2e1ed936a1658808a1bee46f4a82fd6a1f8cc";
uname_s_glob="linux"; uname_m_glob="armv8l"; file="gitstatusd-${uname_s}-aarch64"; version="v1.5.4"; sha256="32b57eb28bf6d80b280e4020a0045184f8ca897b20b570c12948aa6838673225";
uname_s_glob="linux"; uname_m_glob="i686"; file="gitstatusd-${uname_s}-${uname_m}"; version="v1.5.4"; sha256="56d55e2e9a202d3072fa612d8fa1faa61243ffc86418a7fa64c2c9d9a82e0f64";
uname_s_glob="linux"; uname_m_glob="ppc64le"; file="gitstatusd-${uname_s}-${uname_m}"; version="v1.5.4"; sha256="1afd072c8c26ef6ec2d9ac11cef96c84cd6f10e859665a6ffcfb6112c758547e";
uname_s_glob="linux"; uname_m_glob="x86_64"; file="gitstatusd-${uname_s}-${uname_m}"; version="v1.5.4"; sha256="9633816e7832109e530c9e2532b11a1edae08136d63aa7e40246c0339b7db304";
uname_s_glob="msys_nt-10.0"; uname_m_glob="i686"; file="gitstatusd-${uname_s}-${uname_m}"; version="v1.5.1"; sha256="7f9b849fc52e7a95b9b933e25121ad5ae990a1871aad6616922ad7bcf1eebf20";
uname_s_glob="msys_nt-10.0"; uname_m_glob="x86_64"; file="gitstatusd-${uname_s}-${uname_m}"; version="v1.5.1"; sha256="5d3c626b5ee564dbc13ddba89752dc58b0efe925b26dbd8b2304849d9ba01732";
# Fallbacks to official gitstatusd binaries.
uname_s_glob="cygwin_nt-*"; uname_m_glob="i686"; file="gitstatusd-cygwin_nt-10.0-${uname_m}"; version="v1.5.2"; sha256="5a8a809dcebdb6aa9b47d37e086c0485424a9d9c136770eec3c26cedf5bb75e3";
uname_s_glob="cygwin_nt-*"; uname_m_glob="x86_64"; file="gitstatusd-cygwin_nt-10.0-${uname_m}"; version="v1.5.1"; sha256="c84cade0d6b86e04c27a6055f45851f6b46d6b88ba58772f7ca8ef4d295c800f";
uname_s_glob="mingw32_nt-*"; uname_m_glob="i686"; file="gitstatusd-msys_nt-10.0-${uname_m}"; version="v1.5.1"; sha256="7f9b849fc52e7a95b9b933e25121ad5ae990a1871aad6616922ad7bcf1eebf20";
uname_s_glob="mingw32_nt-*"; uname_m_glob="x86_64"; file="gitstatusd-msys_nt-10.0-${uname_m}"; version="v1.5.1"; sha256="5d3c626b5ee564dbc13ddba89752dc58b0efe925b26dbd8b2304849d9ba01732";
uname_s_glob="mingw64_nt-*"; uname_m_glob="i686"; file="gitstatusd-msys_nt-10.0-${uname_m}"; version="v1.5.1"; sha256="7f9b849fc52e7a95b9b933e25121ad5ae990a1871aad6616922ad7bcf1eebf20";
uname_s_glob="mingw64_nt-*"; uname_m_glob="x86_64"; file="gitstatusd-msys_nt-10.0-${uname_m}"; version="v1.5.1"; sha256="5d3c626b5ee564dbc13ddba89752dc58b0efe925b26dbd8b2304849d9ba01732";
uname_s_glob="msys_nt-*"; uname_m_glob="i686"; file="gitstatusd-msys_nt-10.0-${uname_m}"; version="v1.5.1"; sha256="7f9b849fc52e7a95b9b933e25121ad5ae990a1871aad6616922ad7bcf1eebf20";
uname_s_glob="msys_nt-*"; uname_m_glob="x86_64"; file="gitstatusd-msys_nt-10.0-${uname_m}"; version="v1.5.1"; sha256="5d3c626b5ee564dbc13ddba89752dc58b0efe925b26dbd8b2304849d9ba01732";

@ -0,0 +1,406 @@
#!/usr/bin/env zsh
#
# This script does not have a stable API.
#
# Usage: mbuild [-b git-ref] [kernel-arch]...
#
# Builds a bunch of gitstatusd-* binaries. Without arguments builds binaries
# for all platforms. git-ref defaults to master.
#
# Before using this script you need to set up build servers and list them
# in ~/.ssh/config. There should be a Host entry for every value of `assets`
# association defined below. VMs and cloud instances work as well as physical
# machines, including localhost. As long as the machine has been set up as
# described below and you can SSH to it without password, it should work.
#
# ===[ Build Server Setup ]===
#
# Linux
#
# - Install docker.
# $ apt install docker.io # adjust appropriately if there is no `apt`
# $ usermod -aG docker $USER # not needed if going to build as root
# - Install git.
# $ apt install git # adjust appropriately if there is no `apt`
#
# macOS
#
# - Install compiler tools:
# $ xcode-select --install
# - Install homebrew: https://brew.sh/.
# $ bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
#
# FreeBSD
#
# - Install git.
# $ pkg install git
#
# Windows
#
# - Disable Windows Defender (optional).
# ps> Set-MpPreference -DisableRealtimeMonitoring $true
# - Install 64-bit and 32-bit msys2: https://www.msys2.org/wiki/MSYS2-installation/.
# - Open each of them after installation, type `pacman -Syu --noconfirm` and close the window.
# - Then run in powershell while having no msys2 or cygwin windows open:
# ps> C:\msys32\autorebase.bat
# ps> C:\msys64\autorebase.bat
# - Install 64-bit and 32-bit cygwin: https://cygwin.com/install.html.
# - Choose to install 32-bit to c:/cygwin32 instead of the default c:/cygwin.
# - Select these packages: binutils, cmake, gcc-core, gcc-g++, git, make, perl, wget.
#
# IMPORTANT: Install msys2 and cygwin one at a time.
#
# IMPORTANT: msys2 builder can reboot the build machine.
#
# Option 1: OpenSSH for Windows
#
# - Install OpenSSH: https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse.
# ps> Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
# ps> Start-Service sshd
# ps> Set-Service -Name sshd -StartupType 'Automatic'
# - Enable publickey authentication: https://stackoverflow.com/a/50502015/1095235.
# ps> cd $env:USERPROFILE
# ps> mkdir .ssh
# ps> notepad.exe .ssh/authorized_keys
# - Paste your public key, save, close.
# ps> icacls .ssh/authorized_keys /inheritance:r
# ps> notepad.exe C:\ProgramData\ssh\sshd_config
# - Comment out these two lines, save, close:
# # Match Group administrators
# # AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
# ps> Restart-Service sshd
#
# Option 2: OpenSSH from WSL
#
# - Install WSL.
# - Install Ubuntu.
# - Install sshd.
# $ apt install openssh-server
# $ dpkg-reconfigure openssh-server
# $ cat >/etc/ssh/sshd_config <<\END
# ClientAliveInterval 60
# AcceptEnv TERM LANG LC_*
# PermitRootLogin no
# AllowTcpForwarding no
# AllowAgentForwarding no
# AllowStreamLocalForwarding no
# AuthenticationMethods publickey
# END
# service ssh --full-restart
# - Add your public ssh key to ~/.ssh/authorized_keys.
# - Make `sshd` start when Windows boots.
'emulate' '-L' 'zsh' '-o' 'no_aliases' '-o' 'err_return'
setopt no_unset extended_glob pipe_fail prompt_percent typeset_silent \
no_prompt_subst no_prompt_bang pushd_silent warn_create_global
if [[ $ZSH_VERSION != (5.<1->*|<6->.*) || $ZSH_VERSION == 5.4(|.*) ]]; then
print -ru2 -- "[error] unsupported zsh version: $ZSH_VERSION"
return 1
fi
zmodload zsh/system
local -r git_url='https://github.com/romkatv/gitstatus.git'
local -rA assets=(
# target kernel-arch hostname of the build machine
cygwin_nt-10.0-i686 build-windows-x86_64
cygwin_nt-10.0-x86_64 build-windows-x86_64
msys_nt-10.0-i686 build-windows-x86_64
msys_nt-10.0-x86_64 build-windows-x86_64
darwin-arm64 build-macos-arm64
darwin-x86_64 build-macos-x86_64
freebsd-amd64 build-freebsd-amd64
linux-aarch64 build-linux-aarch64
linux-armv6l build-linux-armv7l
linux-armv7l build-linux-armv7l
linux-i686 build-linux-x86_64
linux-ppc64le build-linux-ppc64le
linux-x86_64 build-linux-x86_64
)
local -rA protocol=(
'cygwin_nt-10.0-*' windows
'msys_nt-10.0-*' windows
'darwin-*' unix
'freebsd-*' unix
'linux-*' unix
)
local -r rootdir=${ZSH_SCRIPT:h}
local -r logs=$rootdir/logs
local -r locks=$rootdir/locks
local -r binaries=$rootdir/usrbin
function usage() {
print -r -- 'usage: mbuild [-b REF] [KERNEL-ARCH]...'
}
local OPTARG opt git_ref=master
local -i OPTIND
while getopts ":b:h" opt; do
case $opt in
h) usage; return 0;;
b) [[ -n $OPTARG ]]; git_ref=$OPTARG;;
\?) print -ru2 -- "mbuild: invalid option: -$OPTARG" ; return 1;;
:) print -ru2 -- "mbuild: missing required argument: -$OPTARG"; return 1;;
*) print -ru2 -- "mbuild: invalid option: -$opt" ; return 1;;
esac
done
shift $((OPTIND - 1))
(( $# )) || set -- ${(ko)assets}
set -- ${(u)@}
local platform
for platform; do
if (( ! $+assets[$platform] )); then
print -ru2 -- "mbuild: invalid platform: $platform"
return 1
fi
done
local build='
rm -rf gitstatus
git clone --recursive --shallow-submodules --depth=1 -b '$git_ref' '$git_url'
cd gitstatus
if command -v zsh >/dev/null 2>&1; then
sh=zsh
elif command -v dash >/dev/null 2>&1; then
sh=dash
elif command -v ash >/dev/null 2>&1; then
sh=ash
else
sh=sh
fi
$sh -x ./build -m '
function build-unix() {
local intro flags=(-sw)
case $2 in
linux-ppc64le) ;;
linux-*) flags+=(-d docker);;
darwin-arm64) intro='PATH="/opt/homebrew/bin:$PATH"';;
darwin-*) intro='PATH="/usr/local/bin:$PATH"';;
esac
ssh $1 -- /bin/sh -uex <<<"
$intro
cd /tmp
$build ${2##*-} ${(j: :)${(@q)flags}}"
scp $1:/tmp/gitstatus/usrbin/gitstatusd $binaries/gitstatusd-$2
}
function build-windows() {
local shell=$(ssh $1 'echo $0')
if [[ $shell == '$0'* ]]; then
local c='c:'
else
local c='/mnt/c'
fi
local tmp env bin intro flags=(-w)
case $2 in
cygwin_nt-10.0-i686) bin='cygwin32/bin' ;|
cygwin_nt-10.0-x86_64) bin='cygwin64/bin' ;|
msys_nt-10.0-i686) bin='msys32/usr/bin';|
msys_nt-10.0-x86_64) bin='msys64/usr/bin';|
cygwin_nt-10.0-*)
tmp='/cygdrive/c/tmp'
;|
msys_nt-10.0-*)
tmp='/c/tmp'
env='MSYSTEM=MSYS'
# TODO: fix this (some errors about PGP keys).
# flags+=(-s)
# intro='pacman -S --needed --noconfirm git; '
intro+='PATH="$PATH:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl"'
while true; do
# TODO: run autorebase only when getting an error that can be fixed by autorebasing.
break
local out
out="$(ssh $1 cmd.exe "$c/${bin%%/*}/autorebase.bat" 2>&1)"
[[ $out == *"The following DLLs couldn't be rebased"* ]] || break
# Reboot to get rid of whatever is using those DLLs.
ssh $1 powershell.exe <<<'Restart-Computer -Force' || true
sleep 30
while ! ssh $1 <<<''; do sleep 5; done
done
() {
while true; do
# TODO: fix this (some errors about PGP keys).
break
local -i fd
exec {fd}< <(
ssh $1 $c/$bin/env.exe $env c:/$bin/bash.exe -l 2>&1 <<<"
pacman -Syu --noconfirm
exit")
{
local line
while true; do
IFS= read -u $fd -r line || return 0
if [[ $line == *"warning: terminate MSYS2"* ]]; then
# At this point the machine is hosed. A rogue process with a corrupted name
# is eating all CPU. The top SSH connection won't terminate on its own.
ssh $1 powershell.exe <<<'Restart-Computer -Force' || true
sleep 30
while ! ssh $1 <<<''; do sleep 5; done
break
fi
done
} always {
exec {fd}<&-
kill -- -$sysparams[procsubstpid] 2>/dev/null || true
}
done
} "$@"
;|
esac
ssh $1 $c/$bin/env.exe $env c:/$bin/bash.exe -l <<<"
set -uex
$intro
mkdir -p -- $tmp
cd -- $tmp
$build ${2##*-} ${(j: :)${(@q)flags}}
exit"
scp $1:$c/tmp/gitstatus/usrbin/gitstatusd $binaries/gitstatusd-$2
chmod +x $binaries/gitstatusd-$2
}
if [[ -r /proc/version && "$(</proc/version)" == *Microsoft* ]]; then
() {
(( $# )) || return 0
print -ru2 -- "WARNING: lock files exist: $@"
(( $# )) && rm -- $@
} $locks/*(N)
function flock() {
local fd
sysopen -ro cloexec -u fd <(
exec </dev/null 2>/dev/null
(
trap '' TERM PIPE
local fd
while true; do
sysopen -wo create,excl -u fd -- $1 && break
sleep 1
done
exec {fd}>&-
while true; do
print || break
done
rm -- $1
) &!
)
local REPLY
IFS= read -ru $fd
}
else
function flock() {
: >>$1
zsystem flock $1
}
fi
function build() (
setopt xtrace
local platform=$1
local machine=$assets[$platform]
flock $locks/$machine
build-${protocol[(k)$platform]} $machine $platform
local tmp=gitstatusd-$platform.tmp.$$.tar.gz
( cd -q -- $binaries; tar --owner=0 --group=0 -I 'gzip -9' -cf $tmp gitstatusd-$platform )
mv -f -- $binaries/$tmp $binaries/gitstatusd-$platform.tar.gz
# Make sure the last command is a built-in (important for flock).
:
)
function mbuild() {
local platform pid pids=()
for platform; do
build $platform &>$logs/$platform &
print -r -- "starting build for $platform on $assets[$platform] (pid $!)"
pids+=($platform $!)
done
local failed=()
for platform pid in $pids; do
print -rn -- "$platform => "
if wait $pid; then
print -r -- "ok"
else
print -r -- "error"
failed+=$platform
fi
done
(( $#failed )) || return 0
print
print -r -- "Error logs:"
print
for platform in $failed; do
print -r -- " $platform => $logs/$platform"
done
return 1
}
# Copied from https://github.com/romkatv/run-process-tree.
function run-process-tree() {
zmodload zsh/parameter zsh/param/private || return
local -P opt=(${(kv)options[@]}) || return
local -P pat=(${patchars[@]}) || return
local -P dis_pat=(${dis_patchars[@]}) || return
emulate -L zsh -o err_return || return
setopt monitor traps_async pipe_fail no_unset
zmodload zsh/system
if (( $# == 0 )); then
print -ru2 -- 'usage: run-process-tree command [arg]...'
return 1
fi
local -P stdout REPLY
exec {stdout}>&1
{
{
local -Pi pipe
local -P gid=$sysparams[pid]
local -P sig=(ABRT EXIT HUP ILL INT PIPE QUIT TERM ZERR)
local -P trap=(trap "trap - $sig; kill -- -$sysparams[pid]" $sig)
exec {pipe}>&1 1>&$stdout
$trap
{
$trap
while sleep 1 && print -u $pipe .; do; done
} 2>/dev/null &
local -Pi watchdog=$!
{
trap - ZERR
exec {pipe}>&-
enable -p -- $pat
disable -p -- $dis_pat
options=($opt zle off monitor off)
"$@"
} &
local -Pi ret
wait $! || ret=$?
trap "exit $ret" TERM
kill $watchdog
wait $watchdog
return ret
} | while read; do; done || return
} always {
exec {stdout}>&-
}
}
mkdir -p -- $logs $locks $binaries
() {
run-process-tree mbuild $@
exit
} "$@"

@ -1,28 +0,0 @@
#!/usr/bin/zsh
emulate -L zsh
setopt err_exit no_unset pipe_fail extended_glob xtrace
: ${GITSTATUS_DIR:=${${(%):-%x}:A:h}}
: ${GITSTATUS_URL:=https://github.com/romkatv/gitstatus.git}
readonly GITSTATUS_DIR GITSTATUS_URL
readonly -a IGNORE=(pull-upstream.zsh README.md)
() {
local repo && repo="$(mktemp -d ${TMPDIR:-/tmp}/gitstatus-pull-upstream.XXXXXXXXXX)"
trap "rm -rf ${(q)repo}" EXIT
git clone --depth 1 $GITSTATUS_URL $repo
local dst
for dst in $GITSTATUS_DIR/**/*(.,@); do
local f=${dst#$GITSTATUS_DIR/}
(( ! ${IGNORE[(I)$f]} )) || continue
local src=$repo/$f
[[ -f $src ]] && {
mkdir -p ${dst:h} && cp -f $src $dst || return
} || {
rm -f $dst
}
done
}

@ -0,0 +1,37 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_ALGORITHM_H_
#define ROMKATV_GITSTATUS_ALGORITHM_H_
#include <algorithm>
namespace gitstatus {
// Requires: Iter is a BidirectionalIterator.
//
// Returns iterator pointing to the last value in [begin, end) that compares equal to the value, or
// begin if none compare equal.
template <class Iter, class T>
Iter FindLast(Iter begin, Iter end, const T& val) {
while (begin != end && !(*--end == val)) {}
return end;
}
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_ALGORITHM_H_

@ -0,0 +1,118 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include "arena.h"
#include <algorithm>
#include <type_traits>
#include "bits.h"
#include "check.h"
namespace gitstatus {
namespace {
size_t Clamp(size_t min, size_t val, size_t max) { return std::min(max, std::max(min, val)); }
static const uintptr_t kSingularity = reinterpret_cast<uintptr_t>(&kSingularity);
} // namespace
// Triple singularity. We are all fucked.
Arena::Block Arena::g_empty_block = {kSingularity, kSingularity, kSingularity};
Arena::Arena(Arena::Options opt) : opt_(std::move(opt)), top_(&g_empty_block) {
CHECK(opt_.min_block_size <= opt_.max_block_size);
}
Arena::Arena(Arena&& other) : Arena() { *this = std::move(other); }
Arena::~Arena() {
// See comments in Makefile for the reason sized deallocation is not used.
for (const Block& b : blocks_) ::operator delete(reinterpret_cast<void*>(b.start));
}
Arena& Arena::operator=(Arena&& other) {
if (this != &other) {
// In case std::vector ever gets small object optimization.
size_t idx = other.reusable_ ? other.top_ - other.blocks_.data() : 0;
opt_ = other.opt_;
blocks_ = std::move(other.blocks_);
reusable_ = other.reusable_;
top_ = reusable_ ? blocks_.data() + idx : &g_empty_block;
other.blocks_.clear();
other.reusable_ = 0;
other.top_ = &g_empty_block;
}
return *this;
}
void Arena::Reuse(size_t num_blocks) {
reusable_ = std::min(reusable_, num_blocks);
for (size_t i = reusable_; i != blocks_.size(); ++i) {
const Block& b = blocks_[i];
// See comments in Makefile for the reason sized deallocation is not used.
::operator delete(reinterpret_cast<void*>(b.start));
}
blocks_.resize(reusable_);
if (reusable_) {
top_ = blocks_.data();
top_->tip = top_->start;
} else {
top_ = &g_empty_block;
}
}
void Arena::AddBlock(size_t size, size_t alignment) {
if (alignment > alignof(std::max_align_t)) {
size += alignment - 1;
} else {
size = std::max(size, alignment);
}
if (size <= top_->size() && top_ < blocks_.data() + reusable_ - 1) {
assert(blocks_.front().size() == top_->size());
++top_;
top_->tip = top_->start;
return;
}
if (size <= opt_.max_alloc_threshold) {
size =
std::max(size, Clamp(opt_.min_block_size, NextPow2(top_->size() + 1), opt_.max_block_size));
}
auto p = reinterpret_cast<uintptr_t>(::operator new(size));
blocks_.push_back(Block{p, p, p + size});
if (reusable_) {
if (size < blocks_.front().size()) {
top_ = &blocks_.back();
return;
}
if (size > blocks_.front().size()) reusable_ = 0;
}
std::swap(blocks_.back(), blocks_[reusable_]);
top_ = &blocks_[reusable_++];
}
void* Arena::AllocateSlow(size_t size, size_t alignment) {
assert(alignment && !(alignment & (alignment - 1)));
AddBlock(size, alignment);
assert(Align(top_->tip, alignment) + size <= top_->end);
return Allocate(size, alignment);
}
} // namespace gitstatus

@ -0,0 +1,273 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_ARENA_H_
#define ROMKATV_GITSTATUS_ARENA_H_
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <limits>
#include <new>
#include <type_traits>
#include <vector>
#include "string_view.h"
namespace gitstatus {
// Thread-compatible. Very fast and very flexible w.r.t. allocation size and alignment.
//
// Natural API extensions:
//
// // Donates a block to the arena. When the time comes, it'll be freed with
// // free(p, size, userdata).
// void Donate(void* p, size_t size, void* userdata, void(*free)(void*, size_t, void*));
class Arena {
public:
struct Options {
// The first call to Allocate() will allocate a block of this size. There is one exception when
// the first requested allocation size is larger than this limit. Subsequent blocks will be
// twice as large as the last until they saturate at max_block_size.
size_t min_block_size = 64;
// Allocate blocks at most this large. There is one exception when the requested allocation
// size is larger than this limit.
size_t max_block_size = 8 << 10;
// When the size of the first allocation in a block is larger than this threshold, the block
// size will be equal to the allocation size. This is meant to reduce memory waste when making
// many allocations with sizes slightly over max_block_size / 2. With max_alloc_threshold equal
// to max_block_size / N, the upper bound on wasted memory when making many equally-sized
// allocations is 100.0 / (N + 1) percent. When making allocations of different sizes, the upper
// bound on wasted memory is 50%.
size_t max_alloc_threshold = 1 << 10;
// Natural extensions:
//
// void* userdata;
// void (*alloc)(size_t size, size_t alignment, void* userdata);
// void (*free)(void* p, size_t size, void* userdata);
};
// Requires: opt.min_block_size <= opt.max_block_size.
//
// Doesn't allocate any memory.
Arena(Options opt);
Arena() : Arena(Options()) {}
Arena(Arena&&);
~Arena();
Arena& operator=(Arena&& other);
// Requires: alignment is a power of 2.
//
// Result is never null and always aligned. If size is zero, the result may be equal to the last.
// Alignment above alignof(std::max_align_t) is supported. There is no requirement for alignment
// to be less than size or to divide it.
inline void* Allocate(size_t size, size_t alignment) {
assert(alignment && !(alignment & (alignment - 1)));
uintptr_t p = Align(top_->tip, alignment);
uintptr_t e = p + size;
if (e <= top_->end) {
top_->tip = e;
return reinterpret_cast<void*>(p);
}
return AllocateSlow(size, alignment);
}
template <class T>
inline T* Allocate(size_t n) {
static_assert(!std::is_reference<T>(), "");
return static_cast<T*>(Allocate(n * sizeof(T), alignof(T)));
}
template <class T>
inline T* Allocate() {
return Allocate<T>(1);
}
inline char* MemDup(const char* p, size_t len) {
char* res = Allocate<char>(len);
std::memcpy(res, p, len);
return res;
}
// Copies the null-terminated string (including the trailing null character) to the arena and
// returns a pointer to the copy.
inline char* StrDup(const char* s) {
size_t len = std::strlen(s);
return MemDup(s, len + 1);
}
// Guarantees: !StrDup(p, len)[len].
inline char* StrDup(const char* p, size_t len) {
char* res = Allocate<char>(len + 1);
std::memcpy(res, p, len);
res[len] = 0;
return res;
}
// Guarantees: !StrDup(s)[s.len].
inline char* StrDup(StringView s) {
return StrDup(s.ptr, s.len);
}
template <class... Ts>
inline char* StrCat(const Ts&... ts) {
return [&](std::initializer_list<StringView> ss) {
size_t len = 0;
for (StringView s : ss) len += s.len;
char* p = Allocate<char>(len + 1);
for (StringView s : ss) {
std::memcpy(p, s.ptr, s.len);
p += s.len;
}
*p = 0;
return p - len;
}({ts...});
}
// Copies/moves `val` to the arena and returns a pointer to it.
template <class T>
inline std::remove_const_t<std::remove_reference_t<T>>* Dup(T&& val) {
return DirectInit<std::remove_const_t<std::remove_reference_t<T>>>(std::forward<T>(val));
}
// The same as `new T{args...}` but on the arena.
template <class T, class... Args>
inline T* DirectInit(Args&&... args) {
T* res = Allocate<T>();
::new (const_cast<void*>(static_cast<const void*>(res))) T(std::forward<Args>(args)...);
return res;
}
// The same as `new T(args...)` but on the arena.
template <class T, class... Args>
inline T* BraceInit(Args&&... args) {
T* res = Allocate<T>();
::new (const_cast<void*>(static_cast<const void*>(res))) T{std::forward<Args>(args)...};
return res;
}
// Tip() and TipSize() allow you to allocate the remainder of the current block. They can be
// useful if you are flexible w.r.t. the allocation size.
//
// Invariant:
//
// const void* tip = Tip();
// void* p = Allocate(TipSize(), 1); // grab the remainder of the current block
// assert(p == tip);
const void* Tip() const { return reinterpret_cast<const void*>(top_->tip); }
size_t TipSize() const { return top_->end - top_->tip; }
// Invalidates all allocations (without running destructors of allocated objects) and frees all
// blocks except at most the specified number of blocks. The retained blocks will be used to
// fulfil future allocation requests.
void Reuse(size_t num_blocks = std::numeric_limits<size_t>::max());
private:
struct Block {
size_t size() const { return end - start; }
uintptr_t start;
uintptr_t tip;
uintptr_t end;
};
inline static size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); };
void AddBlock(size_t size, size_t alignment);
bool ReuseBlock(size_t size, size_t alignment);
__attribute__((noinline)) void* AllocateSlow(size_t size, size_t alignment);
Options opt_;
std::vector<Block> blocks_;
// Invariant: !blocks_.empty() <= reusable_ && reusable_ <= blocks_.size().
size_t reusable_ = 0;
// Invariant: (top_ == &g_empty_block) == blocks_.empty().
// Invariant: blocks_.empty() || top_ == &blocks_.back() || top_ < blocks_.data() + reusable_.
Block* top_;
static Block g_empty_block;
};
// Copies of ArenaAllocator use the same thread-compatible Arena without synchronization.
template <class T>
class ArenaAllocator {
public:
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = size_t;
using difference_type = ptrdiff_t;
using propagate_on_container_move_assignment = std::true_type;
template <class U>
struct rebind {
using other = ArenaAllocator<U>;
};
using is_always_equal = std::false_type;
ArenaAllocator(Arena* arena = nullptr) : arena_(*arena) {}
Arena& arena() const { return arena_; }
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
pointer allocate(size_type n, const void* hint = nullptr) { return arena_.Allocate<T>(n); }
void deallocate(T* p, std::size_t n) {}
size_type max_size() const { return std::numeric_limits<size_type>::max() / sizeof(value_type); }
template <class U, class... Args>
void construct(U* p, Args&&... args) {
::new (const_cast<void*>(static_cast<const void*>(p))) U(std::forward<Args>(args)...);
}
template <class U>
void destroy(U* p) {
p->~U();
}
bool operator==(const ArenaAllocator& other) const { return &arena_ == &other.arena_; }
bool operator!=(const ArenaAllocator& other) const { return &arena_ != &other.arena_; }
private:
Arena& arena_;
};
template <class C>
struct LazyWithArena;
template <template <class, class> class C, class T1, class A>
struct LazyWithArena<C<T1, A>> {
using type = C<T1, ArenaAllocator<typename C<T1, A>::value_type>>;
};
template <template <class, class, class> class C, class T1, class T2, class A>
struct LazyWithArena<C<T1, T2, A>> {
using type = C<T1, T2, ArenaAllocator<typename C<T1, T2, A>::value_type>>;
};
template <class C>
using WithArena = typename LazyWithArena<C>::type;
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_DIR_H_

@ -0,0 +1,29 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_BITS_H_
#define ROMKATV_GITSTATUS_BITS_H_
#include <cstddef>
namespace gitstatus {
inline size_t NextPow2(size_t n) { return n < 2 ? 1 : (~size_t{0} >> __builtin_clzll(n - 1)) + 1; }
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_BITS_H_

@ -0,0 +1,61 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_CHECK_H_
#define ROMKATV_GITSTATUS_CHECK_H_
#include "logging.h"
#include <stdexcept>
// The argument must be an expression convertible to bool.
// Does nothing if the expression evaluates to true. Otherwise
// it's equivalent to LOG(FATAL).
#define CHECK(cond...) \
static_cast<void>(0), (!!(cond)) ? static_cast<void>(0) : LOG(FATAL) << #cond << ": "
#define VERIFY(cond...) \
static_cast<void>(0), ::gitstatus::internal_check::Thrower(!(cond)) \
? static_cast<void>(0) \
: LOG(ERROR) << #cond << ": "
namespace gitstatus {
struct Exception : std::exception {
const char* what() const noexcept override { return "Exception"; }
};
namespace internal_check {
class Thrower {
public:
Thrower(bool should_throw) : throw_(should_throw) {}
Thrower(Thrower&&) = delete;
explicit operator bool() const { return !throw_; }
~Thrower() noexcept(false) {
if (throw_) throw Exception();
}
private:
bool throw_;
};
} // namespace internal_check
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_CHECK_H_

@ -0,0 +1,157 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include "check_dir_mtime.h"
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <ctime>
#include <string>
#include <vector>
#include "check.h"
#include "dir.h"
#include "logging.h"
#include "print.h"
#include "scope_guard.h"
#include "stat.h"
namespace gitstatus {
namespace {
constexpr char kDirPrefix[] = ".gitstatus.";
void Touch(const char* path) {
int fd = creat(path, 0444);
VERIFY(fd >= 0) << Errno();
CHECK(!close(fd)) << Errno();
}
bool StatChanged(const char* path, const struct stat& prev) {
struct stat cur;
VERIFY(!lstat(path, &cur)) << Errno();
return !StatEq(prev, cur);
}
void RemoveStaleDirs(const char* root_dir) {
int dir_fd = open(root_dir, O_DIRECTORY | O_CLOEXEC);
if (dir_fd < 0) return;
ON_SCOPE_EXIT(&) { CHECK(!close(dir_fd)) << Errno(); };
Arena arena;
std::vector<char*> entries;
const std::time_t now = std::time(nullptr);
if (!ListDir(dir_fd, arena, entries,
/* precompose_unicode = */ false,
/* case_sensitive = */ true)) {
return;
}
std::string path = root_dir;
const size_t root_dir_len = path.size();
for (const char* entry : entries) {
if (std::strlen(entry) < std::strlen(kDirPrefix)) continue;
if (std::memcmp(entry, kDirPrefix, std::strlen(kDirPrefix))) continue;
struct stat st;
if (fstatat(dir_fd, entry, &st, AT_SYMLINK_NOFOLLOW)) {
LOG(WARN) << "Cannot stat " << Print(entry) << " in " << Print(root_dir) << ": " << Errno();
continue;
}
if (MTim(st).tv_sec + 10 > now) continue;
path.resize(root_dir_len);
path += entry;
size_t dir_len = path.size();
path += "/b/1";
if (unlink(path.c_str()) && errno != ENOENT) {
LOG(WARN) << "Cannot unlink " << Print(path) << ": " << Errno();
continue;
}
for (const char* d : {"/a/1", "/a", "/b", ""}) {
path.resize(dir_len);
path += d;
if (rmdir(path.c_str()) && errno != ENOENT) {
LOG(WARN) << "Cannot remove " << Print(path) << ": " << Errno();
break;
}
}
}
}
} // namespace
bool CheckDirMtime(const char* root_dir) {
try {
RemoveStaleDirs(root_dir);
std::string tmp = std::string() + root_dir + kDirPrefix + "XXXXXX";
VERIFY(mkdtemp(&tmp[0])) << Errno();
ON_SCOPE_EXIT(&) { rmdir(tmp.c_str()); };
std::string a_dir = tmp + "/a";
VERIFY(!mkdir(a_dir.c_str(), 0755)) << Errno();
ON_SCOPE_EXIT(&) { rmdir(a_dir.c_str()); };
struct stat a_st;
VERIFY(!lstat(a_dir.c_str(), &a_st)) << Errno();
std::string b_dir = tmp + "/b";
VERIFY(!mkdir(b_dir.c_str(), 0755)) << Errno();
ON_SCOPE_EXIT(&) { rmdir(b_dir.c_str()); };
struct stat b_st;
VERIFY(!lstat(b_dir.c_str(), &b_st)) << Errno();
while (sleep(1)) {
// zzzz
}
std::string a1 = a_dir + "/1";
VERIFY(!mkdir(a1.c_str(), 0755)) << Errno();
ON_SCOPE_EXIT(&) { rmdir(a1.c_str()); };
if (!StatChanged(a_dir.c_str(), a_st)) {
LOG(WARN) << "Creating a directory doesn't change mtime of the parent: " << Print(root_dir);
return false;
}
std::string b1 = b_dir + "/1";
Touch(b1.c_str());
ON_SCOPE_EXIT(&) { unlink(b1.c_str()); };
if (!StatChanged(b_dir.c_str(), b_st)) {
LOG(WARN) << "Creating a file doesn't change mtime of the parent: " << Print(root_dir);
return false;
}
LOG(INFO) << "All mtime checks have passes. Enabling untracked cache: " << Print(root_dir);
return true;
} catch (const Exception&) {
LOG(WARN) << "Error while testing for mtime capability: " << Print(root_dir);
return false;
}
}
} // namespace gitstatus

@ -0,0 +1,31 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_CHECK_DIR_MTIME_H_
#define ROMKATV_GITSTATUS_CHECK_DIR_MTIME_H_
namespace gitstatus {
// Similar to `git update-index --test-untracked-cache` but performs all tests
// in parallel, so the total testing time is one second regardless of the number
// of tests. It also performs fewer tests because gitstatus imposes fewer
// requirements on the filesystem in order to take advantage of untracked cache.
bool CheckDirMtime(const char* root_dir);
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_CHECK_DIR_MTIME_H_

@ -0,0 +1,237 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include "dir.h"
#include <algorithm>
#include <atomic>
#include <cerrno>
#include <cstring>
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef __linux__
#include <endian.h>
#include <sys/syscall.h>
#endif
#ifdef __APPLE__
#include <iconv.h>
#endif
#include "bits.h"
#include "check.h"
#include "scope_guard.h"
#include "string_cmp.h"
#include "tribool.h"
namespace gitstatus {
namespace {
bool Dots(const char* name) {
if (name[0] == '.') {
if (name[1] == 0) return true;
if (name[1] == '.' && name[2] == 0) return true;
}
return false;
}
} // namespace
// The linux-specific implementation is about 20% faster than the generic (posix) implementation.
#ifdef __linux__
uint64_t Read64(const void* p) {
uint64_t res;
std::memcpy(&res, p, 8);
return res;
}
void Write64(uint64_t x, void* p) { std::memcpy(p, &x, 8); }
void SwapBytes(char** begin, char** end) {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
for (; begin != end; ++begin) Write64(__builtin_bswap64(Read64(*begin)), *begin);
#elif __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__
#error "sorry, not implemented"
#endif
}
template <bool kCaseSensitive>
void SortEntries(char** begin, char** end) {
static_assert(kCaseSensitive, "");
SwapBytes(begin, end);
std::sort(begin, end, [](const char* a, const char* b) {
uint64_t x = Read64(a);
uint64_t y = Read64(b);
// Add 5 for good luck.
return x < y || (x == y && std::memcmp(a + 5, b + 5, 256) < 0);
});
SwapBytes(begin, end);
}
template <>
void SortEntries<false>(char** begin, char** end) {
std::sort(begin, end, StrLt<false>());
}
bool ListDir(int dir_fd, Arena& arena, std::vector<char*>& entries, bool precompose_unicode,
bool case_sensitive) {
struct linux_dirent64 {
ino64_t d_ino;
off64_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[];
};
constexpr size_t kBufSize = 8 << 10;
const size_t orig_size = entries.size();
while (true) {
char* buf = static_cast<char*>(arena.Allocate(kBufSize, alignof(linux_dirent64)));
// Save 256 bytes for the rainy day.
int n = syscall(SYS_getdents64, dir_fd, buf, kBufSize - 256);
if (n < 0) {
entries.resize(orig_size);
return false;
}
for (int pos = 0; pos < n;) {
auto* ent = reinterpret_cast<linux_dirent64*>(buf + pos);
if (!Dots(ent->d_name)) entries.push_back(ent->d_name);
pos += ent->d_reclen;
}
if (n == 0) break;
// The following optimization relies on SYS_getdents64 always returning as many
// entries as would fit. This is not guaranteed by the specification and I don't
// know if this is true in practice. The optimization has no measurable effect on
// gitstatus performance, so it's turned off.
//
// if (n + sizeof(linux_dirent64) + 512 <= kBufSize) break;
}
if (case_sensitive) {
SortEntries<true>(entries.data() + orig_size, entries.data() + entries.size());
} else {
SortEntries<false>(entries.data() + orig_size, entries.data() + entries.size());
}
return true;
}
#else // __linux__
namespace {
char* DirentDup(Arena& arena, const struct dirent& ent, size_t len) {
char* p = arena.Allocate<char>(len + 2);
*p++ = ent.d_type;
std::memcpy(p, ent.d_name, len + 1);
return p;
}
#ifdef __APPLE__
std::atomic<bool> g_iconv_error(true);
Tribool IConvTry(char* inp, size_t ins, char* outp, size_t outs) {
if (outs == 0) return Tribool::kUnknown;
iconv_t ic = iconv_open("UTF-8", "UTF-8-MAC");
if (ic == (iconv_t)-1) {
if (g_iconv_error.load(std::memory_order_relaxed) &&
g_iconv_error.exchange(false, std::memory_order_relaxed)) {
LOG(ERROR) << "iconv_open(\"UTF-8\", \"UTF-8-MAC\") failed";
}
return Tribool::kFalse;
}
ON_SCOPE_EXIT(&) { CHECK(iconv_close(ic) == 0) << Errno(); };
--outs;
if (iconv(ic, &inp, &ins, &outp, &outs) >= 0) {
*outp = 0;
return Tribool::kTrue;
}
return errno == E2BIG ? Tribool::kUnknown : Tribool::kFalse;
}
char* DirenvConvert(Arena& arena, struct dirent& ent, bool do_convert) {
if (!do_convert) return DirentDup(arena, ent, std::strlen(ent.d_name));
size_t len = 0;
do_convert = false;
for (unsigned char c; (c = ent.d_name[len]); ++len) {
if (c & 0x80) do_convert = true;
}
if (!do_convert) return DirentDup(arena, ent, len);
size_t n = NextPow2(len + 2);
while (true) {
char* p = arena.Allocate<char>(n);
switch (IConvTry(ent.d_name, len, p + 1, n - 1)) {
case Tribool::kFalse:
return DirentDup(arena, ent, len);
case Tribool::kTrue:
*p = ent.d_type;
return p + 1;
case Tribool::kUnknown:
break;
}
n *= 2;
}
}
#else // __APPLE__
char* DirenvConvert(Arena& arena, struct dirent& ent, bool do_convert) {
return DirentDup(arena, ent, std::strlen(ent.d_name));
}
#endif // __APPLE__
} // namespace
bool ListDir(int dir_fd, Arena& arena, std::vector<char*>& entries, bool precompose_unicode,
bool case_sensitive) {
const size_t orig_size = entries.size();
dir_fd = dup(dir_fd);
if (dir_fd < 0) return false;
DIR* dir = fdopendir(dir_fd);
if (!dir) {
CHECK(!close(dir_fd)) << Errno();
return false;
}
ON_SCOPE_EXIT(&) { CHECK(!closedir(dir)) << Errno(); };
while (struct dirent* ent = (errno = 0, readdir(dir))) {
if (Dots(ent->d_name)) continue;
entries.push_back(DirenvConvert(arena, *ent, precompose_unicode));
}
if (errno) {
entries.resize(orig_size);
return false;
}
StrSort(entries.data() + orig_size, entries.data() + entries.size(), case_sensitive);
return true;
}
#endif // __linux__
} // namespace gitstatus

@ -0,0 +1,50 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_DIR_H_
#define ROMKATV_GITSTATUS_DIR_H_
#include <cstddef>
#include <vector>
#include "arena.h"
namespace gitstatus {
// On error, leaves entries unchanged and returns false. Does not throw.
//
// On success, appends names of files from the specified directory to entries and returns true.
// Every appended entry is a null-terminated string. At -1 offset is its d_type. All elements
// point into the arena. They are sorted either by strcmp or strcasecmp depending on case_sensitive.
//
// Does not close dir_fd.
//
// There are two distinct implementations of ListDir -- one for Linux and another for everything
// else. The linux-specific implementation is 20% faster.
//
// The reason sorting is bundled with directory listing is performance on Linux. The API of
// getdents64 allows for much faster sorting than what can be done with a plain vector<char*>.
// For the POSIX implementation there is no need to bundle sorting in this way. In fact, it's
// done at the end with a generic StrSort() call.
//
// For best results, reuse the arena and vector for multiple calls to avoid heap allocations.
bool ListDir(int dir_fd, Arena& arena, std::vector<char*>& entries, bool precompose_unicode,
bool case_sensitive);
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_DIR_H_

@ -0,0 +1,250 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include "git.h"
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "arena.h"
#include "check.h"
#include "print.h"
#include "scope_guard.h"
namespace gitstatus {
const char* GitError() {
const git_error* err = git_error_last();
return err && err->message ? err->message : "unknown error";
}
std::string RepoState(git_repository* repo) {
Arena arena;
StringView gitdir(git_repository_path(repo));
// These names mostly match gitaction in vcs_info:
// https://github.com/zsh-users/zsh/blob/master/Functions/VCS_Info/Backends/VCS_INFO_get_data_git.
auto State = [&]() {
switch (git_repository_state(repo)) {
case GIT_REPOSITORY_STATE_NONE:
return "";
case GIT_REPOSITORY_STATE_MERGE:
return "merge";
case GIT_REPOSITORY_STATE_REVERT:
return "revert";
case GIT_REPOSITORY_STATE_REVERT_SEQUENCE:
return "revert-seq";
case GIT_REPOSITORY_STATE_CHERRYPICK:
return "cherry";
case GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE:
return "cherry-seq";
case GIT_REPOSITORY_STATE_BISECT:
return "bisect";
case GIT_REPOSITORY_STATE_REBASE:
return "rebase";
case GIT_REPOSITORY_STATE_REBASE_INTERACTIVE:
return "rebase-i";
case GIT_REPOSITORY_STATE_REBASE_MERGE:
return "rebase-m";
case GIT_REPOSITORY_STATE_APPLY_MAILBOX:
return "am";
case GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE:
return "am/rebase";
}
return "action";
};
auto DirExists = [&](StringView name) {
int fd = open(arena.StrCat(gitdir, "/", name), O_DIRECTORY | O_CLOEXEC);
if (fd < 0) return false;
CHECK(!close(fd)) << Errno();
return true;
};
auto ReadFile = [&](StringView name) {
std::ifstream strm(arena.StrCat(gitdir, "/", name));
std::string res;
strm >> res;
return res;
};
std::string next;
std::string last;
if (DirExists("rebase-merge")) {
next = ReadFile("rebase-merge/msgnum");
last = ReadFile("rebase-merge/end");
} else if (DirExists("rebase-apply")) {
next = ReadFile("rebase-apply/next");
last = ReadFile("rebase-apply/last");
}
std::ostringstream res;
res << State();
if (!next.empty() && !last.empty()) res << ' ' << next << '/' << last;
return res.str();
}
size_t CountRange(git_repository* repo, const std::string& range) {
git_revwalk* walk = nullptr;
VERIFY(!git_revwalk_new(&walk, repo)) << GitError();
ON_SCOPE_EXIT(=) { git_revwalk_free(walk); };
VERIFY(!git_revwalk_push_range(walk, range.c_str())) << GitError();
size_t res = 0;
while (true) {
git_oid oid;
switch (git_revwalk_next(&oid, walk)) {
case 0:
++res;
break;
case GIT_ITEROVER:
return res;
default:
LOG(ERROR) << "git_revwalk_next: " << range << ": " << GitError();
throw Exception();
}
}
}
size_t NumStashes(git_repository* repo) {
size_t res = 0;
auto* cb = +[](size_t index, const char* message, const git_oid* stash_id, void* payload) {
++*static_cast<size_t*>(payload);
return 0;
};
if (!git_stash_foreach(repo, cb, &res)) return res;
// Example error: failed to parse signature - malformed e-mail.
// See https://github.com/romkatv/powerlevel10k/issues/216.
LOG(WARN) << "git_stash_foreach: " << GitError();
return 0;
}
git_reference* Head(git_repository* repo) {
git_reference* symbolic = nullptr;
switch (git_reference_lookup(&symbolic, repo, "HEAD")) {
case 0:
break;
case GIT_ENOTFOUND:
return nullptr;
default:
LOG(ERROR) << "git_reference_lookup: " << GitError();
throw Exception();
}
git_reference* direct = nullptr;
if (git_reference_resolve(&direct, symbolic)) {
LOG(INFO) << "Empty git repo (no HEAD)";
return symbolic;
}
git_reference_free(symbolic);
return direct;
}
const char* LocalBranchName(const git_reference* ref) {
CHECK(ref);
git_reference_t type = git_reference_type(ref);
switch (type) {
case GIT_REFERENCE_DIRECT: {
return git_reference_is_branch(ref) ? git_reference_shorthand(ref) : "";
}
case GIT_REFERENCE_SYMBOLIC: {
static constexpr char kHeadPrefix[] = "refs/heads/";
const char* target = git_reference_symbolic_target(ref);
if (!target) return "";
size_t len = std::strlen(target);
if (len < sizeof(kHeadPrefix)) return "";
if (std::memcmp(target, kHeadPrefix, sizeof(kHeadPrefix) - 1)) return "";
return target + (sizeof(kHeadPrefix) - 1);
}
case GIT_REFERENCE_INVALID:
case GIT_REFERENCE_ALL:
break;
}
LOG(ERROR) << "Invalid reference type: " << type;
throw Exception();
}
RemotePtr GetRemote(git_repository* repo, const git_reference* local) {
git_remote* remote;
git_buf symref = {};
if (git_branch_remote(&remote, &symref, repo, git_reference_name(local))) return nullptr;
ON_SCOPE_EXIT(&) {
git_remote_free(remote);
git_buf_free(&symref);
};
git_reference* ref;
if (git_reference_lookup(&ref, repo, symref.ptr)) return nullptr;
ON_SCOPE_EXIT(&) { if (ref) git_reference_free(ref); };
const char* branch = nullptr;
std::string name = remote ? git_remote_name(remote) : ".";
if (git_branch_name(&branch, ref)) {
branch = "";
} else if (remote) {
VERIFY(std::strstr(branch, name.c_str()) == branch);
VERIFY(branch[name.size()] == '/');
branch += name.size() + 1;
}
auto res = std::make_unique<Remote>();
res->name = std::move(name);
res->branch = branch;
res->url = remote ? (git_remote_url(remote) ?: "") : "";
res->ref = std::exchange(ref, nullptr);
return RemotePtr(res.release());
}
PushRemotePtr GetPushRemote(git_repository* repo, const git_reference* local) {
git_remote* remote;
git_buf symref = {};
if (git_branch_push_remote(&remote, &symref, repo, git_reference_name(local))) return nullptr;
ON_SCOPE_EXIT(&) {
git_remote_free(remote);
git_buf_free(&symref);
};
git_reference* ref;
if (git_reference_lookup(&ref, repo, symref.ptr)) return nullptr;
ON_SCOPE_EXIT(&) { if (ref) git_reference_free(ref); };
std::string name = remote ? git_remote_name(remote) : ".";
auto res = std::make_unique<PushRemote>();
res->name = std::move(name);
res->url = remote ? (git_remote_url(remote) ?: "") : "";
res->ref = std::exchange(ref, nullptr);
return PushRemotePtr(res.release());
}
CommitMessage GetCommitMessage(git_repository* repo, const git_oid& id) {
git_commit* commit;
VERIFY(!git_commit_lookup(&commit, repo, &id)) << GitError();
ON_SCOPE_EXIT(=) { git_commit_free(commit); };
return {.encoding = git_commit_message_encoding(commit) ?: "",
.summary = git_commit_summary(commit) ?: ""};
}
} // namespace gitstatus

@ -0,0 +1,115 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_GIT_H_
#define ROMKATV_GITSTATUS_GIT_H_
#include <git2.h>
#include <cstddef>
#include <memory>
#include <string>
namespace gitstatus {
// Not null.
const char* GitError();
// Not null.
std::string RepoState(git_repository* repo);
// Returns the number of commits in the range.
size_t CountRange(git_repository* repo, const std::string& range);
// How many stashes are there?
size_t NumStashes(git_repository* repo);
// Returns the origin URL or an empty string. Not null.
std::string RemoteUrl(git_repository* repo, const git_reference* ref);
// Returns reference to HEAD or null if not found. The reference is symbolic if the repo is empty
// and direct otherwise.
git_reference* Head(git_repository* repo);
// Returns the name of the local branch, or an empty string.
const char* LocalBranchName(const git_reference* ref);
struct CommitMessage {
// Can be empty, meaning "UTF-8".
std::string encoding;
// The first paragraph of the commit's message as a one-liner.
std::string summary;
};
CommitMessage GetCommitMessage(git_repository* repo, const git_oid& id);
struct Remote {
// Tip of the remote branch.
git_reference* ref;
// Name of the tracking remote. For example, "origin".
std::string name;
// Name of the tracking remote branch. For example, "master".
std::string branch;
// URL of the tracking remote. For example, "https://foo.com/repo.git".
std::string url;
// Note: pushurl is not exposed (but could be).
struct Free {
void operator()(const Remote* p) const {
if (p) {
if (p->ref) git_reference_free(p->ref);
delete p;
}
}
};
};
struct PushRemote {
// Tip of the remote branch.
git_reference* ref;
// Name of the tracking remote. For example, "origin".
std::string name;
// URL of the tracking remote. For example, "https://foo.com/repo.git".
std::string url;
// Note: pushurl is not exposed (but could be).
struct Free {
void operator()(const PushRemote* p) const {
if (p) {
if (p->ref) git_reference_free(p->ref);
delete p;
}
}
};
};
using RemotePtr = std::unique_ptr<Remote, Remote::Free>;
using PushRemotePtr = std::unique_ptr<PushRemote, PushRemote::Free>;
RemotePtr GetRemote(git_repository* repo, const git_reference* local);
PushRemotePtr GetPushRemote(git_repository* repo, const git_reference* local);
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_GIT_H_

@ -0,0 +1,219 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include <time.h>
#include <cstddef>
#include <future>
#include <string>
#include <git2.h>
#include "check.h"
#include "git.h"
#include "logging.h"
#include "options.h"
#include "print.h"
#include "repo.h"
#include "repo_cache.h"
#include "request.h"
#include "response.h"
#include "scope_guard.h"
#include "thread_pool.h"
#include "timer.h"
namespace gitstatus {
namespace {
using namespace std::string_literals;
void Truncate(std::string& s, size_t max_len) {
if (s.size() > max_len) s.resize(max_len);
}
void ProcessRequest(const Options& opts, RepoCache& cache, Request req) {
Timer timer;
ON_SCOPE_EXIT(&) { timer.Report("request"); };
ResponseWriter resp(req.id);
Repo* repo = cache.Open(req.dir, req.from_dotgit);
if (!repo) return;
git_config* cfg;
VERIFY(!git_repository_config(&cfg, repo->repo())) << GitError();
ON_SCOPE_EXIT(=) { git_config_free(cfg); };
VERIFY(!git_config_refresh(cfg)) << GitError();
// Symbolic reference if and only if the repo is empty.
git_reference* head = Head(repo->repo());
if (!head) return;
ON_SCOPE_EXIT(=) { git_reference_free(head); };
// Null if and only if the repo is empty.
const git_oid* head_target = git_reference_target(head);
// Looking up tags may take some time. Do it in the background while we check for stuff.
// Note that GetTagName() doesn't access index, so it'll overlap with index reading and
// parsing.
std::future<std::string> tag = repo->GetTagName(head_target);
ON_SCOPE_EXIT(&) {
if (tag.valid()) {
try {
tag.wait();
} catch (const Exception&) {
}
}
};
// Repository working directory. Absolute; no trailing slash. E.g., "/home/romka/gitstatus".
StringView workdir(git_repository_workdir(repo->repo()));
if (workdir.len == 0) return;
if (workdir.len > 1 && workdir.ptr[workdir.len - 1] == '/') --workdir.len;
resp.Print(workdir);
// Revision. Either 40 hex digits or an empty string for empty repo.
resp.Print(head_target ? git_oid_tostr_s(head_target) : "");
// Local branch name (e.g., "master") or empty string if not on a branch.
resp.Print(LocalBranchName(head));
// Remote tracking branch or null.
RemotePtr remote = GetRemote(repo->repo(), head);
// Tracking remote branch name (e.g., "master") or empty string if there is no tracking remote.
resp.Print(remote ? remote->branch : "");
// Tracking remote name (e.g., "origin") or empty string if there is no tracking remote.
resp.Print(remote ? remote->name : "");
// Tracking remote URL or empty string if there is no tracking remote.
resp.Print(remote ? remote->url : "");
// Repository state, A.K.A. action. For example, "merge".
resp.Print(RepoState(repo->repo()));
IndexStats stats;
// Look for staged, unstaged and untracked. This is where most of the time is spent.
if (req.diff) stats = repo->GetIndexStats(head_target, cfg);
// The number of files in the index.
resp.Print(stats.index_size);
// The number of staged changes. At most opts.max_num_staged.
resp.Print(stats.num_staged);
// The number of unstaged changes. At most opts.max_num_unstaged. 0 if index is too large.
resp.Print(stats.num_unstaged);
// The number of conflicted changes. At most opts.max_num_conflicted. 0 if index is too large.
resp.Print(stats.num_conflicted);
// The number of untracked changes. At most opts.max_num_untracked. 0 if index is too large.
resp.Print(stats.num_untracked);
if (remote && remote->ref) {
const char* ref = git_reference_name(remote->ref);
// Number of commits we are ahead of upstream. Non-negative integer.
resp.Print(CountRange(repo->repo(), ref + "..HEAD"s));
// Number of commits we are behind upstream. Non-negative integer.
resp.Print(CountRange(repo->repo(), "HEAD.."s + ref));
} else {
resp.Print("0");
resp.Print("0");
}
// Number of stashes. Non-negative integer.
resp.Print(NumStashes(repo->repo()));
// Tag that points to HEAD (e.g., "v4.2") or empty string if there aren't any. The same as
// `git describe --tags --exact-match`.
resp.Print(tag.get());
// The number of unstaged deleted files. At most stats.num_unstaged.
resp.Print(stats.num_unstaged_deleted);
// The number of staged new files. At most stats.num_staged.
resp.Print(stats.num_staged_new);
// The number of staged deleted files. At most stats.num_staged.
resp.Print(stats.num_staged_deleted);
// Push remote or null.
PushRemotePtr push_remote = GetPushRemote(repo->repo(), head);
// Push remote name (e.g., "origin") or empty string if there is no push remote.
resp.Print(push_remote ? push_remote->name : "");
// Push remote URL or empty string if there is no push remote.
resp.Print(push_remote ? push_remote->url : "");
if (push_remote && push_remote->ref) {
const char* ref = git_reference_name(push_remote->ref);
// Number of commits we are ahead of push remote. Non-negative integer.
resp.Print(CountRange(repo->repo(), ref + "..HEAD"s));
// Number of commits we are behind upstream. Non-negative integer.
resp.Print(CountRange(repo->repo(), "HEAD.."s + ref));
} else {
resp.Print("0");
resp.Print("0");
}
// The number of files in the index with skip-worktree bit set.
resp.Print(stats.num_skip_worktree);
// The number of files in the index with assume-unchanged bit set.
resp.Print(stats.num_assume_unchanged);
CommitMessage msg = head_target ? GetCommitMessage(repo->repo(), *head_target) : CommitMessage();
Truncate(msg.summary, opts.max_commit_summary_length);
resp.Print(msg.encoding);
resp.Print(msg.summary);
resp.Dump("with git status");
}
int GitStatus(int argc, char** argv) {
tzset();
Options opts = ParseOptions(argc, argv);
g_min_log_level = opts.log_level;
for (int i = 0; i != argc; ++i) LOG(INFO) << "argv[" << i << "]: " << Print(argv[i]);
RequestReader reader(fileno(stdin), opts.lock_fd, opts.parent_pid);
RepoCache cache(opts);
InitGlobalThreadPool(opts.num_threads);
git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0);
git_libgit2_opts(GIT_OPT_DISABLE_INDEX_CHECKSUM_VERIFICATION, 1);
git_libgit2_opts(GIT_OPT_DISABLE_INDEX_FILEPATH_VALIDATION, 1);
git_libgit2_opts(GIT_OPT_DISABLE_READNG_PACKED_TAGS, 1);
git_libgit2_init();
while (true) {
try {
Request req;
if (reader.ReadRequest(req)) {
LOG(INFO) << "Processing request: " << req;
try {
ProcessRequest(opts, cache, req);
LOG(INFO) << "Successfully processed request: " << req;
} catch (const Exception&) {
LOG(ERROR) << "Error processing request: " << req;
}
} else if (opts.repo_ttl >= Duration()) {
cache.Free(Clock::now() - opts.repo_ttl);
}
} catch (const Exception&) {
}
}
}
} // namespace
} // namespace gitstatus
int main(int argc, char** argv) { gitstatus::GitStatus(argc, argv); }

@ -0,0 +1,456 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include "index.h"
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <algorithm>
#include <condition_variable>
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <iterator>
#include <mutex>
#include <stack>
#include "algorithm.h"
#include "check.h"
#include "dir.h"
#include "git.h"
#include "index.h"
#include "print.h"
#include "scope_guard.h"
#include "stat.h"
#include "string_cmp.h"
#include "thread_pool.h"
namespace gitstatus {
namespace {
void CommonDir(Str<> str, const char* a, const char* b, size_t* dir_len, size_t* dir_depth) {
*dir_len = 0;
*dir_depth = 0;
for (size_t i = 1; str.Eq(*a, *b) && *a; ++i, ++a, ++b) {
if (*a == '/') {
*dir_len = i;
++*dir_depth;
}
}
}
size_t Weight(const IndexDir& dir) { return 1 + dir.subdirs.size() + dir.files.size(); }
bool MTimeEq(const git_index_time& index, const struct timespec& workdir) {
if (index.seconds != workdir.tv_sec) return false;
if (int64_t{index.nanoseconds} == workdir.tv_nsec) return true;
#ifdef GITSTATUS_ZERO_NSEC
return index.nanoseconds == 0;
#else
return false;
#endif
}
bool IsModified(const git_index_entry* entry, const struct stat& st, const RepoCaps& caps) {
mode_t mode = st.st_mode;
if (S_ISREG(mode)) {
if (!caps.has_symlinks && S_ISLNK(entry->mode)) {
mode = entry->mode;
} else if (!caps.trust_filemode) {
mode = entry->mode;
} else {
mode = S_IFREG | (mode & 0100 ? 0755 : 0644);
}
} else {
mode &= S_IFMT;
}
bool res = false;
#define COND(field, cond...) \
if (cond) { \
} else \
res = true, \
LOG(DEBUG) << "Dirty candidate (modified): " << Print(entry->path) << ": " #field " "
COND(ino, !entry->ino || entry->ino == static_cast<std::uint32_t>(st.st_ino))
<< entry->ino << " => " << static_cast<std::uint32_t>(st.st_ino);
COND(stage, GIT_INDEX_ENTRY_STAGE(entry) == 0) << "=> " << GIT_INDEX_ENTRY_STAGE(entry);
COND(fsize, int64_t{entry->file_size} == st.st_size) << entry->file_size << " => " << st.st_size;
COND(mtime, MTimeEq(entry->mtime, MTim(st))) << Print(entry->mtime) << " => " << Print(MTim(st));
COND(mode, entry->mode == mode) << std::oct << entry->mode << " => " << std::oct << mode;
#undef COND
return res;
}
int OpenDir(int parent_fd, const char* name) {
return openat(parent_fd, name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
}
void OpenTail(int* fds, size_t nfds, int root_fd, StringView dirname, Arena& arena) {
CHECK(fds && nfds && root_fd >= 0);
std::fill(fds, fds + nfds, -1);
if (!dirname.len) return;
CHECK(dirname.len > 1);
CHECK(dirname.ptr[0] != '/');
CHECK(dirname.ptr[dirname.len - 1] == '/');
char* begin = arena.StrDup(dirname.ptr, dirname.len - 1);
WithArena<std::vector<const char*>> subdirs(&arena);
subdirs.reserve(nfds + 1);
for (char* sep = begin + dirname.len - 1; subdirs.size() < nfds;) {
sep = FindLast(begin, sep, '/');
if (sep == begin) break;
*sep = 0;
subdirs.push_back(sep + 1);
}
subdirs.push_back(begin);
if (subdirs.size() < nfds + 1) subdirs.push_back(".");
CHECK(subdirs.size() <= nfds + 1);
for (size_t i = subdirs.size(); i != 1; --i) {
const char* path = subdirs[i - 1];
if ((root_fd = OpenDir(root_fd, path)) < 0) {
for (; i != subdirs.size(); ++i) {
CHECK(!close(fds[i - 1])) << Errno();
fds[i - 1] = -1;
}
return;
}
fds[i - 2] = root_fd;
}
}
std::vector<const char*> ScanDirs(git_index* index, int root_fd, IndexDir* const* begin,
IndexDir* const* end, const RepoCaps& caps,
const ScanOpts& opts) {
const Str<> str(caps.case_sensitive);
Arena arena;
std::vector<const char*> dirty_candidates;
std::vector<char*> entries;
entries.reserve(128);
auto AddCandidate = [&](const char* kind, const char* path) {
if (kind) LOG(DEBUG) << "Dirty candidate (" << kind << "): " << Print(path);
dirty_candidates.push_back(path);
};
constexpr ssize_t kDirStackSize = 5;
int dir_fd[kDirStackSize];
std::fill(std::begin(dir_fd), std::end(dir_fd), -1);
auto Close = [](int& fd) {
if (fd >= 0) {
CHECK(!close(fd)) << Errno();
fd = -1;
}
};
auto CloseAll = [&] { std::for_each(std::begin(dir_fd), std::end(dir_fd), Close); };
ON_SCOPE_EXIT(&) { CloseAll(); };
if (begin != end) OpenTail(dir_fd, kDirStackSize, root_fd, (*begin)->path, arena);
for (IndexDir* const* it = begin; it != end; ++it) {
IndexDir& dir = **it;
auto Basename = [&](const git_index_entry* e) { return e->path + dir.path.len; };
auto AddUnmached = [&](StringView basename) {
if (!basename.len) {
dir.st = {};
dir.unmatched.clear();
dir.arena.Reuse();
} else if (str.Eq(basename, StringView(".git/"))) {
return;
}
char* path = dir.arena.StrCat(dir.path, basename);
dir.unmatched.push_back(path);
AddCandidate(basename.len ? "new" : "unreadable", path);
};
auto StatFiles = [&]() {
struct stat st;
for (const git_index_entry* file : dir.files) {
if (fstatat(*dir_fd, Basename(file), &st, AT_SYMLINK_NOFOLLOW)) {
AddCandidate(errno == ENOENT ? "deleted" : "unreadable", file->path);
} else if (IsModified(file, st, caps)) {
AddCandidate(nullptr, file->path);
}
}
};
ssize_t d = 0;
if ((it == begin || (d = it[-1]->depth + 1 - dir.depth) < kDirStackSize) && dir_fd[d] >= 0) {
CHECK(d >= 0);
int fd = OpenDir(dir_fd[d], arena.StrDup(dir.basename.ptr, dir.basename.len));
for (ssize_t i = 0; i != d; ++i) Close(dir_fd[i]);
std::rotate(dir_fd, dir_fd + (d ? d : kDirStackSize) - 1, dir_fd + kDirStackSize);
Close(*dir_fd);
*dir_fd = fd;
} else {
CloseAll();
if (dir.path.len) {
CHECK(dir.path.ptr[0] != '/');
CHECK(dir.path.ptr[dir.path.len - 1] == '/');
*dir_fd = OpenDir(root_fd, arena.StrDup(dir.path.ptr, dir.path.len - 1));
} else {
VERIFY((*dir_fd = dup(root_fd)) >= 0) << Errno();
}
}
if (*dir_fd < 0) {
CloseAll();
AddUnmached("");
continue;
}
if (!opts.include_untracked) {
StatFiles();
continue;
}
if (opts.untracked_cache != Tribool::kFalse) {
struct stat st;
if (fstat(*dir_fd, &st)) {
AddUnmached("");
continue;
}
if (opts.untracked_cache == Tribool::kTrue && StatEq(st, dir.st)) {
StatFiles();
for (const char* path : dir.unmatched) AddCandidate("new", path);
continue;
}
dir.st = st;
}
entries.clear();
arena.Reuse();
if (!ListDir(*dir_fd, arena, entries, caps.precompose_unicode, caps.case_sensitive)) {
AddUnmached("");
continue;
}
dir.unmatched.clear();
dir.arena.Reuse();
const git_index_entry* const* file = dir.files.data();
const git_index_entry* const* file_end = file + dir.files.size();
const StringView* subdir = dir.subdirs.data();
const StringView* subdir_end = subdir + dir.subdirs.size();
for (char* entry : entries) {
bool matched = false;
for (; file != file_end; ++file) {
int cmp = str.Cmp(Basename(*file), entry);
if (cmp < 0) {
AddCandidate("deleted", (*file)->path);
} else if (cmp == 0) {
struct stat st;
if (fstatat(*dir_fd, entry, &st, AT_SYMLINK_NOFOLLOW)) {
AddCandidate("unreadable", (*file)->path);
} else if (IsModified(*file, st, caps)) {
AddCandidate(nullptr, (*file)->path);
}
matched = true;
++file;
break;
} else {
break;
}
}
if (matched) continue;
for (; subdir != subdir_end; ++subdir) {
int cmp = str.Cmp(*subdir, entry);
if (cmp > 0) break;
if (cmp == 0) {
matched = true;
++subdir;
break;
}
}
if (!matched) {
StringView basename(entry);
if (entry[-1] == DT_DIR) entry[basename.len++] = '/';
AddUnmached(basename);
}
}
for (; file != file_end; ++file) AddCandidate("deleted", (*file)->path);
}
return dirty_candidates;
}
} // namespace
RepoCaps::RepoCaps(git_repository* repo, git_index* index) {
trust_filemode = git_index_is_filemode_trustworthy(index);
has_symlinks = git_index_supports_symlinks(index);
case_sensitive = git_index_is_case_sensitive(index);
precompose_unicode = git_index_precompose_unicode(index);
LOG(DEBUG) << "Repository capabilities for " << Print(git_repository_workdir(repo)) << ": "
<< "is_filemode_trustworthy = " << std::boolalpha << trust_filemode << ", "
<< "index_supports_symlinks = " << std::boolalpha << has_symlinks << ", "
<< "index_is_case_sensitive = " << std::boolalpha << case_sensitive << ", "
<< "precompose_unicode = " << std::boolalpha << precompose_unicode;
}
Index::Index(git_repository* repo, git_index* index)
: dirs_(&arena_),
splits_(&arena_),
git_index_(index),
root_dir_(git_repository_workdir(repo)),
caps_(repo, index) {
size_t total_weight = InitDirs(index);
InitSplits(total_weight);
}
size_t Index::InitDirs(git_index* index) {
const Str<> str(git_index_is_case_sensitive(index));
const size_t index_size = git_index_entrycount(index);
dirs_.reserve(index_size / 8);
std::stack<IndexDir*> stack;
stack.push(arena_.DirectInit<IndexDir>(&arena_));
size_t total_weight = 0;
auto PopDir = [&] {
CHECK(!stack.empty());
IndexDir* top = stack.top();
CHECK(top->depth + 1 == stack.size());
if (!std::is_sorted(top->subdirs.begin(), top->subdirs.end(), str.Lt)) {
StrSort(top->subdirs.begin(), top->subdirs.end(), str.case_sensitive);
}
total_weight += Weight(*top);
dirs_.push_back(top);
stack.pop();
};
for (size_t i = 0; i != index_size; ++i) {
const git_index_entry* entry = git_index_get_byindex_no_sort(index, i);
IndexDir* prev = stack.top();
size_t common_len, common_depth;
CommonDir(str, prev->path.ptr, entry->path, &common_len, &common_depth);
CHECK(common_depth <= prev->depth);
for (size_t i = common_depth; i != prev->depth; ++i) PopDir();
for (const char* p = entry->path + common_len; (p = std::strchr(p, '/')); ++p) {
IndexDir* top = stack.top();
StringView subdir(entry->path + top->path.len, p);
top->subdirs.push_back(subdir);
IndexDir* dir = arena_.DirectInit<IndexDir>(&arena_);
dir->path = StringView(entry->path, p - entry->path + 1);
dir->basename = subdir;
dir->depth = stack.size();
CHECK(dir->path.ptr[dir->path.len - 1] == '/');
stack.push(dir);
}
CHECK(!stack.empty());
IndexDir* dir = stack.top();
dir->files.push_back(entry);
}
CHECK(!stack.empty());
do {
PopDir();
} while (!stack.empty());
std::reverse(dirs_.begin(), dirs_.end());
return total_weight;
}
void Index::InitSplits(size_t total_weight) {
constexpr size_t kMinShardWeight = 512;
const size_t kNumShards = 16 * GlobalThreadPool()->num_threads();
const size_t shard_weight = std::max(kMinShardWeight, total_weight / kNumShards);
splits_.reserve(kNumShards + 1);
splits_.push_back(0);
for (size_t i = 0, w = 0; i != dirs_.size(); ++i) {
w += Weight(*dirs_[i]);
if (w >= shard_weight) {
w = 0;
splits_.push_back(i + 1);
}
}
if (splits_.back() != dirs_.size()) splits_.push_back(dirs_.size());
CHECK(splits_.size() <= kNumShards + 1);
CHECK(std::is_sorted(splits_.begin(), splits_.end()));
CHECK(std::adjacent_find(splits_.begin(), splits_.end()) == splits_.end());
}
std::vector<const char*> Index::GetDirtyCandidates(const ScanOpts& opts) {
int root_fd = open(root_dir_, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
VERIFY(root_fd >= 0);
ON_SCOPE_EXIT(&) { CHECK(!close(root_fd)) << Errno(); };
CHECK(!splits_.empty());
std::mutex mutex;
std::condition_variable cv;
size_t inflight = splits_.size() - 1;
bool error = false;
std::vector<const char*> res;
for (size_t i = 0; i != splits_.size() - 1; ++i) {
size_t from = splits_[i];
size_t to = splits_[i + 1];
GlobalThreadPool()->Schedule([&, from, to]() {
ON_SCOPE_EXIT(&) {
std::unique_lock<std::mutex> lock(mutex);
CHECK(inflight);
if (--inflight == 0) cv.notify_one();
};
try {
std::vector<const char*> candidates =
ScanDirs(git_index_, root_fd, dirs_.data() + from, dirs_.data() + to, caps_, opts);
if (!candidates.empty()) {
std::unique_lock<std::mutex> lock(mutex);
res.insert(res.end(), candidates.begin(), candidates.end());
}
} catch (const Exception&) {
std::unique_lock<std::mutex> lock(mutex);
error = true;
}
});
}
{
std::unique_lock<std::mutex> lock(mutex);
while (inflight) cv.wait(lock);
}
VERIFY(!error);
StrSort(res.begin(), res.end(), git_index_is_case_sensitive(git_index_));
auto StrEq = [](const char* a, const char* b) { return !strcmp(a, b); };
res.erase(std::unique(res.begin(), res.end(), StrEq), res.end());
return res;
}
} // namespace gitstatus

@ -0,0 +1,84 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_INDEX_H_
#define ROMKATV_GITSTATUS_INDEX_H_
#include <sys/stat.h>
#include <git2.h>
#include <cstddef>
#include <string>
#include <vector>
#include "arena.h"
#include "options.h"
#include "string_view.h"
#include "tribool.h"
namespace gitstatus {
struct RepoCaps {
RepoCaps(git_repository* repo, git_index* index);
bool trust_filemode;
bool has_symlinks;
bool case_sensitive;
bool precompose_unicode;
};
struct ScanOpts {
bool include_untracked;
Tribool untracked_cache;
};
struct IndexDir {
explicit IndexDir(Arena* arena) : files(arena), subdirs(arena) {}
StringView path;
StringView basename;
size_t depth = 0;
struct stat st = {};
WithArena<std::vector<const git_index_entry*>> files;
WithArena<std::vector<StringView>> subdirs;
Arena arena;
std::vector<const char*> unmatched;
};
class Index {
public:
Index(git_repository* repo, git_index* index);
std::vector<const char*> GetDirtyCandidates(const ScanOpts& opts);
private:
size_t InitDirs(git_index* index);
void InitSplits(size_t total_weight);
Arena arena_;
WithArena<std::vector<IndexDir*>> dirs_;
WithArena<std::vector<size_t>> splits_;
git_index* git_index_;
const char* root_dir_;
RepoCaps caps_;
};
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_GIT_H_

@ -0,0 +1,139 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include "logging.h"
#include <pthread.h>
#include <time.h>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <mutex>
#include <string>
namespace gitstatus {
namespace internal_logging {
namespace {
std::mutex g_log_mutex;
constexpr char kHexLower[] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
void FormatThreadId(char (&out)[2 * sizeof(std::uintptr_t) + 1]) {
std::uintptr_t tid = (std::uintptr_t)pthread_self();
char* p = out + sizeof(out) - 1;
*p = 0;
do {
--p;
*p = kHexLower[tid & 0xF];
tid >>= 4;
} while (p != out);
}
void FormatCurrentTime(char (&out)[64]) {
std::time_t time = std::time(nullptr);
struct tm tm;
if (localtime_r(&time, &tm) != &tm || std::strftime(out, sizeof(out), "%F %T", &tm) == 0) {
std::strcpy(out, "undef");
}
}
} // namespace
LogStreamBase::LogStreamBase(const char* file, int line, LogLevel lvl)
: errno_(errno), file_(file), line_(line), lvl_(LogLevelStr(lvl)) {
strm_ = std::make_unique<std::ostringstream>();
}
void LogStreamBase::Flush() {
{
std::string msg = strm_->str();
char tid[2 * sizeof(std::uintptr_t) + 1];
FormatThreadId(tid);
char time[64];
FormatCurrentTime(time);
std::unique_lock<std::mutex> lock(g_log_mutex);
std::fprintf(stderr, "[%s %s %s %s:%d] %s\n", time, tid, lvl_, file_, line_, msg.c_str());
}
strm_.reset();
errno = errno_;
}
std::ostream& operator<<(std::ostream& strm, Errno e) {
// GNU C Library uses a buffer of 1024 characters for strerror(). Mimic to avoid truncations.
char buf[1024];
auto x = strerror_r(e.err, buf, sizeof(buf));
// There are two versions of strerror_r with different semantics. We can figure out which
// one we've got by looking at the result type.
if (std::is_same<decltype(x), int>::value) {
// XSI-compliant version.
strm << (x ? "unknown error" : buf);
} else if (std::is_same<decltype(x), char*>::value) {
// GNU-specific version.
strm << x;
} else {
// Something else entirely.
strm << "unknown error";
}
return strm;
}
} // namespace internal_logging
LogLevel g_min_log_level = INFO;
const char* LogLevelStr(LogLevel lvl) {
switch (lvl) {
case DEBUG:
return "DEBUG";
case INFO:
return "INFO";
case WARN:
return "WARN";
case ERROR:
return "ERROR";
case FATAL:
return "FATAL";
}
return "UNKNOWN";
}
bool ParseLogLevel(const char* s, LogLevel& lvl) {
if (!s)
return false;
else if (!std::strcmp(s, "DEBUG"))
lvl = DEBUG;
else if (!std::strcmp(s, "INFO"))
lvl = INFO;
else if (!std::strcmp(s, "WARN"))
lvl = WARN;
else if (!std::strcmp(s, "ERROR"))
lvl = ERROR;
else if (!std::strcmp(s, "FATAL"))
lvl = FATAL;
else
return false;
return true;
}
} // namespace gitstatus

@ -0,0 +1,124 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_LOGGING_H_
#define ROMKATV_GITSTATUS_LOGGING_H_
#include <cstdlib>
#include <memory>
#include <ostream>
#include <sstream>
#define LOG(severity) LOG_I(severity)
#define LOG_I(severity) \
(::gitstatus::severity < ::gitstatus::g_min_log_level) \
? static_cast<void>(0) \
: ::gitstatus::internal_logging::Assignable() = \
::gitstatus::internal_logging::LogStream<::gitstatus::severity>(__FILE__, __LINE__, \
::gitstatus::severity) \
.ref()
namespace gitstatus {
enum LogLevel {
DEBUG,
INFO,
WARN,
ERROR,
FATAL,
};
const char* LogLevelStr(LogLevel lvl);
bool ParseLogLevel(const char* s, LogLevel& lvl);
extern LogLevel g_min_log_level;
namespace internal_logging {
struct Assignable {
template <class T>
void operator=(const T&) const {}
};
class LogStreamBase {
public:
LogStreamBase(const char* file, int line, LogLevel lvl);
LogStreamBase& ref() { return *this; }
std::ostream& strm() { return *strm_; }
int stashed_errno() const { return errno_; }
protected:
void Flush();
private:
int errno_;
const char* file_;
int line_;
const char* lvl_;
std::unique_ptr<std::ostringstream> strm_;
};
template <LogLevel>
class LogStream : public LogStreamBase {
public:
using LogStreamBase::LogStreamBase;
~LogStream() { this->Flush(); }
};
template <>
class LogStream<FATAL> : public LogStreamBase {
public:
using LogStreamBase::LogStreamBase;
~LogStream() __attribute__((noreturn)) {
this->Flush();
std::abort();
}
};
template <class T>
LogStreamBase& operator<<(LogStreamBase& strm, const T& val) {
strm.strm() << val;
return strm;
}
inline LogStreamBase& operator<<(LogStreamBase& strm, std::ostream& (*manip)(std::ostream&)) {
strm.strm() << manip;
return strm;
}
struct Errno {
int err;
};
std::ostream& operator<<(std::ostream& strm, Errno e);
struct StashedErrno {};
inline LogStreamBase& operator<<(LogStreamBase& strm, StashedErrno) {
return strm << Errno{strm.stashed_errno()};
}
} // namespace internal_logging
inline internal_logging::Errno Errno(int err) { return {err}; }
inline internal_logging::StashedErrno Errno() { return {}; }
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_LOGGING_H_

@ -0,0 +1,362 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include "options.h"
#include <fnmatch.h>
#include <getopt.h>
#include <unistd.h>
#include <algorithm>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include "print.h"
namespace gitstatus {
namespace {
long ParseLong(const char* s) {
errno = 0;
char* end = nullptr;
long res = std::strtol(s, &end, 10);
if (*end || end == s || errno) {
std::cerr << "gitstatusd: not an integer: " << s << std::endl;
std::exit(10);
}
return res;
}
long ParseInt(const char* s) {
long res = ParseLong(s);
if (res < INT_MIN || res > INT_MAX) {
std::cerr << "gitstatusd: integer out of bounds: " << s << std::endl;
std::exit(10);
}
return res;
}
size_t ParseSizeT(const char* s) {
static_assert(sizeof(long) <= sizeof(size_t), "");
long res = ParseLong(s);
return res >= 0 ? res : -1;
}
void PrintUsage() {
std::cout << "Usage: gitstatusd [OPTION]...\n"
<< "Print machine-readable status of the git repos for directories in stdin.\n"
<< "\n"
<< "OPTIONS\n"
<< " -l, --lock-fd=NUM [default=-1]\n"
<< " If non-negative, check whether the specified file descriptor is locked when\n"
<< " not receiving any requests for one second; exit if it isn't locked.\n"
<< "\n"
<< " -p, --parent-pid=NUM [default=-1]\n"
<< " If non-negative, send signal 0 to the specified PID when not receiving any\n"
<< " requests for one second; exit if signal sending fails.\n"
<< "\n"
<< " -t, --num-threads=NUM [default=1]\n"
<< " Use this many threads to scan git workdir for unstaged and untracked files.\n"
<< " Empirically, setting this parameter to twice the number of virtual CPU yields\n"
<< " maximum performance.\n"
<< "\n"
<< " -v, --log-level=STR [default=INFO]\n"
<< " Don't write entries to log whose log level is below this. Log levels in\n"
<< " increasing order: DEBUG, INFO, WARN, ERROR, FATAL.\n"
<< "\n"
<< " -r, --repo-ttl-seconds=NUM [default=3600]\n"
<< " Close git repositories that haven't been used for this long. This is meant to\n"
<< " release resources such as memory and file descriptors. The next request for a\n"
<< " repo that's been closed is much slower than for a repo that hasn't been.\n"
<< " Negative value means infinity.\n"
<< "\n"
<< " -z, --max-commit-summary-length=NUM [default=256]\n"
<< " Truncate commit summary if it's longer than this many bytes.\n"
<< "\n"
<< " -s, --max-num-staged=NUM [default=1]\n"
<< " Report at most this many staged changes; negative value means infinity.\n"
<< "\n"
<< " -u, --max-num-unstaged=NUM [default=1]\n"
<< " Report at most this many unstaged changes; negative value means infinity.\n"
<< "\n"
<< " -c, --max-num-conflicted=NUM [default=1]\n"
<< " Report at most this many conflicted changes; negative value means infinity.\n"
<< "\n"
<< " -d, --max-num-untracked=NUM [default=1]\n"
<< " Report at most this many untracked files; negative value means infinity.\n"
<< "\n"
<< " -m, --dirty-max-index-size=NUM [default=-1]\n"
<< " If a repo has more files in its index than this, override --max-num-unstaged\n"
<< " and --max-num-untracked (but not --max-num-staged) with zeros; negative value\n"
<< " means infinity.\n"
<< "\n"
<< " -e, --recurse-untracked-dirs\n"
<< " Count files within untracked directories like `git status --untracked-files`.\n"
<< "\n"
<< " -U, --ignore-status-show-untracked-files\n"
<< " Unless this option is specified, report zero untracked files for repositories\n"
<< " with status.showUntrackedFiles = false.\n"
<< "\n"
<< " -W, --ignore-bash-show-untracked-files\n"
<< " Unless this option is specified, report zero untracked files for repositories\n"
<< " with bash.showUntrackedFiles = false.\n"
<< "\n"
<< " -D, --ignore-bash-show-dirty-state\n"
<< " Unless this option is specified, report zero staged, unstaged and conflicted\n"
<< " changes for repositories with bash.showDirtyState = false.\n"
<< "\n"
<< " -V, --version\n"
<< " Print gitstatusd version and exit.\n"
<< "\n"
<< " -G, --version-glob=STR [default=*]\n"
<< " Immediately exit with code 11 if gitstatusd version (see --version) doesn't\n"
<< " does not match the specified pattern. Matching is done with fnmatch(3)\n"
<< " without flags.\n"
<< "\n"
<< " -h, --help\n"
<< " Display this help and exit.\n"
<< "\n"
<< "INPUT\n"
<< "\n"
<< " Requests are read from stdin, separated by ascii 30 (record separator). Each\n"
<< " request is made of the following fields, in the specified order, separated by\n"
<< " ascii 31 (unit separator):\n"
<< "\n"
<< " 1. Request ID. Any string. Can be empty.\n"
<< " 2. Path to the directory for which git stats are being requested.\n"
<< " If the first character is ':', it is removed and the remaining path\n"
<< " is treated as GIT_DIR.\n"
<< " 3. (Optional) '1' to disable computation of anything that requires reading\n"
<< " git index; '0' for the default behavior of computing everything.\n"
<< "\n"
<< "OUTPUT\n"
<< "\n"
<< " For every request read from stdin there is response written to stdout.\n"
<< " Responses are separated by ascii 30 (record separator). Each response is made\n"
<< " of the following fields, in the specified order, separated by ascii 31\n"
<< " (unit separator):\n"
<< "\n"
<< " 1. Request id. The same as the first field in the request.\n"
<< " 2. 0 if the directory isn't a git repo, 1 otherwise. If 0, all the\n"
<< " following fields are missing.\n"
<< " 3. Absolute path to the git repository workdir.\n"
<< " 4. Commit hash that HEAD is pointing to. 40 hex digits.\n"
<< " 5. Local branch name or empty if not on a branch.\n"
<< " 6. Upstream branch name. Can be empty.\n"
<< " 7. The remote name, e.g. \"upstream\" or \"origin\".\n"
<< " 8. Remote URL. Can be empty.\n"
<< " 9. Repository state, A.K.A. action. Can be empty.\n"
<< " 10. The number of files in the index.\n"
<< " 11. The number of staged changes.\n"
<< " 12. The number of unstaged changes.\n"
<< " 13. The number of conflicted changes.\n"
<< " 14. The number of untracked files.\n"
<< " 15. Number of commits the current branch is ahead of upstream.\n"
<< " 16. Number of commits the current branch is behind upstream.\n"
<< " 17. The number of stashes.\n"
<< " 18. The last tag (in lexicographical order) that points to the same\n"
<< " commit as HEAD.\n"
<< " 19. The number of unstaged deleted files.\n"
<< " 20. The number of staged new files.\n"
<< " 21. The number of staged deleted files.\n"
<< " 22. The push remote name, e.g. \"upstream\" or \"origin\".\n"
<< " 23. Push remote URL. Can be empty.\n"
<< " 24. Number of commits the current branch is ahead of push remote.\n"
<< " 25. Number of commits the current branch is behind push remote.\n"
<< " 26. Number of files in the index with skip-worktree bit set.\n"
<< " 27. Number of files in the index with assume-unchanged bit set.\n"
<< " 28. Encoding of the HEAD's commit message. Empty value means UTF-8.\n"
<< " 29. The first paragraph of the HEAD's commit message as one line.\n"
<< "\n"
<< "Note: Renamed files are reported as deleted plus new.\n"
<< "\n"
<< "EXAMPLE\n"
<< "\n"
<< " Send a single request and print response (zsh syntax):\n"
<< "\n"
<< " local req_id=id\n"
<< " local dir=$PWD\n"
<< " echo -nE $req_id$'\\x1f'$dir$'\\x1e' | ./gitstatusd | {\n"
<< " local resp\n"
<< " IFS=$'\\x1f' read -rd $'\\x1e' -A resp && print -lr -- \"${(@qq)resp}\"\n"
<< " }\n"
<< "\n"
<< " Output:"
<< "\n"
<< " 'id'\n"
<< " '1'\n"
<< " '/home/romka/gitstatus'\n"
<< " 'bf46bf03dbab7108801b53f8a720caee8464c9c3'\n"
<< " 'master'\n"
<< " 'master'\n"
<< " 'origin'\n"
<< " 'git@github.com:romkatv/gitstatus.git'\n"
<< " ''\n"
<< " '70'\n"
<< " '1'\n"
<< " '0'\n"
<< " '0'\n"
<< " '2'\n"
<< " '0'\n"
<< " '0'\n"
<< " ''\n"
<< " '0'\n"
<< " '0'\n"
<< " '0'\n"
<< " ''\n"
<< " ''\n"
<< " '0'\n"
<< " '0'\n"
<< " '0'\n"
<< " '0'\n"
<< " ''\n"
<< " 'add a build server for darwin-arm64'\n"
<< "\n"
<< "EXIT STATUS\n"
<< "\n"
<< " The command returns zero on success (when printing help or on EOF),\n"
<< " non-zero on failure. In the latter case the output is unspecified.\n"
<< "\n"
<< "COPYRIGHT\n"
<< "\n"
<< " Copyright 2019 Roman Perepelitsa\n"
<< " This is free software; see https://github.com/romkatv/gitstatus for copying\n"
<< " conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR\n"
<< " A PARTICULAR PURPOSE." << std::endl;
}
const char* Version() {
#define _INTERNAL_GITSTATUS_STRINGIZE(x) _INTERNAL_GITSTATUS_STRINGIZE_I(x)
#define _INTERNAL_GITSTATUS_STRINGIZE_I(x) #x
return _INTERNAL_GITSTATUS_STRINGIZE(GITSTATUS_VERSION);
#undef _INTERNAL_GITSTATUS_STRINGIZE_I
#undef _INTERNAL_GITSTATUS_STRINGIZE
}
} // namespace
Options ParseOptions(int argc, char** argv) {
const struct option opts[] = {{"help", no_argument, nullptr, 'h'},
{"version", no_argument, nullptr, 'V'},
{"version-glob", required_argument, nullptr, 'G'},
{"lock-fd", required_argument, nullptr, 'l'},
{"parent-pid", required_argument, nullptr, 'p'},
{"num-threads", required_argument, nullptr, 't'},
{"log-level", required_argument, nullptr, 'v'},
{"repo-ttl-seconds", required_argument, nullptr, 'r'},
{"max-commit-summary-length", required_argument, nullptr, 'z'},
{"max-num-staged", required_argument, nullptr, 's'},
{"max-num-unstaged", required_argument, nullptr, 'u'},
{"max-num-conflicted", required_argument, nullptr, 'c'},
{"max-num-untracked", required_argument, nullptr, 'd'},
{"dirty-max-index-size", required_argument, nullptr, 'm'},
{"recurse-untracked-dirs", no_argument, nullptr, 'e'},
{"ignore-status-show-untracked-files", no_argument, nullptr, 'U'},
{"ignore-bash-show-untracked-files", no_argument, nullptr, 'W'},
{"ignore-bash-show-dirty-state", no_argument, nullptr, 'D'},
{}};
Options res;
while (true) {
switch (getopt_long(argc, argv, "hVG:l:p:t:v:r:z:s:u:c:d:m:eUWD", opts, nullptr)) {
case -1:
if (optind != argc) {
std::cerr << "unexpected positional argument: " << argv[optind] << std::endl;
std::exit(10);
}
return res;
case 'h':
PrintUsage();
std::exit(0);
case 'V':
std::cout << Version() << std::endl;
std::exit(0);
case 'G':
if (int err = fnmatch(optarg, Version(), 0)) {
if (err != FNM_NOMATCH) {
std::cerr << "Cannot match " << Print(Version()) << " against pattern "
<< Print(optarg) << ": error " << err;
std::exit(10);
}
std::cerr << "Version mismatch. Wanted (pattern): " << Print(optarg)
<< ". Actual: " << Print(Version()) << "." << std::endl;
std::exit(11);
}
break;
case 'l':
res.lock_fd = ParseInt(optarg);
break;
case 'p':
res.parent_pid = ParseInt(optarg);
break;
case 'v':
if (!ParseLogLevel(optarg, res.log_level)) {
std::cerr << "invalid log level: " << optarg << std::endl;
std::exit(10);
}
break;
case 'r':
res.repo_ttl = std::chrono::seconds(ParseLong(optarg));
break;
case 't': {
long n = ParseLong(optarg);
if (n <= 0) {
std::cerr << "invalid number of threads: " << n << std::endl;
std::exit(10);
}
res.num_threads = n;
break;
}
case 'z':
res.max_commit_summary_length = ParseSizeT(optarg);
break;
case 's':
res.max_num_staged = ParseSizeT(optarg);
break;
case 'u':
res.max_num_unstaged = ParseSizeT(optarg);
break;
case 'c':
res.max_num_conflicted = ParseSizeT(optarg);
break;
case 'd':
res.max_num_untracked = ParseSizeT(optarg);
break;
case 'm':
res.dirty_max_index_size = ParseSizeT(optarg);
break;
case 'e':
res.recurse_untracked_dirs = true;
break;
case 'U':
res.ignore_status_show_untracked_files = true;
break;
case 'W':
res.ignore_bash_show_untracked_files = true;
break;
case 'D':
res.ignore_bash_show_dirty_state = true;
break;
default:
std::exit(10);
}
}
}
} // namespace gitstatus

@ -0,0 +1,78 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_OPTIONS_H_
#define ROMKATV_GITSTATUS_OPTIONS_H_
#include <chrono>
#include <string>
#include "logging.h"
#include "time.h"
namespace gitstatus {
struct Limits {
// Truncate commit summary if it's longer than this many bytes.
size_t max_commit_summary_length = 256;
// Report at most this many staged changes.
size_t max_num_staged = 1;
// Report at most this many unstaged changes.
size_t max_num_unstaged = 1;
// Report at most this many conflicted changes.
size_t max_num_conflicted = 1;
// Report at most this many untracked files.
size_t max_num_untracked = 1;
// If a repo has more files in its index than this, override max_num_unstaged and
// max_num_untracked (but not max_num_staged) with zeros.
size_t dirty_max_index_size = -1;
// If true, report untracked files like `git status --untracked-files`.
bool recurse_untracked_dirs = false;
// Unless true, report zero untracked files for repositories with
// status.showUntrackedFiles = false.
bool ignore_status_show_untracked_files = false;
// Unless true, report zero untracked files for repositories with
// bash.showUntrackedFiles = false.
bool ignore_bash_show_untracked_files = false;
// Unless true, report zero staged, unstaged and conflicted changes for repositories with
// bash.showDirtyState = false.
bool ignore_bash_show_dirty_state = false;
};
struct Options : Limits {
// Use this many threads to scan git workdir for unstaged and untracked files. Must be positive.
size_t num_threads = 1;
// If non-negative, check whether the specified file descriptor is locked when not receiving any
// requests for one second; exit if it isn't locked.
int lock_fd = -1;
// If non-negative, send signal 0 to the specified PID when not receiving any requests for one
// second; exit if signal sending fails.
int parent_pid = -1;
// Don't write entries to log whose log level is below this. Log levels in increasing order:
// DEBUG, INFO, WARN, ERROR, FATAL.
LogLevel log_level = INFO;
// Close git repositories that haven't been used for this long. This is meant to release resources
// such as memory and file descriptors. The next request for a repo that's been closed is much
// slower than for a repo that hasn't been. Negative value means infinity.
Duration repo_ttl = std::chrono::seconds(3600);
};
Options ParseOptions(int argc, char** argv);
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_OPTIONS_H_

@ -0,0 +1,101 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_PRINT_H_
#define ROMKATV_GITSTATUS_PRINT_H_
#include <sys/stat.h>
#include <iomanip>
#include <ostream>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include <git2.h>
#include "string_view.h"
#include "strings.h"
namespace gitstatus {
template <class T>
struct Printable {
const T& value;
};
template <class T>
Printable<T> Print(const T& val) {
return {val};
}
template <class T>
std::ostream& operator<<(std::ostream& strm, const Printable<T>& p) {
static_assert(!std::is_pointer<std::decay_t<T>>(), "");
return strm << p.value;
}
inline std::ostream& operator<<(std::ostream& strm, const Printable<StringView>& p) {
Quote(strm, p.value.ptr, p.value.ptr + p.value.len);
return strm;
}
inline std::ostream& operator<<(std::ostream& strm, const Printable<std::string>& p) {
Quote(strm, p.value.data(), p.value.data() + p.value.size());
return strm;
}
inline std::ostream& operator<<(std::ostream& strm, const Printable<const char*>& p) {
Quote(strm, p.value, p.value ? p.value + std::strlen(p.value) : nullptr);
return strm;
}
inline std::ostream& operator<<(std::ostream& strm, const Printable<char*>& p) {
Quote(strm, p.value, p.value ? p.value + std::strlen(p.value) : nullptr);
return strm;
}
template <class T, class U>
std::ostream& operator<<(std::ostream& strm, const Printable<std::pair<T, U>>& p) {
return strm << '{' << Print(p.value.first) << ", " << Print(p.value.second) << '}';
}
template <class T>
std::ostream& operator<<(std::ostream& strm, const Printable<std::vector<T>>& p) {
strm << '[';
for (size_t i = 0; i != p.value.size(); ++i) {
if (i) strm << ", ";
strm << Print(p.value[i]);
}
strm << ']';
return strm;
}
inline std::ostream& operator<<(std::ostream& strm, const Printable<struct timespec>& p) {
strm << p.value.tv_sec << '.' << std::setw(9) << std::setfill('0') << p.value.tv_nsec;
return strm;
}
inline std::ostream& operator<<(std::ostream& strm, const Printable<git_index_time>& p) {
strm << p.value.seconds << '.' << std::setw(9) << std::setfill('0') << p.value.nanoseconds;
return strm;
}
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_PRINT_H_

@ -0,0 +1,503 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include "repo.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
#include <atomic>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>
#include "arena.h"
#include "check.h"
#include "check_dir_mtime.h"
#include "dir.h"
#include "git.h"
#include "print.h"
#include "scope_guard.h"
#include "stat.h"
#include "string_cmp.h"
#include "thread_pool.h"
#include "timer.h"
namespace gitstatus {
namespace {
using namespace std::string_literals;
template <class T>
T Load(const std::atomic<T>& x) {
return x.load(std::memory_order_relaxed);
}
template <class T>
void Store(std::atomic<T>& x, T v) {
x.store(v, std::memory_order_relaxed);
}
template <class T>
T Inc(std::atomic<T>& x, T by = 1) {
return x.fetch_add(by, std::memory_order_relaxed);
}
template <class T>
T Dec(std::atomic<T>& x) {
return x.fetch_sub(1, std::memory_order_relaxed);
}
template <class T>
T Exchange(std::atomic<T>& x, T v) {
return x.exchange(v, std::memory_order_relaxed);
}
const char* DeltaStr(git_delta_t t) {
switch (t) {
case GIT_DELTA_UNMODIFIED: return "unmodified";
case GIT_DELTA_ADDED: return "added";
case GIT_DELTA_DELETED: return "deleted";
case GIT_DELTA_MODIFIED: return "modified";
case GIT_DELTA_RENAMED: return "renamed";
case GIT_DELTA_COPIED: return "copied";
case GIT_DELTA_IGNORED: return "ignored";
case GIT_DELTA_UNTRACKED: return "untracked";
case GIT_DELTA_TYPECHANGE: return "typechange";
case GIT_DELTA_UNREADABLE: return "unreadable";
case GIT_DELTA_CONFLICTED: return "conflicted";
}
return "unknown";
}
} // namespace
bool Repo::Shard::Contains(Str<> str, StringView path) const {
if (str.Lt(path, start_s)) return false;
if (end_s.empty()) return true;
path.len = std::min(path.len, end_s.size());
return !str.Lt(end_s, path);
}
Repo::Repo(git_repository* repo, Limits lim) : lim_(std::move(lim)), repo_(repo), tag_db_(repo) {
if (lim_.max_num_untracked) {
GlobalThreadPool()->Schedule([this] {
bool check = CheckDirMtime(git_repository_path(repo_));
std::unique_lock<std::mutex> lock(mutex_);
CHECK(Load(untracked_cache_) == Tribool::kUnknown);
Store(untracked_cache_, check ? Tribool::kTrue : Tribool::kFalse);
cv_.notify_one();
});
} else {
untracked_cache_ = Tribool::kFalse;
}
}
Repo::~Repo() {
{
std::unique_lock<std::mutex> lock(mutex_);
while (untracked_cache_ == Tribool::kUnknown) cv_.wait(lock);
}
if (git_index_) git_index_free(git_index_);
git_repository_free(repo_);
}
IndexStats Repo::GetIndexStats(const git_oid* head, git_config* cfg) {
ON_SCOPE_EXIT(this, orig_lim = lim_) { lim_ = orig_lim; };
auto Off = [&](const char* name) {
int val;
if (git_config_get_bool(&val, cfg, name) || val) return false;
LOG(INFO) << "Honoring git config option: " << name << " = false";
return true;
};
if (!lim_.ignore_status_show_untracked_files && Off("status.showUntrackedFiles")) {
lim_.max_num_untracked = 0;
}
if (!lim_.ignore_bash_show_untracked_files && Off("bash.showUntrackedFiles")) {
lim_.max_num_untracked = 0;
}
if (!lim_.ignore_bash_show_dirty_state && Off("bash.showDirtyState")) {
lim_.max_num_staged = 0;
lim_.max_num_unstaged = 0;
lim_.max_num_conflicted = 0;
}
if (git_index_) {
int new_index;
VERIFY(!git_index_read_ex(git_index_, 0, &new_index)) << GitError();
if (new_index) {
head_ = {};
index_.reset();
}
} else {
VERIFY(!git_repository_index(&git_index_, repo_)) << GitError();
// Query an attribute (doesn't matter which) to initialize repo's attribute
// cache. It's a workaround for synchronization bugs (data races) in libgit2
// that result from lazy cache initialization without synchronization.
// Thankfully, subsequent cache reads and writes are properly synchronized.
const char* attr;
VERIFY(!git_attr_get(&attr, repo_, 0, "x", "x")) << GitError();
}
UpdateShards();
Store(error_, false);
Store(unstaged_, {});
Store(untracked_, {});
Store(unstaged_deleted_, {});
std::vector<const char*> dirty_candidates;
const size_t index_size = git_index_entrycount(git_index_);
if (!lim_.max_num_staged && !lim_.max_num_conflicted) {
head_ = {};
Store(staged_, {});
Store(conflicted_, {});
Store(staged_new_, {});
Store(staged_deleted_, {});
Store(skip_worktree_, {});
Store(assume_unchanged_, {});
} else if (head) {
if (git_oid_equal(head, &head_)) {
LOG(INFO) << "Index and HEAD unchanged; staged = " << Load(staged_)
<< ", conflicted = " << Load(conflicted_);
} else {
head_ = *head;
Store(staged_, {});
Store(conflicted_, {});
Store(staged_new_, {});
Store(staged_deleted_, {});
Store(skip_worktree_, {});
Store(assume_unchanged_, {});
StartStagedScan(head);
}
} else {
head_ = {};
size_t staged = 0;
size_t skip_worktree = 0;
size_t assume_unchanged = 0;
for (size_t i = 0; i != index_size; ++i) {
const git_index_entry* entry = git_index_get_byindex_no_sort(git_index_, i);
if (!(entry->flags_extended & GIT_INDEX_ENTRY_INTENT_TO_ADD)) ++staged;
if (entry->flags_extended & GIT_INDEX_ENTRY_SKIP_WORKTREE) ++skip_worktree;
if (entry->flags & GIT_INDEX_ENTRY_VALID) ++assume_unchanged;
}
Store(staged_, staged);
Store(conflicted_, {});
Store(staged_new_, staged);
Store(staged_deleted_, {});
Store(skip_worktree_, skip_worktree);
Store(assume_unchanged_, assume_unchanged);
}
if (index_size <= lim_.dirty_max_index_size &&
(lim_.max_num_unstaged || lim_.max_num_untracked)) {
if (!index_) index_ = std::make_unique<Index>(repo_, git_index_);
dirty_candidates = index_->GetDirtyCandidates({.include_untracked = lim_.max_num_untracked > 0,
.untracked_cache = Load(untracked_cache_)});
if (dirty_candidates.empty()) {
LOG(INFO) << "Clean repo: no dirty candidates";
} else {
LOG(INFO) << "Found " << dirty_candidates.size() << " dirty candidate(s) spanning from "
<< Print(dirty_candidates.front()) << " to " << Print(dirty_candidates.back());
}
StartDirtyScan(dirty_candidates);
}
Wait();
VERIFY(!Load(error_));
size_t num_staged = std::min(Load(staged_), lim_.max_num_staged);
size_t num_unstaged = std::min(Load(unstaged_), lim_.max_num_unstaged);
return {.index_size = index_size,
.num_staged = num_staged,
.num_unstaged = num_unstaged,
.num_conflicted = std::min(Load(conflicted_), lim_.max_num_conflicted),
.num_untracked = std::min(Load(untracked_), lim_.max_num_untracked),
.num_staged_new = std::min(Load(staged_new_), num_staged),
.num_staged_deleted = std::min(Load(staged_deleted_), num_staged),
.num_unstaged_deleted = std::min(Load(unstaged_deleted_), num_unstaged),
.num_skip_worktree = Load(skip_worktree_),
.num_assume_unchanged = Load(assume_unchanged_)};
}
int Repo::OnDelta(const char* type, const git_diff_delta& d, std::atomic<size_t>& c1, size_t m1,
const std::atomic<size_t>& c2, size_t m2) {
auto Msg = [&]() {
const char* status = DeltaStr(d.status);
std::ostringstream strm;
strm << "Found " << type << " file";
if (strcmp(status, type)) strm << " (" << status << ")";
strm << ": " << Print(d.new_file.path);
return strm.str();
};
size_t v = Inc(c1);
if (v) {
LOG(DEBUG) << Msg();
} else {
LOG(INFO) << Msg();
}
if (v + 1 < m1) return GIT_DIFF_DELTA_DO_NOT_INSERT;
if (Load(c2) < m2) return GIT_DIFF_DELTA_DO_NOT_INSERT | GIT_DIFF_DELTA_SKIP_TYPE;
return GIT_EUSER;
}
void Repo::StartDirtyScan(const std::vector<const char*>& paths) {
if (paths.empty()) return;
git_diff_options opt = GIT_DIFF_OPTIONS_INIT;
opt.payload = this;
opt.flags = GIT_DIFF_INCLUDE_TYPECHANGE_TREES | GIT_DIFF_SKIP_BINARY_CHECK |
GIT_DIFF_DISABLE_PATHSPEC_MATCH | GIT_DIFF_EXEMPLARS;
if (lim_.max_num_untracked) {
opt.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
if (lim_.recurse_untracked_dirs) opt.flags |= GIT_DIFF_RECURSE_UNTRACKED_DIRS;
} else {
opt.flags |= GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS;
}
opt.ignore_submodules = GIT_SUBMODULE_IGNORE_DIRTY;
opt.notify_cb = +[](const git_diff* diff, const git_diff_delta* delta,
const char* matched_pathspec, void* payload) -> int {
if (delta->status == GIT_DELTA_CONFLICTED) return GIT_DIFF_DELTA_DO_NOT_INSERT;
Repo* repo = static_cast<Repo*>(payload);
if (Load(repo->error_)) return GIT_EUSER;
if (delta->status == GIT_DELTA_UNTRACKED) {
return repo->OnDelta("untracked", *delta, repo->untracked_, repo->lim_.max_num_untracked,
repo->unstaged_, repo->lim_.max_num_unstaged);
} else {
if (delta->status == GIT_DELTA_DELETED) Inc(repo->unstaged_deleted_);
return repo->OnDelta("unstaged", *delta, repo->unstaged_, repo->lim_.max_num_unstaged,
repo->untracked_, repo->lim_.max_num_untracked);
}
};
const Str<> str(git_index_is_case_sensitive(git_index_));
auto shard = shards_.begin();
for (auto p = paths.begin(); p != paths.end();) {
opt.range_start = *p;
opt.range_end = *p;
opt.pathspec.strings = const_cast<char**>(&*p);
opt.pathspec.count = 1;
while (!shard->Contains(str, StringView(*p))) ++shard;
while (++p != paths.end() && shard->Contains(str, StringView(*p))) {
opt.range_end = *p;
++opt.pathspec.count;
}
RunAsync([this, opt]() {
git_diff* diff = nullptr;
LOG(DEBUG) << "git_diff_index_to_workdir from " << Print(opt.range_start) << " to "
<< Print(opt.range_end);
switch (git_diff_index_to_workdir(&diff, repo_, git_index_, &opt)) {
case 0:
git_diff_free(diff);
break;
case GIT_EUSER:
break;
default:
LOG(ERROR) << "git_diff_index_to_workdir: " << GitError();
throw Exception();
}
});
}
}
void Repo::StartStagedScan(const git_oid* head) {
git_commit* commit = nullptr;
VERIFY(!git_commit_lookup(&commit, repo_, head)) << GitError();
ON_SCOPE_EXIT(=) { git_commit_free(commit); };
git_tree* tree = nullptr;
VERIFY(!git_commit_tree(&tree, commit)) << GitError();
git_diff_options opt = GIT_DIFF_OPTIONS_INIT;
opt.flags = GIT_DIFF_EXEMPLARS | GIT_DIFF_INCLUDE_TYPECHANGE_TREES;
opt.payload = this;
opt.notify_cb = +[](const git_diff* diff, const git_diff_delta* delta,
const char* matched_pathspec, void* payload) -> int {
Repo* repo = static_cast<Repo*>(payload);
if (Load(repo->error_)) return GIT_EUSER;
if (delta->status == GIT_DELTA_CONFLICTED) {
return repo->OnDelta("conflicted", *delta, repo->conflicted_, repo->lim_.max_num_conflicted,
repo->staged_, repo->lim_.max_num_staged);
} else {
if (delta->status == GIT_DELTA_ADDED) Inc(repo->staged_new_);
if (delta->status == GIT_DELTA_DELETED) Inc(repo->staged_deleted_);
return repo->OnDelta("staged", *delta, repo->staged_, repo->lim_.max_num_staged,
repo->conflicted_, repo->lim_.max_num_conflicted);
}
};
for (const Shard& shard : shards_) {
RunAsync([this, tree, opt, shard]() mutable {
size_t skip_worktree = 0;
size_t assume_unchanged = 0;
for (size_t i = shard.start_i; i != shard.end_i; ++i) {
const git_index_entry* entry = git_index_get_byindex_no_sort(git_index_, i);
if (entry->flags_extended & GIT_INDEX_ENTRY_SKIP_WORKTREE) ++skip_worktree;
if (entry->flags & GIT_INDEX_ENTRY_VALID) ++assume_unchanged;
}
Inc(skip_worktree_, skip_worktree);
Inc(assume_unchanged_, assume_unchanged);
opt.range_start = shard.start_s.c_str();
opt.range_end = shard.end_s.c_str();
git_diff* diff = nullptr;
LOG(DEBUG) << "git_diff_tree_to_index from " << Print(opt.range_start) << " to "
<< Print(opt.range_end);
switch (git_diff_tree_to_index(&diff, repo_, tree, git_index_, &opt)) {
case 0:
git_diff_free(diff);
break;
case GIT_EUSER:
break;
default:
LOG(ERROR) << "git_diff_tree_to_index: " << GitError();
throw Exception();
}
});
}
}
void Repo::UpdateShards() {
constexpr size_t kEntriesPerShard = 512;
const Str<> str(git_index_is_case_sensitive(git_index_));
size_t index_size = git_index_entrycount(git_index_);
ON_SCOPE_EXIT(&) {
LOG(INFO) << "Splitting " << index_size << " object(s) into " << shards_.size() << " shard(s)";
};
if (index_size <= kEntriesPerShard || GlobalThreadPool()->num_threads() < 2) {
shards_ = {{
.start_s = "",
.end_s = "",
.start_i = 0,
.end_i = index_size}};
return;
}
size_t shards =
std::min(index_size / kEntriesPerShard + 1, 2 * GlobalThreadPool()->num_threads());
shards_.clear();
shards_.reserve(shards);
std::string last_s;
size_t last_i = 0;
for (size_t i = 0; i != shards - 1; ++i) {
size_t idx = (i + 1) * index_size / shards;
std::string split = git_index_get_byindex_no_sort(git_index_, idx)->path;
auto pos = split.find_last_of('/');
if (pos == std::string::npos) continue;
split = split.substr(0, pos + 1);
Shard shard;
shard.end_s = split;
--shard.end_s.back();
if (!str.Lt(last_s, shard.end_s)) continue;
shard.start_s = std::move(last_s);
last_s = std::move(split);
shard.start_i = last_i;
shard.end_i = idx;
last_i = idx;
shards_.push_back(std::move(shard));
}
shards_.push_back({
.start_s = std::move(last_s),
.end_s = "",
.start_i = last_i,
.end_i = index_size});
CHECK(!shards_.empty());
CHECK(shards_.size() <= shards);
CHECK(shards_.front().start_s.empty());
CHECK(shards_.front().start_i == 0);
CHECK(shards_.back().end_s.empty());
CHECK(shards_.back().end_i == index_size);
for (size_t i = 0; i != shards_.size(); ++i) {
if (i) {
const git_index_entry* entry = git_index_get_byindex_no_sort(git_index_, shards_[i].start_i);
CHECK(!std::memcmp(shards_[i].start_s.c_str(), entry->path, shards_[i].start_s.size()));
CHECK(str.Lt(shards_[i - 1].end_s, shards_[i].start_s));
CHECK(shards_[i - 1].end_i == shards_[i].start_i);
}
if (i != shards_.size() - 1) {
CHECK(shards_[i].start_i < shards_[i].end_i);
CHECK(str.Lt(shards_[i].start_s, shards_[i].end_s));
}
}
}
void Repo::DecInflight() {
std::unique_lock<std::mutex> lock(mutex_);
CHECK(Load(inflight_) > 0);
if (Dec(inflight_) == 1) cv_.notify_one();
}
void Repo::RunAsync(std::function<void()> f) {
Inc(inflight_);
try {
GlobalThreadPool()->Schedule([this, f = std::move(f)] {
try {
ON_SCOPE_EXIT(&) { DecInflight(); };
f();
} catch (const Exception&) {
if (!Load(error_)) {
std::unique_lock<std::mutex> lock(mutex_);
if (!Load(error_)) {
Store(error_, true);
cv_.notify_one();
}
}
}
});
} catch (...) {
DecInflight();
throw;
}
}
void Repo::Wait() {
std::unique_lock<std::mutex> lock(mutex_);
while (inflight_) cv_.wait(lock);
}
std::future<std::string> Repo::GetTagName(const git_oid* target) {
auto* promise = new std::promise<std::string>;
std::future<std::string> res = promise->get_future();
GlobalThreadPool()->Schedule([=] {
ON_SCOPE_EXIT(&) { delete promise; };
if (!target) {
promise->set_value("");
return;
}
try {
promise->set_value(tag_db_.TagForCommit(*target));
} catch (const Exception&) {
promise->set_exception(std::current_exception());
}
});
return res;
}
} // namespace gitstatus

@ -0,0 +1,126 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_REPO_H_
#define ROMKATV_GITSTATUS_REPO_H_
#include <stddef.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <git2.h>
#include <algorithm>
#include <atomic>
#include <condition_variable>
#include <cstddef>
#include <cstring>
#include <functional>
#include <future>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
#include <vector>
#include "check.h"
#include "index.h"
#include "options.h"
#include "string_cmp.h"
#include "tag_db.h"
#include "time.h"
namespace gitstatus {
struct IndexStats {
size_t index_size = 0;
size_t num_staged = 0;
size_t num_unstaged = 0;
size_t num_conflicted = 0;
size_t num_untracked = 0;
size_t num_staged_new = 0;
size_t num_staged_deleted = 0;
size_t num_unstaged_deleted = 0;
size_t num_skip_worktree = 0;
size_t num_assume_unchanged = 0;
};
class Repo {
public:
explicit Repo(git_repository* repo, Limits lim);
Repo(Repo&& other) = delete;
~Repo();
git_repository* repo() const { return repo_; }
// Head can be null, in which case has_staged will be false.
IndexStats GetIndexStats(const git_oid* head, git_config* cfg);
// Returns the last tag in lexicographical order whose target is equal to the given, or an
// empty string. Target can be null, in which case the tag is empty.
std::future<std::string> GetTagName(const git_oid* target);
private:
struct Shard {
bool Contains(Str<> str, StringView path) const;
std::string start_s;
std::string end_s;
size_t start_i;
size_t end_i;
};
void UpdateShards();
int OnDelta(const char* type, const git_diff_delta& d, std::atomic<size_t>& c1, size_t m1,
const std::atomic<size_t>& c2, size_t m2);
void StartStagedScan(const git_oid* head);
void StartDirtyScan(const std::vector<const char*>& paths);
void DecInflight();
void RunAsync(std::function<void()> f);
void Wait();
Limits lim_;
git_repository* const repo_;
git_index* git_index_ = nullptr;
std::vector<Shard> shards_;
git_oid head_ = {};
TagDb tag_db_;
std::unique_ptr<Index> index_;
std::mutex mutex_;
std::condition_variable cv_;
std::atomic<size_t> inflight_{0};
std::atomic<bool> error_{false};
std::atomic<size_t> staged_{0};
std::atomic<size_t> unstaged_{0};
std::atomic<size_t> conflicted_{0};
std::atomic<size_t> untracked_{0};
std::atomic<size_t> staged_new_{0};
std::atomic<size_t> staged_deleted_{0};
std::atomic<size_t> unstaged_deleted_{0};
std::atomic<size_t> skip_worktree_{0};
std::atomic<size_t> assume_unchanged_{0};
std::atomic<Tribool> untracked_cache_{Tribool::kUnknown};
};
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_REPO_H_

@ -0,0 +1,167 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include "repo_cache.h"
#include <cstring>
#include "check.h"
#include "git.h"
#include "print.h"
#include "scope_guard.h"
#include "string_view.h"
namespace gitstatus {
namespace {
void GitDirs(const char* dir, bool from_dotgit, std::string& gitdir, std::string& workdir) {
git_buf gitdir_buf = {};
git_buf workdir_buf = {};
ON_SCOPE_EXIT(&) {
git_buf_free(&gitdir_buf);
git_buf_free(&workdir_buf);
};
int flags = from_dotgit ? GIT_REPOSITORY_OPEN_NO_SEARCH | GIT_REPOSITORY_OPEN_NO_DOTGIT : 0;
switch (git_repository_discover_ex(&gitdir_buf, &workdir_buf, NULL, NULL, dir, flags, nullptr)) {
case 0:
gitdir.assign(gitdir_buf.ptr, gitdir_buf.size);
workdir.assign(workdir_buf.ptr, workdir_buf.size);
VERIFY(!gitdir.empty() && gitdir.front() == '/' && gitdir.back() == '/');
VERIFY(!workdir.empty() && workdir.front() == '/' && workdir.back() == '/');
break;
case GIT_ENOTFOUND:
gitdir.clear();
workdir.clear();
break;
default:
LOG(ERROR) << "git_repository_open_ext: " << Print(dir) << ": " << GitError();
throw Exception();
}
}
git_repository* OpenRepo(const std::string& dir, bool from_dotgit) {
git_repository* repo = nullptr;
int flags = from_dotgit ? GIT_REPOSITORY_OPEN_NO_SEARCH | GIT_REPOSITORY_OPEN_NO_DOTGIT : 0;
switch (git_repository_open_ext(&repo, dir.c_str(), flags, nullptr)) {
case 0:
return repo;
case GIT_ENOTFOUND:
return nullptr;
default:
LOG(ERROR) << "git_repository_open_ext: " << Print(dir) << ": " << GitError();
throw Exception();
}
}
std::string DirName(std::string path) {
if (path.empty()) return "";
while (path.back() == '/') {
path.pop_back();
if (path.empty()) return "";
}
do {
path.pop_back();
if (path.empty()) return "";
} while (path.back() != '/');
return path;
}
} // namespace
Repo* RepoCache::Open(const std::string& dir, bool from_dotgit) {
if (dir.empty() || dir.front() != '/') return nullptr;
std::string gitdir, workdir;
GitDirs(dir.c_str(), from_dotgit, gitdir, workdir);
if (gitdir.empty()) {
// This isn't quite correct because of differences in canonicalization, .git files and GIT_DIR.
// A proper solution would require tracking the "discovery dir" for every repository and
// performing path canonicalization.
if (from_dotgit) {
Erase(cache_.find(dir.back() == '/' ? dir : dir + '/'));
} else {
std::string path = dir;
if (path.back() != '/') path += '/';
do {
Erase(cache_.find(path + ".git/"));
path = DirName(path);
} while (!path.empty());
}
return nullptr;
}
auto it = cache_.find(gitdir);
if (it != cache_.end()) {
lru_.erase(it->second->lru);
it->second->lru = lru_.insert({Clock::now(), it});
return it->second.get();
}
// Opening from gitdir is faster but we cannot use it when gitdir came from a .git file.
git_repository* repo =
DirName(gitdir) == workdir ? OpenRepo(gitdir, true) : OpenRepo(dir, from_dotgit);
if (!repo) return nullptr;
ON_SCOPE_EXIT(&) {
if (repo) git_repository_free(repo);
};
if (git_repository_is_bare(repo)) return nullptr;
workdir = git_repository_workdir(repo) ?: "";
if (workdir.empty()) return nullptr;
VERIFY(workdir.front() == '/' && workdir.back() == '/') << Print(workdir);
auto x = cache_.emplace(gitdir, nullptr);
std::unique_ptr<Entry>& elem = x.first->second;
if (elem) {
lru_.erase(elem->lru);
} else {
LOG(INFO) << "Initializing new repository: " << Print(gitdir);
// Libgit2 initializes odb and refdb lazily with double-locking. To avoid useless work
// when multiple threads attempt to initialize the same db at the same time, we trigger
// initialization manually before threads are in play.
git_odb* odb;
VERIFY(!git_repository_odb(&odb, repo)) << GitError();
git_odb_free(odb);
git_refdb* refdb;
VERIFY(!git_repository_refdb(&refdb, repo)) << GitError();
git_refdb_free(refdb);
elem = std::make_unique<Entry>(std::exchange(repo, nullptr), lim_);
}
elem->lru = lru_.insert({Clock::now(), x.first});
return elem.get();
}
void RepoCache::Free(Time cutoff) {
while (true) {
if (lru_.empty()) break;
auto it = lru_.begin();
if (it->first > cutoff) break;
Erase(it->second);
}
}
void RepoCache::Erase(Cache::iterator it) {
if (it == cache_.end()) return;
LOG(INFO) << "Closing repository: " << Print(it->first);
lru_.erase(it->second->lru);
cache_.erase(it);
}
} // namespace gitstatus

@ -0,0 +1,60 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_REPO_CACHE_H_
#define ROMKATV_GITSTATUS_REPO_CACHE_H_
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <git2.h>
#include "options.h"
#include "repo.h"
#include "time.h"
namespace gitstatus {
class RepoCache {
public:
explicit RepoCache(Limits lim) : lim_(std::move(lim)) {}
Repo* Open(const std::string& dir, bool from_dotgit);
void Free(Time cutoff);
private:
struct Entry;
using Cache = std::unordered_map<std::string, std::unique_ptr<Entry>>;
using LRU = std::multimap<Time, Cache::iterator>;
void Erase(Cache::iterator it);
Limits lim_;
Cache cache_;
LRU lru_;
struct Entry : Repo {
using Repo::Repo;
LRU::iterator lru;
};
};
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_REPO_CACHE_H_

@ -0,0 +1,130 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include "request.h"
#include <fcntl.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include "check.h"
#include "logging.h"
#include "print.h"
#include "serialization.h"
namespace gitstatus {
namespace {
Request ParseRequest(const std::string& s) {
Request res;
auto begin = s.begin(), end = s.end(), sep = std::find(begin, end, kFieldSep);
VERIFY(sep != end) << "Malformed request: " << s;
res.id.assign(begin, sep);
begin = sep + 1;
if (*begin == ':') {
res.from_dotgit = true;
++begin;
}
sep = std::find(begin, end, kFieldSep);
res.dir.assign(begin, sep);
if (sep == end) return res;
begin = sep + 1;
VERIFY(begin + 1 == end && (*begin == '0' || *begin == '1')) << "Malformed request: " << s;
res.diff = *begin == '0';
return res;
}
bool IsLockedFd(int fd) {
CHECK(fd >= 0);
struct flock flock = {};
flock.l_type = F_RDLCK;
flock.l_whence = SEEK_SET;
CHECK(fcntl(fd, F_GETLK, &flock) != -1) << Errno();
return flock.l_type != F_UNLCK;
}
} // namespace
std::ostream& operator<<(std::ostream& strm, const Request& req) {
strm << Print(req.id) << " for " << Print(req.dir);
if (req.from_dotgit) strm << " [from-dotgit]";
if (!req.diff) strm << " [no-diff]";
return strm;
}
RequestReader::RequestReader(int fd, int lock_fd, int parent_pid)
: fd_(fd), lock_fd_(lock_fd), parent_pid_(parent_pid) {
CHECK(fd != lock_fd);
}
bool RequestReader::ReadRequest(Request& req) {
auto eol = std::find(read_.begin(), read_.end(), kMsgSep);
if (eol != read_.end()) {
std::string msg(read_.begin(), eol);
read_.erase(read_.begin(), eol + 1);
req = ParseRequest(msg);
return true;
}
char buf[256];
while (true) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd_, &fds);
struct timeval timeout = {.tv_sec = 1};
int n;
CHECK((n = select(fd_ + 1, &fds, NULL, NULL, &timeout)) >= 0) << Errno();
if (n == 0) {
if (lock_fd_ >= 0 && !IsLockedFd(lock_fd_)) {
LOG(INFO) << "Lock on fd " << lock_fd_ << " is gone. Exiting.";
std::exit(0);
}
if (parent_pid_ >= 0 && kill(parent_pid_, 0)) {
LOG(INFO) << "Unable to send signal 0 to " << parent_pid_ << ". Exiting.";
std::exit(0);
}
req = {};
return false;
}
CHECK((n = read(fd_, buf, sizeof(buf))) >= 0) << Errno();
if (n == 0) {
LOG(INFO) << "EOF. Exiting.";
std::exit(0);
}
read_.insert(read_.end(), buf, buf + n);
int eol = std::find(buf, buf + n, kMsgSep) - buf;
if (eol != n) {
std::string msg(read_.begin(), read_.end() - (n - eol));
read_.erase(read_.begin(), read_.begin() + msg.size() + 1);
req = ParseRequest(msg);
return true;
}
}
}
} // namespace gitstatus

@ -0,0 +1,50 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_REQUEST_H_
#define ROMKATV_GITSTATUS_REQUEST_H_
#include <deque>
#include <ostream>
#include <string>
namespace gitstatus {
struct Request {
std::string id;
std::string dir;
bool from_dotgit = false;
bool diff = true;
};
std::ostream& operator<<(std::ostream& strm, const Request& req);
class RequestReader {
public:
RequestReader(int fd, int lock_fd, int parent_pid);
bool ReadRequest(Request& req);
private:
int fd_;
int lock_fd_;
int parent_pid_;
std::deque<char> read_;
};
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_REQUEST_H_

@ -0,0 +1,73 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include "response.h"
#include <cctype>
#include <cstring>
#include <iostream>
#include "check.h"
#include "serialization.h"
namespace gitstatus {
namespace {
constexpr char kUnreadable = '?';
void SafePrint(std::ostream& strm, StringView s) {
for (size_t i = 0; i != s.len; ++i) {
char c = s.ptr[i];
strm << (c > 127 || std::isprint(c) ? c : kUnreadable);
}
}
} // namespace
ResponseWriter::ResponseWriter(std::string request_id) : request_id_(std::move(request_id)) {
SafePrint(strm_, request_id_);
Print(1);
}
ResponseWriter::~ResponseWriter() {
if (!done_) {
strm_.str("");
SafePrint(strm_, request_id_);
Print("0");
Dump("without git status");
}
}
void ResponseWriter::Print(ssize_t val) {
strm_ << kFieldSep;
strm_ << val;
}
void ResponseWriter::Print(StringView val) {
strm_ << kFieldSep;
SafePrint(strm_, val);
}
void ResponseWriter::Dump(const char* log) {
CHECK(!done_);
done_ = true;
LOG(INFO) << "Replying " << log;
std::cout << strm_.str() << kMsgSep << std::flush;
}
} // namespace gitstatus

@ -0,0 +1,50 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_RESPONSE_H_
#define ROMKATV_GITSTATUS_RESPONSE_H_
#include <cstddef>
#include <cstdint>
#include <sstream>
#include <string>
#include "string_view.h"
namespace gitstatus {
class ResponseWriter {
public:
ResponseWriter(std::string request_id);
ResponseWriter(ResponseWriter&&) = delete;
~ResponseWriter();
void Print(ssize_t val);
void Print(StringView val);
void Print(const char* val) { Print(StringView(val)); }
void Dump(const char* log);
private:
bool done_ = false;
std::string request_id_;
std::ostringstream strm_;
};
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_RESPONSE_H_

@ -0,0 +1,56 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_SCOPE_GUARD_H_
#define ROMKATV_GITSTATUS_SCOPE_GUARD_H_
#include <utility>
#define ON_SCOPE_EXIT(capture...) \
auto GITSTATUS_INTERNAL_CAT(_gitstatus_scope_guard_, __COUNTER__) = \
::gitstatus::internal_scope_guard::ScopeGuardGenerator() = [capture]()
#define GITSTATUS_INTERNAL_CAT_I(x, y) x##y
#define GITSTATUS_INTERNAL_CAT(x, y) GITSTATUS_INTERNAL_CAT_I(x, y)
namespace gitstatus {
namespace internal_scope_guard {
void Undefined();
template <class F>
class ScopeGuard {
public:
explicit ScopeGuard(F f) : f_(std::move(f)) {}
~ScopeGuard() { std::move(f_)(); }
ScopeGuard(ScopeGuard&& other) : f_(std::move(other.f_)) { Undefined(); }
private:
F f_;
};
struct ScopeGuardGenerator {
template <class F>
ScopeGuard<F> operator=(F f) const {
return ScopeGuard<F>(std::move(f));
}
};
} // namespace internal_scope_guard
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_SCOPE_GUARD_H_

@ -0,0 +1,28 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_SERIALIZATION_H_
#define ROMKATV_GITSTATUS_SERIALIZATION_H_
namespace gitstatus {
constexpr char kFieldSep = 31; // ascii 31 is unit separator
constexpr char kMsgSep = 30; // ascii 30 is record separator
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_SERIALIZATION_H_

@ -0,0 +1,23 @@
#ifndef ROMKATV_GITSTATUS_STAT_H_
#define ROMKATV_GITSTATUS_STAT_H_
#include <sys/stat.h>
namespace gitstatus {
inline const struct timespec& MTim(const struct stat& s) {
#ifdef __APPLE__
return s.st_mtimespec;
#else
return s.st_mtim;
#endif
}
inline bool StatEq(const struct stat& x, const struct stat& y) {
return MTim(x).tv_sec == MTim(y).tv_sec && MTim(x).tv_nsec == MTim(y).tv_nsec &&
x.st_size == y.st_size && x.st_ino == y.st_ino && x.st_mode == y.st_mode;
}
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_STAT_H_

@ -0,0 +1,151 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_STRING_CMP_H_
#define ROMKATV_GITSTATUS_STRING_CMP_H_
#include <string.h> // because there is no std::strcasecmp in C++
#include <algorithm>
#include <cctype>
#include <cstddef>
#include <cstring>
#include "string_view.h"
namespace gitstatus {
// WARNING: These routines assume no embedded null characters in StringView. Violations cause UB.
template <int kCaseSensitive = -1>
struct StrCmp;
template <>
struct StrCmp<0> {
int operator()(StringView x, StringView y) const {
size_t n = std::min(x.len, y.len);
int cmp = strncasecmp(x.ptr, y.ptr, n);
if (cmp) return cmp;
return static_cast<ssize_t>(x.len) - static_cast<ssize_t>(y.len);
}
int operator()(StringView x, const char* y) const {
for (const char *p = x.ptr, *e = p + x.len; p != e; ++p, ++y) {
if (int cmp = std::tolower(*p) - std::tolower(*y)) return cmp;
}
return 0 - *y;
}
int operator()(char x, char y) const { return std::tolower(x) - std::tolower(y); }
int operator()(const char* x, const char* y) const { return strcasecmp(x, y); }
int operator()(const char* x, StringView y) const { return -operator()(y, x); }
};
template <>
struct StrCmp<1> {
int operator()(StringView x, StringView y) const {
size_t n = std::min(x.len, y.len);
int cmp = std::memcmp(x.ptr, y.ptr, n);
if (cmp) return cmp;
return static_cast<ssize_t>(x.len) - static_cast<ssize_t>(y.len);
}
int operator()(StringView x, const char* y) const {
for (const char *p = x.ptr, *e = p + x.len; p != e; ++p, ++y) {
if (int cmp = *p - *y) return cmp;
}
return 0 - *y;
}
int operator()(char x, char y) const { return x - y; }
int operator()(const char* x, const char* y) const { return std::strcmp(x, y); }
int operator()(const char* x, StringView y) const { return -operator()(y, x); }
};
template <>
struct StrCmp<-1> {
explicit StrCmp(bool case_sensitive) : case_sensitive(case_sensitive) {}
template <class X, class Y>
int operator()(const X& x, const Y& y) const {
return case_sensitive ? StrCmp<1>()(x, y) : StrCmp<0>()(x, y);
}
bool case_sensitive;
};
template <int kCaseSensitive = -1>
struct StrLt : private StrCmp<kCaseSensitive> {
using StrCmp<kCaseSensitive>::StrCmp;
template <class X, class Y>
bool operator()(const X& x, const Y& y) const {
return StrCmp<kCaseSensitive>::operator()(x, y) < 0;
}
};
template <int kCaseSensitive = -1>
struct StrEq : private StrCmp<kCaseSensitive> {
using StrCmp<kCaseSensitive>::StrCmp;
template <class X, class Y>
bool operator()(const X& x, const Y& y) const {
return StrCmp<kCaseSensitive>::operator()(x, y) == 0;
}
bool operator()(const StringView& x, const StringView& y) const {
return x.len == y.len && StrCmp<kCaseSensitive>::operator()(x, y) == 0;
}
};
template <int kCaseSensitive = -1>
struct Str {
static_assert(kCaseSensitive == 0 || kCaseSensitive == 1, "");
static const bool case_sensitive = kCaseSensitive;
StrCmp<kCaseSensitive> Cmp;
StrLt<kCaseSensitive> Lt;
StrEq<kCaseSensitive> Eq;
};
template <int kCaseSensitive>
const bool Str<kCaseSensitive>::case_sensitive;
template <>
struct Str<-1> {
explicit Str(bool case_sensitive)
: case_sensitive(case_sensitive),
Cmp(case_sensitive),
Lt(case_sensitive),
Eq(case_sensitive) {}
bool case_sensitive;
StrCmp<-1> Cmp;
StrLt<-1> Lt;
StrEq<-1> Eq;
};
template <class Iter>
void StrSort(Iter begin, Iter end, bool case_sensitive) {
case_sensitive ? std::sort(begin, end, StrLt<true>()) : std::sort(begin, end, StrLt<false>());
}
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_STRING_CMP_H_

@ -0,0 +1,77 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_STRING_VIEW_H_
#define ROMKATV_GITSTATUS_STRING_VIEW_H_
#include <algorithm>
#include <cstddef>
#include <cstring>
#include <ostream>
#include <string>
namespace gitstatus {
// WARNING: StringView must not have embedded null characters. Violations cause UB.
struct StringView {
StringView() : StringView("") {}
// Requires: !memchr(s.data(), 0, s.size()).
//
// WARNING: The existence of this requirement and the fact that this constructor is implicit
// means it's dangerous to have std::string instances with embedded null characters anywhere
// in the program. If you have an std::string `s` with embedded nulls, an innocent-looking
// `F(s)` might perform an implicit conversion to StringView and land you squarely in the
// Undefined Behavior land.
StringView(const std::string& s) : StringView(s.c_str(), s.size()) {}
// Requires: !memchr(ptr, 0, len).
StringView(const char* ptr, size_t len) : ptr(ptr), len(len) {}
// Requires: end >= begin && !memchr(begin, 0, end - begin).
StringView(const char* begin, const char* end) : StringView(begin, end - begin) {}
// Requires: strchr(s, 0) == s + N.
template <size_t N>
StringView(const char (&s)[N]) : StringView(s, N - 1) {
static_assert(N, "");
}
// Explicit because it's the only constructor that isn't O(1).
// Are you sure you don't already known the strings's length?
explicit StringView(const char* ptr) : StringView(ptr, ptr ? std::strlen(ptr) : 0) {}
bool StartsWith(StringView prefix) const {
return len >= prefix.len && !std::memcmp(ptr, prefix.ptr, prefix.len);
}
bool EndsWith(StringView suffix) const {
return len >= suffix.len && !std::memcmp(ptr + (len - suffix.len), suffix.ptr, suffix.len);
}
const char* ptr;
size_t len;
};
inline std::ostream& operator<<(std::ostream& strm, StringView s) {
if (s.ptr) strm.write(s.ptr, s.len);
return strm;
}
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_STRING_VIEW_H_

@ -0,0 +1,71 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include <cassert>
#include "strings.h"
namespace gitstatus {
void CEscape(std::ostream& strm, const char* begin, const char* end) {
assert(!begin == !end);
if (!begin) return;
for (; begin != end; ++begin) {
const unsigned char c = *begin;
switch (c) {
case '\t':
strm << "\\t";
continue;
case '\n':
strm << "\\n";
continue;
case '\r':
strm << "\\r";
continue;
case '"':
strm << "\\\"";
continue;
case '\'':
strm << "\\'";
continue;
case '\\':
strm << "\\\\";
continue;
}
if (c > 31 && c < 127) {
strm << c;
continue;
}
strm << '\\';
strm << static_cast<char>('0' + ((c >> 6) & 7));
strm << static_cast<char>('0' + ((c >> 3) & 7));
strm << static_cast<char>('0' + ((c >> 0) & 7));
}
}
void Quote(std::ostream& strm, const char* begin, const char* end) {
assert(!begin == !end);
if (!begin) {
strm << "null";
return;
}
strm << '"';
CEscape(strm, begin, end);
strm << '"';
}
} // namespace gitstatus

@ -0,0 +1,37 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_STRINGS_H_
#define ROMKATV_GITSTATUS_STRINGS_H_
#include <ostream>
namespace gitstatus {
// If the pointers are null, prints nothing.
//
// Requires: !begin == !end.
void CEscape(std::ostream& strm, const char* begin, const char* end);
// If the pointers are null, prints null without quotes.
//
// Requires: !begin == !end.
void Quote(std::ostream& strm, const char* begin, const char* end);
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_STRING_VIEW_H_

@ -0,0 +1,332 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include "tag_db.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <utility>
#include "check.h"
#include "dir.h"
#include "git.h"
#include "print.h"
#include "scope_guard.h"
#include "stat.h"
#include "string_cmp.h"
#include "thread_pool.h"
#include "timer.h"
namespace gitstatus {
namespace {
using namespace std::string_literals;
static constexpr char kTagPrefix[] = "refs/tags/";
constexpr int8_t kUnhex[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // 3
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 6
};
struct {
bool operator()(const Tag* x, const git_oid& y) const {
return std::memcmp(x->id.id, y.id, GIT_OID_RAWSZ) < 0;
}
bool operator()(const git_oid& x, const Tag* y) const {
return std::memcmp(x.id, y->id.id, GIT_OID_RAWSZ) < 0;
}
bool operator()(const Tag* x, const Tag* y) const {
return std::memcmp(x->id.id, y->id.id, GIT_OID_RAWSZ) < 0;
}
} constexpr ById = {};
struct {
bool operator()(const Tag* x, const char* y) const {
return std::strcmp(x->name, y) < 0;
}
bool operator()(const char* x, const Tag* y) const {
return std::strcmp(x, y->name) < 0;
}
bool operator()(const Tag* x, const Tag* y) const {
return std::strcmp(x->name, y->name) < 0;
}
} constexpr ByName = {};
void ParseOid(unsigned char* oid, const char* begin, const char* end) {
VERIFY(end >= begin + GIT_OID_HEXSZ);
for (size_t i = 0; i != GIT_OID_HEXSZ; i += 2) {
*oid++ = kUnhex[+begin[i]] << 4 | kUnhex[+begin[i + 1]];
}
}
const char* StripTag(const char* ref) {
for (size_t i = 0; i != sizeof(kTagPrefix) - 1; ++i) {
if (*ref++ != kTagPrefix[i]) return nullptr;
}
return ref;
}
git_refdb* RefDb(git_repository* repo) {
git_refdb* res;
VERIFY(!git_repository_refdb(&res, repo)) << GitError();
return res;
}
} // namespace
TagDb::TagDb(git_repository* repo)
: repo_(repo),
refdb_(RefDb(repo)),
pack_(&pack_arena_),
name2id_(&pack_arena_),
id2name_(&pack_arena_) {
CHECK(repo_ && refdb_);
}
TagDb::~TagDb() {
Wait();
git_refdb_free(refdb_);
}
std::string TagDb::TagForCommit(const git_oid& oid) {
ReadLooseTags();
UpdatePack();
std::string res;
std::string ref = "refs/tags/";
size_t prefix_len = ref.size();
for (const char* tag : loose_tags_) {
ref.resize(prefix_len);
ref += tag;
if (res < tag && TagHasTarget(ref.c_str(), &oid)) res = tag;
}
if ((std::unique_lock<std::mutex>(mutex_), id2name_dirty_)) {
for (auto it = name2id_.rbegin(); it != name2id_.rend(); ++it) {
if (!memcmp((*it)->id.id, oid.id, GIT_OID_RAWSZ) && !IsLooseTag((*it)->name)) {
if (res < (*it)->name) res = (*it)->name;
break;
}
}
} else {
auto r = std::equal_range(id2name_.begin(), id2name_.end(), oid, ById);
for (auto it = r.first; it != r.second; ++it) {
if (!IsLooseTag((*it)->name) && res < (*it)->name) res = (*it)->name;
}
}
return res;
}
void TagDb::ReadLooseTags() {
loose_tags_.clear();
loose_arena_.Reuse();
std::string dirname = git_repository_path(repo_) + "refs/tags"s;
int dir_fd = open(dirname.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if (dir_fd < 0) return;
ON_SCOPE_EXIT(&) { CHECK(!close(dir_fd)) << Errno(); };
// TODO: recursively traverse directories so that the file refs/tags/foo/bar gets interpreted
// as the tag foo/bar. See https://github.com/romkatv/gitstatus/issues/254.
(void)ListDir(dir_fd, loose_arena_, loose_tags_, /* precompose_unicode = */ false,
/* case_sensitive = */ true);
}
void TagDb::UpdatePack() {
auto Reset = [&] {
auto Wipe = [](auto& x) {
x.clear();
x.shrink_to_fit();
};
Wait();
Wipe(pack_);
Wipe(name2id_);
Wipe(id2name_);
pack_arena_.Reuse();
std::memset(&pack_stat_, 0, sizeof(pack_stat_));
};
std::string pack_path = git_repository_path(repo_) + "packed-refs"s;
struct stat st;
if (stat(pack_path.c_str(), &st)) {
Reset();
return;
}
if (StatEq(pack_stat_, st)) return;
Reset();
try {
while (true) {
LOG(INFO) << "Parsing " << Print(pack_path);
int fd = open(pack_path.c_str(), O_RDONLY | O_CLOEXEC);
VERIFY(fd >= 0);
ON_SCOPE_EXIT(&) { CHECK(!close(fd)) << Errno(); };
pack_.resize(st.st_size + 1);
ssize_t n = read(fd, &pack_[0], st.st_size + 1);
VERIFY(n >= 0) << Errno();
VERIFY(!fstat(fd, &pack_stat_)) << Errno();
if (!StatEq(st, pack_stat_)) {
st = pack_stat_;
continue;
}
VERIFY(n == st.st_size);
pack_.pop_back();
break;
}
ParsePack();
} catch (const Exception&) {
Reset();
throw;
}
}
void TagDb::ParsePack() {
char* p = &pack_[0];
char* e = p + pack_.size();
// Usually packed-refs starts with the following line:
//
// # pack-refs with: peeled fully-peeled sorted
//
// However, some users can produce pack-refs without this line.
// See https://github.com/romkatv/powerlevel10k/issues/1428.
// I don't know how they do it. Without the header line we cannot
// assume that refs are sorted, which isn't a big deal because we
// can just sort them. What's worse is that refs cannot be assumed
// to be fully-peeled. We don't want to peel them, so we just drop
// all tags.
if (*p != '#') {
LOG(WARN) << "packed-refs doesn't have a header. Won't resolve tags.";
return;
}
char* eol = std::strchr(p, '\n');
if (!eol) return;
*eol = 0;
if (!std::strstr(p, " fully-peeled") || !std::strstr(p, " sorted")) {
LOG(WARN) << "packed-refs has unexpected header. Won't resolve tags.";
}
p = eol + 1;
name2id_.reserve(pack_.size() / 128);
id2name_.reserve(pack_.size() / 128);
std::vector<Tag*> idx;
idx.reserve(pack_.size() / 128);
while (p != e) {
Tag* tag = pack_arena_.Allocate<Tag>();
ParseOid(tag->id.id, p, e);
p += GIT_OID_HEXSZ;
VERIFY(*p++ == ' ');
const char* ref = p;
VERIFY(p = std::strchr(p, '\n'));
p[p[-1] == '\r' ? -1 : 0] = 0;
++p;
if (*p == '^') {
ParseOid(tag->id.id, p + 1, e);
p += GIT_OID_HEXSZ + 1;
if (p != e) {
VERIFY((p = std::strchr(p, '\n')));
++p;
}
}
tag->name = StripTag(ref);
if (!tag->name) continue;
name2id_.push_back(tag);
id2name_.push_back(tag);
}
if (!std::is_sorted(name2id_.begin(), name2id_.end(), ByName)) {
// "sorted" in the header of packed-refs promises that this won't trigger.
std::sort(name2id_.begin(), name2id_.end(), ByName);
}
id2name_dirty_ = true;
GlobalThreadPool()->Schedule([this] {
std::sort(id2name_.begin(), id2name_.end(), ById);
std::unique_lock<std::mutex> lock(mutex_);
CHECK(id2name_dirty_);
id2name_dirty_ = false;
cv_.notify_one();
});
}
void TagDb::Wait() {
std::unique_lock<std::mutex> lock(mutex_);
while (id2name_dirty_) cv_.wait(lock);
}
bool TagDb::IsLooseTag(const char* name) const {
return std::binary_search(loose_tags_.begin(), loose_tags_.end(), name,
[](const char* a, const char* b) { return std::strcmp(a, b) < 0; });
}
bool TagDb::TagHasTarget(const char* name, const git_oid* target) const {
static constexpr size_t kMaxDerefCount = 10;
git_reference* ref;
if (git_refdb_lookup(&ref, refdb_, name)) return false;
ON_SCOPE_EXIT(&) { git_reference_free(ref); };
for (int i = 0; i != kMaxDerefCount && git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC; ++i) {
git_reference* dst;
const char* ref_name = git_reference_name(ref);
if (git_refdb_lookup(&dst, refdb_, ref_name)) {
const char* tag_name = StripTag(ref_name);
auto it = std::lower_bound(name2id_.begin(), name2id_.end(), tag_name, ByName);
return it != name2id_.end() && !strcmp((*it)->name, tag_name) && !IsLooseTag(tag_name) &&
git_oid_equal(&(*it)->id, target);
}
git_reference_free(ref);
ref = dst;
}
if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) return false;
const git_oid* oid = git_reference_target_peel(ref) ?: git_reference_target(ref);
if (git_oid_equal(oid, target)) return true;
for (int i = 0; i != kMaxDerefCount; ++i) {
git_tag* tag;
if (git_tag_lookup(&tag, repo_, oid)) return false;
ON_SCOPE_EXIT(&) { git_tag_free(tag); };
if (git_tag_target_type(tag) == GIT_OBJECT_COMMIT) {
return git_oid_equal(git_tag_target_id(tag), target);
}
oid = git_tag_target_id(tag);
}
return false;
}
} // namespace gitstatus

@ -0,0 +1,79 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_TAG_DB_H_
#define ROMKATV_GITSTATUS_TAG_DB_H_
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <git2.h>
#include <condition_variable>
#include <cstring>
#include <mutex>
#include <string>
#include <vector>
#include "arena.h"
namespace gitstatus {
struct Tag {
const char* name;
git_oid id;
};
class TagDb {
public:
explicit TagDb(git_repository* repo);
TagDb(TagDb&&) = delete;
~TagDb();
std::string TagForCommit(const git_oid& oid);
private:
void ReadLooseTags();
void UpdatePack();
void ParsePack();
void Wait();
bool IsLooseTag(const char* name) const;
bool TagHasTarget(const char* name, const git_oid* target) const;
git_repository* const repo_;
git_refdb* const refdb_;
Arena pack_arena_;
struct stat pack_stat_ = {};
WithArena<std::string> pack_;
WithArena<std::vector<const Tag*>> name2id_;
WithArena<std::vector<const Tag*>> id2name_;
Arena loose_arena_;
std::vector<char*> loose_tags_;
std::mutex mutex_;
std::condition_variable cv_;
bool id2name_dirty_ = false;
};
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_TAG_DB_H_

@ -0,0 +1,87 @@
#include "thread_pool.h"
#include <cassert>
#include <utility>
#include "check.h"
#include "logging.h"
namespace gitstatus {
ThreadPool::ThreadPool(size_t num_threads) : num_inflight_(num_threads) {
for (size_t i = 0; i != num_threads; ++i) {
threads_.emplace_back([=]() { Loop(i + 1); });
}
}
ThreadPool::~ThreadPool() {
{
std::lock_guard<std::mutex> lock(mutex_);
exit_ = true;
}
cv_.notify_all();
sleeper_cv_.notify_one();
for (std::thread& t : threads_) t.join();
}
void ThreadPool::Schedule(Time t, std::function<void()> f) {
std::condition_variable* wake = nullptr;
{
std::unique_lock<std::mutex> lock(mutex_);
work_.push(Work{std::move(t), ++last_idx_, std::move(f)});
if (work_.top().idx == last_idx_) wake = have_sleeper_ ? &sleeper_cv_ : &cv_;
}
if (wake) wake->notify_one();
}
void ThreadPool::Loop(size_t tid) {
auto Next = [&]() -> std::function<void()> {
std::unique_lock<std::mutex> lock(mutex_);
--num_inflight_;
if (work_.empty() && num_inflight_ == 0) idle_cv_.notify_all();
while (true) {
if (exit_) return nullptr;
if (work_.empty()) {
cv_.wait(lock);
continue;
}
Time now = Clock::now();
const Work& top = work_.top();
if (top.t <= now) {
std::function<void()> res = std::move(top.f);
work_.pop();
++num_inflight_;
bool notify = !work_.empty() && !have_sleeper_;
lock.unlock();
if (notify) cv_.notify_one();
return res;
}
if (have_sleeper_) {
cv_.wait(lock);
continue;
}
have_sleeper_ = true;
sleeper_cv_.wait_until(lock, top.t);
assert(have_sleeper_);
have_sleeper_ = false;
}
};
while (std::function<void()> f = Next()) f();
}
void ThreadPool::Wait() {
std::unique_lock<std::mutex> lock(mutex_);
idle_cv_.wait(lock, [&] { return work_.empty() && num_inflight_ == 0; });
}
static ThreadPool* g_thread_pool = nullptr;
void InitGlobalThreadPool(size_t num_threads) {
CHECK(!g_thread_pool);
LOG(INFO) << "Spawning " << num_threads << " thread(s)";
g_thread_pool = new ThreadPool(num_threads);
}
ThreadPool* GlobalThreadPool() { return g_thread_pool; }
} // namespace gitstatus

@ -0,0 +1,74 @@
#ifndef ROMKATV_GITSTATUS_THREAD_POOL_H_
#define ROMKATV_GITSTATUS_THREAD_POOL_H_
#include <condition_variable>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <mutex>
#include <queue>
#include <thread>
#include <tuple>
#include <utility>
#include "time.h"
namespace gitstatus {
class ThreadPool {
public:
explicit ThreadPool(size_t num_threads);
ThreadPool(ThreadPool&&) = delete;
// Waits for the currently running functions to finish.
// Does NOT wait for the queue of functions to drain.
// If you want the latter, call Wait() manually.
~ThreadPool();
// Runs `f` on one of the threads at or after time `t`. Can be called
// from any thread. Can be called concurrently.
//
// Does not block.
void Schedule(Time t, std::function<void()> f);
void Schedule(std::function<void()> f) { Schedule(Clock::now(), std::move(f)); }
// Blocks until the work queue is empty and there are no currently
// running functions.
void Wait();
size_t num_threads() const { return threads_.size(); }
private:
struct Work {
bool operator<(const Work& w) const { return std::tie(w.t, w.idx) < std::tie(t, idx); }
Time t;
int64_t idx;
mutable std::function<void()> f;
};
void Loop(size_t tid);
int64_t last_idx_ = 0;
int64_t num_inflight_;
bool exit_ = false;
// Do we have a thread waiting on sleeper_cv_?
bool have_sleeper_ = false;
std::mutex mutex_;
// Any number of threads can wait on this condvar. Always without a timeout.
std::condition_variable cv_;
// At most one thread can wait on this condvar at a time. Always with a timeout.
std::condition_variable sleeper_cv_;
// Signalled when the work queue is empty and there is nothing inflight.
std::condition_variable idle_cv_;
std::priority_queue<Work> work_;
std::vector<std::thread> threads_;
};
void InitGlobalThreadPool(size_t num_threads);
ThreadPool* GlobalThreadPool();
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_THREAD_POOL_H_

@ -0,0 +1,14 @@
#ifndef ROMKATV_GITSTATUS_TIME_H_
#define ROMKATV_GITSTATUS_TIME_H_
#include <chrono>
namespace gitstatus {
using Clock = std::chrono::steady_clock;
using Time = Clock::time_point;
using Duration = Clock::duration;
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_TIME_H_

@ -0,0 +1,72 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#include "timer.h"
#include <sys/resource.h>
#include <sys/time.h>
#include <time.h>
#include <cmath>
#include <limits>
#include "check.h"
#include "logging.h"
namespace gitstatus {
namespace {
double CpuTimeMs() {
auto ToMs = [](const timeval& tv) { return 1e3 * tv.tv_sec + 1e-3 * tv.tv_usec; };
rusage usage = {};
CHECK(getrusage(RUSAGE_SELF, &usage) == 0) << Errno();
return ToMs(usage.ru_utime) + ToMs(usage.ru_stime);
}
double WallTimeMs() {
// An attempt to call clock_gettime on an ancient version of MacOS fails at runtime.
// It's possible to detect the presence of clock_gettime at runtime but I don't have
// an ancient MacOS to test the code. Hence this.
#ifdef __APPLE__
return std::numeric_limits<double>::quiet_NaN();
#else
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return 1e3 * ts.tv_sec + 1e-6 * ts.tv_nsec;
#endif
}
} // namespace
void Timer::Start() {
cpu_ = CpuTimeMs();
wall_ = WallTimeMs();
}
void Timer::Report(const char* msg) {
double cpu = CpuTimeMs() - cpu_;
if (std::isnan(wall_)) {
LOG(INFO) << "Timing for: " << msg << ": " << cpu << "ms cpu";
} else {
double wall = WallTimeMs() - wall_;
LOG(INFO) << "Timing for: " << msg << ": " << cpu << "ms cpu, " << wall << "ms wall";
}
Start();
}
} // namespace gitstatus

@ -0,0 +1,36 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_TIMER_H_
#define ROMKATV_GITSTATUS_TIMER_H_
namespace gitstatus {
class Timer {
public:
Timer() { Start(); }
void Start();
void Report(const char* msg);
private:
double cpu_;
double wall_;
};
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_TIMER_H_

@ -0,0 +1,27 @@
// Copyright 2019 Roman Perepelitsa.
//
// This file is part of GitStatus.
//
// GitStatus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GitStatus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
#ifndef ROMKATV_GITSTATUS_TRIBOOL_H_
#define ROMKATV_GITSTATUS_TRIBOOL_H_
namespace gitstatus {
enum class Tribool : int { kFalse = 0, kTrue = 1, kUnknown = -1 };
} // namespace gitstatus
#endif // ROMKATV_GITSTATUS_TRIBOOL_H_

@ -1,40 +1,41 @@
typeset -gr __p9k_wizard_columns=55
typeset -gr __p9k_wizard_lines=21
# Fewer than 47 columns will probably work. Haven't tried it.
typeset -gr __p9k_wizard_columns=47
# The bottleneck is ask_tails with nerd fonts. Everything else works fine with 12 lines.
typeset -gr __p9k_wizard_lines=14
typeset -gr __p9k_zd=${ZDOTDIR:-$HOME}
typeset -gr __p9k_zd_u=${${${(q)__p9k_zd}/#(#b)${(q)HOME}(|\/*)/'~'$match[1]}//\%/%%}
typeset -gr __p9k_cfg_basename=.p10k.zsh
typeset -gr __p9k_cfg_path=$__p9k_zd/$__p9k_cfg_basename
typeset -gr __p9k_cfg_path_u=$__p9k_zd_u/$__p9k_cfg_basename
typeset -gr __p9k_zshrc=$__p9k_zd/.zshrc
typeset -gr __p9k_zshrc=${${:-$__p9k_zd/.zshrc}:A}
typeset -gr __p9k_zshrc_u=$__p9k_zd_u/.zshrc
typeset -gr __p9k_root_dir_u=${${${(q)__p9k_root_dir}/#(#b)${(q)HOME}(|\/*)/'~'$match[1]}//\%/%%}
function _p9k_can_configure() {
emulate -L zsh
setopt extended_glob no_prompt_{bang,subst} prompt_percent
[[ $1 == '-q' ]] && local -i q=1 || local -i q=0
function $0_error() {
(( q )) || print -rP "%1F[ERROR]%f %Bp10k configure%b: $1" >&2
}
typeset -g __p9k_cfg_path_o=${POWERLEVEL9K_CONFIG_FILE:=${ZDOTDIR:-~}/.p10k.zsh}
typeset -g __p9k_cfg_basename=${__p9k_cfg_path_o:t}
typeset -g __p9k_cfg_path=${__p9k_cfg_path_o:A}
typeset -g __p9k_cfg_path_u=${${${(q)__p9k_cfg_path_o}/#(#b)${(q)HOME}(|\/*)/'~'$match[1]}//\%/%%}
{
[[ -t 0 && -t 1 ]] || { $0_error "no TTY"; return 1 }
[[ -o multibyte ]] || { $0_error "multibyte option is not set"; return 1 }
[[ -e $__p9k_zd ]] || { $0_error "$__p9k_zd_u does not exist"; return 1 }
[[ -d $__p9k_zd ]] || { $0_error "$__p9k_zd_u is not a directory"; return 1 }
[[ -w $__p9k_zd ]] || { $0_error "$__p9k_zd_u is not writable"; return 1 }
[[ ! -d $__p9k_cfg_path ]] || { $0_error "$__p9k_cfg_path_u is a directory"; return 1 }
[[ ! -d $__p9k_zshrc ]] || { $0_error "$__p9k_zshrc_u is a directory"; return 1 }
[[ ! -e $__p9k_cfg_path || -f $__p9k_cfg_path || -h $__p9k_cfg_path ]] || {
$0_error "$__p9k_cfg_path_u is a special file"
local dir=${__p9k_cfg_path:h}
while [[ ! -e $dir && $dir != ${dir:h} ]]; do dir=${dir:h}; done
if [[ ! -d $dir ]]; then
$0_error "cannot create $__p9k_cfg_path_u because ${dir//\%/%%} is not a directory"
return 1
}
[[ -r $__p9k_root_dir/config/p10k-lean.zsh ]] || {
$0_error "cannot read $__p9k_root_dir_u/config/p10k-lean.zsh"
fi
if [[ ! -w $dir ]]; then
$0_error "cannot create $__p9k_cfg_path_u because ${dir//\%/%%} is readonly"
return 1
}
[[ -r $__p9k_root_dir/config/p10k-classic.zsh ]] || {
$0_error "cannot read $__p9k_root_dir_u/config/p10k-classic.zsh"
fi
[[ ! -e $__p9k_cfg_path || -f $__p9k_cfg_path || -h $__p9k_cfg_path ]] || {
$0_error "$__p9k_cfg_path_u is a special file"
return 1
}
[[ ! -e $__p9k_zshrc || -f $__p9k_zshrc || -h $__p9k_zshrc ]] || {
@ -45,32 +46,38 @@ function _p9k_can_configure() {
$0_error "$__p9k_zshrc_u is not readable"
return 1
}
[[ ! -e $__p9k_zshrc || -w $__p9k_zshrc ]] || {
$0_error "$__p9k_zshrc_u is not writable"
return 1
}
local style
for style in lean lean-8colors classic rainbow pure; do
[[ -r $__p9k_root_dir/config/p10k-$style.zsh ]] || {
$0_error "$__p9k_root_dir_u/config/p10k-$style.zsh is not readable"
return 1
}
done
(( LINES >= __p9k_wizard_lines && COLUMNS >= __p9k_wizard_columns )) || {
$0_error "terminal size too small; must be at least $__p9k_wizard_columns x $__p9k_wizard_lines"
$0_error "terminal size too small; must be at least $__p9k_wizard_columns columns by $__p9k_wizard_lines lines"
return 1
}
[[ -t 0 && -t 1 ]] || {
$0_error "no TTY"
return 2
}
return 0
} always {
unfunction $0_error
}
}
function p9k_configure() {
emulate -L zsh
setopt no_hist_expand extended_glob
eval "$__p9k_intro"
_p9k_can_configure || return
(
local p=("${(@)parameters[(I)AWESOME_*|CODEPOINT_*]}")
if (( $#p )); then
typeset -x -- $p
fi
$__p9k_root_dir/internal/wizard.zsh -d $__p9k_root_dir -f
set -- -f
builtin source $__p9k_root_dir/internal/wizard.zsh
)
local ret=$?
case $ret in
0) source $__p9k_cfg_path;;
0) builtin source $__p9k_cfg_path; _p9k__force_must_init=1;;
69) return 0;;
*) return $ret;;
esac

File diff suppressed because it is too large Load Diff

@ -0,0 +1,197 @@
battery: use the same technique as in vpn_ip to avoid reset=2.
---
implement fake gitstatus api on top of vcs_info (or plain git?) + worker and use it if there is no
gitstatus.
---
- call vcs_info on worker. the tricky question is what to display while "loading".
---
- add _SHOW_SYSTEM to all *env segments.
---
- support states in SHOW_ON_COMMAND: POWERLEVEL9K_SEGMENT_STATE_SHOW_ON_COMMAND='...'
---
add POWERLEVEL9K_${SEGMENT}_${STATE}_SHOW_IN_DIR='pwd_pattern'; implement the same way as
SHOW_ON_UPGLOB. how should it interact with POWERLEVEL9K_${SEGMENT}_DISABLED_DIR_PATTERN?
---
add `p10k upglob`; returns 0 on match and sets REPLY to the directory where match was found.
---
when directory cannot be shortened any further, start chopping off segments from the left and
replacing the chopped off part with `…`. e.g., `…/x/anchor/y/anchor`. the shortest dir
representation is thus `…/last` or `…/last` depending on whether the last segment is an anchor.
the replacement parameter's value is `…/` (with a slash) to allow for `x/anchor/y/anchor`.
---
- add to faq: how do i display an environment variable in prompt? link it from "extensible"
---
- add to faq: how do i display an icon in prompt? link it from "extensible"
---
- add root_indicator to config templates
---
- test chruby and add it to config templates
---
- add ssh to config templates
---
- add swift version to config templates; see if there is a good pattern for PROJECT_ONLY
---
- add swiftenv
---
- add faq: how to customize directory shortening? mention POWERLEVEL9K_DIR_TRUNCATE_BEFORE_MARKER,
POWERLEVEL9K_DIR_MAX_LENGTH and co., and truncate_to_last.
---
fix a bug in zsh: https://github.com/romkatv/powerlevel10k/issues/502. to reproduce:
```zsh
emulate zsh -o prompt_percent -c 'print -P "%F{#ff0000}red%F{green}%B bold green"'
```
---
add `p10k explain` that prints something like this:
```text
segment icons meaning
---
---
---
---
---
---
---
---
--
status ✔ ✘ exit code of the last command
```
implement it the hard way: for every enabled segment go over all its {state,icon} pairs, resolve
the icon (if not absolute), apply VISUAL_IDENTIFIER_EXPANSION, remove leading and trailing
whitespace and print without formatting (sort of like `print -P | cat`); print segment names in
green and icons in bold; battery can have an unlimited number of icons, so `...` would be needed
(based on total length of concatenated icons rather than the number of icons); user-defined
segments would have "unknown" icons by default (yellow and not bold); can allow them to
participate by defining `explainprompt_foo` that populates array `reply` with strings like this:
'-s STATE -i LOCK_ICON +r'; the first element must be segment description.
---
add `docker_context` prompt segment; similar to `kubecontext`; the data should come from
`currentContext` field in `~/.docker/config.json` (according to
https://github.com/starship/starship/issues/995); there is also `DOCKER_CONTEXT`; more info:
https://docs.docker.com/engine/reference/commandline/context_use; also
https://github.com/starship/starship/pull/996.
---
support `env`, `ionice` and `strace` precommands in `parser.zsh`.
---
Add ruler to configuration wizard. Options: `─`, `·`, `╌`, `┄`, `▁`, `═`.
---
Add frame styles to the wizard.
```text
╭─
╰─
┌─
└─
┏━
┗━
╔═
╚═
▛▀
▙▄
```
Prompt connection should have matching options.
---
Add `POWERLEVEL9K_{LEFT,RIGHT}_SEGMENT_MIRROR_SEPARATOR`. If set, left segments get separated with
`POWERLEVEL9K_LEFT_SEGMENT_SEPARATOR` followed by `POWERLEVEL9K_LEFT_SEGMENT_MIRROR_SEPARATOR`.
Each is drawn without background. The first with the foreground of left segment, the second with
the background of right segment. To insert space in between, embed it in
`POWERLEVEL9K_{LEFT,RIGHT}_SEGMENT_MIRROR_SEPARATOR`.
`POWERLEVEL9K_{LEFT,RIGHT}_SUBSEGMENT_SEPARATOR` is unused.
---
Add *Segment Connection* screen to configuration wizard with options *Fused*, *Touching* and
*Disjoint*. The last two differ by the absence/presence of space between `SEGMENT_SEPARATOR` and
`SEGMENT_MIRROR_SEPARATOR`.
*Fused* requires line separator (there is already a screen for it) but the other two options require
two filled separators similar to heads and tail. Figure out how to present this choice.
---
Optimize auto-wizard check.
```text
time ( repeat 1000 [[ -z "${parameters[(I)POWERLEVEL9K_*~(POWERLEVEL9K_MODE|POWERLEVEL9K_CONFIG_FILE)]}" ]] )
user=0.21s system=0.05s cpu=99% total=0.264
time ( repeat 1000 [[ -z "${parameters[(I)POWERLEVEL9K_*]}" ]] )
user=0.17s system=0.00s cpu=99% total=0.175
```
---
Add the equivalent of `P9K_PYTHON_VERSION` to all `*env` segments where it makes sense.
---
Define `P9K_ICON` on initialization. Fill it with `$icon`. Duplicate every key that ends in `_ICON`.
Respect `POWERLEVEL9K_VCS_STASH_ICON` overrides but not anything with segment name or state.
Define `POWERLEVEL9K_VCS_*` parameters in config templates for all symbols used in
`my_git_formatter`. Add missing entries to `icons`. Use `$P9K_ICON[...]` within `my_git_formatter`.
Add a screen to the wizard to choose between clear and circled icons.
---
Add a screen to the wizard asking whether to set `POWERLEVEL9K_VCS_DISABLED_WORKDIR_PATTERN='~'`.
Show it only if there is `$HOME/.git`. By default this parameter should be commented out.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,382 @@
typeset -grA __p9k_pb_cmd_skip=(
'}' 'always' # handled specially
'{' ''
'{' ''
'|' ''
'||' ''
'&' ''
'&&' ''
'|&' ''
'&!' ''
'&|' ''
')' ''
'(' ''
'()' ''
'!' ''
';' ''
'if' ''
'fi' ''
'elif' ''
'else' ''
'then' ''
'while' ''
'until' ''
'do' ''
'done' ''
'esac' ''
'end' ''
'coproc' ''
'nocorrect' ''
'noglob' ''
'time' ''
'[[' '\]\]'
'((' '\)\)'
'case' '\)|esac'
';;' '\)|esac'
';&' '\)|esac'
';|' '\)|esac'
'foreach' '\(*\)'
)
typeset -grA __p9k_pb_precommand=(
'-' ''
'builtin' ''
'command' ''
'exec' '-[^a]#[a]'
'nohup' ''
'setsid' ''
'eatmydata' ''
'catchsegv' ''
'pkexec' '--user'
'doas' '-[^aCu]#[acU]'
'nice' '-[^n]#[n]|--adjustment'
'stdbuf' '-[^ioe]#[ioe]|--(input|output|error)'
'sudo' '-[^aghpuUCcrtT]#[aghpuUCcrtT]|--(close-from|group|host|prompt|role|type|other-user|command-timeout|user)'
'ssh-agent' '-[^aEPt]#[aEPt]'
'tabbed' '-[^gnprtTuU]#[gnprtTuU]'
'chronic' ''
'ifne' ''
)
typeset -grA __p9k_pb_redirect=(
'&>' ''
'>' ''
'>&' ''
'<' ''
'<&' ''
'<>' ''
'&>|' ''
'>|' ''
'&>>' ''
'>>' ''
'>>&' ''
'&>>|' ''
'>>|' ''
'<<<' ''
)
typeset -grA __p9k_pb_term=(
'|' ''
'||' ''
';' ''
'&' ''
'&&' ''
'|&' ''
'&!' ''
'&|' ''
';;' ''
';&' ''
';|' ''
'(' ''
')' ''
'()' '' # handled specially
'}' '' # handled specially
)
typeset -grA __p9k_pb_term_skip=(
'(' '\)'
';;' '\)|esac'
';&' '\)|esac'
';|' '\)|esac'
)
# Usage: _p9k_parse_buffer <buffer> [token-limit]
#
# Parses the specified command line buffer and pupulates array P9K_COMMANDS
# with commands from it. Terminates early and returns 1 if there are more
# tokens than the specified limit.
#
# Broken:
#
# ---------------
# : $(x)
# ---------------
# : `x`
# ---------------
# ${x/}
# ---------------
# - -- x
# ---------------
# command -p -p x
# ---------------
# *
# ---------------
# x=$y; $x
# ---------------
# alias x=y; y
# ---------------
# x <<END
# ; END
# END
# ---------------
# Setup:
# setopt interactive_comments
# alias x='#'
# Punchline:
# x; y
# ---------------
#
# More brokenness with non-standard options (ignore_braces, ignore_close_braces, etc.).
function _p9k_parse_buffer() {
[[ ${2:-0} == <-> ]] || return 2
local rcquotes
[[ -o rcquotes ]] && rcquotes=rcquotes
eval "$__p9k_intro"
setopt no_nomatch $rcquotes
typeset -ga P9K_COMMANDS=()
local -r id='(<->|[[:alpha:]_][[:IDENT:]]#)'
local -r var="\$$id|\${$id}|\"\$$id\"|\"\${$id}\""
local -i e ic c=${2:-'1 << 62'}
local skip n s r state token cmd prev
local -a aln alp alf v
if [[ -o interactive_comments ]]; then
ic=1
local tokens=(${(Z+C+)1})
else
local tokens=(${(z)1})
fi
{
while (( $#tokens )); do
(( e = $#state ))
while (( $#tokens == alp[-1] )); do
aln[-1]=()
alp[-1]=()
if (( $#tokens == alf[-1] )); then
alf[-1]=()
(( e = 0 ))
fi
done
while (( c-- > 0 )) || return; do
token=$tokens[1]
tokens[1]=()
if (( $+galiases[$token] )); then
(( $aln[(eI)p$token] )) && break
s=$galiases[$token]
n=p$token
elif (( e )); then
break
elif (( $+aliases[$token] )); then
(( $aln[(eI)p$token] )) && break
s=$aliases[$token]
n=p$token
elif [[ $token == ?*.?* ]] && (( $+saliases[${token##*.}] )); then
r=${token##*.}
(( $aln[(eI)s$r] )) && break
s=${saliases[$r]%% #}
n=s$r
else
break
fi
aln+=$n
alp+=$#tokens
[[ $s == *' ' ]] && alf+=$#tokens
(( ic )) && tokens[1,0]=(${(Z+C+)s}) || tokens[1,0]=(${(z)s})
done
case $token in
'<<'(|-))
state=h
continue
;;
*('`'|['<>=$']'(')*)
if [[ $token == ('`'[^'`']##'`'|'"`'[^'`']##'`"'|'$('[^')']##')'|'"$('[^')']##')"'|['<>=']'('[^')']##')') ]]; then
s=${${token##('"'|)(['$<>']|)?}%%?('"'|)}
(( ic )) && tokens+=(';' ${(Z+C+)s}) || tokens+=(';' ${(z)s})
fi
;;
esac
case $state in
*r)
state[-1]=
continue
;;
a)
if [[ $token == $skip ]]; then
if [[ $token == '{' ]]; then
P9K_COMMANDS+=$cmd
cmd=
state=
else
skip='{'
fi
continue
else
state=t
fi
;& # fall through
t|p*)
if (( $+__p9k_pb_term[$token] )); then
if [[ $token == '()' ]]; then
state=
else
P9K_COMMANDS+=$cmd
if [[ $token == '}' ]]; then
state=a
skip=always
else
skip=$__p9k_pb_term_skip[$token]
state=${skip:+s}
fi
fi
cmd=
continue
elif [[ $state == t ]]; then
continue
elif [[ $state == *x ]]; then
if (( $+__p9k_pb_redirect[$token] )); then
prev=
state[-1]=r
continue
else
state[-1]=
fi
fi
;;
s)
if [[ $token == $~skip ]]; then
state=
fi
continue
;;
h)
while (( $#tokens )); do
(( e = ${tokens[(i)${(Q)token}]} ))
if [[ $tokens[e-1] == ';' && $tokens[e+1] == ';' ]]; then
tokens[1,e]=()
break
else
tokens[1,e]=()
fi
done
while (( $#alp && alp[-1] >= $#tokens )); do
aln[-1]=()
alp[-1]=()
done
state=t
continue
;;
esac
if (( $+__p9k_pb_redirect[${token#<0-255>}] )); then
state+=r
continue
fi
if [[ $token == *'$'* ]]; then
if [[ $token == $~var ]]; then
n=${${token##[^[:IDENT:]]}%%[^[:IDENT:]]}
[[ $token == *'"' ]] && v=("${(P)n}") || v=(${(P)n})
tokens[1,0]=(${(@qq)v})
continue
fi
fi
case $state in
'')
if (( $+__p9k_pb_cmd_skip[$token] )); then
skip=$__p9k_pb_cmd_skip[$token]
[[ $token == '}' ]] && state=a || state=${skip:+s}
continue
fi
if [[ $token == *=* ]]; then
v=${(S)token/#(<->|([[:alpha:]_][[:IDENT:]]#(|'['*[^\\](\\\\)#']')))(|'+')=}
if (( $#v < $#token )); then
if [[ $v == '(' ]]; then
state=s
skip='\)'
fi
continue
fi
fi
: ${token::=${(Q)${~token}}}
;;
p2)
if [[ -n $prev ]]; then
prev=
else
: ${token::=${(Q)${~token}}}
if [[ $token == '{'$~id'}' ]]; then
state=p2x
prev=$token
else
state=p
fi
continue
fi
;& # fall through
p)
if [[ -n $prev ]]; then
token=$prev
prev=
else
: ${token::=${(Q)${~token}}}
case $token in
'{'$~id'}') prev=$token; state=px; continue;;
[^-]*) ;;
--) state=p1; continue;;
$~skip) state=p2; continue;;
*) continue;;
esac
fi
;;
p1)
if [[ -n $prev ]]; then
token=$prev
prev=
else
: ${token::=${(Q)${~token}}}
if [[ $token == '{'$~id'}' ]]; then
state=p1x
prev=$token
continue
fi
fi
;;
esac
if (( $+__p9k_pb_precommand[$token] )); then
prev=
state=p
skip=$__p9k_pb_precommand[$token]
cmd+=$token$'\0'
else
state=t
[[ $token == ('(('*'))'|'`'*'`'|'$'*|['<>=']'('*')'|*$'\0'*) ]] || cmd+=$token$'\0'
fi
done
} always {
[[ $state == (px|p1x) ]] && cmd+=$prev
P9K_COMMANDS+=$cmd
P9K_COMMANDS=(${(u)P9K_COMMANDS%$'\0'})
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,219 @@
# invoked in worker: _p9k_worker_main <pgid>
function _p9k_worker_main() {
mkfifo -- $_p9k__worker_file_prefix.fifo || return
echo -nE - s$_p9k_worker_pgid$'\x1e' || return
exec <$_p9k__worker_file_prefix.fifo || return
zf_rm -- $_p9k__worker_file_prefix.fifo || return
local -i reset
local req fd
local -a ready
local _p9k_worker_request_id
local -A _p9k_worker_fds # fd => id$'\x1f'callback
local -A _p9k_worker_inflight # id => inflight count
function _p9k_worker_reply() {
print -nr -- e${(pj:\n:)@}$'\x1e' || kill -- -$_p9k_worker_pgid
}
# usage: _p9k_worker_async <work> <callback>
function _p9k_worker_async() {
local fd async=$1
sysopen -r -o cloexec -u fd <(() { eval $async; } && print -n '\x1e') || return
(( ++_p9k_worker_inflight[$_p9k_worker_request_id] ))
_p9k_worker_fds[$fd]=$_p9k_worker_request_id$'\x1f'$2
}
trap '' PIPE
{
while zselect -a ready 0 ${(k)_p9k_worker_fds}; do
[[ $ready[1] == -r ]] || return
for fd in ${ready:1}; do
if [[ $fd == 0 ]]; then
local buf=
[[ -t 0 ]] # https://www.zsh.org/mla/workers/2020/msg00207.html
if sysread -t 0 'buf[$#buf+1]'; then
while [[ $buf != *$'\x1e' ]]; do
sysread 'buf[$#buf+1]' || return
done
else
(( $? == 4 )) || return
fi
for req in ${(ps:\x1e:)buf}; do
_p9k_worker_request_id=${req%%$'\x1f'*}
() { eval $req[$#_p9k_worker_request_id+2,-1] }
(( $+_p9k_worker_inflight[$_p9k_worker_request_id] )) && continue
print -rn -- d$_p9k_worker_request_id$'\x1e' || return
done
else
local REPLY=
while true; do
if sysread -i $fd 'REPLY[$#REPLY+1]'; then
[[ $REPLY == *$'\x1e' ]] || continue
else
(( $? == 5 )) || return
break
fi
done
local cb=$_p9k_worker_fds[$fd]
_p9k_worker_request_id=${cb%%$'\x1f'*}
unset "_p9k_worker_fds[$fd]"
exec {fd}>&-
if [[ $REPLY == *$'\x1e' ]]; then
REPLY[-1]=""
() { eval $cb[$#_p9k_worker_request_id+2,-1] }
fi
if (( --_p9k_worker_inflight[$_p9k_worker_request_id] == 0 )); then
unset "_p9k_worker_inflight[$_p9k_worker_request_id]"
print -rn -- d$_p9k_worker_request_id$'\x1e' || return
fi
fi
done
done
} always {
kill -- -$_p9k_worker_pgid
}
}
# invoked in master: _p9k_worker_invoke <request-id> <list>
function _p9k_worker_invoke() {
[[ -n $_p9k__worker_resp_fd ]] || return
local req=$1$'\x1f'$2$'\x1e'
if [[ -n $_p9k__worker_req_fd && $+_p9k__worker_request_map[$1] == 0 ]]; then
_p9k__worker_request_map[$1]=
print -rnu $_p9k__worker_req_fd -- $req
else
_p9k__worker_request_map[$1]=$req
fi
}
function _p9k_worker_cleanup() {
# __p9k_intro bugs out here in some cases for some reason.
emulate -L zsh
[[ $_p9k__worker_shell_pid == $sysparams[pid] ]] && _p9k_worker_stop
return 0
}
function _p9k_worker_stop() {
# See comments in _p9k_worker_cleanup.
emulate -L zsh
add-zsh-hook -D zshexit _p9k_worker_cleanup
[[ -n $_p9k__worker_resp_fd ]] && zle -F $_p9k__worker_resp_fd
[[ -n $_p9k__worker_resp_fd ]] && exec {_p9k__worker_resp_fd}>&-
[[ -n $_p9k__worker_req_fd ]] && exec {_p9k__worker_req_fd}>&-
[[ -n $_p9k__worker_pid ]] && kill -- -$_p9k__worker_pid 2>/dev/null
[[ -n $_p9k__worker_file_prefix ]] && zf_rm -f -- $_p9k__worker_file_prefix.fifo
_p9k__worker_pid=
_p9k__worker_req_fd=
_p9k__worker_resp_fd=
_p9k__worker_shell_pid=
_p9k__worker_request_map=()
return 0
}
function _p9k_worker_receive() {
eval "$__p9k_intro"
[[ -z $_p9k__worker_resp_fd ]] && return
{
(( $# <= 1 )) || return
local buf resp
[[ -t $_p9k__worker_resp_fd ]] # https://www.zsh.org/mla/workers/2020/msg00207.html
if sysread -i $_p9k__worker_resp_fd -t 0 'buf[$#buf+1]'; then
while [[ $buf == *[^$'\x05\x1e']$'\x05'# ]]; do
sysread -i $_p9k__worker_resp_fd 'buf[$#buf+1]' || return
done
else
(( $? == 4 )) || return
fi
local -i reset max_reset
for resp in ${(ps:\x1e:)${buf//$'\x05'}}; do
local arg=$resp[2,-1]
case $resp[1] in
d)
local req=$_p9k__worker_request_map[$arg]
if [[ -n $req ]]; then
_p9k__worker_request_map[$arg]=
print -rnu $_p9k__worker_req_fd -- $req || return
else
unset "_p9k__worker_request_map[$arg]"
fi
;;
e)
() { eval $arg }
(( reset > max_reset )) && max_reset=reset
;;
s)
[[ -z $_p9k__worker_req_fd ]] || return
[[ $arg == <1-> ]] || return
_p9k__worker_pid=$arg
sysopen -w -o cloexec -u _p9k__worker_req_fd $_p9k__worker_file_prefix.fifo || return
local req=
for req in $_p9k__worker_request_map; do
print -rnu $_p9k__worker_req_fd -- $req || return
done
_p9k__worker_request_map=({${(k)^_p9k__worker_request_map},''})
;;
*)
return 1
;;
esac
done
if (( max_reset == 2 )); then
_p9k__refresh_reason=worker
_p9k_set_prompt
_p9k__refresh_reason=''
fi
(( max_reset )) && _p9k_reset_prompt
return 0
} always {
(( $? )) && _p9k_worker_stop
}
}
function _p9k_worker_start() {
setopt monitor || return
{
[[ -n $_p9k__worker_resp_fd ]] && return
if [[ -n "$TMPDIR" && ( ( -d "$TMPDIR" && -w "$TMPDIR" ) || ! ( -d /tmp && -w /tmp ) ) ]]; then
local tmpdir=$TMPDIR
else
local tmpdir=/tmp
fi
_p9k__worker_file_prefix=$tmpdir/p10k.worker.$EUID.$sysparams[pid].$EPOCHSECONDS
sysopen -r -o cloexec -u _p9k__worker_resp_fd <(
exec 0</dev/null
if [[ -n $_POWERLEVEL9K_WORKER_LOG_LEVEL ]]; then
exec 2>$_p9k__worker_file_prefix.log
setopt xtrace
else
exec 2>/dev/null
fi
builtin cd -q / || return
zmodload zsh/zselect || return
! { zselect -t0 || (( $? != 1 )) } || return
local _p9k_worker_pgid=$sysparams[pid]
_p9k_worker_main &
{
trap '' PIPE
while syswrite $'\x05'; do zselect -t 1000; done
zf_rm -f $_p9k__worker_file_prefix.fifo
kill -- -$_p9k_worker_pgid
} &
exec =true) || return
_p9k__worker_pid=$sysparams[procsubstpid]
zle -F $_p9k__worker_resp_fd _p9k_worker_receive
_p9k__worker_shell_pid=$sysparams[pid]
add-zsh-hook zshexit _p9k_worker_cleanup
} always {
(( $? )) && _p9k_worker_stop
}
}

@ -1,573 +0,0 @@
{"version": 2, "width": 127, "height": 45, "timestamp": 1559376160, "env": {"SHELL": "/usr/bin/zsh", "TERM": "xterm-256color"}, "title": "p9k vs p10k"}
[0.53704, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[1.802793, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.54 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h"]
[2.645571, "i", "c"]
[2.645863, "o", "c"]
[2.749229, "i", "a"]
[2.749471, "o", "\bca"]
[2.821008, "i", "t"]
[2.821208, "o", "t"]
[2.917345, "i", " "]
[2.917563, "o", " "]
[3.141259, "i", "~"]
[3.141483, "o", "~"]
[3.317344, "i", "/"]
[3.31756, "o", "/"]
[3.501341, "i", "."]
[3.501574, "o", "."]
[3.709525, "i", "z"]
[3.709787, "o", "z"]
[4.285646, "i", "s"]
[4.28589, "o", "s"]
[4.40539, "i", "h"]
[4.405619, "o", "h"]
[4.517287, "i", "r"]
[4.517532, "o", "r"]
[4.741459, "i", "c"]
[4.741702, "o", "c"]
[5.957417, "i", "\r"]
[5.957699, "o", "\u001b[?2004l\r\r\n"]
[5.963966, "o", "export NVM_DIR=~/nvm\r\nsource $NVM_DIR/nvm.sh\r\n\r\nPOWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(load todo background_jobs kubecontext nvm dir vcs)\r\nPOWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=()\r\nPOWERLEVEL9K_DIR_PATH_ABSOLUTE=true\r\nPOWERLEVEL9K_SHORTEN_STRATEGY=truncate_with_package_name\r\n\r\nsource ~/powerlevel9k/powerlevel9k.zsh-theme\r\n"]
[5.964191, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[6.960979, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.53 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h"]
[7.341627, "i", "e"]
[7.341903, "o", "e"]
[7.557579, "i", "c"]
[7.557797, "o", "\bec"]
[7.629363, "i", "h"]
[7.629586, "o", "h"]
[7.757141, "i", "o"]
[7.757369, "o", "o"]
[7.837404, "i", " "]
[7.83764, "o", " "]
[7.965308, "i", "o"]
[7.965505, "o", "o"]
[8.085223, "i", "r"]
[8.08542, "o", "r"]
[8.181345, "i", "i"]
[8.181584, "o", "i"]
[8.285333, "i", "g"]
[8.285535, "o", "g"]
[8.357376, "i", "i"]
[8.357591, "o", "i"]
[8.501418, "i", "n"]
[8.501621, "o", "n"]
[8.581417, "i", "a"]
[8.581623, "o", "a"]
[8.661315, "i", "l"]
[8.661516, "o", "l"]
[8.789288, "i", " "]
[8.78952, "o", " "]
[8.973335, "i", "p"]
[8.97356, "o", "p"]
[9.125345, "i", "o"]
[9.125551, "o", "o"]
[9.253231, "i", "w"]
[9.253426, "o", "w"]
[9.301294, "i", "e"]
[9.301469, "o", "e"]
[9.373118, "i", "r"]
[9.373317, "o", "r"]
[9.516979, "i", "l"]
[9.517165, "o", "l"]
[9.557044, "i", "e"]
[9.557246, "o", "e"]
[9.741259, "i", "v"]
[9.741461, "o", "v"]
[9.797193, "i", "e"]
[9.797413, "o", "e"]
[9.868882, "i", "l"]
[9.869078, "o", "l"]
[10.036815, "i", "9"]
[10.037002, "o", "9"]
[10.180929, "i", "k"]
[10.181134, "o", "k"]
[10.413048, "i", "\r"]
[10.413272, "o", "\u001b[?2004l\r\r\n"]
[10.413438, "o", "original powerlevel9k\r\n"]
[10.413519, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[11.421676, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.53 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h"]
[11.573397, "i", "l"]
[11.573648, "o", "l"]
[11.773387, "i", "s"]
[11.773623, "o", "\bls"]
[12.013242, "i", "\r"]
[12.013481, "o", "\u001b[?2004l\r\r\n"]
[12.015871, "o", "azure-pipelines.yml cgmanifest.json gulpfile.js product.json resources test\t\t tslint.json\r\nbuild\t\t CONTRIBUTING.md LICENSE.txt README.md\t scripts ThirdPartyNotices.txt yarn.lock\r\ncglicenses.json extensions package.json remote\t src\t tsfmt.json\r\n"]
[12.016178, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[12.36554, "i", "p"]
[12.365781, "o", "p"]
[12.493436, "i", "w"]
[12.493666, "o", "w"]
[12.693192, "i", "d"]
[12.693423, "o", "d"]
[13.00701, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.53 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h"]
[13.007104, "o", "p\bpwd"]
[13.453428, "i", "\r"]
[13.45367, "o", "\u001b[?2004l\r\r\n"]
[13.453791, "o", "/home/romka/projects/vscode\r\n"]
[13.453887, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[14.349251, "i", "\r"]
[14.349349, "o", "\r\n"]
[14.456024, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.53 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h\u001b[?2004l\r\r\n\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[14.485142, "i", "\r"]
[14.485402, "o", "\r\n"]
[14.637102, "i", "\r"]
[14.637302, "o", "\r\n"]
[14.797341, "i", "\r"]
[14.797434, "o", "\r\n"]
[14.94944, "i", "\r"]
[14.949542, "o", "\r\n"]
[15.109413, "i", "e"]
[15.109507, "o", "e"]
[15.309269, "i", "c"]
[15.309362, "o", "c"]
[15.397125, "i", "h"]
[15.39722, "o", "h"]
[15.493601, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.52 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h\u001b[?2004l\r\r\n"]
[15.493698, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[15.509382, "i", "o"]
[15.509602, "o", "o"]
[15.653098, "i", " "]
[15.653296, "o", " "]
[16.501217, "i", "a"]
[16.501314, "o", "a"]
[16.511071, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.52 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h\u001b[?2004l\r\r\n"]
[16.511154, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[16.701189, "i", " "]
[16.701425, "o", " "]
[17.093404, "i", "b"]
[17.093502, "o", "b"]
[17.221118, "i", "i"]
[17.221356, "o", "i"]
[17.300863, "i", "t"]
[17.301097, "o", "t"]
[17.532571, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.52 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h\u001b[?2004l\r\r\n\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[17.877348, "i", " "]
[17.877587, "o", " "]
[18.205341, "i", "s"]
[18.205619, "o", "s"]
[18.325276, "i", "l"]
[18.3255, "o", "l"]
[18.469261, "i", "o"]
[18.469534, "o", "o"]
[18.533346, "i", "w"]
[18.533582, "o", "w"]
[18.547089, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.52 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h\u001b[?2004l\r\r\n"]
[18.547178, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[19.565682, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.52 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m "]
[19.565787, "o", "\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004he\becho a bi"]
[19.565836, "o", "t sl"]
[19.566076, "o", "ow"]
[19.589236, "i", " "]
[19.589418, "o", " "]
[19.749008, "i", "h"]
[19.749231, "o", "h"]
[19.876872, "i", "u"]
[19.877089, "o", "u"]
[20.053127, "i", "h"]
[20.053343, "o", "h"]
[20.7413, "i", "\r"]
[20.741536, "o", "\u001b[?2004l\r\r\n"]
[20.741719, "o", "a bit slow huh\r\n"]
[20.741768, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[21.727487, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.52 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h"]
[22.829268, "i", "\r"]
[22.829523, "o", "\u001b[?2004l\r\r\n"]
[22.829632, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[22.973134, "i", "\r"]
[22.973394, "o", "\r\n"]
[23.10913, "i", "\r"]
[23.109377, "o", "\r\n"]
[23.237105, "i", "\r"]
[23.237321, "o", "\r\n"]
[23.348944, "i", "\r"]
[23.349046, "o", "\r\n"]
[23.837798, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.52 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h\u001b[?2004l\r\r\n"]
[23.837904, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[24.832648, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.52 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h"]
[24.832756, "o", "\u001b[?2004l\r\r\n\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[25.832667, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.52 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h\u001b[?2004l\r\r\n\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[26.181402, "i", "\u0003"]
[26.181692, "o", "^C"]
[26.182089, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m"]
[26.182196, "o", "\u001b[K\u001b[105C\u001b[39m\u001b[0m\u001b[49m$(build_right_prompt)$reset_color\r\u001b[?2004h"]
[27.445169, "i", "c"]
[27.445436, "o", "c"]
[27.612934, "i", "d"]
[27.613158, "o", "\rcd"]
[27.756896, "i", " "]
[27.757162, "o", " "]
[28.165022, "i", "s"]
[28.165255, "o", "s"]
[28.268955, "i", "r"]
[28.269166, "o", "r"]
[28.484901, "i", "c"]
[28.485152, "o", "c"]
[29.637189, "i", "\r"]
[29.63745, "o", "\u001b[?2004l\r\r\n"]
[29.637628, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[30.143699, "o", "truncatePath:4: bad math expression: illegal character: \\\r\n"]
[30.646309, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.52 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h"]
[32.013179, "i", "\r"]
[32.013428, "o", "\u001b[?2004l\r\r\n"]
[32.013549, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[32.517756, "o", "truncatePath:4: bad math expression: illegal character: \\\r\n"]
[32.973297, "i", "w"]
[32.973372, "o", "w"]
[33.03069, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.52 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h"]
[33.030753, "o", "w"]
[33.125041, "i", "t"]
[33.125269, "o", "\bwt"]
[33.269129, "i", "f"]
[33.269353, "o", "f"]
[33.653444, "i", "\r"]
[33.653708, "o", "\u001b[?2004l\r\r\n"]
[33.654751, "o", "zsh: command not found: wtf\r\n"]
[33.655067, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[34.154929, "o", "truncatePath:4: bad math expression: illegal character: \\\r\n"]
[34.663887, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.52 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h"]
[34.725177, "i", "c"]
[34.725427, "o", "c"]
[34.924913, "i", "d"]
[34.925115, "o", "\bcd"]
[35.077086, "i", " "]
[35.07735, "o", " "]
[35.292953, "i", "."]
[35.293177, "o", "."]
[35.42103, "i", "."]
[35.421273, "o", "."]
[35.629217, "i", "\r"]
[35.629483, "o", "\u001b[?2004l\r\r\n"]
[35.629712, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[36.638245, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[42m \u001b[30mL \u001b[30m0.56 \u001b[48;5;244m\u001b[32m \u001b[30m☑ \u001b[30m7 \u001b[45m\u001b[38;5;244m \u001b[37m⎈ \u001b[37mminikube \u001b[45m\u001b[30m \u001b[30m⬢ \u001b[30m12.3.1 \u001b[44m\u001b[35m \u001b[30mcode-oss-dev \u001b[42m\u001b[34m \u001b[30m master \u001b[49m\u001b[32m\u001b[39m \u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[K\u001b[00m\u001b[60D\u001b[?2004h"]
[37.477061, "i", "s"]
[37.47733, "o", "s"]
[37.588878, "i", "o"]
[37.589089, "o", "\bso"]
[37.700765, "i", "u"]
[37.700985, "o", "u"]
[37.796705, "i", "r"]
[37.796949, "o", "r"]
[37.988864, "i", "c"]
[37.989098, "o", "c"]
[38.180799, "i", "e"]
[38.181013, "o", "e"]
[38.420809, "i", " "]
[38.421035, "o", " "]
[38.604822, "i", "~"]
[38.605035, "o", "~"]
[38.764974, "i", "/"]
[38.765208, "o", "/"]
[39.197038, "i", "o"]
[39.197274, "o", "o"]
[39.36479, "i", "w"]
[39.365033, "o", "w"]
[39.404619, "i", "e"]
[39.404787, "o", "e"]
[39.500881, "i", "r"]
[39.501076, "o", "r"]
[39.981133, "i", ""]
[39.981387, "o", "\b \b"]
[40.100922, "i", ""]
[40.101164, "o", "\b \b"]
[40.244966, "i", ""]
[40.245181, "o", "\b \b"]
[40.781038, "i", ""]
[40.781341, "o", "\b \b"]
[41.397117, "i", "p"]
[41.397357, "o", "p"]
[41.549006, "i", "o"]
[41.549223, "o", "o"]
[41.66894, "i", "\t"]
[41.669987, "o", "werlevel"]
[42.39715, "i", "1"]
[42.397388, "o", "1"]
[42.637011, "i", "\t"]
[42.637557, "o", "0k"]
[43.317189, "i", "/"]
[43.317426, "o", "/"]
[43.50879, "i", "p"]
[43.508993, "o", "p"]
[43.669076, "i", "o"]
[43.669314, "o", "o"]
[43.74891, "i", "\t"]
[43.749325, "o", "werlevel"]
[44.077215, "i", "1"]
[44.077486, "o", "1"]
[44.340992, "i", "\t"]
[44.341411, "o", "0k.zsh-theme\u001b[1m \u001b[0m"]
[45.261252, "i", "\r"]
[45.261515, "o", "\b\u001b[0m \b\u001b[?2004l\r\r\n"]
[45.287095, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[45.595079, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[46.077089, "i", "e"]
[46.077322, "o", "e"]
[46.276969, "i", "c"]
[46.277208, "o", "\bec"]
[46.348751, "i", "h"]
[46.348969, "o", "h"]
[46.508875, "i", "o"]
[46.509094, "o", "o"]
[46.604929, "i", " "]
[46.605148, "o", " "]
[46.740751, "i", "t"]
[46.740977, "o", "t"]
[46.828853, "i", "h"]
[46.829071, "o", "h"]
[46.908719, "i", "e"]
[46.90893, "o", "e"]
[47.068923, "i", " "]
[47.069147, "o", " "]
[47.205066, "i", "s"]
[47.205306, "o", "s"]
[47.373022, "i", "a"]
[47.373266, "o", "a"]
[47.516846, "i", "m"]
[47.517072, "o", "m"]
[47.588891, "i", "e"]
[47.589101, "o", "e"]
[47.732787, "i", " "]
[47.733003, "o", " "]
[47.908991, "i", "c"]
[47.909219, "o", "c"]
[47.98101, "i", "o"]
[47.981233, "o", "o"]
[48.132892, "i", "n"]
[48.133112, "o", "n"]
[48.501069, "i", "f"]
[48.501307, "o", "f"]
[48.605085, "i", "i"]
[48.605318, "o", "i"]
[48.692956, "i", "g"]
[48.693179, "o", "g"]
[48.836976, "i", "\r"]
[48.837202, "o", "\u001b[?2004l\r\r\n"]
[48.837389, "o", "the same config\r\n"]
[48.837478, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[48.848952, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[49.301199, "i", "e"]
[49.301437, "o", "e"]
[49.492908, "i", "c"]
[49.49313, "o", "\bec"]
[49.540911, "i", "h"]
[49.541102, "o", "h"]
[49.644811, "i", "o"]
[49.64501, "o", "o"]
[49.732905, "i", " "]
[49.733092, "o", " "]
[49.805042, "i", "t"]
[49.805265, "o", "t"]
[49.884917, "i", "h"]
[49.885119, "o", "h"]
[49.9726, "i", "e"]
[49.972829, "o", "e"]
[50.036777, "i", " "]
[50.036994, "o", " "]
[50.132761, "i", "s"]
[50.132964, "o", "s"]
[50.300762, "i", "a"]
[50.300978, "o", "a"]
[50.420838, "i", "m"]
[50.421037, "o", "m"]
[50.476859, "i", "e"]
[50.477044, "o", "e"]
[50.556939, "i", " "]
[50.557134, "o", " "]
[50.692809, "i", "p"]
[50.693014, "o", "p"]
[50.756686, "i", "r"]
[50.756859, "o", "r"]
[50.86083, "i", "o"]
[50.861015, "o", "o"]
[51.325156, "i", "m"]
[51.325389, "o", "m"]
[51.524926, "i", "p"]
[51.525147, "o", "p"]
[51.645054, "i", "t"]
[51.645277, "o", "t"]
[51.821133, "i", "\r"]
[51.82137, "o", "\u001b[?2004l\r\r\n"]
[51.82155, "o", "the same prompt\r\n"]
[51.82163, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[51.833309, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.53 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[52.373203, "i", "e"]
[52.373441, "o", "e"]
[52.549106, "i", "c"]
[52.549339, "o", "\bec"]
[52.612882, "i", "h"]
[52.613054, "o", "h"]
[52.732732, "i", "o"]
[52.732936, "o", "o"]
[52.81272, "i", " "]
[52.812893, "o", " "]
[52.892775, "i", "b"]
[52.892965, "o", "b"]
[52.988718, "i", "u"]
[52.988905, "o", "u"]
[53.068771, "i", "t"]
[53.068984, "o", "t"]
[53.16478, "i", " "]
[53.164995, "o", " "]
[53.26088, "i", "f"]
[53.261093, "o", "f"]
[53.364842, "i", "a"]
[53.365037, "o", "a"]
[53.548877, "i", "s"]
[53.549081, "o", "s"]
[53.620878, "i", "t"]
[53.621084, "o", "t"]
[53.828977, "i", "!"]
[53.829212, "o", "!"]
[54.00484, "i", "\r"]
[54.005073, "o", "\u001b[?2004l\r\r\n"]
[54.005239, "o", "but fast!\r\n"]
[54.005328, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[54.01702, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.55 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[54.941013, "i", "l"]
[54.941252, "o", "l"]
[54.996943, "i", "s"]
[54.997163, "o", "\bls"]
[55.212915, "i", "\r"]
[55.213166, "o", "\u001b[?2004l\r\r\n"]
[55.215862, "o", "azure-pipelines.yml cgmanifest.json gulpfile.js product.json resources test\t\t tslint.json\r\nbuild\t\t CONTRIBUTING.md LICENSE.txt README.md\t scripts ThirdPartyNotices.txt yarn.lock\r\ncglicenses.json extensions package.json remote\t src\t tsfmt.json\r\n"]
[55.21612, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[55.22789, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.55 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[55.701246, "i", "p"]
[55.701481, "o", "p"]
[55.780794, "i", "w"]
[55.781022, "o", "\bpw"]
[55.924905, "i", "d"]
[55.925126, "o", "d"]
[56.045009, "i", "\r"]
[56.04525, "o", "\u001b[?2004l\r\r\n"]
[56.045413, "o", "/home/romka/projects/vscode\r\n"]
[56.045495, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[56.057015, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.55 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[56.24519, "i", "c"]
[56.24544, "o", "c"]
[56.421036, "i", "d"]
[56.421263, "o", "\bcd"]
[56.524989, "i", " "]
[56.525211, "o", " "]
[56.645023, "i", "s"]
[56.645242, "o", "s"]
[56.684883, "i", "r"]
[56.685114, "o", "r"]
[56.876966, "i", "c"]
[56.877193, "o", "c"]
[56.972829, "i", "\r"]
[56.973067, "o", "\u001b[?2004l\r\r\n"]
[56.973332, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[56.985413, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.55 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev/\u001b[0m\u001b[30m\u001b[44m\u001b[30msrc \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[56C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[56D\u001b[?2004h"]
[57.205194, "i", "c"]
[57.205449, "o", "c"]
[57.373149, "i", "d"]
[57.373389, "o", "\bcd"]
[57.47697, "i", " "]
[57.477182, "o", " "]
[57.620957, "i", "."]
[57.621177, "o", "."]
[57.756947, "i", "."]
[57.757161, "o", "."]
[57.941039, "i", "\r"]
[57.941263, "o", "\u001b[?2004l\r\r\n"]
[57.941513, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[57.953015, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.55 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[58.581266, "i", "\r"]
[58.581538, "o", "\u001b[?2004l\r\r\n\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[58.593219, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.55 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.081009, "i", "\r"]
[59.081281, "o", "\u001b[?2004l\r\r\n"]
[59.081429, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.093237, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.110986, "i", "\r"]
[59.111193, "o", "\u001b[?2004l\r\r\n"]
[59.111314, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.12356, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.143273, "i", "\r"]
[59.143485, "o", "\u001b[?2004l\r\r\n"]
[59.143613, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.155374, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.173369, "i", "\r"]
[59.17359, "o", "\u001b[?2004l\r\r\n"]
[59.173683, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.185113, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.20241, "i", "\r"]
[59.202603, "o", "\u001b[?2004l\r\r\n"]
[59.202716, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.214455, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.233834, "i", "\r"]
[59.234018, "o", "\u001b[?2004l\r\r\n"]
[59.234128, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.24564, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.262345, "i", "\r"]
[59.262542, "o", "\u001b[?2004l\r\r\n"]
[59.262655, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.274662, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.292442, "i", "\r"]
[59.292644, "o", "\u001b[?2004l\r\r\n"]
[59.292742, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.30501, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.322867, "i", "\r"]
[59.323066, "o", "\u001b[?2004l\r\r\n"]
[59.323163, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.335113, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.352291, "i", "\r"]
[59.352496, "o", "\u001b[?2004l\r\r\n"]
[59.352635, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.364051, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.383162, "i", "\r"]
[59.383361, "o", "\u001b[?2004l\r\r\n"]
[59.383485, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.395, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.414121, "i", "\r"]
[59.414333, "o", "\u001b[?2004l\r\r\n"]
[59.414437, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.425938, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.444624, "i", "\r"]
[59.444904, "o", "\u001b[?2004l\r\r\n"]
[59.445057, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.456824, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.474566, "i", "\r"]
[59.474735, "o", "\u001b[?2004l\r\r\n"]
[59.474827, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.486114, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.504654, "i", "\r"]
[59.504847, "o", "\u001b[?2004l\r\r\n"]
[59.504961, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.516844, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.534681, "i", "\r"]
[59.534897, "o", "\u001b[?2004l\r\r\n"]
[59.534989, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.547367, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.564722, "i", "\r"]
[59.564909, "o", "\u001b[?2004l\r\r\n"]
[59.565018, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.576476, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.59495, "i", "\r"]
[59.595135, "o", "\u001b[?2004l\r\r\n"]
[59.595259, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.606554, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.625117, "i", "\r"]
[59.625332, "o", "\u001b[?2004l\r\r\n"]
[59.625445, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.637157, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.656009, "i", "\r"]
[59.656191, "o", "\u001b[?2004l\r\r\n"]
[59.656301, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.667971, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.68654, "i", "\r"]
[59.686754, "o", "\u001b[?2004l\r\r\n"]
[59.686864, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.698208, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.718816, "i", "\r"]
[59.719023, "o", "\u001b[?2004l\r\r\n"]
[59.719125, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.730853, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[59.750483, "i", "\r"]
[59.750685, "o", "\u001b[?2004l\r\r\n"]
[59.750823, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[59.762142, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[39m\u001b[0m\u001b[49m\u001b[0m\u001b[42m \u001b[30mL \u001b[0m\u001b[30m\u001b[42m\u001b[30m0.54 \u001b[32m\u001b[0m\u001b[32m\u001b[42m\u001b[48;5;244m \u001b[30m☑ \u001b[0m\u001b[30m\u001b[48;5;244m\u001b[30m7 \u001b[38;5;244m\u001b[0m\u001b[38;5;244m\u001b[48;5;244m\u001b[45m \u001b[37m⎈ \u001b[0m\u001b[37m\u001b[45m\u001b[37mminikube \u001b[0m\u001b[37m\u001b[45m\u001b[45m\u001b[0m\u001b[37m\u001b[45m\u001b[30m \u001b[30m⬢ \u001b[0m\u001b[30m\u001b[45m\u001b[30m12.3.1 \u001b[35m\u001b[0m\u001b[35m\u001b[45m\u001b[44m \u001b[0m\u001b[35m\u001b[44m\u001b[30mcode-oss-dev \u001b[34m\u001b[0m\u001b[34m\u001b[44m\u001b[42m \u001b[0m\u001b[34m\u001b[42m\u001b[30m\u001b[0m\u001b[30m\u001b[42m\u001b[30m master \u001b[49m\u001b[0m\u001b[30m\u001b[32m\u001b[39m \u001b[39m\u001b[49m\u001b[0m\u001b[K\u001b[60C\u001b[39m\u001b[0m\u001b[49m\u001b[39m\u001b[0m\u001b[49m\u001b[60D\u001b[?2004h"]
[60.412948, "i", "\u0004"]
[60.413188, "o", "\u001b[?2004l\r\r\n"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 61 KiB

@ -18,27 +18,66 @@
'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand'
(( $+__p9k_root_dir )) || typeset -gr __p9k_root_dir=${POWERLEVEL9K_INSTALLATION_DIR:-${${(%):-%x}:A:h}}
(( $+__p9k_intro )) || {
# Leading spaces before `local` are important. Otherwise Antigen will remove `local` (!!!).
# __p9k_trapint is to work around bugs in zsh: https://www.zsh.org/mla/workers/2020/msg00612.html.
# Likewise for `trap ":"` instead of the plain `trap ""`.
typeset -gr __p9k_intro_base='emulate -L zsh -o no_hist_expand -o extended_glob -o no_prompt_bang -o prompt_percent -o no_prompt_subst -o no_aliases -o no_bg_nice -o typeset_silent -o no_rematch_pcre
(( $+__p9k_trapped )) || { local -i __p9k_trapped; trap : INT; trap "trap ${(q)__p9k_trapint:--} INT" EXIT }
local -a match mbegin mend
local -i MBEGIN MEND OPTIND
local MATCH OPTARG IFS=$'\'' \t\n\0'\'
typeset -gr __p9k_intro_locale='[[ $langinfo[CODESET] != (utf|UTF)(-|)8 ]] && _p9k_init_locale && { [[ -n $LC_ALL ]] && local LC_ALL=$__p9k_locale || local LC_CTYPE=$__p9k_locale }'
typeset -gr __p9k_intro_no_locale="${${__p9k_intro_base/ match / match reply }/ MATCH / MATCH REPLY }"
typeset -gr __p9k_intro_no_reply="$__p9k_intro_base; $__p9k_intro_locale"
typeset -gr __p9k_intro="$__p9k_intro_no_locale; $__p9k_intro_locale"
}
zmodload zsh/langinfo
function _p9k_init_locale() {
if (( ! $+__p9k_locale )); then
typeset -g __p9k_locale=
(( $+commands[locale] )) || return
local -a loc
loc=(${(@M)$(locale -a 2>/dev/null):#*.(utf|UTF)(-|)8}) || return
(( $#loc )) || return
typeset -g __p9k_locale=${loc[(r)(#i)C.UTF(-|)8]:-${loc[(r)(#i)en_US.UTF(-|)8]:-$loc[1]}}
fi
[[ -n $__p9k_locale ]]
}
() {
emulate -L zsh
setopt no_hist_expand extended_glob no_prompt_bang no_prompt_subst prompt_percent no_aliases
eval "$__p9k_intro"
if (( $+__p9k_sourced )); then
prompt_powerlevel9k_setup
return
(( $+functions[_p9k_setup] )) && _p9k_setup
return 0
fi
typeset -gr __p9k_dump_file=${XDG_CACHE_HOME:-~/.cache}/p10k-dump-${(%):-%n}.zsh
if [[ -z $__p9k_dump_file(.zwc|)(#qNW) ]] && source $__p9k_dump_file 2>/dev/null && (( $+functions[_p9k_preinit] )); then
if [[ $__p9k_dump_file != $__p9k_instant_prompt_dump_file ]] && (( ! $+functions[_p9k_preinit] )) && source $__p9k_dump_file 2>/dev/null && (( $+functions[_p9k_preinit] )); then
_p9k_preinit
fi
typeset -gr __p9k_sourced=1
if [[ -w $__p9k_root_dir && -w $__p9k_root_dir/internal && -w $__p9k_root_dir/gitstatus && ${(%):-%#} == % ]]; then
local f
for f in $__p9k_root_dir/{powerlevel9k.zsh-theme,powerlevel10k.zsh-theme,internal/p10k.zsh,internal/icons.zsh,internal/configure.zsh,gitstatus/gitstatus.plugin.zsh}; do
[[ $f.zwc -nt $f ]] || zcompile $f
done
typeset -gr __p9k_sourced=13
if [[ $ZSH_VERSION == (5.<1->*|<6->.*) ]]; then
if [[ -w $__p9k_root_dir && -w $__p9k_root_dir/internal && -w $__p9k_root_dir/gitstatus ]]; then
local f
for f in $__p9k_root_dir/{powerlevel9k.zsh-theme,powerlevel10k.zsh-theme,internal/p10k.zsh,internal/icons.zsh,internal/configure.zsh,internal/worker.zsh,internal/parser.zsh,gitstatus/gitstatus.plugin.zsh,gitstatus/install}; do
[[ $f.zwc -nt $f ]] && continue
zmodload -F zsh/files b:zf_mv b:zf_rm
local tmp=$f.tmp.$$.zwc
{
# `zf_mv -f src dst` fails on NTFS if `dst` is not writable, hence `zf_rm`.
zf_rm -f -- $f.zwc && zcompile -R -- $tmp $f && zf_mv -f -- $tmp $f.zwc
} always {
(( $? )) && zf_rm -f -- $tmp
}
done
fi
fi
source $__p9k_root_dir/internal/p10k.zsh || true
builtin source $__p9k_root_dir/internal/p10k.zsh || true
}
(( $+__p9k_instant_prompt_active )) && unsetopt prompt_cr prompt_sp || setopt prompt_cr prompt_sp
(( ${#__p9k_src_opts} )) && setopt ${__p9k_src_opts[@]}
'builtin' 'unset' '__p9k_src_opts'

Loading…
Cancel
Save