Compare commits

..

169 Commits

Author SHA1 Message Date
fb2d270e2d Print build directory once selected 2025-04-09 16:50:35 +01:00
a0468b7842 Always enable CMake color diagnostics 2025-02-07 12:22:28 +00:00
8ff71513b2 Add completions for session command 2024-09-17 20:36:09 +01:00
2fea9a3795 Update build usage and error message 2024-09-17 19:43:57 +01:00
ee2dac70db Only migrate histfile if target doesn't exist 2024-09-11 20:30:01 +01:00
Kenneth Benzie (Benie)
8812ef8544 Use XDG base dir vars instead of defaults 2024-09-10 07:39:51 -07:00
1e53581d17 Add configurable session host shortnames 2024-08-23 21:40:31 +01:00
6c86d1c0cc Add session command 2024-08-21 23:00:52 +01:00
4ff10eb05e Use neovim as man pager 2024-08-03 00:09:45 +01:00
0ad3647ddc Make prompt also detect running in a container 2024-07-13 10:13:21 +00:00
b5dedf6d56 Also notify ignore fg 2024-07-08 13:41:17 +01:00
c401ecfb86 Also export BUILD_DIR to an absolute path 2024-06-21 14:16:10 +01:00
e7da727896 Also ignore watch commands 2024-06-17 19:37:57 +01:00
192659fd84 Also ignore cat & bat 2024-05-25 17:45:07 +01:00
6632715529 Teach golang xdg manners 2024-05-17 21:44:04 +01:00
37fd8b00e3 Also ignore podman notifications 2024-05-17 17:22:52 +01:00
3be19a22a0 Fix fresh prompt cleanup when options were specified 2024-05-11 22:43:27 +01:00
fda79768b7 Also ignore [i]python 2024-05-09 12:06:33 +01:00
88fdfe7a84 Properly cleanup fresh prompt theme
If `prompt <theme>` is used, prior to this patch the `fresh_line_one`
precmd hook would not be removed. This is no longer the case and cleanup
is correctly performed.
2024-05-08 23:36:21 +01:00
d0cf713a02 Also ignore zsh & bash 2024-05-08 23:00:13 +01:00
e1f16b56b0 Also notify ignore slides 2024-05-08 22:52:34 +01:00
f983c1e205 Also ignore top like tools in notify complete 2024-05-08 14:42:21 +01:00
52a9552bf7 Don't edit an autoenv on init 2024-05-06 21:52:19 +01:00
96a1272506 Remove zcurses build-dir selector 2024-05-04 10:39:10 +01:00
f7bca0102a Tweak .build-dir widget and only enable during build-dir 2024-05-04 10:31:08 +01:00
dcacb1de42 Add .build-var zle widget
Press Ctrl-B to fuzzy find all configuration CMake variables for the
current build directory. Once a variable is selected, rewrite the
command-line to set the selected CMake variable.
2024-05-03 22:44:30 +01:00
766ac3c5bf Move fzf-history-search to utilities
Also rename to .fzf-history-search to avoid it turning up in normal
command completion as an option.
2024-05-03 22:38:19 +01:00
2d56207f1e Stop disabling Ex mode 2024-05-03 22:31:32 +01:00
c20d18e62d More tweaks for build-dir fzf invocation 2024-05-03 15:59:54 +01:00
6388b076bd Add ping to notify ignore list 2024-05-03 15:06:25 +01:00
a3ca92e2a6 Search entire history with fzf in Ctrl-R 2024-05-02 23:57:44 +01:00
d12bc6f756 Make C-r work more like build-dir 2024-05-01 21:41:49 +01:00
e269e6ff8d Swap fzf args in build-dir to make more sense 2024-05-01 21:41:25 +01:00
b4ce10f1bd Tweak build-dir fzf invocation 2024-05-01 21:29:00 +01:00
1bdaa8ac08 Fix bug in build-dir with single build dir 2024-05-01 21:28:26 +01:00
47082002f9 Define fzf theme based on Kanagawa 2024-05-01 21:27:44 +01:00
ba9eba596f Limit the max size of the build-dir fzf window 2024-05-01 17:33:53 +01:00
0efb635f02 Use fzf by default for build-dir selector 2024-05-01 14:27:19 +01:00
f50db402af Also ignore man on notify command completed 2024-04-24 20:35:32 +01:00
bc3fcea5dd Also don't notify if cmatrix exits 2024-04-24 00:46:00 +01:00
29b232527a Fix sandbox create (but how did it break?!?) 2024-04-23 22:23:41 +01:00
eae2e82bdb Add glab to the list if commands to notify ignore 2024-04-20 16:58:39 +01:00
0951c445f4 Expand frequent-directory & check dir exists 2024-04-18 21:59:29 +01:00
b9373430b0 Also ignore gh for long command notifications 2024-04-16 17:40:05 +01:00
6280d90bd9 Make notify command threshold 60 seconds again 2024-04-13 16:43:57 +01:00
3accfe0bec Add install.zsh for standalone installs 2024-04-13 16:10:41 +01:00
a9fb5104ac Don't notify when select commands exit 2024-04-12 22:51:42 +01:00
6678fe0aaf Assume layouts are executable not tmux scripts 2024-04-12 20:58:25 +01:00
1ca9e4f6ae Use a bit of clang-format on git-prompt.c 2024-04-08 20:33:26 +01:00
7aa78e94d1 Notify via OSC 9 after long running command completes 2024-04-07 23:24:50 +01:00
42260925a0 Fix tmux-dcs-passthrough & notify utilities
These two have been sitting in a broken state for quite a while but I
findally RTFM and realised that the escape characters in the escape
sequence need to be doubled up in order for tmux to properly pass
through the escape sequence.
2024-04-07 23:01:02 +01:00
a6d97c1eac Add fuzzy history search with fzf 2024-04-07 19:29:01 +01:00
1bf5d10b74 Don't underline precommands 2024-04-04 21:31:43 +01:00
edf37ebf07 Use vimdebug in build-debug if nvim is available 2024-04-02 16:09:31 +01:00
18bcb6ccde Add CMAKE_EXPORT_COMPILE_COMMANDS env var 2024-03-09 13:18:25 +00:00
8a9e66db32 Add ls-iommu utility 2023-12-22 13:11:39 +00:00
1e60a5ddd5 Add hashes for ~/.config ~/.local and ~/.cache 2023-12-21 16:15:34 +00:00
4b0425b2d4 Add url command to {en,de}code text 2023-10-19 18:05:04 +01:00
5c62ff219c Remove unused tasks.yaml 2023-10-19 17:47:46 +01:00
1121b9a193 Alias wol to wakeonlan 2023-10-05 19:59:28 +01:00
0c4cd8880b Add sourcing of local ignored file 2023-06-21 22:05:57 +01:00
e30f86800d Don't check for vim when using $EDITOR 2023-06-17 15:15:00 +01:00
ad5dc95e4d Add script to list completions available for instlled commands 2023-02-18 15:06:04 +00:00
d226ac7097 Also load ~/.config/private/zshrc if present 2023-02-16 10:26:38 +00:00
e7750cb0a9 Remove chevrons from prompt 2023-02-03 11:20:21 +00:00
Benie
efbfa23241 Add new homebrew install locaiton to PATH 2022-12-10 15:59:39 +00:00
b95b365276 Don't attempt to set invalid environment variable names 2022-11-25 13:28:49 +00:00
501353a534 Add sandbox error message for invalid commands 2022-11-09 16:42:46 +00:00
02abb0960c Always use nvim for vimdebug command 2022-11-06 22:05:49 +00:00
a81465daad Only set WGETRC if $HOME/.config/wget/rc exists 2022-11-06 14:56:49 +00:00
5a33d2b5ac Add autoenv add=local subcommand
The `add=local` subcommand creates `.local/bin` if it doesn't exit and
then updates the autoenv to add it to `PATH`.
2022-10-26 20:31:51 +01:00
c691d335c0 Disable zsh-history-substring-search highlights 2022-10-11 17:16:23 +01:00
715014ed3d Specify compdump file location to compinit 2022-09-20 22:45:54 +01:00
efcea9e8a5 Change value of WGETRC 2022-09-20 22:45:42 +01:00
ea61bde858 Change sandbox prompt highlight color 2022-07-29 17:45:12 +01:00
a96aa50fbe Add --show option to build-dir command
The new option shows the current build directory, if present.
2022-07-11 13:47:05 +01:00
c61c86e979 Add ~Sandbox hashed directory 2022-06-12 21:03:54 +01:00
8790bc0c4e Use $EDITOR rather the vim directory 2022-03-31 22:13:26 +01:00
b349befbf4 Be explicit about python absolute path
One some distros `virtualenv` still uses a Python 2 executable, I always
set `python` to point to Python 3 so be explicit about getting the
absolute path to `python` when creating a `virtualenv` with `autoenv
add=py`.
2022-03-22 13:29:33 +00:00
74f2dd7dae Fix autoenv add=py .enter when run in subdirectory 2022-03-22 13:29:33 +00:00
a362ab0e04 Prefer nvim over vim for EDITOR, don't use which 2022-02-26 17:22:51 +00:00
a422ab1125 Also install ag 2022-02-19 11:13:39 +00:00
5d1f53e6b1 Add prompt support for distrobox 2022-01-14 19:51:33 +00:00
8628448d5d Also alias batcat 2022-01-07 15:55:25 +00:00
b1129a164d Don't use which, use command -v instead 2021-12-15 00:22:04 +00:00
5e6ad90a98 Fix package become & use package name lists 2021-12-15 00:21:28 +00:00
3e743d6757 Create directories 2021-12-15 00:07:02 +00:00
63b7170ccb Fix bug in almostontop that truncated long prompts
Add collection of cursor line immediately after the previous command
completes and use this when calculating the number of lines required to
move the screen in order to display only the latest prompt.
2021-12-07 17:06:39 +00:00
3978f2b1c2 Prompt to run $ command if present 2021-11-22 23:12:51 +00:00
709c65ce7b Move main.yaml to tasks.yaml 2021-11-19 22:04:42 +00:00
782589ff81 Add unzip to Debian package list 2021-11-06 15:29:37 +00:00
cc5840fd20 Start using Ansible for config management 2021-11-05 14:07:45 +00:00
014dadecb2 Only set WGETRC when ~/.config/wgetrc exists 2021-08-03 14:19:08 +01:00
b89428cd32 Extract .tar.xz properly on Linux 2021-07-27 23:52:47 +01:00
85b531e773 Use a different bat theme
Don't use Solarized Dark theme because not all `bat` installs make it
available.
2021-07-14 21:21:58 +01:00
acfd0cdee4 More escape sequence utilities
* Add `tmux-dcs-passthrough` to passthrough escape sequences tmux
  doesn't understand.
* Add `notify` to post a notification via the terminal emulator.
2021-06-17 22:46:14 +01:00
4561adf530 Teach ipython to use XDG base dirs 2021-06-17 22:46:14 +01:00
a7a8d7da8f Properly extract .tar.xz on macOS 2021-06-17 22:46:14 +01:00
20a3911ab7 Ensure pynvim is installed in autoenv's 2021-04-17 17:39:57 +01:00
ff87027cf7 Fix a long standing issue with fresh_almostontop()
Up till now setting the `-a` flag of the `prompt_fresh_setup` theme
resulted in duplicate prompts being printed to the terminal. The first,
the interactive prompt with syntax highlighting, and a second after a
call to the `clear` command without syntax highlighting. This patch
replaces the old implementation with one which does not use `clear`.
Instead it queries the terminal for the current cursor position, then
uses this to move to the bottom of the terminal, print a number of new
lines to move the stale command output off screen, and finally move
almost back to the top ready for the invoked command to print it's
output.
2021-03-20 00:03:20 +00:00
b4d22fc49f Remove guake workaround 2021-03-09 19:19:08 +00:00
b694e9cdf5 Add copy and paste aliases to clipboard commands
Interact with the clipboard through the `copy` and `paste` aliases.

`copy` is defined when:

1. An `ssh` connection is detected, using OSC-52.
2. macOS is detected, using `pbcopy`.
3. `xsel` is detected.

`paste` is define when:

1. macOS is detected, using `pbpaste`.
2. `xsel` is detected.
2021-03-02 20:04:33 +00:00
d91d6b3534 Wrap bat with additional arguments 2021-03-02 20:02:30 +00:00
309a8833c8 Make using docker on macOS nicer 2021-02-20 15:36:26 +00:00
c4a91481db Add autoenv reload subcommand
The `autoenv reload` subcommand reloads the current environment.
2021-02-09 16:47:27 +00:00
0b5fc5ad97 Set CMAKE_GENERATOR when ninja is present 2021-01-18 19:11:24 +00:00
258baeba77 Add support for Fedora 2020-12-31 15:55:53 +00:00
b6c11ecdfb Add cmake-uninstall script 2020-09-12 15:47:36 +01:00
92bacb5785 Teach various tools XDG Base Directory spec manners 2020-08-22 10:43:26 +01:00
6935281118 Fix ignore pattern for cloned plugins 2020-08-22 10:42:49 +01:00
6be7ac0e4e Fix cls alias when in tmux on iTerm2 2020-07-31 12:24:43 +01:00
a67649e844 Add frequent-directory function
`frequent-directory` exports and environment variable and creates a hash
directory with the given argument of the form `<name>=<path>`.
2020-07-30 11:24:56 +01:00
01fcdc1863 Update cls to work correctly in Windows Terminal 2020-07-17 23:10:16 +01:00
6d92a82d8c Load autoenv plugin later to make build-dir ready 2020-07-08 16:06:14 +01:00
81657d6f50 Update vim version check for enabling vimdebug 2020-02-06 13:36:05 +00:00
db124794ef Add unversioned brew python links to PATH
The `python` Homebrew package installs unversioned links to Python 3
executables in `/usr/local/opt/python/libexec/bin`. Add this directory
to the `PATH` environment variable when it's present.
2020-01-16 23:25:09 +00:00
ec8675fa86 Use XDG base dirs for ccache 2020-01-14 10:54:24 +00:00
9164432cc2 Don't store less history 2019-12-10 13:26:36 +00:00
39a4d589b3 Change default pylint data storage location 2019-12-10 12:16:44 +00:00
6eec18c98e Set EDITOR to vim if it exists 2019-11-10 13:47:09 +00:00
1cf7e1dcaf Don't send git clone to /dev/null 2019-10-05 19:12:21 +01:00
908ef3efa5 Add autoenv add=py to streamline virtualenvs 2019-10-05 19:11:26 +01:00
4252d06e65 Fix ccache PATH on Manjaro 2019-10-01 22:50:20 +01:00
9854518c76 Fix Home/End on Arch where $key is not auto setup 2019-09-18 22:01:12 +01:00
aab16bd355 Add zsh pacman package 2019-09-17 20:41:26 +01:00
4812d5e564 Don't prompt for sandbox authorization
Automatically approve `.enter`/`.exit` scripts when creating or renaming
sandboxes.
2019-09-10 20:13:10 +01:00
610cae2f57 Check for tmux session in prompt
Before invoking the `tmux` command to unset the vim pane variable first
check that a `tmux` session exists.
2019-09-05 11:22:47 +01:00
a3832ff49e Automatically authorize sandbox .enter/.exit 2019-09-03 21:06:48 +01:00
a2509a88b5 Add git clone support to sandbox create
Partially address #13 by adding the `--git <repo>` option to `sandbox
create`. This enables the quick cloning of a remote repository instead
of doing the tedious dance of creating a sandbox, cloning the remote
repo, deleting the sandbox repo them moving the `.git` directory before
doing a `git reset --hard HEAD`.

Additionally, improve the error messages for all `sandbox` commands,
clean up the completions a little, and use a consistent style in the
scripts.
2019-08-29 00:56:26 +01:00
8997d9cae0 Add zsh-completions
The [zsh-completions](https://github.com/zsh-users/zsh-completions) repo
contains completions for various commands but not all of these are
useful so the `update-completion-links.zsh` script inspects the `PATH`
to determine which of the completions should be symlinked to
`~/.local/share/zsh/site-functions` which resides on the `fpath`.
2019-08-23 21:11:56 +01:00
8526bdb4e3 Export CTEST_OUTPUT_ON_FAILURE=1
When a `ctest` run contains a failed test, actually print the `stdout`
and `stderr` output.
2019-08-22 21:32:15 +01:00
47f821e80a Don't unset tmux option when not in tmux 2019-08-22 21:31:56 +01:00
fcae9e885e Unset the vim navigation flag on prompt redraw
Make using the `@vim$TMUX_PANE` window flag much more robust by
unsetting it every time the zsh prompt is drawn and setting it again
using a `FocusGained` `autocmd` in vim. This removes the need for the
hacky check for zsh in the conditional defined in the `in_vim` variable.
2019-08-16 21:57:33 +01:00
7a8cf750bd Don't apply Begin/End key fix on macOS 2019-06-07 20:07:32 +01:00
7a0c73dabb autoenv: Automatically update autoenv during edit
Fixes #18 by exiting the autoenv before invoking vim for editing the
`.enter` and `.exit` scripts, then enters the autoenv after vim exits.
This reduces the number of steps required to update the current autoenv
state.
2019-05-30 19:22:04 +01:00
0da54801e4 Fix HOME and END key bindings in zle 2019-05-22 10:51:54 +01:00
4b2b0d38c7 Drop fast-syntax-highlighting due to being wrong
When using `git` aliases, the alias would be highlighted red by
fast-syntax-highlighting even though the alias is valid so remove it and
go back to zsh-syntax-highlighting instead.
2019-05-02 12:10:37 +01:00
a095e9383c Escape * in vimdebug before passing to debug
With `setopt nonomatch` unescaped `*` can be used in command arguments
however when passing command arguments to `vimdebug` the `*` _should_
be escaped so that the debugger e.g. `gdb` will correctly invoke the
program where `setopt nonomatch` does not apply.
2019-04-18 10:41:12 +01:00
6bd2b8f0cc Add fzf to install 2019-03-24 16:24:31 +00:00
036f0255f8 Improve readability of posix exit codes in prompt 2019-03-13 11:12:37 +00:00
b842fb6437 Add utilities plugin with archive extract command 2019-01-21 12:47:09 +00:00
ce65ae40bc Add weather alias to curl wttr.in 2019-01-08 12:31:27 +00:00
1e46ca4633 Fix sandbox not using .enter 2018-11-30 19:45:25 +00:00
256cd06e5a build-dir now exports build_dir envvar
In addition to setting the `~build` hashed directory, also export the
`build_dir` environment variable to enable commands like this:

```
cmake . -B$build_dir
```
2018-11-07 10:58:04 +00:00
9037d2dd41 Default to using VIM's termdebug plugin for debug
VIM 8.1 added the optional plugin termdebug which integrates gdb
with separate buffers for source, output, and gdb console. This adds the
`vimdebug` command which enables the termdebug plugin and executes the
`:TermdebugCommand` with the given arguments.
2018-11-07 10:53:14 +00:00
7b87688885 Use pinentry-curses for lastpass-cli on Debian 2018-10-31 17:33:16 +00:00
352a1c3f12 Fix git-prompt not resetting bold for untracked 2018-10-15 11:48:23 +01:00
8b099b103b Add ~/Projects hashed directory 2018-09-13 10:28:51 +01:00
9eee926c56 Move variable decl into for loop in git-prompt.c 2018-09-12 09:53:07 +01:00
29fb84b995 Disable GCC warning for fread in git-prompt.c 2018-09-12 09:48:44 +01:00
5f2c5b58da Move entire git-prompt to C 2018-09-11 20:56:27 +01:00
2740f9bc8d Add paging to sandbox list command 2018-09-05 20:37:10 +01:00
2589b63023 Fix build-dir not stooping on error, remove build-dir.py 2018-09-03 11:32:58 +01:00
6a4531423e Make virtualenv and docker prompt vars local 2018-09-01 10:39:09 +01:00
8819cd4d18 Make C-S work in vim again 2018-08-30 22:48:26 +01:00
585925df38 Fix vi-mode grips
Tips from [zsh-vimto](https://github.com/laurenkt/zsh-vimto).

* Remove delay when changing mode
* Enable backspace when returning to viins from vicmd mode
2018-08-30 22:44:22 +01:00
2ac97afdd1 Update options
Fix spellings of various options, enable some new options found in
[https://github.com/willghatch/zsh-saneopt](zsh-saneopt).
2018-08-30 22:30:11 +01:00
f24253b8c1 Remove use of RPS1
Following on from the previous commit, use of `RPS1` results in the
prompt being redrawn when the terminal gets narrower, this makes the
line drawn by `fresh_line_one` scroll off the screen. By removing any
use of `RPS1` this behaviour goes away.
2018-08-30 21:57:18 +01:00
df819f58a8 Update fresh prompt
* When a command fails, don't print the error code at the end of the
  first line but directly after the git stats.
* Remove `cr` from `prompt_opts` since there is no longer a new line in
  `PS1`, combined with above, this result in no new lines being inserted
  when the terminal becomes narrower e.g. a horizontal tmux split.
* Remove `fresh_visible_length` function and instead use the length of
  string variables e.g. `${#userhost}`.
2018-08-30 21:04:05 +01:00
c636dd078c Update sandbox to use .enter and .exit 2018-08-28 22:15:33 +01:00
0992b65d17 Don't explicitly add python to PATH
After fixing the macOS `/etc/zprofile` issue rewriting the `PATH`
environment variable it is no longer necessary to explicitly add
`/usr/local/opt/python/libexec/bin` to `PATH` since Homebrew installed
python 2.x is installed in `/usr/local/bin` and is used by default.
2018-08-28 21:58:22 +01:00
9e9c43a0cf Fix error in build-dir when --build is not set 2018-08-28 14:44:19 +01:00
0ab04406ec Fix macOS PATH being rewritten in /etc/zprofile
macOS is obnoxious and overwrites the PATH from a users ~/.zshenv, which is
sourced first, in /etc/zprofile by calling `/usr/libexec/path_helper -s` so
this is required so that PATH is once again set to the desired value.
2018-08-26 20:19:12 +01:00
e17ff47d5e Only load layout when inside tmux 2018-08-26 19:11:29 +01:00
ff8bb3e4ab Change layout path to ~/.local/share/tmux/layouts 2018-08-26 18:39:02 +01:00
31d06e0f19 Add sandbox directory color to fresh_line_one 2018-08-26 15:37:30 +01:00
7bb6a459ee Fix autoenv's use of zstat 2018-08-25 15:45:11 +01:00
9e4c984822 Fix chsh to work on macOS 2018-08-24 18:26:13 +01:00
9af452a8e2 Update readme file 2018-08-24 12:29:15 +01:00
27 changed files with 1447 additions and 545 deletions

6
$ Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env zsh
read -p "Are you sure? [y/N]: " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
exec "$@"
fi

View File

@ -1,31 +0,0 @@
---
- location: ~/.config/zsh
- apt:
- zsh
- zsh-doc
- brew:
- zsh
- command:
- install: sudo chsh $USER -s `which zsh`
remove: sudo chsh $USER -s `which bash`
- symlink:
- {src: zlogin, dst: ~/.zlogin}
- {src: zlogout, dst: ~/.zlogout}
- {src: zprofile, dst: ~/.zprofile}
- {src: zshenv, dst: ~/.zshenv}
- {src: zshrc, dst: ~/.zshrc}
- src: prompt_fresh_setup
dst: ~/.local/share/zsh/site-functions/prompt_fresh_setup
- src: build/_build-dir
dst: ~/.local/share/zsh/site-functions/_build-dir
- src: sandbox/_sandbox
dst: ~/.local/share/zsh/site-functions/_sandbox
- src: layout/_layout
dst: ~/.local/share/zsh/site-functions/_layout
- src: notes/_note
dst: ~/.local/share/zsh/site-functions/_note
- repo:
- https://github.com/zsh-users/zsh-autosuggestions.git
- https://github.com/zsh-users/zsh-history-substring-search.git
- https://github.com/zdharma/fast-syntax-highlighting.git
- message: zsh will be the default prompt after next login

4
.gitignore vendored
View File

@ -1,2 +1,4 @@
# Ignore all plugin files in subdirectories # Ignore all plugin files in subdirectories
*/* zsh-*/
local
zsh*.local

View File

@ -2,15 +2,13 @@
<!-- TODO: GIF --> <!-- TODO: GIF -->
## [conduit][conduit] ## Ansible
Simple, local, configuration manager. To install this Zsh configuration:
Installation of the configuration files in this repository is orchestrated by ```console
[conduit][conduit] as defined in the [`.conduit.yaml`](.conduit.yaml) file. This $ ansible-playbook main.yaml --ask-become-pass
includes [Zsh][zsh] package installs, setting [Zsh][zsh] as the users default ```
shell, and symbolic linking file such as [`zshrc`](zshrc) to `~/.zshrc`, and
cloning plugin repositories. The repository is cloned to `~/.config/zsh`.
## Prompt ## Prompt
@ -51,10 +49,25 @@ display. This results in no noticeable lag when redrawing the prompt.
Plugins are sourced manually and their git repositories tracked by Plugins are sourced manually and their git repositories tracked by
[conduit][conduit], no plugin manager is used. [conduit][conduit], no plugin manager is used.
* [zsh-autosuggestions][zsh-autosuggestions] Fish-like autosuggestions for zsh.
* [zsh-syntax-highlighting][syntax] Fish shell like syntax highlighting for Zsh. * [zsh-syntax-highlighting][syntax] Fish shell like syntax highlighting for Zsh.
* [zsh-history-substring-search][search] Zsh port of the Fish shell's history * [zsh-history-substring-search][search] Zsh port of the Fish shell's history
search. search.
In addition to third party plugins the following are custom plugins residing in
this repository.
* [autoenv](autoenv/autoenv.zsh) is a inspired by [zsh-autoenv][zsh-autoenv] but
simplified by removing customization points and using a less intrusive UI.
* [build](build/build.plugin.zsh) is a collection of commands to make it easier
to build projects focuses on C/C++ development.
* [sandbox](sandbox/sandbox.plugin.zsh) is a command which sets up a throw away
directory for quickly testing ideas.
* [layout](layout/layout.plugin.zsh) is a command which setups up `tmux` panes
in a window with scripts.
* [notes](notes/notes.plugin.zsh) is a command to quickly edit markdown note
files.
## Environment & Settings ## Environment & Settings
The bulk of, if not all, configuration occurs in [`zshenv`](zshenv) and The bulk of, if not all, configuration occurs in [`zshenv`](zshenv) and
@ -135,6 +148,8 @@ Various aliases are defined at the end of [zshrc](zshrc) for convenience.
[zsh]: https://www.zsh.org/ [zsh]: https://www.zsh.org/
[git]: https://git-scm.com/ [git]: https://git-scm.com/
[git-prompt]: https://github.com/olivierverdier/zsh-git-prompt [git-prompt]: https://github.com/olivierverdier/zsh-git-prompt
[zsh-autosuggestions]: https://github.com/zdharma/fast-syntax-highlighting
[zsh-autoenv]: https://github.com/Tarrasch/zsh-autoenv
[syntax]: https://github.com/zsh-users/zsh-syntax-highlighting [syntax]: https://github.com/zsh-users/zsh-syntax-highlighting
[search]: https://github.com/zsh-users/zsh-history-substring-search [search]: https://github.com/zsh-users/zsh-history-substring-search
[vim-mode]: https://github.com/sharat87/zsh-vim-mode [vim-mode]: https://github.com/sharat87/zsh-vim-mode

View File

@ -16,6 +16,9 @@ _autoenv() {
init:'add .enter and .exit scripts in current directory' init:'add .enter and .exit scripts in current directory'
edit:'edit .enter and .exit scripts in current directory' edit:'edit .enter and .exit scripts in current directory'
deinit:'remove .enter and .exit scripts in current directory' deinit:'remove .enter and .exit scripts in current directory'
reload:'reload the current environment'
add=local:'add .local/bin to PATH'
add=py:'add Python virtualenv to the autoenv'
) )
_describe -t commands command commands && ret=0 ;; _describe -t commands command commands && ret=0 ;;
esac esac

View File

@ -12,7 +12,7 @@ autoenv() {
case "$cmd" in case "$cmd" in
-h|--help) # Display help. -h|--help) # Display help.
echo "\ echo "\
usage: autoenv [-h] {init,edit,deinit} usage: autoenv [-h] {init,edit,deinit,reload,add=py}
options: options:
-h, --help show this help message and exit -h, --help show this help message and exit
@ -20,73 +20,139 @@ options:
commands: commands:
init add .enter and .exit scripts in current directory init add .enter and .exit scripts in current directory
edit edit .enter and .exit scripts in current directory edit edit .enter and .exit scripts in current directory
deinit remove .enter and .exit scripts in current directory" deinit remove .enter and .exit scripts in current directory
reload reload the current environment
add=local add .local/bin to PATH
add=py add Python virtualenv to the autoenv"
;; ;;
init) # Create enter and exit scripts in current directory. init) # Create .enter and .exit scripts in current directory.
if [ -f $PWD/.enter ] || [ -f $PWD/.exit ]; then if [ -f $PWD/.enter ] || [ -f $PWD/.exit ]; then
echo '.enter or .exit already exists'; return 1 echo '.enter or .exit already exists'; return 1
fi fi
# Create then edit enter and exit scripts. # Create the .enter and .exit scripts.
touch .enter .exit && autoenv edit touch .enter .exit
# If enter script exists, authorize it. # If enter script exists, authorize it.
[ -f $PWD/.enter ] && _autoenv_authorized $PWD/.enter yes [ -f $PWD/.enter ] && _autoenv_authorized $PWD/.enter yes
# If exit script exists, authorize it. # If exit script exists, authorize it.
[ -f $PWD/.exit ] && _autoenv_authorized $PWD/.exit yes [ -f $PWD/.exit ] && _autoenv_authorized $PWD/.exit yes
# Enter the new autoenv. # Enter the autoenv.
_autoenv_enter $PWD ;; _autoenv_enter $PWD
;;
edit) # Edit enter and exit scripts in current directory. edit) # Edit .enter and .exit scripts in current directory.
if ! [ -f $PWD/.enter ] || ! [ -f $PWD/.exit ]; then if ! [ -f $PWD/.enter ] || ! [ -f $PWD/.exit ]; then
echo '.enter or .exit not found'; return 1 echo '.enter or .exit not found'; return 1
fi fi
# If vim exists, edit enter and exit scripts. # Exit the autoenv before editing.
if which vim &> /dev/null; then _autoenv_exit $PWD
vim -p $PWD/.enter $PWD/.exit if $EDITOR -p $PWD/.enter $PWD/.exit; then
else # If enter script exists, authorize it.
echo 'vim not found'; return 1 [ -f $PWD/.enter ] && _autoenv_authorized $PWD/.enter yes
fi ;; # If exit script exists, authorize it.
[ -f $PWD/.exit ] && _autoenv_authorized $PWD/.exit yes
fi
# Enter the autoenv.
_autoenv_enter $PWD
;;
deinit) # Remove enter and exit scripts in current directory. deinit) # Remove .enter and .exit scripts in current directory.
if [ -f $PWD/.enter ] || [ -f $PWD/.exit ]; then if ! [ -f $PWD/.enter ] || ! [ -f $PWD/.exit ]; then
# Prompt user to confirm removal of enter and exit scripts. echo '.enter or .exit not found'; return 1
while true; do fi
read "answer?Are you sure [y/N]? " # Prompt user to confirm removal of enter and exit scripts.
case "$answer" in while true; do
y|Y|yes) read "answer?Are you sure [y/N]? "
# Remove enter and exit scripts if they exist. case "$answer" in
[ -f $PWD/.enter ] && rm $PWD/.enter y|Y|yes)
[ -f $PWD/.exit ] && rm $PWD/.exit # Exit the autoenv.
break ;; _autoenv_exit $PWD
*) break ;; # Remove enter and exit scripts if they exist.
esac [ -f $PWD/.enter ] && rm $PWD/.enter
done [ -f $PWD/.exit ] && rm $PWD/.exit
else break ;;
echo '.enter and .exit not found'; return 1 *) break ;;
fi ;; esac
done
;;
reload) # Reload the current environment
if ! [ -f $PWD/.enter ] || ! [ -f $PWD/.exit ]; then
echo '.enter or .exit not found'; return 1
fi
# Exit the autoenv before editing.
_autoenv_exit $PWD
# Enter the autoenv.
_autoenv_enter $PWD
;;
add=local) # Add .local/bin to PATH
if ! [ -f $PWD/.enter ] || ! [ -f $PWD/.exit ]; then
echo '.enter or .exit not found'; return 1
fi
_autoenv_exit $PWD
# Create .local/bin if not present
if ! [ -d $PWD/.local/bin ]; then
mkdir -p $PWD/.local/bin
fi
# On enter: store PATH and insert .local/bin
echo 'OLDPATH=$PATH' >> .enter
echo 'PATH=$PWD/.local/bin:$PATH' >> .enter
# On exit: reset PATH
echo 'PATH=$OLDPATH' >> .exit
echo 'unset OLDPATH' >> .exit
# Authorize modified autoenv
_autoenv_authorized $PWD/.enter yes
_autoenv_authorized $PWD/.exit yes
_autoenv_enter $PWD
;;
add=py) # Add Python virtualenv to the sandbox
if ! [ -f $PWD/.enter ] || ! [ -f $PWD/.exit ]; then
echo '.enter or .exit not found'; return 1
fi
_autoenv_exit $PWD
virtualenv -p `command -v python` .local
echo 'source ${0:a:h}/.local/bin/activate' >> .enter
echo 'deactivate' >> .exit
_autoenv_authorized $PWD/.enter yes
_autoenv_authorized $PWD/.exit yes
_autoenv_enter $PWD
pip install pynvim
;;
*) # Invalid arguments, show help then error. *) # Invalid arguments, show help then error.
echo "invalid arguments: $@" echo "invalid arguments: $@"
autoenv --help autoenv --help
return 1 ;; return 1
;;
esac esac
} }
# Global entered directories array. # Global entered directories array.
_autoenv_entered=() _autoenv_entered=()
# Load zstat from stat module for inspecting modified time.
zmodload -F zsh/stat b:zstat
# Check if the given file is authorized, if not prompt the user to authorize, # Check if the given file is authorized, if not prompt the user to authorize,
# ignore, or view the file. Authorized files and their modified times are # ignore, or view the file. Authorized files and their modified times are
# stored in the ~/.cache/autoenv/authorized file to make authorization # stored in the $XDG_STATE_HOME/autoenv/authorized file to make authorization
# persistent. # persistent.
_autoenv_authorized() { _autoenv_authorized() {
local file=$1 yes=$2 local file=$1 yes=$2
# If autoenv cache directory does not exist, create it. # If autoenv state directory does not exist, create it.
! [ -d ~/.cache/autoenv ] && mkdir -p ~/.cache/autoenv ! [ -d ${XDG_STATE_HOME:-$HOME/.local/state}/autoenv ] && \
mkdir -p ${XDG_STATE_HOME:-$HOME/.local/state}/autoenv
# Migrate from cache to state directory
[ -f $HOME/.cache/autoenv/authorized ] && \
mv $HOME/.cache/autoenv/authorized \
${XDG_STATE_HOME:-$HOME/.local/state}/autoenv/authorized
# If the authorized file does not exist, create it. # If the authorized file does not exist, create it.
! [ -f ~/.cache/autoenv/authorized ] && touch ~/.cache/autoenv/authorized ! [ -f ${XDG_STATE_HOME:-$HOME/.local/state}/autoenv/authorized ] && \
touch ${XDG_STATE_HOME:-$HOME/.local/state}/autoenv/authorized
# Load the authorized file into a map of authorized key value pairs. # Load the authorized file into a map of authorized key value pairs.
typeset -A authorized=(`cat ~/.cache/autoenv/authorized`) typeset -A authorized=(`cat ${XDG_STATE_HOME:-$HOME/.local/state}/autoenv/authorized`)
# If the file has been removed, return. # If the file has been removed, return.
! [ -f $file ] && return 1 ! [ -f $file ] && return 1
# If the given file has been authorized, i.e. the modified time matches that # If the given file has been authorized, i.e. the modified time matches that
@ -108,7 +174,7 @@ _autoenv_authorized() {
# Add file to the authorized map. # Add file to the authorized map.
authorized[$file]=$modified_time authorized[$file]=$modified_time
# Store authorized map in authorized file. # Store authorized map in authorized file.
echo ${(kv)authorized} > ~/.cache/autoenv/authorized echo ${(kv)authorized} > ${XDG_STATE_HOME:-$HOME/.local/state}/autoenv/authorized
} }
# Source an enter script and add its directory to the global entered # Source an enter script and add its directory to the global entered

View File

@ -1,6 +1,7 @@
#compdef build-dir #compdef build-dir
_arguments \ _arguments \
'(-h --help)'{-h,--help}'[]' \ '(-h --help)'{-h,--help}'[show this help message and exit]' \
'(-s --show)'{-s,--show}'[show the current build directory]' \
'--build[invoke a build after selection]' \ '--build[invoke a build after selection]' \
'1:directory:_files' '1:directory:_files'

View File

@ -1,46 +0,0 @@
#!/usr/bin/env python
"""The pick_build_dir command selects a build directory
The pick_build_dir command scans the current directory for directories starting
with ``build`` and prompts the user to select one from the list.
"""
from __future__ import print_function
from argparse import ArgumentParser
from os import listdir
from os.path import curdir, isdir
from sys import stderr
from pick import Picker
def main():
"""Main entry point to build-dir.py script."""
parser = ArgumentParser()
parser.add_argument('output')
parser.add_argument('--default', action='store_true')
args = parser.parse_args()
directories = []
for directory in listdir(curdir):
if isdir(directory) and directory.startswith('build'):
directories.append(directory)
if len(directories) == 0:
print('no build directories found', file=stderr)
exit(1)
build_dirs = sorted(directories)
if args.default:
build_dir = build_dirs[0]
else:
picker = Picker(build_dirs, 'Select a build directory:')
picker.register_custom_handler(ord(''), lambda _: exit(1))
build_dir, _ = picker.start()
with open(args.output, 'w') as output:
output.write(build_dir)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
exit(130)

View File

@ -7,21 +7,31 @@ alias build="build-dir --build"
# Detect installed debugger and set the `debug` alias to debug a program with # Detect installed debugger and set the `debug` alias to debug a program with
# command line arguments. # command line arguments.
if [ `uname` = Linux ]; then if [ `uname` = Linux ]; then
if which cgdb &> /dev/null; then autoload -U regexp-replace
alias debug='cgdb --args' function vimdebug() {
elif which gdb &> /dev/null; then # For each item in $* replace * and \* and then replace \ with \\
local args=()
for arg in "$@"; do
regexp-replace arg '\*' '\\*'
args+=($arg)
done
nvim "+packadd termdebug" "+TermdebugCommand $args"
}
if command -v nvim &> /dev/null; then
alias debug=vimdebug
elif command -v gdb &> /dev/null; then
alias debug='gdb --args' alias debug='gdb --args'
fi fi
elif [ `uname` = Darwin ]; then elif [ `uname` = Darwin ]; then
which lldb &> /dev/null && \ command -v lldb &> /dev/null && \
alias debug='lldb --' alias debug='lldb --'
fi fi
# Interactively choose a `~build` directory for `build` to build. # Interactively choose a `~build` directory for `build` to build.
build-dir() { build-dir() {
local usage='usage: build-dir [-h] [--build] [<directory>]' local usage='usage: build-dir [-h] [-s] [--build] [<directory>]'
local -a help do_build local -a help show do_build
zparseopts -D h=help -help=help -build=do_build zparseopts -D h=help -help=help s=show -show=show -build=do_build
if [[ -n $help ]]; then if [[ -n $help ]]; then
cat << EOF cat << EOF
$usage $usage
@ -33,134 +43,128 @@ positional arguments:
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
-s, --show show the current build directory
--build invoke a build after selection --build invoke a build after selection
EOF EOF
return return
fi fi
error() { echo "\e[31merror:\e[0m $1"; return 1 } error() { echo "\e[31merror:\e[0m $1" }
local build_dir warning() { echo "\e[33mwarning:\e[0m $1" }
if [[ -n $show ]]; then
if [[ ! -n $build_dir ]]; then
error "build directory not set"
return 1
else
echo "$build_dir"
return
fi
fi
local local_build_dir
if [[ ${#*} -gt 1 ]]; then if [[ ${#*} -gt 1 ]]; then
echo $usage echo $usage
error "unexpected position arguments: ${*[2,${#*}]}" error "unexpected positional arguments: ${*[2,${#*}]}"; return 1
elif [[ ${#*} -eq 1 ]]; then elif [[ ${#*} -eq 1 ]]; then
build_dir=${*[1]} if [[ ! -d ${*[1]} ]]; then
[[ ! -d $build_dir ]] && \ warning "directory not found: ${*[1]}"
error "directory not found: $build_dir" else
local_build_dir=${*[1]}
fi
fi fi
# If <directory> was not set begin selection # If <directory> was not set begin selection
if [[ -z $build_dir ]]; then if [[ -z $local_build_dir ]]; then
# Find build directories # Find build directories
local -a build_dirs local -a local_build_dirs
for entry in `ls -A`; do for entry in `ls -A`; do
[ -d $entry ] && [[ $entry =~ build* ]] && \ [ -d $entry ] && [[ $entry =~ build* ]] && \
build_dirs+=${entry/\//} local_build_dirs+=${entry/\//}
done done
# Interactively select a build directory if more than 1 found # Interactively select a build directory if more than 1 found
integer index=0 integer index=0
if [[ ${#build_dirs} -eq 0 ]]; then if [[ ${#local_build_dirs} -eq 0 ]]; then
error "no build directories found" error "no build directories found"; return 1
elif [[ ${#build_dirs} -gt 1 ]]; then elif [[ ${#local_build_dirs} -eq 1 ]]; then
zmodload zsh/curses && { local_build_dir=${local_build_dirs[1]}
# Get the size of the terminal elif [[ ${#local_build_dirs} -gt 1 ]]; then
local size=`stty size` # Use fzf to select a build directory
integer height=${size% *} local max=$(( $( tput lines ) / 2 ))
integer width=${size#* } local best=$(( ${#local_build_dirs} + 4 ))
local_build_dir=$(
# Create the window and hide the cursor printf '%s\n' "${local_build_dirs[@]}" |
zcurses init fzf --layout=reverse --tac --info=hidden --border=rounded \
zcurses addwin build-dir $height $width 0 0 --cycle --height=$(( $best < $max ? $best : $max ))
)
# Hide the cursor for zcurses, trap SIGINT to ensure cleanup in if [[ $? -ne 0 ]]; then
# always-list occurs below return 1
tput civis; trap 'return 130' INT fi
# Enter display loop
local key keypad
while (( 1 )); do
zcurses clear build-dir
# Add the prompt text
zcurses move build-dir 1 1
zcurses string build-dir 'Select a build directory:'
# Add the selections text
for (( i = 0; i < ${#build_dirs}; i++ )); do
integer line=$i+3
zcurses move build-dir $line 1
[[ $index -eq $i ]] &&
zcurses string build-dir "* " ||
zcurses string build-dir " "
zcurses string build-dir ${build_dirs[$i+1]}
done
# Display the text the and wait for input
zcurses refresh build-dir
zcurses input build-dir key keypad
# Handle user input
case $key in
(UP|k|$'\C-P')
[[ $index -gt 0 ]] && index=$index-1 ;;
(DOWN|j|$'\C-N')
[[ $index -lt ${#build_dirs}-1 ]] && index=$index+1 ;;
(ENTER|$'\n')
break ;;
esac
done
} always {
# Restore the cursor and cleanup zcurses
tput cvvis; tput cnorm
zcurses delwin build-dir
zcurses end
}
fi fi
fi fi
# On success setup the build directory for use # If `build.ninja` exists in alias `ninja`, return.
if [[ $? -eq 0 ]]; then local build
# Set the build directory from selection if empty [ -f $local_build_dir/build.ninja ] && \
[[ -z $build_dir ]] && \ build="ninja -C $local_build_dir"
build_dir=${build_dirs[$index+1]}
# If `build.ninja` exists in alias `ninja`, return. # If `Makefile` exists in alias `make`, return.
local build if [ -f $local_build_dir/Makefile ]; then
[ -f $build_dir/build.ninja ] && \ [ `uname` = Darwin ] && \
build="ninja -C $build_dir" local cpu_count=`sysctl -n hw.ncpu` ||
local cpu_count=`grep -c '^processor' /proc/cpuinfo`
# If `Makefile` exists in alias `make`, return. build="make -j $cpu_count -C $local_build_dir"
if [ -f $build_dir/Makefile ]; then
[ `uname` = Darwin ] && \
local cpu_count=`sysctl -n hw.ncpu` ||
local cpu_count=`grep -c '^processor' /proc/cpuinfo`
build="make -j $cpu_count -C $build_dir"
fi
# If the build variable is not defined the command could not be determined
if [ -z $build ]; then
echo "\e[33mwarning:\e[0m build command detection failed: $build_dir"
# Prompt user to enter a build command
vared -p 'enter comand: ' build
fi
# Redefine the `build` alias and update the `~build` hash directory
alias build="$build"
hash -d build=$build_dir
# If `--build` is specified then evaluate the command.
[[ -n $do_build ]] && eval build
fi fi
# If the build variable is not defined the command could not be determined
if [ -z $build ]; then
warning "build command detection failed: $local_build_dir"
# Prompt user to enter a build command
vared -p 'enter comand: ' build
fi
# Redefine the `build` alias and update the `~build` hash directory
alias build="$build"
hash -d build=$local_build_dir
export build_dir=$local_build_dir
export BUILD_DIR=$PWD/$local_build_dir
echo "$build_dir"
# If `--build` is specified then evaluate the command.
if [[ -n $do_build ]]; then
eval build
fi
# Bind C-B to fuzzy find & complete cmake variables.
zle -N .build-var
bindkey '^B' .build-var
} }
# Build then run a target residing in `~build/bin`. # Build then run a target residing in `~build/bin`.
build-run() { build-run() {
local target=$1; shift 1 local target=$1; shift 1
eval build $target && ~build/bin/$target $* eval build $target && ~build/bin/$target "$@"
} }
# Build then debug a target residing in `~build/bin`. # Build then debug a target residing in `~build/bin`.
build-debug() { build-debug() {
local target=$1; shift 1 local target=$1; shift 1
eval build $target && debug ~build/bin/$target $* eval build $target && debug ~build/bin/$target "$@"
}
# Fuzzy find CMake variables, select one to set the variable via a command.
.build-var() {
local var=$(
cat $build_dir/CMakeCache.txt |
grep --color=never -Ex '^\w+:\w+=.*$' |
fzf --layout=reverse --info=hidden --border=rounded \
--cycle --height=50%
)
if [[ -n "$var" ]]; then
if [[ "$BUFFER" = "cmake"* ]]; then
BUFFER="$BUFFER-D$var"
else
BUFFER="cmake -B\$build_dir -D$var"
fi
zle end-of-line
fi
zle reset-prompt
} }

105
cmake-uninstall Executable file
View File

@ -0,0 +1,105 @@
#!/usr/bin/env python3
"""Uninstall a previously installed CMake installation.
Read the ``install_manifest.txt`` file from a CMake build directory
which has been installed then delete the files, and optionally the empty
subdirectories of the install prefix, specified within.
"""
from argparse import ArgumentParser, RawDescriptionHelpFormatter
from os import listdir, path, remove, rmdir
from sys import stderr
def uninstall(build_dir, recursive=False):
"""Uninstall a previoulsy installed CMake installation.
Arguments:
:build_dir: Path to the build directory containing the
``install_manifest.txt`` of files to uninstall.
:recursive: Boolean flag to enable recursively uninstall empty
directories up to the install prefix specified in ``CMakeCache.txt``.
"""
# Get the list of installed files from the install_manifest.txt
install_manifest_path = path.join(build_dir, 'install_manifest.txt')
with open(install_manifest_path, 'r') as install_manifest_file:
install_manifest = sorted(install_manifest_file.read().splitlines())
# Delete files from the filesystem
removed = []
directories = []
for entry in install_manifest:
directories.append(path.dirname(entry))
if path.isfile(entry):
remove(entry)
removed.append(entry)
if recursive:
# Get the install prefix from CMakeCache.txt
cmakecache_path = path.join(build_dir, 'CMakeCache.txt')
with open(cmakecache_path, 'r') as cmakecache_file:
for line in cmakecache_file.read().splitlines():
if line.startswith('CMAKE_INSTALL_PREFIX'):
prefix = path.normpath(line.split('=')[1])
break
while True:
# Remove duplicates from list
directories = list(dict.fromkeys(directories))
# Find directories in list which are not empty
not_empty = []
for index, entry in enumerate(directories):
if listdir(entry):
not_empty.append(index)
# Remove directories which are not empty from list
for index in reversed(not_empty):
del directories[index]
# Delete directories from the filesystem
to_del = []
to_append = []
for index, entry in enumerate(directories):
rmdir(entry)
removed.append(entry)
to_del.append(index)
parent = path.dirname(entry)
# Add parent directory to the list when not the install prefix
if path.normpath(parent) != prefix:
to_append.append(parent)
# Remove deleted directories from list
for index in reversed(to_del):
del directories[index]
directories += to_append
# Exit loop when no more directories in list
if not directories:
break
return removed
def main():
"""Command line entry point."""
cli = ArgumentParser(description=__doc__,
formatter_class=RawDescriptionHelpFormatter)
cli.add_argument('--version', action='version', version='%(prog)s 0.1.0')
cli.add_argument('-q',
'--quiet',
action='store_true',
help="don't print removed entries to stdout")
cli.add_argument('-r',
'--recursive',
action='store_true',
help='recursively remove empty directories')
cli.add_argument('build_dir',
help='path to the installed CMake build directory')
args = cli.parse_args()
try:
removed = uninstall(args.build_dir, recursive=args.recursive)
if not args.quiet:
for entry in removed:
print(f'-- Uninstalling: {entry}')
except FileNotFoundError as error:
print(f'error: file not found: {error.filename}', file=stderr)
exit(1)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
exit(130)

204
git-prompt.c Normal file
View File

@ -0,0 +1,204 @@
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if __linux__
#include <sys/wait.h>
#endif
#ifdef DEBUG
#define check(CONDITION) \
if (CONDITION) { \
fprintf(stderr, "error: %s: %d: %s\n", __FILE__, __LINE__, #CONDITION); \
exit(0); \
}
#else
#define check(CONDITION) \
if (CONDITION) { \
exit(0); \
}
#endif
typedef struct process {
pid_t pid;
FILE *out;
} process_t;
process_t process_open(char *command) {
int fds[2];
check(pipe(fds));
int pid = fork();
check(pid == -1);
if (pid == 0) { // child process
close(fds[0]);
dup2(fds[1], STDOUT_FILENO);
dup2(STDOUT_FILENO, STDERR_FILENO);
char *argv[] = {"sh", "-c", command, NULL};
exit(execvp(argv[0], argv));
} else { // parent process
close(fds[1]);
process_t process = {pid, fdopen(fds[0], "rb")};
return process;
}
}
int process_close(process_t process) {
fclose(process.out);
int status;
check(process.pid != waitpid(process.pid, &status, 0));
if (WIFEXITED(status)) {
return WEXITSTATUS(status);
}
return 0;
}
char *trim(char *str) {
char *end;
while (isspace((unsigned char)*str)) {
str++;
}
if (*str == 0) {
return str;
}
end = str + strlen(str) - 1;
while (end > str && isspace((unsigned char)*end)) {
end--;
}
end[1] = '\0';
return str;
}
char *append(char *buffer, int count, ...) {
va_list list;
va_start(list, count);
for (int i = 0; i < count; i++) {
strcat(buffer, va_arg(list, char *));
}
va_end(list);
return buffer;
}
char *inttostr(char *buffer, int value) {
sprintf(buffer, "%d", value);
return buffer;
}
int main() {
// get the current branch name
process_t process = process_open("git symbolic-ref --short HEAD");
char branch_buf[256] = {};
fread(branch_buf, 1, sizeof(branch_buf), process.out);
if (process_close(process)) {
// current HEAD is not a symbolic ref
process = process_open("git rev-parse --abbrev-ref HEAD");
memset(branch_buf, 0, sizeof(branch_buf));
fread(branch_buf, 1, sizeof(branch_buf), process.out);
check(process_close(process));
if (strcmp("HEAD", trim(branch_buf)) == 0) {
// get the commit hash
process = process_open("git rev-parse --short HEAD");
memset(branch_buf, 0, sizeof(branch_buf));
fread(branch_buf, 1, sizeof(branch_buf), process.out);
check(process_close(process));
}
}
char *branch = trim(branch_buf);
char prompt[1024] = {};
append(prompt, 3, " %{%F{66}%}", branch, "%{%f%}");
// get the upstream remote if one exists
char command[1024] = {};
append(command, 3, "git config branch.", branch, ".remote");
process = process_open(command);
char remote_buf[256] = {};
fread(remote_buf, 1, sizeof(remote_buf), process.out);
if (process_close(process) == 0) {
char *remote = trim(remote_buf);
// get the number of commits ahead of the remote
memset(command, 0, sizeof(command));
process = process_open(append(command, 5,
"git rev-list --right-only refs/remotes/",
remote, "/", branch, "...HEAD --count"));
char count[32] = {};
fread(count, 1, sizeof(count), process.out);
if (process_close(process) == 0 && strcmp("0", trim(count))) {
append(prompt, 2, "", trim(count));
}
// get the number of commits behind the remote
memset(command, 0, sizeof(command));
process = process_open(append(command, 5,
"git rev-list --left-only refs/remotes/",
remote, "/", branch, "...HEAD --count"));
memset(count, 0, sizeof(count));
fread(count, 1, sizeof(count), process.out);
if (process_close(process) == 0 && strcmp("0", trim(count))) {
append(prompt, 2, "", trim(count));
}
}
append(prompt, 1, " ");
// get the status and parse it
process = process_open("git status --porcelain");
char status[2048];
int indexed = 0, modified = 0, deleted = 0, untracked = 0, unmerged = 0;
while (NULL != fgets(status, sizeof(status) - 1, process.out)) {
char X = status[0];
char Y = status[1];
if (X == '?' && Y == '?') {
++untracked;
} else if ((X == 'A' && (Y == 'A' || Y == 'U')) ||
(X == 'D' && (Y == 'D' || Y == 'U')) ||
(X == 'U' && (Y == 'A' || Y == 'D' || Y == 'D' || Y == 'U'))) {
++unmerged;
} else {
switch (X) {
case ' ':
switch (Y) {
case 'M': ++modified; break;
case 'D': ++deleted; break;
} break;
case 'D': ++indexed;
switch (Y) {
case ' ': break;
case 'M': ++modified; break;
} break;
case 'M': case 'A': case 'R': case 'C': ++indexed;
switch (Y) {
case ' ': break;
case 'M': ++modified; break;
case 'D': ++deleted; break;
} break;
}
}
}
check(process_close(process));
if (indexed || modified || deleted || unmerged || untracked) { // modified
char int_buf[32];
if (indexed) {
append(prompt, 3, "%{%F{2}%}*", inttostr(int_buf, indexed), "%{%f%}");
}
if (modified) {
append(prompt, 3, "%{%F{1}%}+", inttostr(int_buf, modified), "%{%f%}");
}
if (deleted) {
append(prompt, 3, "%{%F{1}%}-", inttostr(int_buf, deleted), "%{%f%}");
}
if (unmerged) {
append(prompt, 3, "%{%B%F{1}%}×", inttostr(int_buf, unmerged), "%{%f%b%}");
}
if (untracked) {
append(prompt, 1, "%{%F{1}%}…%{%f%}");
}
} else { // clean
append(prompt, 1, "%{%B%F{2}%}✓%{%f%b%}");
}
// print the prompt
puts(prompt);
return 0;
}

92
install.zsh Executable file
View File

@ -0,0 +1,92 @@
#!/usr/bin/env zsh
error() {
echo "error: $*"
exit 1
}
directories=(
~/.cache/zsh
~/.local/bin
~/.local/share/zsh/plugins
~/.local/share/zsh/site-functions
)
for directory in $directories; do
mkdir -p $directory
done
plugins=(
zsh-users/zsh-autosuggestions
zsh-users/zsh-history-substring-search
zsh-users/zsh-syntax-highlighting
zsh-users/zsh-completions
)
for plugin in $plugins; do
plugin_name=${plugin/*\//}
plugin_directory=~/.local/share/zsh/plugins/$plugin_name
if [ -d $plugin_directory ]; then
if ! git -C $plugin_directory diff-index --quiet HEAD --; then
error $plugin_directory contains unstaged changes
fi
pull=`git -C $plugin_directory pull`
if [ "$pull" != "Already up to date." ] && \
[ "$pull" != "Already up-to-date." ]; then
echo changed pulled $plugin_directory
fi
else
git clone https://github.com/$plugin.git $plugin_directory > /dev/null
echo changed cloned $plugin_directory
fi
old_plugin_directory=~/.config/zsh/$plugin_name
if [ -d $old_plugin_directory ]; then
rm -rf $old_plugin_directory
echo changed removed $old_plugin_directory
fi
done
declare -A symlinks
symlinks=(
~/.config/zsh/zlogin ~/.zlogin
~/.config/zsh/zlogout ~/.zlogout
~/.config/zsh/zprofile ~/.zprofile
~/.config/zsh/zshenv ~/.zshenv
~/.config/zsh/zshrc ~/.zshrc
~/.config/zsh/prompt_fresh_setup
~/.local/share/zsh/site-functions/prompt_fresh_setup
~/.config/zsh/cmake-uninstall ~/.local/bin/cmake-uninstall
~/.config/zsh/$ ~/.local/bin/$
~/.config/zsh/url/url ~/.local/bin/url
)
for completion in ~/.config/zsh/**/_*; do
filename=`basename $completion`
symlinks[$completion]=~/.local/share/zsh/site-functions/$filename
done
completions=( ~/.local/share/zsh/plugins/zsh-completions/src/* )
for completion in $completions; do
filename=`basename $completion`
name=${filename:1}
if command -v $name > /dev/null; then
symlinks[$completion]=~/.local/share/zsh/site-functions/$filename
fi
done
for source in ${(k)symlinks}; do
dest=$symlinks[$source]
if [ -L $dest ]; then
target=`readlink $dest`
if [ "$target" != "$source" ]; then
rm $dest
ln -s $source $dest
echo changed replace incorrect symlink $dest
fi
elif [ -f $dest ]; then
error symlink failed $dest exists but is a regular file
else
ln -s $source $dest
echo changed created symlink $dest
fi
done

View File

@ -1,7 +1,7 @@
#compdef layout #compdef layout
__get_layouts() { __get_layouts() {
ls -1 ~/.config/tmux/layouts 2>/dev/null | \ ls -1 ~/.local/share/tmux/layouts 2>/dev/null | \
while read -r layout; do echo $layout; done while read -r layout; do echo $layout; done
} }

View File

@ -2,7 +2,7 @@ layout() {
if [[ "$1" == "" ]]; then if [[ "$1" == "" ]]; then
echo "usage: layout <layout> [name]" echo "usage: layout <layout> [name]"
else else
tmux source-file ~/.config/tmux/layouts/$1 ~/.local/share/tmux/layouts/$1
if [[ "$2" != "" ]]; then if [[ "$2" != "" ]]; then
tmux rename-window $2 tmux rename-window $2
fi fi

View File

@ -0,0 +1,22 @@
#!/usr/bin/env zsh
# Loop over available completions and add existing commands to array.
local -a completions
completions=(~/.config/zsh/zsh-completions/src/*)
local -a command_list
for completion in $completions; do
local filename=$(basename $completion)
local name=${filename:1}
if command -v $name &> /dev/null; then
command_list+=($name)
fi
done
# Print JSON array of commands Ansible can consume.
echo '['
local length=${#command_list[@]}
for (( i = 1; i < $length; i++ )); do
echo " \"${command_list[$i]}\","
done
echo " \"${command_list[-1]}\""
echo ']'

6
ls-iommu.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
for d in /sys/kernel/iommu_groups/*/devices/*; do
n=${d#*/iommu_groups/*}; n=${n%%/*}
printf '%s ' "$n"
lspci -nns "${d##*/}"
done

View File

@ -1,17 +1,18 @@
prompt_fresh_help() { prompt_fresh_help() {
echo "\ echo "\
options: options:
-a enable almostontop like behaviour" -a enable almostontop like behaviour
-r recompile git-prompt executable"
} }
prompt_fresh_setup() { prompt_fresh_setup() {
fresh_compile_git_prompt
# Parse options # Parse options
local almostontop=0 local almostontop=0
while getopts 'a' opt; do local recompile=0
while getopts 'ar' opt; do
case $opt in case $opt in
a) local almostontop=1 ;; a) local almostontop=1 ;;
r) local recompile=1 ;;
*) prompt -h fresh; return 1 ;; *) prompt -h fresh; return 1 ;;
esac esac
done done
@ -19,199 +20,173 @@ prompt_fresh_setup() {
autoload -U add-zsh-hook autoload -U add-zsh-hook
# Hook to print the first line of the "two line" prompt, this line is not # Hook to print the first line of the "two line" prompt, this line is not
# actually part of the prompt so does not get redrawn which can sometimes # actually part of the prompt so does not get redrawn, this is preferable
# cause lines before the prompt to disappear. # since sometimes lines before the prompt can disappear.
add-zsh-hook precmd fresh_line_one add-zsh-hook precmd fresh_line_one
if [ $almostontop -eq 1 ]; then if [ $almostontop -eq 1 ]; then
# Hook to clear the screen then prints the prompt with previous command at # Hook to clear the screen then prints the prompt with previous command at
# the top of the screen. # the top of the screen.
add-zsh-hook preexec fresh_almostontop add-zsh-hook precmd fresh_almostontop_precmd
add-zsh-hook preexec fresh_almostontop_preexec
else else
add-zsh-hook -d preexec fresh_almostontop add-zsh-hook -d preexec fresh_almostontop_preexec
add-zsh-hook -d precmd fresh_almostontop_precmd
fi fi
if [ "$USERNAME" = "root" ]; then [ $recompile -eq 1 ] && prompt_cleanup
local user="%{%F{9}%}%n%{%f%}" fresh_compile_git_prompt
if [ "$USER" = "root" ]; then
local user="%{%F{1}%}%n%{%f%}"
else else
local user="%{%F{35}%}%n%{%f%}" local user="%{%F{35}%}%n%{%f%}"
fi fi
if [ "$SSH_CONNECTION" != "" ]; then local userhost=$USER
local user="%{%F{35}%}$user%{%f%}@%{%F{244}%}%M%{%f%}" if [ "$SSH_CONNECTION" != "" ] || [ "$container" != "" ]; then
local user="$user@%{%F{244}%}%M%{%f%}"
local userhost="$userhost@`hostname`"
fi fi
local length=`fresh_visible_length "$user"` PS1="$user "
PS2="${(l:${#userhost}:: :)} "
PS1="«$user» " prompt_opts=(percent sp subst)
PS2="${(l:$length + 1:: :)}» "
RPS1='$(fresh_rprompt)'
prompt_opts=(cr percent sp subst)
} }
prompt_cleanup() { prompt_cleanup() {
if [ -f ~/.cache/zsh/git-prompt ]; then rm ~/.cache/zsh/git-prompt; fi [ -f ${XDG_CACHE_HOME:-$HOME/.cache}/zsh/git-prompt ] && \
rm ${XDG_CACHE_HOME:-$HOME/.cache}/zsh/git-prompt
} }
fresh_line_one() { fresh_line_one() {
# First get the last commands exit code before doing anything # First get the last commands exit code before doing anything
local exit_code=$? local exit_code=$?
# Clean up if fresh is no longer the current prompt theme
if [[ "`prompt -c | tail -1 | xargs`" != "fresh"* ]]; then
add-zsh-hook -d precmd fresh_line_one
return
fi
# Construct the time and directory portions of the prompt # Construct the time and directory portions of the prompt
local time_stamp="%{%F{244}%}%D{%H:%M:%S}%{%f%}" local time_stamp="%{%F{244}%}%D{%H:%M:%S}%{%f%}"
local directory="%{%F{37}%}%~%{%f%}" [[ -n $SANDBOX_HOME ]] && \
local directory="%{%F{220}%}$SANDBOX_NAME${PWD#$SANDBOX_HOME}%{%f%}" || \
local directory="%{%F{37}%}%~%{%f%}"
# Check we are in a git repository # Check we are in a git repository
if `git rev-parse --git-dir > /dev/null 2>&1`; then local git=`${XDG_CACHE_HOME:-$HOME/.cache}/zsh/git-prompt`
# Get git branch name & exit early if not found
local branch="`git symbolic-ref HEAD 2> /dev/null`"
if [ "" = "$branch" ]; then
local branch="`git rev-parse --abbrev-ref HEAD`"
if [ "HEAD" = "$branch" ]; then
local branch="`git rev-parse --short $branch`"
fi
fi
if [ "$branch" != "" ]; then # If the last command failed, display its error code at the right
local branch=${branch#refs/heads/} if [[ $exit_code -ne 0 ]]; then
# Get the number of commits ahead/behind from the remote branch case $exit_code in
local remote="`git config branch.$branch.remote 2> /dev/null`" 129) exit_code="SIGHUP" ;; # 128 + 1
if [ "" != "remote" ]; then 130) exit_code="SIGINT" ;; # 128 + 2
local branches="refs/remotes/$remote/$branch...HEAD" 131) exit_code="SIGQUIT" ;; # 128 + 3
local nahead=`git rev-list --right-only $branches --count 2> /dev/null` 132) exit_code="SIGILL" ;; # 128 + 4
if [ "0" -ne "$nahead" ]; then local ahead="↑$nahead"; fi 133) exit_code="SIGTRAP" ;; # 128 + 5
local nbehind=`git rev-list --left-only $branches --count 2> /dev/null` 134) exit_code="SIGABRT" ;; # 128 + 6
if [ "0" -ne "$nbehind" ]; then local behind="↓$nbehind"; fi 134) exit_code="SIGIOT" ;; # 128 + 6
fi 135) exit_code="SIGBUS" ;; # 128 + 7
136) exit_code="SIGFPE" ;; # 128 + 8
# Construct the git prompt 137) exit_code="SIGKILL" ;; # 128 + 9
local git="%{%F{66}%}$branch%{%f%}$ahead$behind " 138) exit_code="SIGUSR1" ;; # 128 + 10
139) exit_code="SIGSEGV" ;; # 128 + 11
if [ -f ~/.cache/zsh/git-prompt ]; then 140) exit_code="SIGUSR2" ;; # 128 + 12
# Get the change counts from git-prompt 141) exit_code="SIGPIPE" ;; # 128 + 13
local counts=(`~/.cache/zsh/git-prompt`) 142) exit_code="SIGALRM" ;; # 128 + 14
143) exit_code="SIGTERM" ;; # 128 + 15
# Parse the results from git-prompt 144) exit_code="SIGSTKFLT" ;; # 128 + 16
if [ 0 -eq ${#counts[@]} ]; then # clean 145) exit_code="SIGCHLD" ;; # 128 + 17
local git="$git%{%B%F{2}%}✓%{%f%b%}"; 146) exit_code="SIGCONT" ;; # 128 + 18
else 147) exit_code="SIGSTOP" ;; # 128 + 19
if [ 0 != $counts[1] ]; then # indexed 148) exit_code="SIGTSTP" ;; # 128 + 20
local git="$git%{%F{2}%}*$counts[1]%{%f%}" 149) exit_code="SIGTTIN" ;; # 128 + 21
fi 150) exit_code="SIGTTOU" ;; # 128 + 22
if [ 0 != $counts[2] ]; then # modified 151) exit_code="SIGURG" ;; # 128 + 23
local git="$git%{%F{1}%}+$counts[2]%{%f%}"; 152) exit_code="SIGXCPU" ;; # 128 + 24
fi 153) exit_code="SIGXFSZ" ;; # 128 + 25
if [ 0 != $counts[3] ]; then # deleted 154) exit_code="SIGVTALRM" ;; # 128 + 26
local git="$git%{%F{1}%}-$counts[3]%{%f%}"; 155) exit_code="SIGPROF" ;; # 128 + 27
fi 156) exit_code="SIGWINCH" ;; # 128 + 28
if [ 0 != $counts[4] ]; then # unmerged 157) exit_code="SIGIO" ;; # 128 + 29
local git="$git%{%B%F{1}%}×$counts[4]%{%f%b%}"; 158) exit_code="SIGPWR" ;; # 128 + 30
fi 159) exit_code="SIGSYS" ;; # 128 + 31
if [ 0 != $counts[5] ]; then # untracked esac
local git="$git%{%F{1}%}…%{%f%}"; local result=" %{%B%F{1}%}$exit_code%{%f%b%}"
fi
fi
fi
fi
fi fi
# Construct the prompt string # Unset vim/tmux navigate flag to handle C-z and multiple vim jobs.
local line="$time_stamp $directory $git" [[ ! -z "$TMUX" ]] && \
[[ "`tmux show-window-options`" = *"@vim$TMUX_PANE"* ]] && \
tmux set-window-option -u @vim$TMUX_PANE
# If a virtualenv is enabled, display it's basename
if [[ ! -z "$VIRTUAL_ENV" ]]; then
local py=" %{%F{4}%}py%{%f%}%{%F{3}%}$(basename $VIRTUAL_ENV)%{%f%}"
fi
# If docker-machine env is active, display the machines name
if [[ ! -z "$DOCKER_MACHINE_NAME" ]]; then
local docker=" %{%F{6}%}$DOCKER_MACHINE_NAME%{%f%}"
fi
# Print the first line of the prompt # Print the first line of the prompt
if [[ $exit_code -eq 0 ]]; then print -P "$time_stamp $directory$git$py$docker$result"
print -P "$line"
else
# The last command failed, display its error code at the right
local result="%{%B%F{1}%}$exit_code%{%f%b%}"
local length=`fresh_visible_length "$line$result"`
print -P "$line${(l:COLUMNS - $length - 1:: :)}$result"
fi
} }
fresh_rprompt() { # Executed before each prompt.
rprompt="" fresh_almostontop_precmd() {
if [[ ! -z "$DOCKER_MACHINE_NAME" ]]; then # CSI ESC[6n gets the cursor position in the form ESC[<row>;<column>R
rprompt="$rprompt %{%F{3}%}$DOCKER_MACHINE_NAME%{%f%}" printf "\033[6n"
fi # Discard prefix delimited by [
if [[ ! -z "$VIRTUAL_ENV" ]]; then read -s -d [
rprompt="$rprompt %{%F{3}%}$(basename $VIRTUAL_ENV)%{%f%}" # Store the <row> delimited by ; in row_before
fi read -s -d \; row_before
echo $rprompt # Discard suffix delimted by R otherwise it is output to the tty
read -s -d R
} }
fresh_almostontop() { # Executed just after a command has been read and is about to be executed.
clear fresh_almostontop_preexec() {
fresh_line_one # CSI ESC[6n gets the cursor position in the form ESC[<row>;<column>R
print -P "$PROMPT"'$1' printf "\033[6n"
} # Discard prefix delimited by [
read -s -d [
fresh_visible_length() { # Store the <row> delimited by ; in row
echo $(( ${#${(S%%)1//(\%(KF1]|)\{*\}|\%[Bbkf])}} )) read -s -d \; row
# Discard suffix delimted by R otherwise it is output to the tty
read -s -d R
# Move the cursor to the bottom of the terminal
# CSI ESC[<num>B moves the cursor down <num> lines
let "down = $LINES - $row"
printf "\033[${down}B"
# Calculate the number of lines in the prompt
let "prompt_lines = ($row - $row_before) + 2"
# Print new lines to push the old command out of view
let "new = $row - $prompt_lines"
for (( i = 0; i < $new; i++ )); do
printf "\n"
done
# Move the cursor to the line below the prompt
# CSI ESC[<num>A moves the cursor up <num> lines
let "up = $LINES - $prompt_lines"
printf "\033[${up}A"
} }
fresh_compile_git_prompt() { fresh_compile_git_prompt() {
# Compile a simple C executable which parses the output of `git status # Compile a simple C program which parses the output of `git status
# --procelain` to greatly decrease the time taken to render the prompt # --procelain` to greatly decrease the time taken to draw the prompt
local cache=~/.cache/zsh [ ! -d ${XDG_CACHE_HOME:-$HOME/.cache}/zsh ] && \
if [ ! -d $cache ]; then mkdir -p $cache; fi mkdir -p ${XDG_CACHE_HOME:-$HOME/.cache}/zsh
if [ ! -f $cache/git-prompt ]; then if [ ! -f ${XDG_CACHE_HOME:-$HOME/.cache}/zsh/git-prompt ]; then
cc -x c -std=gnu99 -O3 -DNDEBUG -o $cache/git-prompt - 2> /dev/null << EOF cc -std=gnu99 -O3 -DNDEBUG -Wno-unused-result \
#include <stdio.h> ${XDG_CONFIG_HOME:-$HOME/.config}/zsh/git-prompt.c \
#include <stdlib.h> -o ${XDG_CACHE_HOME:-$HOME/.cache}/zsh/git-prompt
int main() {
FILE *file = popen("git status --porcelain", "r");
if (NULL == file) { return 0; }
char status[2048];
int indexed = 0, modified = 0, deleted = 0, untracked = 0, unmerged = 0;
while (NULL != fgets(status, sizeof(status) - 1, file)) {
char X = status[0];
char Y = status[1];
if (X == '?' && Y == '?') {
++untracked;
} else if ((X == 'A' && (Y == 'A' || Y == 'U')) ||
(X == 'D' && (Y == 'D' || Y == 'U')) ||
(X == 'U' && (Y == 'A' || Y == 'D' || Y == 'D' || Y == 'U'))) {
++unmerged;
} else {
switch (X) {
case ' ':
switch (Y) {
case 'M': ++modified; break;
case 'D': ++deleted; break;
} break;
case 'D': ++indexed;
switch (Y) {
case ' ': break;
case 'M': ++modified; break;
} break;
case 'M': case 'A': case 'R': case 'C': ++indexed;
switch (Y) {
case ' ': break;
case 'M': ++modified; break;
case 'D': ++deleted; break;
} break;
}
}
}
pclose(file);
if (indexed || modified || deleted || unmerged || untracked) {
printf("%d %d %d %d %d", indexed, modified, deleted, unmerged, untracked);
}
return 0;
}
EOF
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "git prompt disabled, are the system development headers installed?" echo "git-prompt was not compiled, is a C99 toolchain installed?"
fi fi
fi fi
} }

View File

@ -1,46 +1,42 @@
#compdef sandbox #compdef sandbox
__get_sandboxes() {
/bin/ls $SANDBOX_ROOT 2> /dev/null
}
__sandboxes() { __sandboxes() {
local -a sandboxes local -a sandboxes
sandboxes=(${(fo)"$(__get_sandboxes)"}) sandboxes=(${(fo)"$(ls $SANDBOX_ROOT 2> /dev/null)"})
_describe 'in' sandboxes _describe 'in' sandboxes
} }
_sandbox_cmds() {
local commands; commands=(
'create:Create a new sandbox'
'rename:Rename an existing sandbox'
'destroy:Destroy an existing sandbox'
'list:Show all existing sandboxes'
'enable:Enable an existing sandbox'
'disable:Disable the current sandbox'
)
_describe -t commands 'sandbox command' commands "$@"
}
_sandbox() { _sandbox() {
local context curcontext="$curcontext" state line local context curcontext="$curcontext" state line
typeset -A opt_args typeset -A opt_args
_arguments -C \ _arguments -C \
'1: :_sandbox_cmds' \ '1: :->cmd' \
'*::arg:->args' '*:: :->args'
case $state in case $state in
(cmd)
local commands; commands=(
'create:Create a new sandbox'
'rename:Rename an existing sandbox'
'destroy:Destroy an existing sandbox'
'list:Show all existing sandboxes'
'enable:Enable an existing sandbox'
'disable:Disable the current sandbox'
)
_describe -t commands 'sandbox command' commands "$@"
;;
(args) (args)
curcontext="${curcontext%:*:*}:sandbox-cmd-$words[1]:" curcontext="${curcontext%:*:*}:sandbox-cmd-$words[1]:"
case $line[1] in case $line[1] in
(create|list|disable) (create)
_arguments -C '--git[repository to clone]: :'
;; ;;
(enable|destroy) (rename|enable|destroy)
_arguments -C '1:: :__sandboxes' _arguments -C '1:: :__sandboxes'
;; ;;
(rename) (list|disable)
_arguments -C '1:: :__sandboxes'
;; ;;
esac esac
esac esac

View File

@ -1,103 +1,127 @@
if [[ "" == $SANDBOX_ENV_IN_FILE ]]; then
export SANDBOX_ENV_IN_FILE=$AUTOENV_IN_FILE
fi
if [[ "" == $SANDBOX_ENV_OUT_FILE ]]; then
export SANDBOX_ENV_OUT_FILE=$AUTOENV_OUT_FILE
fi
if [[ "" == $SANDBOX_ROOT ]]; then if [[ "" == $SANDBOX_ROOT ]]; then
export SANDBOX_ROOT=$HOME/Sandbox export SANDBOX_ROOT=$HOME/Sandbox
fi fi
sandbox() { sandbox() {
local usage="usage: sandbox {create,destroy,enable,disable} [name]" local usage="\
usage: sandbox [-h] {create,rename,destroy,enable,disable,list} ..
sandbox create [--git <repo>] <name>
sandbox rename <old-name> <new-name>
sandbox destroy <name>
sandbox enable <name>
sandbox disable
sandbox list"
if [[ "" == $1 ]]; then error() { print -P "%F{red}error:%f $1" }
echo $usage
return 1
fi
case $1 in local cmd=$1
[[ -z "$cmd" ]] && \
error "missing command\n$usage" && return 1
shift 1
case $cmd in
create) create)
if [[ "" == $2 ]]; then # Parse command arguments.
echo $usage local git=false
return 1 for arg in $@; do
if [ "${arg[1]}" = - ]; then
if [ "$git" = true ]; then
error "invalid --git <repo> $arg\n$usage" && return 1
elif [ "$arg" = --git ]; then
git=true
else
error "invalid option $arg\n$usage" && return 1
fi
else
if [ "$git" = true ]; then
local repo=$arg
git=false
elif [[ -z "$name" ]]; then
error "invalid argument $arg\n$usage" && return 1
else
local name=$arg
fi
fi
done
unset git
[[ -z "$name" ]] && \
error "missing argument <name>\n$usage" && return 1
local sandbox=$SANDBOX_ROOT/$name
[[ -d "$sandbox" ]] && \
error "sandbox already exists $name" && return 1
if [[ -n "$repo" ]]; then
mkdir -p $SANDBOX_ROOT &> /dev/null
git clone $repo $sandbox
cd $sandbox
else
mkdir -p $sandbox &> /dev/null
cd $sandbox
git init &> /dev/null
fi fi
echo "SANDBOX_HOME=\$(dirname -- "\$0:a")" >> $sandbox/.enter
local sandbox=$SANDBOX_ROOT/$2 echo "SANDBOX_NAME=$name" >> $sandbox/.enter
if [[ -d $sandbox ]]; then _autoenv_authorized $sandbox/.enter yes
echo "Sandbox '$2' already exists" echo "unset SANDBOX_NAME" >> $sandbox/.exit
return 2 echo "unset SANDBOX_HOME" >> $sandbox/.exit
fi _autoenv_authorized $sandbox/.exit yes
_autoenv_enter $sandbox
mkdir -p $sandbox &> /dev/null
begin=$PWD
cd $sandbox
echo "SANDBOX_HOME=\$(dirname -- "\$0:a")" >> $SANDBOX_ENV_IN_FILE
echo "SANDBOX_NAME=$2" >> $SANDBOX_ENV_IN_FILE
echo "unset SANDBOX_NAME" >> $SANDBOX_ENV_OUT_FILE
echo "unset SANDBOX_HOME" >> $SANDBOX_ENV_OUT_FILE
git init &> /dev/null
cd $begin
cd $sandbox
;; ;;
rename) rename)
if [[ "" == $2 || "" == $3 ]]; then local old_name=$1 new_name=$2
echo $usage [[ -z "$old_name" ]] && \
return 1 error "missing argument <old-name>\n$usage" && return 1
fi [[ -z "$new_name" ]] && \
error "missing argument <new-name>\n$usage" && return 1
mv $SANDBOX_ROOT/$2 $SANDBOX_ROOT/$3 local old=$SANDBOX_ROOT/$old_name new=$SANDBOX_ROOT/$new_name
sed -i "" "s/$2/$3/g" $SANDBOX_ROOT/$3/.env [[ ! -d "$old" ]] && \
error "sandbox does not exist $old_name" && return 1
[[ -d "$new" ]] && \
error "sandbox already exists $new_name" && return 1
[[ "$PWD" = "$old"* ]] && _autoenv_exit $PWD
mv $old $new
sed -i "s/$old_name/$new_name/g" $new/.enter
_autoenv_authorized $new/.enter yes
_autoenv_authorized $new/.exit yes
[[ "$PWD" = "$old"* ]] && cd $new
;; ;;
destroy) destroy)
if [[ "" == $2 ]]; then local name=$1
echo $usage [[ -z "$name" ]] && \
return 1 error "missing argument <name>\n$usage" && return 1
fi local sandbox=$SANDBOX_ROOT/$name
[[ ! -d $sandbox ]] && \
local sandbox=$SANDBOX_ROOT/$2 error "sandbox does not exist $name" && return 1
if [[ ! -d $sandbox ]]; then [[ "$PWD" = "$sandbox"* ]] && cd ~
echo "Sandbox '$2' does not exist"
return 2
fi
cd -
if [[ "${SANDBOX_ROOT##$PWD}" = "${SANDBOX_ROOT}" ]]; then
cd $HOME
fi
rm -rf $sandbox rm -rf $sandbox
;; ;;
list) list)
/bin/ls -1 $SANDBOX_ROOT ls -1 $SANDBOX_ROOT | less -F -K -R -X
;; ;;
enable) enable)
if [[ "" == $2 ]]; then local name=$1
echo $usage [[ -z "$name" ]] && \
return 1 error "missing argument <name>\n$usage" && return 1
fi
local sandbox=$SANDBOX_ROOT/$2
if [[ ! -d $sandbox ]]; then
echo "Sandbox '$2' does not exist"
return 2
fi
local sandbox=$SANDBOX_ROOT/$name
[[ ! -d $sandbox ]] && \
error "sandbox does not exist $name" && return 1
export SANDBOX_RETURN=$PWD export SANDBOX_RETURN=$PWD
cd $sandbox cd $sandbox
;; ;;
disable)
if [[ -z $SANDBOX_RETURN ]]; then
echo "Sandbox is not currently active"
return 2
fi
disable)
[[ -z "$SANDBOX_RETURN" ]] && \
error "sandbox is not currently active" && return 1
cd $SANDBOX_RETURN cd $SANDBOX_RETURN
unset $SANDBOX_RETURN unset SANDBOX_RETURN
;;
*)
error "invalid sandbox command: $cmd" && return 1
;; ;;
esac esac
} }

32
session/_session Normal file
View File

@ -0,0 +1,32 @@
#compdef session
__session_sessions() {
list() {
for item in $HOME/.local/share/tmux/layouts/session-*; do
item=${item#$HOME/.local/share/tmux/layouts/}
echo ${item#session-}
done
}
local -a sessions
sessions=(${(fo)"$(list)"})
_describe 'session' sessions
}
__session_hosts() {
list() {
declare -A hosts
if [ -f ~/.config/session ]; then
source ~/.config/session
for key val in "${(@kv)hosts}"; do
echo $key
done
fi
}
local -a hosts
hosts=(${(fo)"$(list)"})
_describe 'host' hosts
}
_arguments \
':session:__session_sessions' \
':host:__session_hosts'

View File

@ -0,0 +1,33 @@
session() {
if [[ "$1" == "" ]]; then
echo "usage: session <name> [<host>]"
else
local name=$1
local host=$2
if [[ "$3" != "" ]]; then
echo "$fg[red]error:$reset_color invalid argument: $3"
return 1
fi
declare -A hosts
if [ -f ~/.config/session ]; then
source ~/.config/session
fi
local url=$hosts[$host]
host=${url:-$host}
if [[ "$TMUX" == "" ]]; then
local cmd="tmux new-session -As $name"
if [[ "$host" != "" ]]; then
cmd="ssh $host -t $cmd"
fi
eval $cmd
else
if [[ "$host" != "" ]]; then
echo "$fg[red]error:$reset_color <host> not allowed inside tmux session"
return 1
fi
tmux list-sessions | grep "$name:" &> /dev/null || \
tmux new-session -Ads $name -c $HOME
tmux switch-client -t $name
fi
fi
}

22
url/_url Normal file
View File

@ -0,0 +1,22 @@
#compdef url
_url() {
local ret=1 context curcontext="$curcontext" state line
typeset -A opt_args
_arguments -C -w -s \
'(-h --help)'{-h,--help}'[show this help message and exit]' \
'1: :->command'
case $state in
(command)
declare -a commands
local commands=(
encode:'encode unencoded text'
decode:'decode encoded text'
)
_describe -t commands command commands && ret=0 ;;
esac
return ret
}

27
url/url Executable file
View File

@ -0,0 +1,27 @@
#!/usr/bin/env python
"""URL encode or decode text."""
from argparse import ArgumentParser
from urllib import parse
def main():
cli = ArgumentParser(description=__doc__)
cli.add_argument('command',
choices=['encode', 'decode'],
help='type of processing to perform on text')
cli.add_argument('text',
nargs='?',
help='optional text read from stdin when omitted')
args = cli.parse_args()
print({
'encode': parse.quote_plus,
'decode': parse.unquote_plus,
}[args.command](args.text if args.text else input()))
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
exit(130)

View File

@ -0,0 +1,195 @@
# A collection of various shell utilities.
autoload colors && colors
# Abstract different ways to copy to the clipboard.
if [ -n "$SSH_CONNECTION" ] ; then
# Use OSC-52 to set the clipboard
alias copy='base64 | xargs -0 printf "\033]52;c;%s\a"'
elif [ "`uname`" = "Darwin" ]; then
# Use pbcopy to set the clipboard
alias copy='pbcopy'
elif which xclip &> /dev/null; then
# Use xclip to set the clipboard
alias copy='xclip -selection c'
fi
# Abstract different ways to paste from the clipboard.
# TODO: Use OSC-52 to get the clipboard, not widely supported though
if [ "`uname`" = "Darwin" ]; then
# Use pbpaste to get the clipboard
alias paste='pbpaste'
elif which xclip &> /dev/null; then
# Use xclip to get the clipboard
alias paste='xclip -selection c -o'
fi
# Passthrough an escape sequences tmux doesn't know about.
tmux-dcs-passthrough() {
local escape_sequence=$1
if [ -n "$TMUX" ]; then
# Replace single \x1b or \033 with two, this is required for tmux to
# properly pass-through the escape sequence.
escape_sequence=${escape_sequence//\\x1b/\\x1b\\x1b}
escape_sequence=${escape_sequence//\\033/\\x1b\\x1b}
printf '\x1bPtmux;\x1b'"$escape_sequence"'\x1b\\'
else
printf "$escape_sequence"
fi
}
# OSC 9 - Post a notification - supported by iTerm2, kitty, WezTerm, others?
notify() {
tmux-dcs-passthrough '\x1b]9;'"$*"'\x7'
}
# Send a desktop notification when long running commands complete.
notify_command_threshold=60
notify_ignore_list=(
bash
bat
btop
cat
cmatrix
fg
gh
git
glab
htop
ipython
man
nvim
ping
podman
python
session
slides
ssh
sudo
sudoedit
tmux
top
vi
vim
watch
zsh
)
notify-ignore() {
for ignore in $notify_ignore_list; do
if [[ "$1" = "$ignore"* ]]; then
return 0
fi
done
return 1
}
notify-preexec() {
if notify-ignore $1; then
return
fi
notify_command_start=`date +%s`
notify_command=$1
}
add-zsh-hook preexec notify-preexec
notify-precmd() {
if ! [[ -z $notify_command_start ]]; then
local notify_command_end=`date +%s`
local notify_command_time=$(($notify_command_end - $notify_command_start))
if [[ $notify_command_time -gt $notify_command_threshold ]]; then
notify "completed: $notify_command"
fi
unset notify_command
unset notify_command_start
fi
}
add-zsh-hook precmd notify-precmd
# Detect the type and extract an archive file.
extract() {
if [ -f $1 ]; then
case $1 in
*.tar.bz2) tar xvjf $1 ;;
*.tar.gz) tar xvzf $1 ;;
*.tar.xz) [ `"uname"` = "Darwin" ] && tar xvJf $1 || tar xf $1 ;;
*.bz2) bunzip2 $1 ;;
*.rar) unrar x $1 ;;
*.gz) gunzip $1 ;;
*.tar) tar xvf $1 ;;
*.tbz2) tar xvjf $1 ;;
*.tgz) tar xvzf $1 ;;
*.zip) unzip $1 ;;
*.Z) uncompress $1 ;;
*.7z) 7zr x $1 ;;
*) echo "$fg[red]error:$reset_color unable to extract '$1'" ;;
esac
else
echo "$fg[red]error:$reset_color file not found '$1'"
fi
}
if which bat &> /dev/null; then
# Wrap bat to specify a theme, always enable color, pipe the output to less.
# Both --theme and --color can be specified multiple times and will override
# these defaults.
bat() {
command bat --theme='TwoDark' --color always --paging auto "$@"
}
elif which batcat &> /dev/null; then
bat() {
command batcat --theme='TwoDark' --color always --paging auto "$@"
}
fi
if which docker-machine &> /dev/null; then
# Wrap the docker command to print a message if a docker-machine is not
# running, rather than just stating it can not find it's socket.
docker() {
command docker "$@"
if ! docker-machine active &> /dev/null; then
echo "$fg[red]error:$reset_color no active host found, run:" \
"docker-machine start <machine>"
return 1
fi
}
# Wrap the docker-machine command to automatically update the environment.
# When a machine is started, set the environment variables provided by
# docker-machine env <machine>. When a machine is stopped, unset the same
# variables.
docker-machine() {
command docker-machine "$@"
if [ "start" = "$1" ]; then
eval `docker-machine env $2`
elif [ "stop" = "$1" ]; then
unset DOCKER_MACHINE_NAME
unset DOCKER_CERT_PATH
unset DOCKER_HOST
unset DOCKER_TLS_VERIFY
fi
}
fi
ls-iommu() {
$HOME/.config/zsh/ls-iommu.sh | sort -n
}
# Fuzzy history search with fzf
function .fzf-history-search() {
local selected
selected=$(
cat $HISTFILE | # get entire history
sed 's/ *[0-9]* *//' | # remove cruft
awk '!seen[$0]++' | # remove duplicates
fzf --layout=reverse --tac --cycle --info=hidden \
--border=rounded --height=50%
)
if [[ -n "$selected" ]]; then
BUFFER="$selected"
zle end-of-line
fi
zle reset-prompt
}
zle -N .fzf-history-search
bindkey '^R' .fzf-history-search

View File

@ -1,2 +1,7 @@
# .zprofile [1] Used for executing user's commands at start, will be sourced # .zprofile [1] Used for executing user's commands at start, will be sourced
# when starting as a login shell. # when starting as a login shell.
# macOS is obnoxious and overwrites the PATH from a users ~/.zshenv, which is
# sourced first, in /etc/zprofile by calling `/usr/libexec/path_helper -s` so
# this is required so that PATH is once again set to the desired value.
[ `uname` = Darwin ] && source ~/.zshenv

118
zshenv
View File

@ -2,25 +2,89 @@
# contain commands that produce output or assume the shell is attached to a # contain commands that produce output or assume the shell is attached to a
# tty. This file will always be sourced. # tty. This file will always be sourced.
[ -f ~/.config/zsh/zshenv.local ] && source ~/.config/zsh/zshenv.local
# Ensure cache and state directories exist
[ ! -d -${XDG_CACHE_HOME:-$HOME/.cache}/zsh ] && \
mkdir -p ${XDG_CACHE_HOME:-$HOME/.cache}/zsh
[ ! -d -${XDG_STATE_HOME:-$HOME/.local/state}/zsh ] && \
mkdir -p ${XDG_STATE_HOME:-$HOME/.local/state}/zsh
# Enable saving command history to file # Enable saving command history to file
[ ! -d $HOME/.cache/zsh ] && mkdir -p $HOME/.cache/zsh HISTFILE=${XDG_STATE_HOME:-$HOME/.local/state}/zsh/histfile
HISTFILE=$HOME/.cache/zsh/histfile HISTSIZE=20000
HISTSIZE=5000 SAVEHIST=20000
SAVEHIST=5000
# Migrate histfile from cache to state directory
! [ -f $HISTFILE ] && [ -f $HOME/.cache/zsh/histfile ] && \
mv $HOME/.cache/zsh/histfile \
${XDG_STATE_HOME:-$HOME/.local/state}/zsh/histfile
# Remove vi mode switch delay
KEYTIMEOUT=1
# Enable time stats for long lasting commands # Enable time stats for long lasting commands
REPORTTIME=5 REPORTTIME=5
# Add Homebrew python to PATH on macOS if present
[ "`uname`" = "Darwin" ] && [ -d /usr/local/opt/python/libexec/bin ] &&
PATH=/usr/local/opt/python/libexec/bin:$PATH
# Add ~/.local to the environment # Add ~/.local to the environment
fpath+=$HOME/.local/share/zsh/site-functions fpath+=$HOME/.local/share/zsh/site-functions
PATH=$HOME/.local/bin:$PATH PATH=$HOME/.local/bin:$PATH
MANPATH=$HOME/.local/share/man:$MANPATH MANPATH=$HOME/.local/share/man:$MANPATH
INFOPATH=$HOME/.local/share/info:$INFOPATH INFOPATH=$HOME/.local/share/info:$INFOPATH
# Add ccache compiler aliases to PATH and use XDG base dir paths
if [ `uname` = Darwin ]; then
if [ `uname -m` = arm64 ]; then
homebrew_root=/opt/homebrew
[ -d /opt/homebrew/bin ] && \
PATH=$homebrew_root/bin:$PATH
else
homebrew_root=/usr/local
fi
[ -d $homebrew_root/opt/python/libexec/bin ] && \
PATH=$homebrew_root/opt/python/libexec/bin:$PATH
[ -f $homebrew_root/bin/ccache ] && \
PATH=$homebrew_root/opt/ccache/libexec:$PATH
elif [ -f /usr/bin/ccache ]; then
if [ -d /usr/lib/ccache/bin ]; then
PATH=/usr/lib/ccache/bin:$PATH
elif [ -d /usr/lib/ccache ]; then
PATH=/usr/lib/ccache:$PATH
fi
fi
export CCACHE_CONFIGPATH=${XDG_CONFIG_HOME:-$HOME/.config}/ccache
export CCACHE_DIR=${XDG_CACHE_HOME:-$HOME/.cache}/ccache
# Add default CMake options
command -v ninja &> /dev/null && \
export CMAKE_GENERATOR=Ninja
export CMAKE_EXPORT_COMPILE_COMMANDS=ON
export CMAKE_COLOR_DIAGNOSTICS=ON
# Remove duplicates from environment variables
typeset -U fpath
typeset -U PATH; export PATH
typeset -U MANPATH; export MANPATH
typeset -U INFOPATH; export INFOPATH
# Set default editor.
if command -v nvim &> /dev/null; then
export EDITOR=`command -v nvim`
# Also use nvim for man pages
export MANPAGER='nvim +Man!'
elif command -v vim &> /dev/null; then
export EDITOR=`command -v vim`
fi
export GIT_EDITOR=$EDITOR
if command -v fzf &> /dev/null; then
export FZF_DEFAULT_OPTS='--no-bold
--color=fg:#c5c9c5,fg+:#c5c9c5,bg:#000000,bg+:#393836
--color=hl:#8ea4a2,hl+:#8ea4a2,info:#afaf87,marker:#C8C093
--color=prompt:#C8C093,spinner:#8992a7,pointer:#FF9E3B,header:#87afaf
--color=gutter:#000000,border:#54546D,label:#aeaeae,query:#c5c9c5'
fi
# Use ~/.local for pip installs on macOS # Use ~/.local for pip installs on macOS
[ "`uname`" = "Darwin" ] && export PYTHONUSERBASE=$HOME/.local [ "`uname`" = "Darwin" ] && export PYTHONUSERBASE=$HOME/.local
@ -32,11 +96,47 @@ export LESS_TERMCAP_so=`printf "\e[1;40;32m"`
export LESS_TERMCAP_se=`printf "\e[0m"` export LESS_TERMCAP_se=`printf "\e[0m"`
export LESS_TERMCAP_us=`printf "\e[0;34m"` export LESS_TERMCAP_us=`printf "\e[0;34m"`
export LESS_TERMCAP_ue=`printf "\e[0m"` export LESS_TERMCAP_ue=`printf "\e[0m"`
# Disable storing less history
export LESSHISTFILE=/dev/null
# Force GoogleTest to output colors # Force GoogleTest to output colors
export GTEST_COLOR=yes export GTEST_COLOR=yes
# Allow completions for GoogleTest break on failure # Allow completions for GoogleTest break on failure
export GTEST_BREAK_ON_FAILURE=0 export GTEST_BREAK_ON_FAILURE=0
# Force CTest to verbose output
export CTEST_OUTPUT_ON_FAILURE=1
# User ~/.local/share for persistent pylint data
export PYLINTHOME=~/.local/share/pylint
# Disable virtualenv prompt # Disable virtualenv prompt
VIRTUAL_ENV_DISABLE_PROMPT=1 export VIRTUAL_ENV_DISABLE_PROMPT=1
# If pinentry-curses exists, use it for lastpass-cli
command -v pinentry-curses &> /dev/null && \
export LPASS_PINENTRY=pinentry-curses
# Teach these some XDG Base Directory Spec manners
export IPYTHONDIR=${XDG_CONFIG_HOME:-$HOME/.config}/ipython
command -v cargo &> /dev/null && \
export CARGO_HOME=$HOME/.local/share/cargo
if command -v ccache &> /dev/null; then
export CCACHE_CONFIGPATH=${XDG_CONFIG_HOME:-$HOME/.config}/ccache.conf
export CCACHE_DIR=${XDG_CACHE_HOME:-$HOME/.cache}/ccache
fi
command -v conan &> /dev/null && \
export CONAN_USER_HOME=$HOME/.local/share/conan
command -v docker &> /dev/null && \
export DOCKER_CONFIG=$HOME/.local/share/docker
export GTK_RC_FILES=${XDG_CONFIG_HOME:-$HOME/.config}/gtk/gtkrc
export GTK2_RC_FILES=${XDG_CONFIG_HOME:-$HOME/.config}/gtk-2.0/gtkrc
export PYLINTHOME=${XDG_CACHE_HOME:-$HOME/.cache}/pylint
command -v rustup &> /dev/null && \
export RUSTUP_HOME=$HOME/.local/share/rustup
[ -f ${XDG_CONFIG_HOME:-$HOME/.config}/wget/rc ] && \
export WGETRC=${XDG_CONFIG_HOME:-$HOME/.config}/wget/rc
# TODO: terminfo
export GOBIN=$HOME/.local/bin
export GOPATH=$HOME/.local/share/go
export GOCACHE=${XDG_CACHE_HOME:-$HOME/.cache}/go/build
export GOMODCACHE=${XDG_CACHE_HOME:-$HOME/.cache}/go/pkg/mod
export GOTMPDIR=${XDG_CACHE_HOME:-$HOME/.cache}/go/tmp

144
zshrc
View File

@ -3,8 +3,12 @@
# Load plugin scripts # Load plugin scripts
source-plugin() { source-plugin() {
if [ -d ~/.config/zsh/$1 ]; then local shared_plugin=${XDG_DATA_HOME:-$HOME/.local/share}/zsh/plugins/$1/$1.plugin.zsh
source ~/.config/zsh/$1/$1.plugin.zsh local local_plugin=${XDG_CONFIG_HOME:-$HOME/.config}/zsh/$1/$1.plugin.zsh
if [ -f $shared_plugin ]; then
source $shared_plugin
elif [ -f $local_plugin ]; then
source $local_plugin
else else
echo "zsh plugin not found: $1" echo "zsh plugin not found: $1"
fi fi
@ -17,13 +21,13 @@ ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(end-of-line vi-end-of-line)
# Search history with a command substring # Search history with a command substring
source-plugin zsh-history-substring-search source-plugin zsh-history-substring-search
HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND=
HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND=
# Command syntax highlighting # Command syntax highlighting
source-plugin fast-syntax-highlighting source-plugin zsh-syntax-highlighting
fast-theme -q ~/.config/zsh/fresh.ini (( ${+ZSH_HIGHLIGHT_STYLES} )) || typeset -A ZSH_HIGHLIGHT_STYLES
ZSH_HIGHLIGHT_STYLES[precommand]=fg=green
# Automatically source .enter and .exit scripts on cd
source-plugin autoenv
# Build system helper commands # Build system helper commands
source-plugin build source-plugin build
@ -31,19 +35,29 @@ source-plugin build
# Project sandboxing commands # Project sandboxing commands
source-plugin sandbox source-plugin sandbox
# Various shell utilities
source-plugin utilities
# Automatically source .enter and .exit scripts on cd
source-plugin autoenv
# Session manager
source-plugin session
# Layout tmux window commands # Layout tmux window commands
source-plugin layout [ "$TMUX" != "" ] && source-plugin layout
# Note taking commands # Note taking commands
source-plugin notes source-plugin notes
# Remove duplicates from history # Remove duplicates from history
setopt hist_ignore_all_dups setopt histignoredups
setopt hist_reduce_blanks
setopt hist_save_no_dups
# Enable multi-terminal history # Enable multi-terminal history
setopt inc_append_history setopt share_history
# Disable error when no glob matches are found
setopt nonomatch
# Enable comments in the prompt # Enable comments in the prompt
setopt interactive_comments setopt interactive_comments
@ -52,17 +66,20 @@ setopt interactive_comments
setopt ignore_eof setopt ignore_eof
# Disable sound # Disable sound
unsetopt beep setopt nobeep
# Disable tty flow control, allows vim to use '<Ctrl>S' # Disable tty flow control, allows vim to use '<Ctrl>S'
unsetopt flow_control && stty -ixon setopt noflowcontrol; stty -ixon
# Enable completions in the middle of a word
setopt completeinword
# Initialize completions # Initialize completions
autoload -U compinit autoload -U compinit
compinit compinit -d ${XDG_CACHE_HOME:-$HOME/.cache}/zsh/compdump
# Add pip to the old completion engine if present # Add pip to the old completion engine if present
if which pip &> /dev/null; then if command -v pip &> /dev/null; then
function _pip_completion { function _pip_completion {
local words cword local words cword
read -Ac words read -Ac words
@ -82,6 +99,9 @@ prompt fresh
# Enable vi mode line editor keymap # Enable vi mode line editor keymap
bindkey -v bindkey -v
# Enable backspace after returning to viins from vicmd mode
bindkey '^?' backward-delete-char
# Enable yank, change, and delete whole line with 'Y', 'cc', and 'dd' # Enable yank, change, and delete whole line with 'Y', 'cc', and 'dd'
bindkey -M vicmd 'Y' vi-yank-whole-line bindkey -M vicmd 'Y' vi-yank-whole-line
@ -109,9 +129,6 @@ bindkey -M vicmd 'j' history-substring-search-down
bindkey -r '^[h' bindkey -r '^[h'
bindkey -M vicmd 'K' run-help bindkey -M vicmd 'K' run-help
# Disable Ex mode with ':'
bindkey -rM vicmd ':'
# Enable '<Shirt><Tab>' reverse order completions # Enable '<Shirt><Tab>' reverse order completions
bindkey '^[[Z' reverse-menu-complete bindkey '^[[Z' reverse-menu-complete
@ -120,17 +137,22 @@ autoload -U edit-command-line
zle -N edit-command-line zle -N edit-command-line
bindkey -M vicmd '^V' edit-command-line bindkey -M vicmd '^V' edit-command-line
# Get the shells parent process name. # Enable HOME and END keys
ppid_name() { echo $(ps -p $(ps -p $(echo $$) -o ppid=) -o comm=) } if [[ `uname` = Linux ]]; then
# If Home and End are not working as expected setup zkbd mappings.
[ -f ~/.zkbd/$TERM-${${DISPLAY:t}:-$VENDOR-$OSTYPE} ] && \
source ~/.zkbd/$TERM-${${DISPLAY:t}:-$VENDOR-$OSTYPE}
[[ -n ${key[Home]} ]] && bindkey "${key[Home]}" beginning-of-line
[[ -n ${key[End]} ]] && bindkey "${key[End]}" end-of-line
fi
# Enable changing cursor shape based on vi mode # Enable changing cursor shape based on vi mode
if [ "$ITERM_PROFILE" != "" ] && [ "$TMUX" = "" ]; then if [ "$ITERM_PROFILE" != "" ] && [ "$TMUX" = "" ]; then
# iTerm2 cursor shape escape sequences outside tmux # iTerm2 cursor shape escape sequences outside tmux
cursor_block="\e]50;CursorShape=0\C-G" cursor_block="\e]50;CursorShape=0\C-G"
cursor_line="\e]50;CursorShape=1\C-G" cursor_line="\e]50;CursorShape=1\C-G"
elif [ "$(ppid_name)" != "python2" ]; then else
# iTerm2 inside tmux or VTE compatible cursor shape escape sequences, # iTerm2 inside tmux or VTE compatible cursor shape escape sequences.
# exclude Guake even though it's VTE based it doesn't like these
cursor_block="\e[2 q" cursor_block="\e[2 q"
cursor_line="\e[6 q" cursor_line="\e[6 q"
fi fi
@ -155,48 +177,70 @@ if [[ ! -z "$cursor_block" && ! -z "$cursor_line" ]]; then
zle -N zle-line-finish zle -N zle-line-finish
fi fi
# Frequntly used directories
function frequent-directory() {
if [ -d "$2" ]; then
# Replace - with _ in environment variable name.
local name=${1//-/_}
local value=$2
export $name=$value
hash -d $1
fi
}
frequent-directory Desktop "$HOME/Desktop"
frequent-directory Documents "$HOME/Documents"
frequent-directory Downloads "$HOME/Downloads"
frequent-directory Projects "$HOME/Projects"
frequent-directory Sandbox "$HOME/Sandbox"
frequent-directory cache "${XDG_CACHE_HOME:-$HOME/.cache}"
frequent-directory config "${XDG_CONFIG_HOME:-$HOME/.config}"
frequent-directory local "$HOME/.local"
# Load work related config # Load work related config
[ -f ~/.config/work/zshrc ] && source ~/.config/work/zshrc [ -f ${XDG_CONFIG_HOME:-$HOME/.config}/work/zshrc ] && \
source ${XDG_CONFIG_HOME:-$HOME/.config}/work/zshrc
# Remove duplicates from environment variables [ -f ${XDG_CONFIG_HOME:-$HOME/.config}/private/zshrc ] && \
typeset -U PATH source ${XDG_CONFIG_HOME:-$HOME/.config}/private/zshrc
typeset -U MANPATH [ -f ${XDG_CONFIG_HOME:-$HOME/.config}/zsh/local ] && \
typeset -U INFOPATH source ${XDG_CONFIG_HOME:-$HOME/.config}/zsh/local
[ -f ${XDG_CONFIG_HOME:-$HOME/.config}/zsh/zshrc.local ] && \
# Add ccache symlink directory to start of PATH, this must be after source ${XDG_CONFIG_HOME:-$HOME/.config}/zsh/zshrc.local
# `typeset -U PATH` because on macOS this reorders the list so ccache's
# symlinks will no longer be at the start of PATH rendering it unusable.
if [ `uname` = Darwin ]; then
[ -f /usr/local/bin/ccache ] && \
PATH=/usr/local/opt/ccache/libexec:$PATH
else
[ -f /usr/bin/ccache ] && \
PATH=/usr/lib/ccache:$PATH
fi
# Aliases # Aliases
alias grep='grep --color=always' alias grep='grep --color=always'
which cmake &> /dev/null && \ command -v cmake &> /dev/null && \
alias cninja='cmake -GNinja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON' alias cninja='cmake -GNinja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON'
which ssh &> /dev/null && \ command -v ssh &> /dev/null && \
alias ssh='TERM=xterm-256color ssh' alias ssh='TERM=xterm-256color ssh'
alias weather="curl wttr.in"
alias cls="clear && printf '\e[3J'"
case `uname` in case `uname` in
Linux) Linux)
[ "$TMUX" = "" ] && \
alias cls="printf '\ec'" || \
alias cls="clear && printf '\e[3J'"
alias ls='ls -F --color=auto' alias ls='ls -F --color=auto'
if which cgdb &> /dev/null; then if command -v cgdb &> /dev/null; then
alias debug='cgdb --args' alias debug='cgdb --args'
elif which gdb &> /dev/null; then elif command -v gdb &> /dev/null; then
alias debug='gdb --args' alias debug='gdb --args'
fi fi
;; ;;
Darwin) Darwin)
alias cls="clear && printf '\e[3J'"
alias ls='ls -GFh' alias ls='ls -GFh'
which lldb &> /dev/null && \ command -v lldb &> /dev/null && \
alias debug='lldb --' alias debug='lldb --'
;; ;;
esac esac
command -v wol > /dev/null && \
alias wakeonlan='wol'
# Append any aliases to notify_ignore_list if they contain any ignore commands
# NOTE: Keep this at the end of ~/.zshrc so all aliases are processed
for name in ${(k)aliases}; do
cmd=${${${$(alias $name)#${name}=}#\'}#\"}
for ignore in $notify_ignore_list; do
if [[ "$cmd" = "$ignore"* ]]; then
notify_ignore_list+=( $name )
fi
done
done