19 Commits

Author SHA1 Message Date
34965bb98d Move entire git-prompt to C 2018-09-11 18:12:45 +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 325 additions and 250 deletions

View File

@@ -6,8 +6,8 @@
- brew: - brew:
- zsh - zsh
- command: - command:
- install: sudo chsh $USER -s `which zsh` - install: sudo chsh -s `which zsh` $USER
remove: sudo chsh $USER -s `which bash` remove: sudo chsh -s `which bash` $USER
- symlink: - symlink:
- {src: zlogin, dst: ~/.zlogin} - {src: zlogin, dst: ~/.zlogin}
- {src: zlogout, dst: ~/.zlogout} - {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 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-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 * [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,7 +151,9 @@ 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
[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 [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
[tmux]: https://tmux.github.io [tmux]: https://tmux.github.io

View File

@@ -75,6 +75,9 @@ commands:
# 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 ~/.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

@@ -37,15 +37,18 @@ optional arguments:
EOF EOF
return return
fi fi
error() { echo "\e[31merror:\e[0m $1"; return 1 } error() { echo "\e[31merror:\e[0m $1" }
warning() { echo "\e[33mwarning:\e[0m $1" }
local build_dir local build_dir
if [[ ${#*} -gt 1 ]]; then if [[ ${#*} -gt 1 ]]; then
echo $usage echo $usage
error "unexpected position arguments: ${*[2,${#*}]}" error "unexpected position arguments: ${*[2,${#*}]}"; return 1
elif [[ ${#*} -eq 1 ]]; then elif [[ ${#*} -eq 1 ]]; then
if [[ ! -d ${*[1]} ]]; then
warning "directory not found: ${*[1]}"
else
build_dir=${*[1]} build_dir=${*[1]}
[[ ! -d $build_dir ]] && \ fi
error "directory not found: $build_dir"
fi fi
# If <directory> was not set begin selection # If <directory> was not set begin selection
@@ -60,7 +63,7 @@ EOF
# 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 [[ ${#build_dirs} -eq 0 ]]; then
error "no build directories found" error "no build directories found"; return 1
elif [[ ${#build_dirs} -gt 1 ]]; then elif [[ ${#build_dirs} -gt 1 ]]; then
zmodload zsh/curses && { zmodload zsh/curses && {
# Get the size of the terminal # Get the size of the terminal
@@ -139,7 +142,7 @@ EOF
# If the build variable is not defined the command could not be determined # If the build variable is not defined the command could not be determined
if [ -z $build ]; then if [ -z $build ]; then
echo "\e[33mwarning:\e[0m build command detection failed: $build_dir" warning "build command detection failed: $build_dir"
# Prompt user to enter a build command # Prompt user to enter a build command
vared -p 'enter comand: ' build vared -p 'enter comand: ' build
fi fi
@@ -149,7 +152,9 @@ EOF
hash -d build=$build_dir hash -d build=$build_dir
# If `--build` is specified then evaluate the command. # If `--build` is specified then evaluate the command.
[[ -n $do_build ]] && eval build if [[ -n $do_build ]]; then
eval build
fi
fi fi
} }

201
git-prompt.c Normal file
View File

@@ -0,0 +1,201 @@
#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
#define check(CONDITION) \
if (CONDITION) { \
fprintf(stderr, "error: %s: %d: %s\n", __FILE__, __LINE__, #CONDITION); \
exit(0); \
}
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;
int i;
va_start(list, count);
for (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() {
process_t process;
// check we are in a git repo
process = process_open("git rev-parse --git-dir");
check(process_close(process));
// get the current branch name
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%}");
}
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 #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 tmux source-file ~/.local/share/tmux/layouts/$1
if [[ "$2" != "" ]]; then if [[ "$2" != "" ]]; then
tmux rename-window $2 tmux rename-window $2
fi fi

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,8 +20,8 @@ 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
@@ -31,28 +32,29 @@ prompt_fresh_setup() {
add-zsh-hook -d preexec fresh_almostontop add-zsh-hook -d preexec fresh_almostontop
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
local userhost=$USER
if [ "$SSH_CONNECTION" != "" ]; then 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 fi
local length=`fresh_visible_length "$user"`
PS1="«$user» " PS1="«$user» "
PS2="${(l:$length + 1:: :)}» " PS2="«${(l:${#userhost}:: :)}» "
RPS1='$(fresh_rprompt)' prompt_opts=(percent sp subst)
prompt_opts=(cr percent sp subst)
} }
prompt_cleanup() { 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() { fresh_line_one() {
@@ -61,85 +63,30 @@ fresh_line_one() {
# 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%}"
[[ -n $SANDBOX_HOME ]] && \
local directory="%{%F{3}%}$SANDBOX_NAME${PWD#$SANDBOX_HOME}%{%f%}" || \
local directory="%{%F{37}%}%~%{%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=`~/.cache/zsh/git-prompt`
# Get git branch name & exit early if not found
local branch="`git symbolic-ref HEAD 2> /dev/null`" # If the last command failed, display its error code at the right
if [ "" = "$branch" ]; then if [[ $exit_code -ne 0 ]]; then
local branch="`git rev-parse --abbrev-ref HEAD`" local result=" %{%B%F{1}%}$exit_code%{%f%b%}"
if [ "HEAD" = "$branch" ]; then
local branch="`git rev-parse --short $branch`"
fi
fi fi
if [ "$branch" != "" ]; then # If a virtualenv is enabled, display it's basename
local branch=${branch#refs/heads/} if [[ ! -z "$VIRTUAL_ENV" ]]; then
# Get the number of commits ahead/behind from the remote branch local py=" %{%F{4}%}py%{%f%}%{%F{3}%}$(basename $VIRTUAL_ENV)%{%f%}"
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
fi fi
# Construct the git prompt # If docker-machine env is active, display the machines name
local git="%{%F{66}%}$branch%{%f%}$ahead$behind " if [[ ! -z "$DOCKER_MACHINE_NAME" ]]; then
local docker=" %{%F{6}%}$DOCKER_MACHINE_NAME%{%f%}"
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%}"
fi 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 # 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() {
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
} }
fresh_almostontop() { fresh_almostontop() {
@@ -148,70 +95,14 @@ fresh_almostontop() {
print -P "$PROMPT"'$1' print -P "$PROMPT"'$1'
} }
fresh_visible_length() {
echo $(( ${#${(S%%)1//(\%(KF1]|)\{*\}|\%[Bbkf])}} ))
}
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 ~/.cache/zsh ] && mkdir -p ~/.cache/zsh
if [ ! -d $cache ]; then mkdir -p $cache; fi if [ ! -f ~/.cache/zsh/git-prompt ]; then
if [ ! -f $cache/git-prompt ]; then cc -std=gnu99 -O3 -DNDEBUG ~/.config/zsh/git-prompt.c -o ~/.cache/zsh/git-prompt
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
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,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 if [[ "" == $SANDBOX_ROOT ]]; then
export SANDBOX_ROOT=$HOME/Sandbox export SANDBOX_ROOT=$HOME/Sandbox
fi fi
@@ -33,11 +27,11 @@ sandbox() {
begin=$PWD begin=$PWD
cd $sandbox cd $sandbox
echo "SANDBOX_HOME=\$(dirname -- "\$0:a")" >> $SANDBOX_ENV_IN_FILE echo "SANDBOX_HOME=\$(dirname -- "\$0:a")" >> .enter
echo "SANDBOX_NAME=$2" >> $SANDBOX_ENV_IN_FILE echo "SANDBOX_NAME=$2" >> .enter
echo "unset SANDBOX_NAME" >> $SANDBOX_ENV_OUT_FILE echo "unset SANDBOX_NAME" >> .exit
echo "unset SANDBOX_HOME" >> $SANDBOX_ENV_OUT_FILE echo "unset SANDBOX_HOME" >> .exit
git init &> /dev/null git init &> /dev/null
@@ -73,7 +67,7 @@ sandbox() {
rm -rf $sandbox rm -rf $sandbox
;; ;;
list) list)
/bin/ls -1 $SANDBOX_ROOT /bin/ls -1 $SANDBOX_ROOT | less -F -K -R -X
;; ;;
enable) enable)
if [[ "" == $2 ]]; then if [[ "" == $2 ]]; then

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

25
zshenv
View File

@@ -5,22 +5,35 @@
# Enable saving command history to file # Enable saving command history to file
[ ! -d $HOME/.cache/zsh ] && mkdir -p $HOME/.cache/zsh [ ! -d $HOME/.cache/zsh ] && mkdir -p $HOME/.cache/zsh
HISTFILE=$HOME/.cache/zsh/histfile HISTFILE=$HOME/.cache/zsh/histfile
HISTSIZE=5000 HISTSIZE=20000
SAVEHIST=5000 SAVEHIST=20000
# 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
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 # Use ~/.local for pip installs on macOS
[ "`uname`" = "Darwin" ] && export PYTHONUSERBASE=$HOME/.local [ "`uname`" = "Darwin" ] && export PYTHONUSERBASE=$HOME/.local

37
zshrc
View File

@@ -32,18 +32,19 @@ source-plugin build
source-plugin sandbox source-plugin sandbox
# 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,10 +53,13 @@ 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
@@ -82,6 +86,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
@@ -158,22 +165,6 @@ fi
# Load work related config # Load work related config
[ -f ~/.config/work/zshrc ] && source ~/.config/work/zshrc [ -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 # Aliases
alias grep='grep --color=always' alias grep='grep --color=always'
which cmake &> /dev/null && \ which cmake &> /dev/null && \