#+title: My .zshrc file #+author: Jacopo De Simoi #+hugo_base_dir: /ssh:ssh.jacopods.xyz:gists/ #+hugo_section: zshrc #+options: creator:t toc:nil * Setup org-babel This helper function checks the tags of the current headline and returns a list of corresponding filenames. For instance if the tags are daily and pi, the function returns '(".zshrc" ".zshrc.pi") #+name:def-tag #+begin_src emacs-lisp :results output silent (setq-local tag-to-filenames-alist '( ("daily" . ".zshrc") ("spare" . ".zshrc.spare") ("pi" . "/ssh:ssh.jacopods.xyz:.zshrc") ("android" . ".zshrc.android"))) (defun org-tags-to-filenames () (when (boundp 'tag-to-filenames-alist) (let ((tags (car (last (org-heading-components))))) (when (stringp tags) (remove nil (mapcar (lambda (tag) (cdr (assoc tag tag-to-filenames-alist))) (org-split-string tags ":"))))))) #+end_src Execute the following block to export and publish on the π #+begin_src emacs-lisp :results no (org-hugo-export-wim-to-md t) (shell-command "ssh ssh.jacopods.xyz 'cd gists;/snap/bin/hugo -D;rsync -rP public/* /var/www/html'") #+end_src #+RESULTS: : 0 * zshrc :@zsh: All posts in here will have the category set to /zsh/. ** zshrc :properties: :export_file_name: zshrc-file :export_date: 2020-08-05 :export_hugo_menu: :menu "main" :header-args: :tangle (org-tags-to-filenames) :end: This is my ~.zshrc~; it will be used in many environments: - daily driver (gentoo box with kde) - spare boxes (gentoo boxes (e.g. xspoons, eightspoons)) - android box in termux - raspberry π Each environment has slightly different setups, which will be tangled to different files according to the function `org-tags-to-filenames', defined in the previous section. *** TODO should conditionally add stuff for root and non-root users What would be easier? runtime or not? *** TODO replace em-world alias with a function accepting arguments now, the em-world is an alias that only exists in the version of zshrc that I use for root. How do I want to proceed? *** TODO have a look at this idea: Instead of defining a lot of functions in your `.zshrc', all of which you may not use, it is often better to use the autoload builtin. The idea is, you create a directory where function definitions are stored, declare the names in your `.zshrc', and tell the shell where to look for them. Whenever you reference a function, the shell will automatically load it into memory. #+begin_src sh :tangle no % mkdir /tmp/funs % cat >/tmp/funs/yp ypmatch $1 passwd.byname ^D % cat >/tmp/funs/cx chmod +x $* ^D % FPATH=/tmp/funs % autoload cx yp % functions cx yp undefined cx () undefined yp () % chmod 755 /tmp/funs/{cx,yp} % yp egsirer egsirer:*:3214:35:Emin Gun Sirer:/u/egsirer:/bin/sh % functions yp yp () { ypmatch $1 passwd.byname } #+end_src *** Include :daily: First, include a script that sets a number of confidential data (e.g. API keys and such) #+begin_src sh source ~/.config/confidential.sh # This defines a number of env variables: # ANDROID_A3=xxxx # ANDROID_BLU=xxx # ANDROID_IP=xxx.xxx.xxx.xxx #+end_src Then, add helper directory to fpath #+begin_src sh fpath=(~/clones/zshrc/ $fpath) #+end_src *** urxvt helpers :daily: #+begin_src sh function terminal-size () { case $1 in 2560x1440) echo 82x71;; 1080x1920) echo 104x47;; 2240x1400) echo 71x69;; esac } #+end_src *** KDE helpers :daily: #+begin_src sh :tangle kde-utils.sh #!/bin/zsh function kde-active-output-name () { qdbus6 org.kde.KWin /KWin org.kde.KWin.activeOutputName } function kde-active-output-resolution () { kscreen-console outputs | grep $(kde-active-output-name) -A10 | grep "^Size:" 2&>/dev/null | cut -f2 -d'(' | sed -e 's/)//' -e 's/, /x/' } function kde-current-activity-name () { qdbus6 org.kde.ActivityManager /ActivityManager/Activities org.kde.ActivityManager.Activities.ActivityName `kde-current-activity` } #+end_src Define a number of KDE helpers. - ~kde-current-activity~ returns the id of the current activity - ~kde-current-activity-name~ returns the name of the current activity #+begin_src sh :tangle kde-utils.sh #!/bin/zsh function kde-current-activity () { qdbus6 org.kde.ActivityManager /ActivityManager/Activities org.kde.ActivityManager.Activities.CurrentActivity } function kde-current-activity-name () { qdbus6 org.kde.ActivityManager /ActivityManager/Activities org.kde.ActivityManager.Activities.ActivityName `kde-current-activity` } #+end_src - ~kde-cd-build~ changes directory to the build dir of the current project - ~kde-cd-src~ changes directory to the src dir of the current project #+begin_src sh :tangle kde-utils.sh local kde_src_basedir="kde/src" local kde_build_basedir="kde/build" function kde-cd-build () { cd ${PWD/$kde_src_basedir/$kde_build_basedir/} } function kde-cd-src () { cd ${PWD/$kde_build_basedir/$kde_src_basedir/} } #+end_src - ~kde-osd-message~ Sends a message through OSD #+begin_src sh :tangle kde-utils.sh function kde-osd-message() { qdbus6 org.freedesktop.Notifications /org/kde/osdService org.kde.osdService.showText alert $1 } #+end_src #+begin_src sh source ~/scripts/kde-utils.sh #+end_src *** Do not litter :daily: #+begin_src sh if [ "$TERM_PROGRAM" = tmux ]; then # suppress tmout in tmux else TMOUT=300 fi #+end_src *** Android helpers :daily: These are various helpers to drive my current Android phone when connected to the box. #+begin_src sh function run-task () { adb -s $ANDROID_CUR shell am broadcast --user 0 -a net.dinglish.tasker.run_task -e task "$1" } function android-remote-keyboard() { # should set this up in a tmux session adb -s $ANDROID_CUR shell ime set de.onyxbits.remotekeyboard/.RemoteKeyboardService; adb -s $ANDROID_CUR forward tcp:6023 tcp:2323; sleep 1; telnet 127.0.0.1 6023 } function android-remote-keyboard-wifi() { # should set this up in a tmux session adb -s $ANDROID_IP:5555 shell ime set de.onyxbits.remotekeyboard/.RemoteKeyboardService; adb -s $ANDROID_IP:5555 forward tcp:6023 tcp:2323; sleep 1; telnet 127.0.0.1 6023 } function android-remote-keyboard-blu() { # should set this up in a tmux session adb -s $ANDROID_BLU shell ime set de.onyxbits.remotekeyboard/.RemoteKeyboardService; adb -s $ANDROID_BLU forward tcp:6028 tcp:2323; sleep 1; telnet 127.0.0.1 6028 } function setup-ipwebcam() { adb -s $ANDROID_BLU forward tcp:8097 tcp:8080 ffmpeg -i http://localhost:8097/video -map 0:v -pix_fmt yuv420p -f v4l2 /dev/video2 adb -s $ANDROID_BLU forward --remove tcp:8097 } function setup-pi-webcam() { ffmpeg -i http://192.168.0.41:8080/stream/video.mjpeg -map 0:v -pix_fmt yuv420p -f v4l2 /dev/video2 } #+end_src This is an autoremote helper #+begin_src sh function autoremote () { curl "https://autoremotejoaomgcd.appspot.com/sendmessage?key=f8eK0OaZQVk:APA91bEZaciLdVb_c4yv2fNQW-2iSEjJ-2MYZMBokyGhrdLe1AKwt-zxm1C_WKdZ1prBYho8BKqKj4YTR4jzt6LQv9oRjrYrvKiRgs8ghFmnqmOT98qJCFFAsLaxpKyAgZx_M6UuH-Rk&message=$(echo $1 | sed -e 's/ /\%20/g')&password=$(pass autoremote)" } #+end_src **** TODO The last bit is really pi material *** Misc helpers :pi:daily:android: - tmux guard This function checks if we are in a tmux session before executing the command; otherwise print an error and bail out #+begin_src sh function tmux-guard() { if [[ -v TMUX ]]; then $@ else echo tmux-guard: ensure you are in a tmux session to run $@ fi } #+end_src - wttr.in #+begin_src sh function wttr() { local location=Toronto [[ $(tput cols) -le 124 ]] && local narrow=n; curl -H "Accept-Language: ${LANG%_*}" wttr.in/"${1:-$location}?T$narrow" } #+end_src - This is an helper for moving a file to some other place and adding a link back to the original position. ~bl~ stands for backlink BIG FAT WARNING: this needs to specify an actual file as a destination (similar to ln) adding a directory would not work. #+begin_src sh function bl() { mv $1 $2 ln $2 $1 } #+end_src *** xournal helper :daily: - xournal make #+begin_src sh function xou-mk () { /home/jacopods/clones/xournalpp/build/xournalpp $1 -p ${1:r}.pdf } #+end_src *** konsole helpers :daily: #+begin_src sh function set-terminal-title() { echo -en "\e]2;$@\a" } function get-konsole-title() { qdbus "${KONSOLE_DBUS_SERVICE}" "${KONSOLE_DBUS_SESSION}" tabTitleFormat 0 } function set-konsole-title() { qdbus "${KONSOLE_DBUS_SERVICE}" "${KONSOLE_DBUS_SESSION}" setTabTitleFormat 0 $1 } function set-konsole-pomo-title() { previous_title=$(get-konsole-title) set-konsole-title "pomodoro"; } function restore-konsole-title() { set-konsole-title ${previous_title} } #+end_src *** color helpers :daily: #+begin_src sh function lunarized-pick() { (cd ~/scripts/.lunarized; cat $(find | grep -v "^.$" | sed -e "s+^./++" | fzf)) } #+end_src *** paper-books helpers :daily: #+begin_src sh function o--generic () { (cd $1; eca "$(find | sed -e "s+^./++" | fzf)") } function o--generic-pdf () { (cd $1; eca "$(find -iname "*pdf" | sed -e "s+^./++" | fzf)") } #+end_src Should we rather use aliases? yes please #+begin_src sh function o-books () { (o--generic ~/work/books) } function o-papers () { (o--generic ~/work/papers) } function o-offprints () { (o--generic ~/work/offprints) } function o-cmp () { (o--generic-pdf ~/work/editor/cmp/submissions) } #+end_src *** shell helpers :daily:pi:android: This function is a poor-man eselect for configuration files it mv's filename to filename_ or viceversa #+begin_src sh function uv() { if [[ -f $1 ]]; then if [[ ${1:(-1)} == '_' ]]; then mv -i $1 ${1%_} else mv -i $1 $1_ fi else echo $0: \'$1\': no such file or directory return 1 fi } #+end_src *** emacs helpers :daily:pi: Here we take care of setting up the emacs workflow **** Emacs aliases for the pi :pi: #+begin_src sh export EMACS="emacsclient" export EMACS_DEF_ARGUMENTS="--alternate-editor=emacs" #+end_src **** specialized helper for the daily box :daily: #+begin_src sh export EMACS="/home/jacopods/.emacs.d/emacsclient-activities" export EMACS_DEF_ARGUMENTS="" #+end_src **** Define the eca function :daily:pi: #+begin_src sh # Emacs stuff SOLARIZED="true" eca() { if [[ "$SSH_CONNECTION" != '' ]]; then EMACS_ARGUMENTS="-t" else EMACS_ARGUMENTS="-n" fi $EMACS $EMACS_DEF_ARGUMENTS $EMACS_ARGUMENTS $@ } #+end_src **** magit :daily:pi: #+begin_src sh magit() { # TODO: add parameter just in case eca -e "(magit-status \"$(pwd)\")" eca -e "(x-focus-frame nil)" } bindkey -s '^X^G' 'magit\n' #+end_src **** mu4e + agenda :daily: #+begin_src sh function μ() { eca -e "(mu4e)" eca -e "(x-focus-frame nil)" } bindkey -s '^Xμ' 'μ\n' function agenda() { # TODO: add parameter just in case eca -e "(org-agenda-list)" eca -e "(x-focus-frame nil)" } function kill-emacs() { eca -e "(kill-emacs)" } #+end_src *** media helpers :daily: **** brownian noise :daily: #+begin_src sh function brown () { if [ $# -eq 1 ]; then mpv ~/sound/brown.flac -loop=$(($1-1)) else mpv ~/sound/brown.flac fi } #+end_src **** Fuzzy search unreal mods and play for 25 minutes :daily: #+begin_src sh alias xmp-unreal='(cd ~/tmp/unreal-mods; xmp "$(find . | fzf)" -U 1500)' #+end_src *** oh-my-zsh setup :daily:pi:android: #+begin_src sh # Path to your oh-my-zsh configuration. ZSH=$HOME/.oh-my-zsh # Set name of the theme to load. # Look in ~/.oh-my-zsh/themes/ ZSH_THEME="gentoo-wilder" # Set to this to use case-sensitive completion CASE_SENSITIVE="true" # Uncomment this to disable bi-weekly auto-update checks # DISABLE_AUTO_UPDATE="true" # Uncomment to change how often before auto-updates occur? (in days) # export UPDATE_ZSH_DAYS=13 # Uncomment following line if you want to disable colors in ls # DISABLE_LS_COLORS="true" # Uncomment following line if you want to disable autosetting terminal title. DISABLE_AUTO_TITLE="true" # Uncomment following line if you want to disable command autocorrection # DISABLE_CORRECTION="true" # Uncomment following line if you want red dots to be displayed while waiting for completion # COMPLETION_WAITING_DOTS="true" # Uncomment following line if you want to disable marking untracked files under # VCS as dirty. This makes repository status check for large repositories much, # much faster. DISABLE_UNTRACKED_FILES_DIRTY="true" eval `dircolors ~/.dir_colors` setopt AUTO_PUSHD setopt PUSHD_MINUS setopt BASH_AUTO_LIST setopt RM_STAR_WAIT setopt HIST_FIND_NO_DUPS setopt AUTO_NAME_DIRS setopt CDABLE_VARS # Uncomment following line if you want to shown in the command execution time stamp # in the history command output. The optional three formats: "mm/dd/yyyy"|"dd.mm.yyyy"| # yyyy-mm-dd # HIST_STAMPS="mm/dd/yyyy" # Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*) # Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/ # Example format: plugins=(rails git textmate ruby lighthouse) plugins=(git colorize wd history-substring-search) export FZF_WD_BINDKEY="^X^B" source $ZSH/oh-my-zsh.sh #source $ZSH/z.sh if [[ "$TERM" == "dumb" ]] then unsetopt zle unsetopt prompt_cr unsetopt prompt_subst unfunction precmd unfunction preexec PS1='$ ' fi # try to use system colors for completion zstyle ':completion:*' list-colors "${(@s.:.)LS_COLORS}" # reset default oh-my-zsh matcher-list zstyle ':completion:*' matcher-list '' # smart: ignore parent directory when completing ../ zstyle ':completion:*:(cd|mv|cp):*' ignore-parents parent pwd zstyle ':completion:*:(rm|kill|diff):*' ignore-line yes autoload -U compinit && compinit # User configuration export PATH="/usr/local/bin:/usr/bin:/bin:/opt/bin:/usr/games/bin:$PATH" bindkey -s '^[(' '()^B' bindkey -s '^[{' '{}^B' # Make ctrl-Backspace work bindkey "\e[9;5~" backward-delete-word autoload zmv #+end_src This expands ... to ../.. and so on. See [[https://stackoverflow.com/questions/23456873/multi-dot-paths-in-zsh-like-cd][this post]] for source and further reference #+begin_src sh if is-at-least 5.0.0 && [[ ! $UID -eq 0 ]]; then ## http://www.zsh.org/mla/users/2010/msg00769.html function rationalize-dot() { local MATCH # keep the regex match from leaking to the environment if [[ $LBUFFER =~ '(^|/| | |'$'\n''|\||;|&)\.\.$' && ! $LBUFFER = p4* ]]; then #if [[ ! $LBUFFER = p4* && $LBUFFER = *.. ]]; then LBUFFER+=/.. else zle self-insert fi } zle -N rationalize-dot bindkey . rationalize-dot bindkey -M isearch . self-insert fi #+end_src *** TODO editor env variables :daily: This needs to be diff'd among the versions #+begin_src sh export EDITOR="$EMACS -n" export VISUAL=$EDITOR export GIT_EDITOR=$EMACS export SUDO_EDITOR=$EMACS #+end_src *** pass management :daily: #+begin_src sh alias pass-fzf="PASSWORD_STORE_ENABLE_EXTENSIONS=true pass fzf" #+end_src *** fzf colour options :daily: #+begin_src sh export FZF_DEFAULT_OPTS=" --color='dark,fg+:red,pointer:red,info:blue,hl:yellow,hl+:yellow'" #+end_src *** git helpers :daily: #+begin_src sh function git-create-pi-remote () { REPO_NAME=$(basename "`pwd`") source ~/scripts/git-init-pi4.sh "$REPO_NAME.git" git remote add π "git@ssh.jacopods.xyz:repos/$REPO_NAME.git" } function git-create-thinkspoon-remote () { REPO_NAME=$(basename "`pwd`") source ~/scripts/git-init-thinkspoon.sh "$REPO_NAME.git" git remote add thinkspoon "git@thinkspoon.local:repos/$REPO_NAME.git" } function git-current-branch () { # do I want to give up on revision numbers in detached-head state? git rev-parse --abbrev-ref HEAD | grep -v HEAD || \ git describe --exact-match HEAD 2> /dev/null || \ git rev-parse HEAD } #+end_src **** TODO Create a script to add an arbitrary remote *** Aliases :pi:android:daily: #+begin_src sh ## Aliases alias e="eca" alias E=sudoedit alias mpv-pomodoro="mpv --script=~/scripts/mpv/auto-pomodoro.lua" alias alexa="/home/jacopods/clones/alexa-remote-control/alexa_remote_control.sh" alias ta="tmux attach" #+end_src **** Aliases specific for daily :daily: #+begin_src sh alias urxvt="urxvtc" alias mpv="mpv --no-audio-display" alias top="urxvt -e htop &" alias mk="~/scripts/latex-mk $@" alias neofetch="~/clones/neofetch/neofetch --source ~/clones/neofetch/ascii/gentoo-one --separator ' ▏' --bold off --colors 13 12 5 1 12 12 | sed -e 's/bree/Bree/g' | sed -e 's/2560x/2560×/'" alias xou="source /home/jacopods/scripts/setwacom.sh;/home/jacopods/clones/xournalpp/build/xournalpp" alias xmp="/home/jacopods/clones/xmp-cli/src/xmp" #+end_src **** Aliases for the pi :pi: #+begin_src sh alias hugo="/snap/bin/hugo" #+end_src *** dnd management :daily: #+begin_src sh alias with-dnd="~/scripts/dnd-wrapper.py " #+end_src This silences the fan: #+begin_src sh alias with-power-save="powerprofilesctl launch -p power-saver -r 'quiet operations' " #+end_src *** with-mpc :daily: #+begin_src sh function with-mpc-fade () { ~/scripts/mpc-fade $@ ~/scripts/mpc-fade } # Define an alias with a space at the end so that we can chain with # other non-global aliases () alias with-mpc-fade='with-mpc-fade ' #+end_src *** Pomodoro aliases :pi:android: These aliases help setting up termdown to countdown for the pomodoro technique #+begin_src sh termdown_bin=/usr/bin/termdown alias pomo="$termdown_bin 25m -aW -f 3x5 -c 180 -b -q 10 -s $@" alias heirloom="$termdown_bin -s 37m -aW -f 3x5 -c 300 -b -q 10 $@" alias pomodorino="$termdown_bin 14m -aW -f 3x5 -c 120 -b -q 10 -s $@" alias pomodoro=pomo alias pomo-break="$termdown_bin 5m -aW -f 3x5 -c 60 -b -q 10 $@" alias pomodorino-break="$termdown_bin 2m30s -aW -f 3x5 -c 45 -b -q 10 $@" #+end_src *** Wrapped pomodoro aliases :daily: Here we wrap the commands in a python script that takes care of setting do not disturb on the KDE notification system #+begin_src sh termdown_bin=/usr/bin/termdown termdown_opts="-aWb -f 3x5 " pomo_cmd="$termdown_bin $termdown_opts 25m -c 180 -q 10 -s $@" heirloom_cmd="$termdown_bin $termdown_opts 37m -c 300 -q 10 -s $@" pomodorino_cmd="$termdown_bin $termdown_opts 14m -c 120 -q 10 -s $@" pomo_break_cmd="$termdown_bin $termdown_opts 5m -c 60 -q 10 $@" pomodorino_break_cmd="$termdown_bin 2m30s $termdown_opts -c 45 -q 10 $@" alias pomo="with-dnd '$pomo_cmd' Pomodoro" alias pomodoro=pomo alias heirloom="with-dnd '$heirloom_cmd' Pomodoro" alias pomodorino="with-dnd '$pomodorino_cmd' Pomodoro" alias pomo-break="with-dnd '$pomo_break_cmd' Pomodoro" alias pomodorino-break="with-dnd '$pomodorino_break_cmd' Pomodoro" #+end_src *** Android aliases :daily: #+begin_src sh alias android-unlock='~/scripts/unlock-android.sh' #$(cat ~/scripts/unlock-android.gpg | gpg 2>/dev/null)' alias android-kbd="android-remote-keyboard" alias dock="~/scripts/dock-a3.sh" #+end_src *** Misc helpers :daily: #+begin_src sh alias K=/home/jacopods/tmp/keymaps/remap-keyboard export EZA_COLORS="xx=0" alias ls=' eza --no-quotes' alias sl=' eza --no-quotes' # a frequent typo alias c=' cd' alias cd=' cd' alias o="xdg-open" alias acroread="env WINEPREFIX=$HOME/.wine32 WINEARCH='win32' wine ~/.wine32/drive_c/Program\ Files/Adobe/Reader\ 11.0/Reader/AcroRd32.exe >/dev/null 2>/dev/null" function run-silent() { "$@" 2>/dev/null } alias git-init-coxeter="source ~/scripts/git-init-coxeter.sh" alias -s pdf='run-silent okular' alias -s djvu='run-silent okular' alias -s tex=emacs alias d.u='ssh dropbox.utoronto "~/dropbox.py"' alias -g C='| xclip' #+end_src *** Named directories :daily: Add frequently accessed directories to the hash for quicker reference #+begin_src sh hash -d papers="/home/jacopods/work/papers" hash -d books="/home/jacopods/work/books" hash -d kde="/scratch/src/kde" hash -d kwin="/scratch/src/kde/kde/workspace/kwin" #+end_src *** Un-colemak bindings :daily: Mitigate muscle memory typos by changing the bindings for the keys ~t~ and ~f~ in colemak #+begin_src sh bindkey "^t" forward-char bindkey "^[t" forward-word bindkey "^g" transpose-chars bindkey "^[g" transpose-words #+end_src *** Connection warning :daily: #+begin_src sh ip a | grep nordlynx >>/dev/null && echo → Connected to $fg_bold[magenta]NordVPN$reset_color true #+end_src **** TODO Rearrange this bit :PROPERTIES: :CREATED: [2021-05-01 Sat 13:35] :END: * Local variables # local variables: # org-confirm-babel-evaluate: nil # eval: (save-excursion (org-babel-goto-named-src-block "def-tag") # (org-babel-execute-src-block) (outline-hide-sublevels 1)) # end: