26 Commits

Author SHA1 Message Date
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
13 changed files with 356 additions and 267 deletions

View File

@@ -3,11 +3,12 @@
- apt:
- zsh
- zsh-doc
- pinentry-curses
- brew:
- zsh
- command:
- install: sudo chsh $USER -s `which zsh`
remove: sudo chsh $USER -s `which bash`
- install: sudo chsh -s `which zsh` $USER
remove: sudo chsh -s `which bash` $USER
- symlink:
- {src: zlogin, dst: ~/.zlogin}
- {src: zlogout, dst: ~/.zlogout}

View File

@@ -51,10 +51,26 @@ display. This results in no noticeable lag when redrawing the prompt.
Plugins are sourced manually and their git repositories tracked by
[conduit][conduit], no plugin manager is used.
* [zsh-syntax-highlighting][syntax] Fish shell like syntax highlighting for Zsh.
* [zsh-autosuggestions][zsh-autosuggestions] Fish-like autosuggestions for zsh.
* [fast-syntax-highlighting][syntax] Optimized and extended
zsh-syntax-highlighting - Fish shell like syntax highlighting for Zsh.
* [zsh-history-substring-search][search] Zsh port of the Fish shell's history
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
The bulk of, if not all, configuration occurs in [`zshenv`](zshenv) and
@@ -135,7 +151,9 @@ Various aliases are defined at the end of [zshrc](zshrc) for convenience.
[zsh]: https://www.zsh.org/
[git]: https://git-scm.com/
[git-prompt]: https://github.com/olivierverdier/zsh-git-prompt
[syntax]: https://github.com/zsh-users/zsh-syntax-highlighting
[zsh-autosuggestions]: https://github.com/zdharma/fast-syntax-highlighting
[zsh-autoenv]: https://github.com/Tarrasch/zsh-autoenv
[syntax]: https://github.com/zdharma/fast-syntax-highlighting
[search]: https://github.com/zsh-users/zsh-history-substring-search
[vim-mode]: https://github.com/sharat87/zsh-vim-mode
[tmux]: https://tmux.github.io

View File

@@ -75,6 +75,9 @@ commands:
# Global entered directories array.
_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,
# ignore, or view the file. Authorized files and their modified times are
# stored in the ~/.cache/autoenv/authorized file to make authorization

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,7 +7,10 @@ alias build="build-dir --build"
# Detect installed debugger and set the `debug` alias to debug a program with
# command line arguments.
if [ `uname` = Linux ]; then
if which cgdb &> /dev/null; then
if [[ "`vim --version`" =~ "^VIM - Vi IMproved 8\.1.*$" ]]; then
function vimdebug() { vim "+packadd termdebug" "+TermdebugCommand $*" }
alias debug='vimdebug'
elif which cgdb &> /dev/null; then
alias debug='cgdb --args'
elif which gdb &> /dev/null; then
alias debug='gdb --args'
@@ -37,31 +40,34 @@ optional arguments:
EOF
return
fi
error() { echo "\e[31merror:\e[0m $1"; return 1 }
local build_dir
error() { echo "\e[31merror:\e[0m $1" }
warning() { echo "\e[33mwarning:\e[0m $1" }
local local_build_dir
if [[ ${#*} -gt 1 ]]; then
echo $usage
error "unexpected position arguments: ${*[2,${#*}]}"
error "unexpected position arguments: ${*[2,${#*}]}"; return 1
elif [[ ${#*} -eq 1 ]]; then
build_dir=${*[1]}
[[ ! -d $build_dir ]] && \
error "directory not found: $build_dir"
if [[ ! -d ${*[1]} ]]; then
warning "directory not found: ${*[1]}"
else
local_build_dir=${*[1]}
fi
fi
# If <directory> was not set begin selection
if [[ -z $build_dir ]]; then
if [[ -z $local_build_dir ]]; then
# Find build directories
local -a build_dirs
local -a local_build_dirs
for entry in `ls -A`; do
[ -d $entry ] && [[ $entry =~ build* ]] && \
build_dirs+=${entry/\//}
local_build_dirs+=${entry/\//}
done
# Interactively select a build directory if more than 1 found
integer index=0
if [[ ${#build_dirs} -eq 0 ]]; then
error "no build directories found"
elif [[ ${#build_dirs} -gt 1 ]]; then
if [[ ${#local_build_dirs} -eq 0 ]]; then
error "no build directories found"; return 1
elif [[ ${#local_build_dirs} -gt 1 ]]; then
zmodload zsh/curses && {
# Get the size of the terminal
local size=`stty size`
@@ -86,13 +92,13 @@ EOF
zcurses string build-dir 'Select a build directory:'
# Add the selections text
for (( i = 0; i < ${#build_dirs}; i++ )); do
for (( i = 0; i < ${#local_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]}
zcurses string build-dir ${local_build_dirs[$i+1]}
done
# Display the text the and wait for input
@@ -104,7 +110,7 @@ EOF
(UP|k|$'\C-P')
[[ $index -gt 0 ]] && index=$index-1 ;;
(DOWN|j|$'\C-N')
[[ $index -lt ${#build_dirs}-1 ]] && index=$index+1 ;;
[[ $index -lt ${#local_build_dirs}-1 ]] && index=$index+1 ;;
(ENTER|$'\n')
break ;;
esac
@@ -121,35 +127,38 @@ EOF
# On success setup the build directory for use
if [[ $? -eq 0 ]]; then
# Set the build directory from selection if empty
[[ -z $build_dir ]] && \
build_dir=${build_dirs[$index+1]}
[[ -z $local_build_dir ]] && \
local_build_dir=${local_build_dirs[$index+1]}
# If `build.ninja` exists in alias `ninja`, return.
local build
[ -f $build_dir/build.ninja ] && \
build="ninja -C $build_dir"
[ -f $local_build_dir/build.ninja ] && \
build="ninja -C $local_build_dir"
# If `Makefile` exists in alias `make`, return.
if [ -f $build_dir/Makefile ]; then
if [ -f $local_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"
build="make -j $cpu_count -C $local_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"
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=$build_dir
hash -d build=$local_build_dir
export build_dir=$local_build_dir
# If `--build` is specified then evaluate the command.
[[ -n $do_build ]] && eval build
if [[ -n $do_build ]]; then
eval build
fi
fi
}

202
git-prompt.c Normal file
View File

@@ -0,0 +1,202 @@
#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;
}

View File

@@ -1,7 +1,7 @@
#compdef layout
__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
}

View File

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

View File

@@ -1,17 +1,18 @@
prompt_fresh_help() {
echo "\
options:
-a enable almostontop like behaviour"
-a enable almostontop like behaviour
-r recompile git-prompt executable"
}
prompt_fresh_setup() {
fresh_compile_git_prompt
# Parse options
local almostontop=0
while getopts 'a' opt; do
local recompile=0
while getopts 'ar' opt; do
case $opt in
a) local almostontop=1 ;;
r) local recompile=1 ;;
*) prompt -h fresh; return 1 ;;
esac
done
@@ -19,8 +20,8 @@ prompt_fresh_setup() {
autoload -U add-zsh-hook
# 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
# cause lines before the prompt to disappear.
# actually part of the prompt so does not get redrawn, this is preferable
# since sometimes lines before the prompt can disappear.
add-zsh-hook precmd fresh_line_one
if [ $almostontop -eq 1 ]; then
@@ -31,28 +32,29 @@ prompt_fresh_setup() {
add-zsh-hook -d preexec fresh_almostontop
fi
if [ "$USERNAME" = "root" ]; then
local user="%{%F{9}%}%n%{%f%}"
[ $recompile -eq 1 ] && prompt_cleanup
fresh_compile_git_prompt
if [ "$USER" = "root" ]; then
local user="%{%F{1}%}%n%{%f%}"
else
local user="%{%F{35}%}%n%{%f%}"
fi
local userhost=$USER
if [ "$SSH_CONNECTION" != "" ]; then
local user="%{%F{35}%}$user%{%f%}@%{%F{244}%}%M%{%f%}"
local user="$user@%{%F{244}%}%M%{%f%}"
local userhost="$userhost@`hostname`"
fi
local length=`fresh_visible_length "$user"`
PS1="«$user» "
PS2="${(l:$length + 1:: :)}» "
PS2="«${(l:${#userhost}:: :)}» "
RPS1='$(fresh_rprompt)'
prompt_opts=(cr percent sp subst)
prompt_opts=(percent sp subst)
}
prompt_cleanup() {
if [ -f ~/.cache/zsh/git-prompt ]; then rm ~/.cache/zsh/git-prompt; fi
[ -f ~/.cache/zsh/git-prompt ] && rm ~/.cache/zsh/git-prompt
}
fresh_line_one() {
@@ -61,85 +63,30 @@ fresh_line_one() {
# Construct the time and directory portions of the prompt
local time_stamp="%{%F{244}%}%D{%H:%M:%S}%{%f%}"
[[ -n $SANDBOX_HOME ]] && \
local directory="%{%F{3}%}$SANDBOX_NAME${PWD#$SANDBOX_HOME}%{%f%}" || \
local directory="%{%F{37}%}%~%{%f%}"
# Check we are in a git repository
if `git rev-parse --git-dir > /dev/null 2>&1`; then
# 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
local git=`~/.cache/zsh/git-prompt`
# If the last command failed, display its error code at the right
if [[ $exit_code -ne 0 ]]; then
local result=" %{%B%F{1}%}$exit_code%{%f%b%}"
fi
if [ "$branch" != "" ]; then
local branch=${branch#refs/heads/}
# Get the number of commits ahead/behind from the remote branch
local remote="`git config branch.$branch.remote 2> /dev/null`"
if [ "" != "remote" ]; then
local branches="refs/remotes/$remote/$branch...HEAD"
local nahead=`git rev-list --right-only $branches --count 2> /dev/null`
if [ "0" -ne "$nahead" ]; then local ahead="↑$nahead"; fi
local nbehind=`git rev-list --left-only $branches --count 2> /dev/null`
if [ "0" -ne "$nbehind" ]; then local behind="↓$nbehind"; fi
# 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
# Construct the git prompt
local git="%{%F{66}%}$branch%{%f%}$ahead$behind "
if [ -f ~/.cache/zsh/git-prompt ]; then
# Get the change counts from git-prompt
local counts=(`~/.cache/zsh/git-prompt`)
# Parse the results from git-prompt
if [ 0 -eq ${#counts[@]} ]; then # clean
local git="$git%{%B%F{2}%}✓%{%f%b%}";
else
if [ 0 != $counts[1] ]; then # indexed
local git="$git%{%F{2}%}*$counts[1]%{%f%}"
# 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
if [ 0 != $counts[2] ]; then # modified
local git="$git%{%F{1}%}+$counts[2]%{%f%}";
fi
if [ 0 != $counts[3] ]; then # deleted
local git="$git%{%F{1}%}-$counts[3]%{%f%}";
fi
if [ 0 != $counts[4] ]; then # unmerged
local git="$git%{%B%F{1}%}×$counts[4]%{%f%b%}";
fi
if [ 0 != $counts[5] ]; then # untracked
local git="$git%{%F{1}%}…%{%f%}";
fi
fi
fi
fi
fi
# Construct the prompt string
local line="$time_stamp $directory $git"
# Print the first line of the prompt
if [[ $exit_code -eq 0 ]]; then
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() {
rprompt=""
if [[ ! -z "$DOCKER_MACHINE_NAME" ]]; then
rprompt="$rprompt %{%F{3}%}$DOCKER_MACHINE_NAME%{%f%}"
fi
if [[ ! -z "$VIRTUAL_ENV" ]]; then
rprompt="$rprompt %{%F{3}%}$(basename $VIRTUAL_ENV)%{%f%}"
fi
echo $rprompt
print -P "$time_stamp $directory$git$py$docker$result"
}
fresh_almostontop() {
@@ -148,70 +95,15 @@ fresh_almostontop() {
print -P "$PROMPT"'$1'
}
fresh_visible_length() {
echo $(( ${#${(S%%)1//(\%(KF1]|)\{*\}|\%[Bbkf])}} ))
}
fresh_compile_git_prompt() {
# Compile a simple C executable which parses the output of `git status
# --procelain` to greatly decrease the time taken to render the prompt
local cache=~/.cache/zsh
if [ ! -d $cache ]; then mkdir -p $cache; fi
if [ ! -f $cache/git-prompt ]; then
cc -x c -std=gnu99 -O3 -DNDEBUG -o $cache/git-prompt - 2> /dev/null << EOF
#include <stdio.h>
#include <stdlib.h>
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
# Compile a simple C program which parses the output of `git status
# --procelain` to greatly decrease the time taken to draw the prompt
[ ! -d ~/.cache/zsh ] && mkdir -p ~/.cache/zsh
if [ ! -f ~/.cache/zsh/git-prompt ]; then
cc -std=gnu99 -O3 -DNDEBUG -Wno-unused-result \
~/.config/zsh/git-prompt.c -o ~/.cache/zsh/git-prompt
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
}

View File

@@ -1,9 +1,3 @@
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
export SANDBOX_ROOT=$HOME/Sandbox
fi
@@ -33,11 +27,11 @@ sandbox() {
begin=$PWD
cd $sandbox
echo "SANDBOX_HOME=\$(dirname -- "\$0:a")" >> $SANDBOX_ENV_IN_FILE
echo "SANDBOX_NAME=$2" >> $SANDBOX_ENV_IN_FILE
echo "SANDBOX_HOME=\$(dirname -- "\$0:a")" >> .enter
echo "SANDBOX_NAME=$2" >> .enter
echo "unset SANDBOX_NAME" >> $SANDBOX_ENV_OUT_FILE
echo "unset SANDBOX_HOME" >> $SANDBOX_ENV_OUT_FILE
echo "unset SANDBOX_NAME" >> .exit
echo "unset SANDBOX_HOME" >> .exit
git init &> /dev/null
@@ -73,7 +67,7 @@ sandbox() {
rm -rf $sandbox
;;
list)
/bin/ls -1 $SANDBOX_ROOT
/bin/ls -1 $SANDBOX_ROOT | less -F -K -R -X
;;
enable)
if [[ "" == $2 ]]; then

View File

@@ -1,2 +1,7 @@
# .zprofile [1] Used for executing user's commands at start, will be sourced
# 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

29
zshenv
View File

@@ -5,22 +5,35 @@
# Enable saving command history to file
[ ! -d $HOME/.cache/zsh ] && mkdir -p $HOME/.cache/zsh
HISTFILE=$HOME/.cache/zsh/histfile
HISTSIZE=5000
SAVEHIST=5000
HISTSIZE=20000
SAVEHIST=20000
# Remove vi mode switch delay
KEYTIMEOUT=1
# Enable time stats for long lasting commands
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
fpath+=$HOME/.local/share/zsh/site-functions
PATH=$HOME/.local/bin:$PATH
MANPATH=$HOME/.local/share/man:$MANPATH
INFOPATH=$HOME/.local/share/info:$INFOPATH
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
# Remove duplicates from environment variables
typeset -U fpath
typeset -U PATH; export PATH
typeset -U MANPATH; export MANPATH
typeset -U INFOPATH; export INFOPATH
# Use ~/.local for pip installs on macOS
[ "`uname`" = "Darwin" ] && export PYTHONUSERBASE=$HOME/.local
@@ -40,3 +53,7 @@ export GTEST_BREAK_ON_FAILURE=0
# Disable virtualenv prompt
VIRTUAL_ENV_DISABLE_PROMPT=1
# If pinentry-curses exists, use it for lastpass-cli
which pinentry-curses &> /dev/null && \
export LPASS_PINENTRY=pinentry-curses

40
zshrc
View File

@@ -32,18 +32,19 @@ source-plugin build
source-plugin sandbox
# Layout tmux window commands
source-plugin layout
[ "$TMUX" != "" ] && source-plugin layout
# Note taking commands
source-plugin notes
# Remove duplicates from history
setopt hist_ignore_all_dups
setopt hist_reduce_blanks
setopt hist_save_no_dups
setopt histignoredups
# 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
setopt interactive_comments
@@ -52,10 +53,13 @@ setopt interactive_comments
setopt ignore_eof
# Disable sound
unsetopt beep
setopt nobeep
# 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
autoload -U compinit
@@ -82,6 +86,9 @@ prompt fresh
# Enable vi mode line editor keymap
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'
bindkey -M vicmd 'Y' vi-yank-whole-line
@@ -158,22 +165,6 @@ fi
# Load work related config
[ -f ~/.config/work/zshrc ] && source ~/.config/work/zshrc
# Remove duplicates from environment variables
typeset -U PATH
typeset -U MANPATH
typeset -U INFOPATH
# Add ccache symlink directory to start of PATH, this must be after
# `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
alias grep='grep --color=always'
which cmake &> /dev/null && \
@@ -200,3 +191,6 @@ case `uname` in
alias debug='lldb --'
;;
esac
# Hashed Directories
hash -d Projects="$HOME/Projects"