#basics stty -ixon export BROWSER="vivaldi-snapshot" #export BROWSER="qutebrowser" export XDG_CONFIG_HOME="$HOME/.config" export EDITOR="vim" # keep dictionaries in ~/bin/ export STARDICT_DATA_DIR="$HOME/bin/dict/" export NOTES_DIR="$HOME/notes" export TERM="screen-256color" export GREP_COLOR='mt=00;38;5;166' export CM_HISTLENGTH=50 export BAT_THEME="Solarized (dark)" #my scripts on PATH export PATH=/usr/local/bin:$PATH export PATH=$PATH:$HOME/bin export PATH=$PATH:$HOME/bin/bash-scripts tre() { command tre "$@" -e && source "/tmp/tre_aliases_$USER" 2>/dev/null; } # set vi mode but keep control l set -o vi bind -m vi-command 'Control-l: clear-screen' bind -m vi-insert 'Control-l: clear-screen' # Alias definitions if [ -f ~/.aliases ]; then . ~/.aliases fi #make bash better bind "set completion-ignore-case on" bind "set completion-map-case on" bind "set show-all-if-ambiguous on" # Append to the history file, don't overwrite it shopt -s histappend # Save multi-line commands as one command shopt -s cmdhist # Record each line as it gets issued PROMPT_COMMAND='history -a' # Automatically trim long paths in the prompt (requires Bash 4.x) PROMPT_DIRTRIM=2 # Huge history. Doesn't appear to slow things down, so why not? HISTSIZE=500000 HISTFILESIZE=100000 # Avoid duplicate entries HISTCONTROL="erasedups:ignoreboth" # Don't record some commands export HISTIGNORE="&:[ ]*:exit:ls:bg:fg:history" # Useful timestamp format HISTTIMEFORMAT='%F %T ' #Better, faster directory navigation shopt -s autocd shopt -s cdable_vars export FZF_DEFAULT_OPTS=" --color dark,hl:33,hl+:37,fg+:235,bg+:136,fg+:254 --color info:254,prompt:37,spinner:108,pointer:235,marker:235 --no-mouse --height 70% -1 --multi --inline-info --preview='[[ \$(file --mime {}) =~ binary ]] && echo {} is a binary file || (bat --style=numbers --color=always {} || cat {}) 2> /dev/null | head -300' --preview-window='right:wrap' --bind='f3:execute(bat --style=numbers {} || less -f {}),f2:toggle-preview,ctrl-d:half-page-down,ctrl-u:half-page-up,ctrl-a:select-all+accept,ctrl-y:execute-silent(echo {+} | wl-copy),ctrl-x:execute(rm -i {+})+abort,ctrl-j:down,ctrl-k:up'" if type rg &> /dev/null; then export FZF_DEFAULT_COMMAND='rg --files --no-ignore-vcs --hidden' export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND" fi # Don't use ~ to define your home here, it won't work. export wir="$HOME/wired" export lux="$HOME/lux" export n="$HOME/notes" export doc="$HOME/documents" export p="$HOME/pictures" CDPATH=.:~/notes:~/sites:~/documents:~/wired:~/pictures # Correct minor errors in the spelling of a directory shopt -s cdspell shopt -s dirspell # colorized man pages man() { env \ LESS_TERMCAP_md=$(printf "\e[1;31m") \ LESS_TERMCAP_me=$(printf "\e[0m") \ LESS_TERMCAP_se=$(printf "\e[0m") \ LESS_TERMCAP_so=$(printf "\e[1;44;33m") \ LESS_TERMCAP_ue=$(printf "\e[0m") \ LESS_TERMCAP_us=$(printf "\e[1;32m") \ man "$@" } # Git custom prompt export GITAWAREPROMPT=~/bin/git-aware-prompt source "${GITAWAREPROMPT}/main.sh" export PS1="\[\033[33;1m\]\[\033[m\]\$(pwd-prompt.bash) \[$txtred\]\$git_dirty\[$txtrst\]$ " # Complete all the things source ~/bin/pass-completion.bash source /usr/share/fzf/key-bindings.bash source /usr/share/fzf/completion.bash fzf-snippet() { selected="$(cat ~/documents/snippets | sed '/^$/d' | sort -n | fzf -e -i )" # remove tags, leading and trailing spaces, also no newline printf "$selected" | sed -e s/\;\;\.\*\$// | sed 's/^[ \t]*//;s/[ \t]*$//' | wl-copy } fzf-snip() { selected="$(python ~/bin/snippet.py | fzf -e -i )" #strip tags and any trailing space before sending to wl-copy echo -e "$selected"| sed -e 's/tags\:\.\*\$//;$d' | wl-copy } # get a forecast: function fore(){ ~/./bin/weather-2.3/weather -f ${1:-30606} } #search any folder like you're in nvalt: function nv() { ${EDITOR:-vim} "$(find ${2:-~/notes} -maxdepth ${3:-1} -type f -print0 | xargs -0 grep -li $1 | fzf --preview="bat {}" --preview-window=right:70%:wrap)"; } #search any folder like you're in nvalt but have ripgrep at your disposal function fn() { ${EDITOR:-vim} "$(rg -l $1 ${2:-~/notes} | fzf --preview="bat {}" --preview-window=right:70%:wrap)"; } # same thing, but context function nvl(){ find ${2:-.} -maxdepth ${3:-1} -type f -print0 | xargs -0 grep -i -n -E $1 | less -R } #find in "notes" which might be in any of half a dozen folders function fntt(){ find ~/notes ~/documents/bookmarks ~/documents/reading\ notes -type f -maxdepth 2 -print0 | xargs -0 grep -$2i $1 } function fnt(){ ${EDITOR:-vim} "$(rg -l $1 ~/notes/ ~/documents/bookmarks/ ~/documents/reading\ notes/ ~/lux/ | fzf --preview="bat {}" --preview-window=right:70%:wrap)"; } #fuzzy find function f() { ${EDITOR:-vim} "$(rg -l $1 ${2:-.} | fzf --preview="bat {}" --preview-window=right:70%:wrap)"; } function fg(){ ${EDITOR:-vim} "$(grep -nr $1 ${2:-.} | fzf --preview="bat {}" --preview-window=right:70%:wrap)"; } #fuzzy find file names only function ff() { ag -g "$1" ${2:-.} | fzf --preview="bat {}" --preview-window=right:70%:wrap } # Notational Velocity function @td() { rg -l $1 ${2:-~/gtd} | fzf --preview="bat {}" --preview-window=right:70%:wrap } # converts HTML to markdown using pandoc, run on a folder of files and get markdown function htmltotext(){ find . -name \*.html -type f -exec pandoc -f html -t markdown -o {}.txt {} \; } function tolux() { scp $3 $1 lxf:/home/lxf/$2 } function rsynctolux() { rsync -avzhe ssh --progress $1 lxf:/home/lxf/$2 } function frlux() { scp $3 lxf:/home/lxf/$1 $2 } function maketar() { tar cvzf "${1%%/}.tar.gz" "${1%%/}/"; } function extract() # Handy Extract Program { if [ -f $1 ] ; then case $1 in *.tar.bz2) tar xvjf $1 ;; *.tar.gz) tar xvzf $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) 7z x $1 ;; *) echo "'$1' cannot be extracted via >extract<" ;; esac else echo "'$1' is not a valid file!" fi } # pip should only run if there is a virtualenv currently activated export PIP_REQUIRE_VIRTUALENV=true # cache pip-installed packages to avoid re-downloading export PIP_DOWNLOAD_CACHE=$HOME/.pip/cache export BAT_PAGER="less -R" export BAT_THEME="Monokai Extended" # Create a new directory and enter it function md() { mkdir -p "$@" && cd "$@" } # Encode webm: function webm() { ffmpeg -i $1 -c:v libvpx -quality good -cpu-used 0 -b:v 7000k -qmin 10 -qmax 42 -maxrate 500k -bufsize 2500k -threads 8 -vf scale=-1:720 -c:a libvorbis -b:a 192k -f webm $1.webm } # encode ogg v: function ogv() { ffmpeg -i $1 -codec:v libtheora -qscale:v 4 -s hd720 $1.ogv } function lamer() { cd $1 for f in * do temp=$f new=${temp%.*} lame $f $new.mp3 -h -V 0 --vbr-new --verbose done cd - } # Start an HTTP server from a directory, optionally specifying the port function server2() { local port="${1:-8000}" # Set the default Content-Type to `text/plain` instead of `application/octet-stream` # And serve everything as UTF-8 (although not technically correct, this doesn’t break anything for binary files) python -c $'from BaseHTTPServer import BaseHTTPRequestHandler \nmap = BaseHTTPRequestHandler.extensions_map;\nmap[""] = "text/plain";\nfor key, value in map.items():\n\tmap[key] = value + ";charset=UTF-8";\nserver.test();' "$port" } export DISABLE_AUTO_TITLE=”true” function smartresize() { mogrify -path $3 -filter Triangle -define filter:support=2 -thumbnail $2 -unsharp 0.25x0.08+8.3+0.045 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level=9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -colorspace sRGB $1 } # words, they make me happy and I want to read them all page by page function d() { sdcv "$1" | less } function book() { local url url=$(cat .config/qutebrowser/bookmarks/urls | fzf | cut -d ' ' -f 1) && qutebrowser "$url" } function timer(){ seconds="$((60*$1))" date1=$((`date +%s` + $seconds)); while [ "$date1" -ge `date +%s` ]; do echo -ne "$(date -u --date @$(($date1 - `date +%s`)) +%H:%M:%S)\r"; sleep 0.1 done mpv ~/bin/clap.mp3 &>/dev/null } function ,n(){ # mirrors a notes search within vim # optional search term if [ $# -eq 0 ]; then SEL=$(rg --max-depth=1 -l ".*" ~/notes/ --line-number --sort path | cut -c 17- | fzf -e -i --bind 'tab:up') else SEL=$(rg --max-depth=1 -l "$1" ~/notes/ --line-number --sort path | cut -c 17- | fzf -e -i --bind 'tab:up') fi content=~/notes/"$SEL" vim "$content" } # Some GTD scripts # # #Set up a base dir GTD_DIR="$HOME/notes/gtd/" function ca() { # ca = create action var="$GTD_DIR$1.txt" touch "$var" if [ "x$2" != "x" ]; then echo "$2" >"$var" fi if [ "x$2" != "x" ]; then echo "$3" >>"$var" fi } #function na() { # # na = (show) next actions # # print all next actions (tasks prefaced by 'qq') # # optional project, area, or context i.e. @email @phone # clear # if [ $# -eq 0 ]; then # echo '----------- next actions ----------' # echo ' ' # rg -l qq $GTD_DIR | cut -c 21- | rev | cut -c 5- | rev # echo ' ' # echo '-----------------------------------' # else # echo '------------ '"$1"' next actions ---------' # rg $1 $GTD_DIR | rg qq | cut -c 24- | rev | cut -c 12- | rev # echo '-----------------------------------------' # fi #} function na() { # na = (show) next actions # print all next actions (anothing not a project basically) # optional project, area, or context, or both proj, area and context i.e. @email @phone clear if [ $# -eq 0 ]; then echo '----------- all tasks ----------' echo ' ' rg --max-depth=1 -l ".*" $GTD_DIR -g '!proj*' --line-number --sort path | cut -c 21- | rev | cut -c 5- | rev | nl echo ' ' echo '-----------------------------------' else #test for negation (not prefix) if [[ "$1" =~ ^not* ]]; then myString="${1:3}" #test for second input if [ $# -eq 2 ]; then echo "----------- all $1 tasks that are $2 ----------" echo ' ' rg --max-depth=1 --files-without-match "$myString" $GTD_DIR -g '!proj*' --line-number --sort path | while read line; do rg --with-filename "$2" "$line"| cut -c 21- ; done else # just one negative search echo "----------- all $1 tasks ----------" echo ' ' rg --max-depth=1 --files-without-match "$myString" $GTD_DIR -g '!proj*' --line-number --sort path | cut -c 21- | rev | cut -c 5- | rev | nl fi else #test for second input if [ $# -eq 2 ]; then echo "----------- all $1 tasks that are $2 ----------" echo ' ' rg --max-depth=1 -l "$1" $GTD_DIR -g '!proj*' --line-number --sort path | while read line; do rg --line-number --with-filename "$2" "$line"| cut -c 21- ; done #rg -l "$1" $GTD_DIR -g '!proj*' --line-number --sort path | rg "$2" | cut -c 21- | rev | cut -c 5- | rev | nl else # just one search echo "----------- all $1 tasks ----------" echo ' ' rg -l --max-depth=1 "$1" $GTD_DIR -g '!proj*' --line-number --sort path | cut -c 21- | rev | cut -c 5- | rev | nl fi fi echo ' ' echo '-----------------------------------' fi } function ea() { # ea = edit action # pull a list of tasks with an optional search term # then edit the selected task with vim SEL=$(rg --max-depth=1 -l $1 $GTD_DIR -g '!proj*'| cut -c 21- | fzf -e -i --bind 'tab:up') #trickery to add to beginning of the file content="$GTD_DIR$SEL" vim "$content" } function ean() { # ea = edit action name # pull a list of tasks with an optional search term # then rename the selected task with input SEL=$(rg -l ".*" $GTD_DIR -g '!proj*'| cut -c 21- | fzf -e -i --bind 'tab:up') #trickery to add to beginning of the file content="$GTD_DIR$SEL" echo "$content" read varname mv "$content" "$GTD_DIR$varname.txt" } function da(){ # da = delete action # if it's done get rid of it, but with a confirm dialog SEL=$(rg -l --max-depth=1 ".*" $GTD_DIR -g '!proj*'| cut -c 21- | fzf -e -i --bind 'tab:up') #trickery to add to beginning of the file content="$GTD_DIR$SEL" echo "$content" cat "$content"; read -p "Are you sure? " -n 1 -r echo # (optional) move to a new line if [[ ! $REPLY =~ ^[Yy]$ ]] then return 0 else mv "$content" "$GTD_DIR""done/" fi } function pa() { # pa = print action # pull a list of tasks with an optional search term # then cat the contents of the file SEL=$(rg --max-depth=1 -l $1 $GTD_DIR -g '!proj*'| cut -c 21- | fzf -e -i --bind 'tab:up') #trickery to add to beginning of the file content="$GTD_DIR$SEL" cat "$content" } ## Project functions function pc(){ # pc = project create proj="$GTD_DIR""proj ""$1.txt" touch "$proj" if [ "x$2" != "x" ]; then echo "$2" >"$proj" fi if [ "x$3" != "x" ]; then echo "$3" >>"$proj" fi } function pl(){ # pl = project list clear if [ $# -eq 0 ]; then echo '----------- all projects ----------' echo ' ' rg --files $GTD_DIR --line-number --sort path | rg -w proj* | cut -c 26- | rev | cut -c 5- | rev | nl echo ' ' echo '-----------------------------------' else #test for negation (not prefix) if [[ "$1" =~ ^not* ]]; then myString="${1:3}" #test for second input if [ $# -eq 2 ]; then echo "----------- all $1 tasks that are $2 ----------" echo ' ' rg --max-depth=1 --files-without-match "$myString" $GTD_DIR -w proj* --line-number --sort path | while read line; do rg --with-filename "$2" "$line"| cut -c 21- ; done else # just one negative search echo "----------------- all $1 projects ----------------" echo ' ' rg --max-depth=1 --files-without-match "$myString" $GTD_DIR | rg -w proj* --sort path | cut -c 26- | rev | cut -c 5- | rev | nl echo ' ' echo '--------------------------------------------------------' fi else echo "--------- all $1 projects ----------" echo ' ' rg $1 $GTD_DIR | rg -w proj* --sort path | cut -c 26- | rev | cut -c 12- | rev | nl echo ' ' echo '---------------------------------------' fi fi } function pe() { # pe = project edit if [ $# -eq 0 ]; then SEL=$(rg --files $GTD_DIR | rg -w proj* | cut -c 26- | rev | cut -c 5- | rev| fzf -e -i --bind 'tab:up') else SEL=$(rg $1 $GTD_DIR | rg -w proj* | cut -c 26- | rev | cut -c 12- | rev |fzf -e -i --bind 'tab:up') fi content="$GTD_DIR"proj" $SEL" echo $content vim "$content".txt } function pd() { # pd = project delete # if it's done get rid of it, but with a confirm dialog SEL=$(rg --files $GTD_DIR | rg -w proj* | cut -c 26- | rev | cut -c 5- | rev | fzf -e -i --bind 'tab:up') #trickery to add to beginning of the file content="$GTD_DIR"proj" $SEL".txt echo "$content" cat "$content"; read -p "Are you sure? " -n 1 -r echo # (optional) move to a new line if [[ ! $REPLY =~ ^[Yy]$ ]] then return 0 else rm "$content" fi } ## Calendar functions based on Khal function wk { khal new -a wired -i } function wctd() { # wctd = wired calendar todo # defaults to three months clear START=$(date +%m-01-%Y); END=$(date -d "-2 month ago" +'%m-01-%Y'); khal list -a wired $START $END | rg @td } function wctdd() { # wctd = wired calendar todo with dates # defaults to three months clear START=$(date +%m-01-%Y); END=$(date -d "-2 month ago" +'%m-01-%Y'); khal list -a wired $START $END } function wcw() { # wcw = wired calendar weekly view # View todos for the week clear if [ $(date +%w) = 1 ]; then START=$(date -dmonday +%m-%d-%Y); else START=$(date -dlast-monday +%m-%d-%Y); fi END=$(date -dfriday +%m-%d-%Y); khal list -a wired $START $END | rg @td } fd() { dir=$(zg ${1:-~/} -path '*/\.*' -prune -o -type d -print 2> /dev/null | fzf +m) && cd "$dir" } # set variable identifying the chroot you work in if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then debian_chroot=$(cat /etc/debian_chroot) fi # set a fancy prompt (non-color, unless we know we "want" color) case "$TERM" in xterm-color) color_prompt=yes;; esac # uncomment for a colored prompt, if the terminal has the capability force_color_prompt=yes if [ -n "$force_color_prompt" ]; then if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then # We have color support; assume it's compliant with Ecma-48 # (ISO/IEC-6429). (Lack of such support is extremely rare, and such # a case would tend to support setf rather than setaf.) color_prompt=yes else color_prompt= fi fi if [ "$color_prompt" = yes ]; then PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\W\[\033[00m\]\$ ' else PS1='${debian_chroot:+($debian_chroot)}\u@\h:\W\$ ' fi unset color_prompt force_color_prompt # If this is an xterm set the title to user@host:dir #case "$TERM" in # xterm*|rxvt*) # PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \W\a\]$PS1" # ;; # *) # ;; #esac # enable color support of ls and also add handy aliases if [ -x /usr/bin/dircolors ]; then test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" alias ls='ls --color=auto' alias dir='dir --color=auto' alias vdir='vdir --color=auto' alias grep='grep --color=auto' alias fgrep='fgrep --color=auto' alias egrep='grep -E --color=auto' fi # enable programmable completion features if ! shopt -oq posix; then if [ -f /usr/share/bash-completion/bash_completion ]; then . /usr/share/bash-completion/bash_completion elif [ -f /etc/bash_completion ]; then . /etc/bash_completion fi fi # Add RVM to PATH for scripting export PATH="$PATH:$HOME/.rvm/bin" if ! pgrep -u $USER ssh-agent > /dev/null; then ssh-agent > ~/.ssh-agent-thing fi if [[ "$SSH_AGENT_PID" == "" ]]; then eval $(<~/.ssh-agent-thing) fi ssh-add -l >/dev/null || alias ssh='ssh-add -l >/dev/null || ssh-add && unalias ssh; ssh' if [ -n "$DESKTOP_SESSION" ];then eval $(gnome-keyring-daemon --start) export SSH_AUTH_SOCK fi #export WINEPREFIX=$HOME/.config/wine/ #export WINEARCH=win32 #PATH="$(ruby -e 'print Gem.user_dir')/bin:$PATH" fd() { local dir dir=$(find ${1:-.} -path '*/\.*' -prune \ -o -type d -print 2> /dev/null | fzf +m) && cd "$dir" } # fshow - git commit browser fshow() { git log --graph --color=always \ --format="%C(auto)%h%d %s %C(black)%C(bold)%cr" "$@" | fzf --ansi --no-sort --reverse --tiebreak=index --bind=ctrl-s:toggle-sort \ --bind "ctrl-m:execute: (grep -o '[a-f0-9]\{7\}' | head -1 | xargs -I % sh -c 'git show --color=always % | less -R') << 'FZF-EOF' {} FZF-EOF" } #dirsize - finds directory sizes and lists them for the current directory ds () { du -shx -- * .[a-zA-Z0-9_]* 2>/dev/null | grep -E '^ *[0-9.]*[MG]' | sort -n >/tmp/list grep -E '^ *[0-9.]*M' /tmp/list grep -E '^ *[0-9.]*G' /tmp/list rm /tmp/list } #download movies yt () { yt-dlp -S height:1080 https://www.youtube.com/watch?v="$1" } spell() { local candidates oldifs word array_pos oldifs="$IFS" IFS=':' # Parse the apsell format and return a list of ":" separated words read -a candidates <<< "$(printf "%s\n" "$1" \ | aspell -a \ | awk -F':' '/^&/ { split($2, a, ",") result="" for (x in a) { gsub(/^[ \t]/, "", a[x]) result = a[x] ":" result } gsub(/:$/, "", result) print result }')" # Reverse number and print the parsed bash array because the list comes # out of gawk backwards for item in "${candidates[@]}"; do printf '%s\n' "$item" done \ | tac \ | nl \ | less -FirSX printf "[ $(tput setaf 2)?$(tput sgr0) ]\t%s" \ 'Enter the choice (empty to cancel, 0 for input): ' read index [[ -z "$index" ]] && return [[ "$index" == 0 ]] && word="$1" [[ -z "$word" ]] && { array_pos=$(( ${#candidates[@]} - index )) word="${candidates[$array_pos]}" } [[ -n "$word" ]] && { printf "$word" | xsel -p printf "Copied '%s' to clipboard!\n" "$word" } || printf "[ $(tput setaf 1):($(tput sgr0) ] %s\n" 'No match found' IFS="$oldifs" } RIPGREP_CONFIG_PATH=~/.ripgreprc GPG_TTY=$(tty) export GPG_TTY [ -d "$HOME/.w3m/bin" ] && PATH="$HOME/.w3m/bin:$PATH"