zsh/zshrc

2573 lines
82 KiB
Bash
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# /etc/zsh/zshrc ou ~/.zshrc
# Fichier de configuration principal de zsh, lu au lancement des shells interactifs
# (et non des shells d'interprétation de fichier)
# Formation Debian GNU/Linux par Alexis de Lattre
# http://formation-debian.via.ecp.fr/
################
# 1. Les alias #
################
# Gestion du 'ls' : couleur & ne touche pas aux accents
alias ls='ls --classify --tabsize=0 --literal --color=auto --show-control-chars --human-readable'
# Copie en récursif et qui garde la date des fichiers copiés
#alias cp='cp -Rp'
alias cp='cp -R' # **cp** copy files and directories recursively # TEST
# Copie distante, ajout de la récursivité tout le temps:
alias scp='scp -r'
# Demande confirmation avant d'écraser un fichier
alias cP='cp --interactive'
alias mv='mv --interactive'
alias rm='rm --interactive'
# ls shortcut {{{
if [ ! $(command -v eza) ]; then
## with ls {{{
alias ll='ls -l'
## Show hidden files
alias la='ll --almost-all'
## Show hidden only
alias lla='la --directory .*'
alias l.='ls --directory .*'
alias llh='ll | head'
alias llp='ll | $PAGER'
alias llw='ll | wc --lines'
## Sort by date
alias lll='ls -l -t --human-readable --reverse'
alias llll='ls -l -t --human-readable --reverse'
alias lld='ls -l --directory */ --human-readable'
alias lr='ls --recursive | grep ":$" | sed -e '\''s/:$//'\'' -e '\''s/[^-][^\/]*\//--/g'\'' -e '\''s/^/ /'\'' -e '\''s/-/|/'\'''
## }}}
## with eza (forked from exa) {{{
else
alias exa=eza
alias ll='eza --color=always --long --group --git'
## Show hidden files
alias la='ll --all --sort .name'
## Show hidden only
alias lla='ll --list-dirs .*'
alias l.='ls --directory .*'
alias llh='ll | head'
alias llp='ll | $PAGER'
alias llw='ll | wc --lines'
## Sort by date
alias lll='ll --sort=modified'
alias llll='ll --sort=modified'
## Give a tree of current directory
alias llt='ll --tree'
alias lld='ll --group-directories-first'
alias lr='ls --recursive | grep ":$" | sed -e '\''s/:$//'\'' -e '\''s/[^-][^\/]*\//--/g'\'' -e '\''s/^/ /'\'' -e '\''s/-/|/'\'''
## }}}
fi
# }}}
# cat with number on output lines
alias ca='cat --number'
# docker related
alias d='docker'
# Correct ip command
alias ipa='ip a'
# Disable because of "There is no rawcontrolchars option" warning…
# less with raw character
#alias less='less --rawcontrolchars'
#alias less='less --quiet'
# Call last command
alias pp='fc -e -'
# Call last command in edit mode
alias ppe='fc'
# Call last command with sudo
alias pps='sudo $(fc -ln -1)'
# fdfind
## disregard vcs ignore files (.gitignore…) as homedir is a git repository…
alias fd='fd --no-ignore-vcs'
# sudo
## Please consider using "Defaults env_keep+=HOME" configuration in sudoers {{{
### This is Ubuntu default behaviour.
### This will allow to share user's homedir/dotfiles with root throught sudo commands
## }}}
## Ensure sudo can use aliases (end whitespace) {{{
### `man zshall` partie Aliasing: "If the text ends with a space, the next word in the shell input is treated as though it were in command position for
### purposes of alias expansion. "
alias s='sudo '
## }}}
## sudo aliases {{{
if [ ${USER} != "root" ]; then
alias sc='sudo systemctl '
alias scu='systemctl --user'
alias sd='sudo docker'
alias si='sudo iptables -L -vn '
alias sj='sudo journalctl '
alias sn='sudo nft list ruleset'
alias sv='sudo vi '
alias sz='sudo zsh'
else
alias sc='systemctl '
alias scu='systemctl --user'
alias sd='docker'
alias si='iptables -L -vn '
alias sj='journalctl '
alias sn='nft list ruleset'
alias vi='vi -S ~/.vim/vimrc '
alias sv='vi -S ~/.vim/vimrc '
fi
## }}}
# Envoyer une notification via libnotify-bin (fin d'une commande, ...)
# Nécessite le paquet libnotify-bin
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
# Nettoyage de l'écran
alias c='clear'
# Liste le contenu du dossier
alias dir='dir --color=always'
# Page de manuel en anglais
alias mane="LANG=C man "
# Afficher les lignes trop longues sur la ligne suivante plutot que de remplacer par un "$":
alias most='most -w'
## System
# APT|Aptitude|dpkg|… commands {{{
if [ -d /etc/apt ]; then
alias acle='sudo aptitude clean'
alias afil='apt-file search --'
alias aful='sudo aptitude full-upgrade'
alias ains='sudo aptitude install'
alias alis='apt list --upgradable'
alias apol='apt-cache policy'
alias apur="sudo aptitude purge '~c'"
alias aupd='sudo apt update'
alias aupg='sudo aptitude upgrade'
alias arem='sudo aptitude remove'
alias apts='apt search'
alias asea='aptitude search --'
alias asho='aptitude show'
alias aver='apt-show-versions'
alias awhy='aptitude why'
alias insexperimental='sudo aptitude --target-release experimental install'
alias anorepos="apt list --installed | sed --silent 's/\(.*\)\/.*,local.*/\1/p' | tr '\n' ' '"
alias gdpkg='dpkg --list | grep --extended-regexp -- '
fi
# }}}
# Pacman commands {{{
if [ -d /etc/pacman.d ]; then
alias pacle='echo "$(ls -1 /var/cache/pacman/pkg | wc --lines) packages to clean" && sudo pacman --sync --clean'
alias pafil='pacman --files --regex --'
alias paful='sudo pacman --sync --sysupgrade --'
alias pains='sudo pacman --sync --'
alias palis='pacman --query --upgrades --'
alias papol='pacman --sync --info --'
alias paupd='sudo pacman --sync --refresh --'
alias paupg='sudo pacman --sync --'
alias parem='sudo pacman --remove --'
alias paremdep='sudo pacman --remove --recursive --'
alias paorph='pacman --query --unrequired --deps --quiet --'
alias papurge='pacman --query --unrequired --deps --quiet -- | sudo pacman --remove --recursive --nosave -- -'
#alias apts='apt search'
alias pasea='pacman --sync --search --'
alias pasho='pacman --sync --info --'
#alias awhy='aptitude why'
#alias anorepos="apt list --installed | sed --silent 's/\(.*\)\/.*,local.*/\1/p' | tr '\n' ' '"
alias gpackage='pacman --query --search -- | grep --extended-regexp -- '
fi
# }}}
# Yay commands for AUR Archlinux User Repository {{{
if command -v yay > /dev/null; then
alias yains='yay --sync --'
alias yalis='yay --query --upgrades --'
alias yapol='yay --sync --info --'
#alias apts='apt search'
alias yasea='yay --sync --search --'
alias yasho='yay --sync --info --'
#alias awhy='aptitude why'
#alias anorepos="apt list --installed | sed --silent 's/\(.*\)\/.*,local.*/\1/p' | tr '\n' ' '"
fi
# }}}
# Filter pending mail by date
alias maildate='sudo mailq |grep "^[A-F0-9]" |sort -k5n -k6n'
# Grep aliases {{{
alias grep='grep --color=always --ignore-case '
alias gerp='grep --ignore-case'
alias Grep='\grep '
alias gmount='mount | grep --extended-regexp -- '
alias gdf='df | grep --extended-regexp -- '
# }}}
# Espace disque
alias df='df --block-size=1K --print-type --human-readable'
alias dus='du --total --human-readable | sort --human-numeric-sort'
alias dua='du --all --total --human-readable | sort --human-numeric-sort'
alias ncdu='gdu'
# Gestion des processus:
# Si htop n'est pas installé sur la machine:
if [ ! -f "`which htop`" ]; then
alias htop=top
fi
# Qu'est-ce qui consomme de la mémoire vive sur le système
alias wotgobblemem='ps -o time,ppid,pid,nice,pcpu,pmem,user,comm -A | sort --numeric-sort --key=6 | tail -15'
# ps aliases
alias px='ps faux|grep --invert-match -- grep|grep --extended-regexp --ignore-case --regexp=VSZ -e '
## ps with fzf
alias fpx="ps -ef | fzf --bind 'ctrl-r:reload(ps -ef)' --header 'Press CTRL-R to reload' --header-lines=1 --color fg:188,bg:233,hl:103,fg+:222,bg+:234,hl+:104"
alias pxf="ps -ef | fzf --bind 'ctrl-r:reload(ps -ef)' --header 'Press CTRL-R to reload' --header-lines=1 --color fg:188,bg:233,hl:103,fg+:222,bg+:234,hl+:104"
## ps last entries with watch|tail|grep
alias wps="watch \"ps faux | tail --lines=30 -- | grep --invert-match --extended-regexp '(tail|ps faux|grep)' --\""
alias psw="watch \"ps faux | tail --lines=30 -- | grep --invert-match --extended-regexp '(tail|ps faux|grep)' --\""
# Décompression
alias untargz='tar --gzip --extract --verbose -f'
alias untarbz2='tar --bzip2 --extract --verbose -f'
# Terminal multiplexer
alias ta='tmux a || tmux'
alias td='tmux detach'
# Send the content of a file to a privatebin
# Needs cpaste or any other Third party clients for PrivateBin
# https://github.com/PrivateBin/PrivateBin/wiki/Third-party-clients
alias pbin='~/repos/cpaste/cpaste --sourcecode --expire 1week --file '
## Git aliases Try to prefix with 'gg' {{{
### Get status of the repo
alias ggstatus='git status'
### Show differences between changes and index and ensure to display colors even with a pipe
alias ggdiff='git diff --color=always'
### Show differences between changes and index WITHOUT any colors
alias ggnocolordiff='git diff --color=never'
### Show only words/characters differences
alias ggwdiff='git diff --color-words=. --patience'
### Add changes to index
alias ggadd='git add'
### Restore changes to be committed
alias ggrestore='git restore --staged'
### Remove files from the index
alias ggrm='git rm'
### Move or rename file
alias ggmv='git mv'
### Cancel changes
alias ggcheckout='git checkout --'
### Print lines matching a pattern
alias ggrep='git grep --color --line-number --perl-regexp'
alias gggrep='git grep --color --line-number --perl-regexp'
### Show commit logs
alias gglog="git log --graph --full-history --all --color --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset'"
### Show last 20 commits with graph
alias gglg="git --no-pager log --graph --pretty=tformat:'%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%an %ar)%Creset' -20"
### Show all commits with graph
alias ggllg="git log --graph --pretty=tformat:'%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%an %ar)%Creset'"
### Display all commits/changes of a file
alias ggchanges="git log --follow --perl-regexp --"
### Commands that might require a valid gpg-agent
#### Download any new commits
alias ggpull='load-gpg-agent && git pull'
#### Commit changes
alias ggco='load-gpg-agent && git commit'
alias ggcommit='load-gpg-agent && git commit'
#### Amend changes
alias ggamend='load-gpg-agent && git commit --amend'
#### Update remote repository
alias ggpush='load-gpg-agent && git push'
## }}}
# Lister les fichiers de configuration inutiles
alias purge='grep-status --no-field-names --show-field=Package --field=Status config-files'
## Piped alias
alias -g H='| head'
alias -g T='tail --follow'
alias -g G='| grep --invert-match grep -- | grep --extended-regexp'
alias -g L='| less'
alias -g M="| most"
alias -g S="| sort"
alias -g V="| vimmanpager"
alias -g W="| wc --lines"
alias -g X="| xclip -selection clipboard"
alias -g TM="| tmux load-buffer -- -"
alias -g B="&|"
alias -g HL="--help"
alias -g MM="2>&1 | most"
alias -g LL="2>&1 | less"
alias -g CA="2>&1 | cat --show-all"
alias -g NE="2> /dev/null"
alias -g NUL="> /dev/null 2>&1"
## Affichage de l'historique
if [ "$PAGER" = "most" ]; then
# En commencant par la fin avec most (bidouillage, on est pas sensé avoir):
alias hist="fc -El 0 | most +$HISTSIZE"
# Une fois dans un fichier avec most, la touche 'B' permet d'aller à la fin du fichier
else
# En commencant par la fin avec less:
alias hist="fc -El 0 | $PAGER +G"
#alias hist="less +G ~/.zsh/history"
fi
alias ghist='fc -El 0 | grep --'
## Gestion des répertoires
alias u='cd ..'
alias cd..='cd ..'
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'
# Revenir dans le dossier dans lequel on se trouvait précédemment
alias cd-='cd -'
alias uu='cd -'
alias uuu='cd -2'
# Afficher la pile des dossiers:
alias dirs='dirs -v'
# Créer les répertoires précédents si ils n'existent pas
alias mkdir='mkdir --parents'
# Affiche l'arborescence du répertoire courant
#alias tree="find . | sed 's/[^/]*\//| /g;s/| *\([^| ]\)/+--- \1/'"
#La commande tree "basique" fait ça très bien ...
# Affiche la variable $PATH ligne par ligne
alias path='printf %s $PATH | tr ":" "\n"'
# Edite le dernier fichier d'un dossier
## Fonctionement:
## (. correspond au fichier
## om les classent par date de modification
## [1] choisit le premier
##  désactive les options GLOB_DOTS
alias vil='vi *(.om[1]^D)'
# Lancer vi pour qu'il ne conserve aucune trace du fichier
## Faire précéder la commande d'un espace empêche l'enregistrement dans l'historique du shell
alias vnb='vi -n "+set noundofile" "+set nobackup"'
# Différence entre deux fichiers
alias diff='colordiff -u'
alias diffs='\diff --side-by-side'
# Recherche toutes les occurences de l'arguments passé en paramètre dans l'historique des commandes
alias param='fc -l 0 | grep --'
# Multimédia
##Extraire la piste audio d'un .avi
alias avi2wav='mplayer -vc dummy -vo null -ao pcm:file=video.wav'
##Modifie la bar de progression du gestionnaire de téléchargement Axel
alias axel='axel -a --num-connection=20'
## List video file's subtitles
alias ff.list.subs='ffprobe -loglevel error -select_streams s -show_entries stream=index:stream_tags=language -of csv=p=0'
## List video file's audio stream
alias ff.list.audio='ffprobe -loglevel error -select_streams a -show_entries stream=index:stream_tags=language -of csv=p=0'
# Calculatrice en ligne de commande
alias caltos='bc'
#alias df='df --human-readable'
#alias du='du --human-readable'
alias mutt='neomutt'
alias m='neomutt'
alias md='mkdir'
alias rd='rmdir'
#Internet
## Minimal webserver from current directory and available at http://IP.AD.RE.SS:8002
## See : https://docs.python.org/3/library/http.server.html
alias httpserv="python3 -m http.server -b $(ip route get 1 | awk '{print $(NF-2);exit}') 8002"
## Minimal webserver with upload option and storage in dedicated directory
alias httpup="mkdir --parent -- /tmp/http.upload.directory && cd -- /tmp/http.upload.directory && python3 ${HOME}/bin/upload-http-server.py --listen $(ip route get 1 | awk '{print $(NF-2);exit}') --port 8004"
## Limite l'envoi à 3 requêtes pour ping
alias ping="ping -c 3"
alias ping6="ping6 -c 3"
## JOSM
alias josm="java -jar -Xmx2048M /opt/josm-tested.jar"
# Khard
alias kemail='khard email'
alias kmail='khard email'
alias kphone='khard phone'
alias ktel='khard phone'
# SSH {{{
#########
# Load ssh-agent with a fix socket path {{{
## This function can be used :
## 1. in zlogin (for a new shell)
## 2. with recossh alias to load a new ssh-agent
function load-ssh-agent() {
# If a ssh-key is available
if find "${HOME}/.ssh" -maxdepth 1 -type f -iname "id_*" | grep --quiet -- .; then
## If ssh-agent is not already launched
if ! ps -x | grep --invert-match -- grep | grep --fixed-strings --quiet -- "ssh-agent -a ${SSH_AGENT_SOCK}"; then
### Remove any previous socket and environment files
rm --force -- "${SSH_AGENT_SOCK}" "${SSH_AGENT_ENV}"
### Start ssh-agent with a specified socket path
### AND store informations in a file
ssh-agent -a "${SSH_AGENT_SOCK}" > "${SSH_AGENT_ENV}"
fi
## Load content of ssh-agent environment file
source "${SSH_AGENT_ENV}"
fi
}
# }}}
# Add ed25519 ssh-key to ssh-agent {{{
function load-ssh-ed25519() {
# If a ED25519 ssh-key is available
# AND not already loaded in ssh-agent
if [ -f "${SSH_ED25519_KEY}" ] &&
! ssh-add -l | grep --quiet --ignore-case -- "(ed25519)"; then
ssh-add "${SSH_ED25519_KEY}"
fi
}
# }}}
# Add rsa ssh-key to ssh-agent {{{
function load-ssh-rsa() {
# If a RSA ssh-key is available
# AND not already loaded in ssh-agent
if [ -f "${SSH_RSA_KEY}" ] &&
! ssh-add -l | grep --quiet --ignore-case -- "(rsa)"; then
ssh-add "${SSH_RSA_KEY}"
fi
}
# }}}
# Clear old entries in known_hosts {{{
function clearsshkey() {
sed -i "${1}d" ~/.ssh/known_hosts
}
# }}}
# recossh will:
# (re)load ssh-agent informations
# run the previous ssh command
alias recossh='load-ssh-agent &&
$(fc -lr 4900 | \grep --max-count=1 --extended-regexp "[0-9]{1,4} ssh " | cut --delimiter=" " --fields=4-)'
# For development and tests
alias sshdev='ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=accept-new'
alias sshdev-copy-id='ssh-copy-id -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=accept-new'
alias scpdev='scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=accept-new'
# }}}
# GPG {{{
#########
# (re)Load gpg-agent {{{
## This function can be used :
## 1. with aliases (git commit,…)
function load-gpg-agent() {
## If a gpg key is available
if [ -f "${GPG_PRIV_KEY}" ]; then
## Remove any previous test file
rm --force -- "${GPG_TEST_FILE}"
## Run a gpg command on the test file
gpg --quiet --for-your-eyes-only --decrypt "${GPG_TEST_FILE}.gpg" > /dev/null
fi
}
# }}}
# }}}
# Taskwarrior {{{
## Aliases
alias t="task"
### Most recent tasks first
alias tarecent="task simple limit:page"
alias taold="task oldest limit:page"
### All pending tasks
alias tapending="task rc._forcecolor:on +PENDING all | less"
### Filter by tag
alias tawork="task rc._forcecolor:on +work | head"
alias taperso="task rc._forcecolor:on +perso | head"
alias tarm=tadel
## Functions
## search in pending tasks by task's name (case INsensitive) {{{
function tase() {
local search=""
for i; do; search="$search /$i/"; done;
task rc.search.case.sensitive:no +PENDING $search all || return 0
}
## }}}
## search in pending tasks by task's name (case SENSITIVE) {{{
function tasec() {
local search=""
for i; do; search="$search /$i/"; done;
task $search +PENDING all || return 0
}
## }}}
## search in all tasks by task's name (case INsensitive) {{{
function tall() {
local search=""
for i; do; search="$search /$i/"; done;
task rc.search.case.sensitive:no $search all || return 0
}
## }}}
## Delete a task {{{
function tadel() {
local tadel_task_id
local tadel_task_desc
local tadel_confirmation
# Verify argument
if [ "${#}" -eq 1 ]; then
## Get the first arg as task ID
tadel_task_id="${1}"
else
## If no argument or more than one
## Ask the user to choose an ID in the 20 more recents tasks {{{
task newest limit:20 || return 0
printf '%b' "Enter the ${MAGENTAB}ID${RESET} of the task to remove : "
read -r tadel_task_id
## }}}
fi
# If no task with this ID exists, exit function {{{
if ! task "${tadel_task_id}" | grep --quiet -- "^ID *${tadel_task_id}"; then
printf '%b' "No available task with ${REDB}${tadel_task_id}${RESET} ID."
return 1
fi
# }}}
# Get task's description
tadel_task_desc=$(task "${tadel_task_id}" | sed --quiet "s/^Description *\(.*\)/\1/p")
printf '%b' "Delete the task \"${MAGENTAB}${tadel_task_id} ${tadel_task_desc}${RESET}\" [Y/n] ? "
read -r tadel_confirmation
# Check confirmation
if printf -- '%s' "${tadel_confirmation:=y}" | grep --quiet --word-regexp -- "y"; then
task rc.confirmation:no "${tadel_task_id}" delete
printf '%b' "\"${MAGENTAB}${tadel_task_id} ${tadel_task_desc}${RESET}\" task was removed.\n"
fi
# Also offer to purge this task
tapurge "${tadel_task_desc}"
}
## }}}
## Mark a task as done {{{
function tadone() {
local tadone_task_regexp
local tadone_task_id
local tadone_task_desc
local tadone_confirmation
# Verify argument
if [ "${#}" -eq 0 ]; then
## If no argument
## Ask the user to choose a task description from the last week Timewarrior activities {{{
timew summary :week :ids || return 0
printf '%b' "Enter the ${MAGENTAB}a pattern${RESET} matching the expected task to mark as complete : "
read -r tadone_task_regexp
else
## Merge all args into one var
tadone_task_regexp="${*}"
## }}}
fi
#printf '%b' "Pattern to search a task is ${REDB}${tadone_task_regexp}${RESET}.\n"
tadone_task_id=$(task "${tadone_task_regexp}" simpleid | grep --after-context=2 -- ID | tail --lines=1 || return 0)
# If no task with this ID exists, exit function {{{
if [ -z "${tadone_task_id}" ]; then
printf '%b' "No available task with ${REDB}${tadone_task_regexp}${RESET} pattern."
return 1
fi
# }}}
# Get task's description
tadone_task_desc=$(task "${tadone_task_id}" | sed --quiet "s/^Description *\(.*\)/\1/p")
printf '%b' "Mark the task \"${MAGENTAB}${tadone_task_id} ${tadone_task_desc}${RESET}\" as done [Y/n] ? "
read -r tadone_confirmation
# Check confirmation
if printf -- '%s' "${tadone_confirmation:=y}" | grep --quiet --word-regexp -- "y"; then
task "${tadone_task_id}" done
printf '%b' "\"${MAGENTAB}${tadone_task_id} ${tadone_task_desc}${RESET}\" task is now complete."
fi
}
## }}}
## Purge an old task {{{
function tapurge() {
local tapurge_task_regexp
local tapurge_task_desc
local tapurge_confirmation
# Verify argument
if [ "${#}" -eq 0 ]; then
## If no argument
## Ask the user to choose a task description from the deleted tasks list {{{
task all status:deleted || return 0
printf '%b' "Enter few ${MAGENTAB}words matching the description${RESET} of the expected task to purge : "
read -r tapurge_task_regexp
else
## Merge all args into one var
tapurge_task_regexp="${*}"
## }}}
fi
tapurge_task_desc=$(task "${tapurge_task_regexp}" simpledeleted | grep --after-context=2 -- "^Description" | tail --lines=1 || return 0)
# If no task with this Description exists, exit function {{{
if [ -z "${tapurge_task_desc}" ]; then
printf '%b' "No available task with ${REDB}${tapurge_task_regexp}${RESET} pattern."
return 1
fi
# }}}
printf '%b' "Completly purge the task \"${MAGENTAB}${tapurge_task_desc}${RESET}\" [Y/n] ? "
read -r tapurge_confirmation
# Check confirmation
if printf -- '%s' "${tapurge_confirmation:=y}" | grep --quiet --word-regexp -- "y"; then
task rc.confirmation:no "${tapurge_task_desc}" purge
printf '%b' "\"${MAGENTAB}${tapurge_task_desc}${RESET}\" was purged."
fi
}
## }}}
## Take note for a task {{{
function tanote() {
local tanote_task_regexp
local tanote_task_id
local tanote_task_desc
local tanote_confirmation
# Verify argument
if [ "${#}" -eq 0 ]; then
## If no argument
## Ask the user to choose a task description from the recent tasks {{{
task simple limit:page || return 0
printf '%b' "Enter ${MAGENTAB}a pattern${RESET} matching the expected task that need notes : "
read -r tanote_task_regexp
else
## Merge all args into one var
tanote_task_regexp="${*}"
## }}}
fi
tanote_task_id=$(task "${tanote_task_regexp}" simpleid | grep --after-context=2 -- ID | tail --lines=1 || return 0)
# If no task with this ID exists, exit function {{{
if [ -z "${tanote_task_id}" ]; then
printf '%b' "No available task with ${REDB}${tanote_task_regexp}${RESET} pattern."
return 1
fi
# }}}
# Get task's description
tanote_task_desc=$(task "${tanote_task_id}" | sed --quiet "s/^Description *\(.*\)/\1/p")
printf '%b' "Add notes to \"${MAGENTAB}${tanote_task_id} ${tanote_task_desc}${RESET}\" task [Y/n] ? "
read -r tanote_confirmation
# Check confirmation
if printf -- '%s' "${tanote_confirmation:=y}" | grep --quiet --word-regexp -- "y"; then
task note "${tanote_task_id}"
fi
}
## }}}
## Completion {{{
zstyle ':completion:*:*:task:*' verbose yes
zstyle ':completion:*:*:task:*:descriptions' format '%U%B%d%b%u'
zstyle ':completion:*:*:task:*' group-name ''
## }}}
# }}}
# Timewarrior {{{
## Aliases
alias tid="tiday"
alias tiw="tiweek"
alias tim="timonth"
alias timv="timove"
alias tiresize="tiduration"
## Functions
## Display tasks of today {{{
function tiday() {
if [ "${#}" -eq 0 ]; then
timew summary :day :ids || return 0
else
timew summary :day :ids "${*}" || return 0
fi
}
## }}}
## Display tasks of last day {{{
function tilastday() {
if [ "${#}" -eq 0 ]; then
timew summary :yesterday :ids || return 0
else
timew summary :yesterday :ids "${*}" || return 0
fi
}
## }}}
## Display tasks of this week {{{
function tiweek() {
if [ "${#}" -eq 0 ]; then
timew summary :week :ids || return 0
else
timew summary :week :ids "${*}" || return 0
fi
}
## }}}
## Display tasks of last week {{{
function tilastweek() {
if [ "${#}" -eq 0 ]; then
timew summary :lastweek :ids || return 0
else
timew summary :lastweek :ids "${*}" || return 0
fi
}
## }}}
## Display tasks of this month {{{
function timonth() {
if [ "${#}" -eq 0 ]; then
timew summary :month :ids || return 0
else
timew summary :month :ids "${*}" || return 0
fi
}
## }}}
## Display tasks of last month {{{
function tilastmonth() {
if [ "${#}" -eq 0 ]; then
timew summary :lastmonth :ids || return 0
else
timew summary :lastmonth :ids "${*}" || return 0
fi
}
## }}}
## Display tasks of this year {{{
function tiyear() {
if [ "${#}" -eq 0 ]; then
timew summary :year :ids || return 0
else
timew summary :year :ids "${*}" || return 0
fi
}
## }}}
## Display tasks of last year {{{
function tilastyear() {
if [ "${#}" -eq 0 ]; then
timew summary :lastyear :ids || return 0
else
timew summary :lastyear :ids "${*}" || return 0
fi
}
## }}}
## Double spent time on a task {{{
## "double" cause by default my tasks runs for 25 minutes
function tidouble() {
# Default duration time to add to a task
local tidouble_extra_time="25mins"
local tidouble_task_id
local tidouble_confirmation
local tidouble_task_desc
# Verify argument
if [ "${#}" -eq 1 ]; then
## Get the first arg as task ID
tidouble_task_id="${1}"
else
## If no argument or more than one
## Ask the user to choose an ID in tasks from the yesterday {{{
timew summary from yesterday :ids || return 0
printf '%b' "Enter the ${MAGENTAB}ID${RESET} of the task to double spent time should be doubled : "
read -r tidouble_task_id
## }}}
fi
# If no task with this ID exists, exit function {{{
if ! timew summary :year :ids | grep --quiet -- " @${tidouble_task_id} "; then
printf '%b' "No available task in the last year with ${REDB}${tidouble_task_id}${RESET} ID."
return 1
fi
# }}}
# Get task's description from all task of this year
tidouble_task_desc=$(timew summary :year :ids | sed --quiet "s/.*@\(${tidouble_task_id} .*\)/\1/p" | sed 's/ */ /g')
printf '%b' "Add ${tidouble_extra_time} to \"${MAGENTAB}${tidouble_task_desc}${RESET}\" [Y/n] ? "
read -r tidouble_confirmation
# Check confirmation
if printf -- '%s' "${tidouble_confirmation:=y}" | grep --quiet --word-regexp -- "y"; then
timew lengthen @"${tidouble_task_id}" "${tidouble_extra_time}" || return 0
timew split @"${tidouble_task_id}" || return 0
printf '%b' "${tidouble_extra_time} were added to \"${MAGENTAB}${tidouble_task_desc}${RESET}\" task."
fi
}
## }}}
## Delete a time tracking {{{
function tirm() {
local tirm_task_id
local tirm_task_desc
local tirm_confirmation
# Verify argument
if [ "${#}" -eq 1 ]; then
## Get the first arg as task ID
tirm_task_id="${1}"
else
## If no argument or more than one
## Ask the user to choose an ID in tasks from the yesterday {{{
timew summary from yesterday :ids || return 0
printf '%b' "Enter the ${MAGENTAB}ID${RESET} of the task to delete : "
read -r tirm_task_id
## }}}
fi
# If no task with this ID exists, exit function {{{
if ! timew summary :year :ids | grep --quiet -- " @${tirm_task_id} "; then
printf '%b' "No available task in the last year with ${REDB}${tirm_task_id}${RESET} ID."
return 1
fi
# }}}
# Get task's description from all task of this year
tirm_task_desc=$(timew summary :year :ids | sed --quiet "s/.*@\(${tirm_task_id} .*\)/\1/p" | sed 's/ */ /g')
printf '%b' "Delete to \"${MAGENTAB}${tirm_task_desc}${RESET}\" [Y/n] ? "
read -r tirm_confirmation
# Check confirmation
if printf -- '%s' "${tirm_confirmation:=y}" | grep --quiet --word-regexp -- "y"; then
timew delete @"${tirm_task_id}" || return 0
printf '%b' "${tirm_task_desc} was deleted"
fi
}
## }}}
## Modify the start of a time tracking {{{
function tistart() {
# Define new_start empty by default
local tistart_time_new_start=""
local tistart_time_id
local tistart_time_desc
local tistart_time_start_day
local tistart_confirmation
# Verify argument
case "${#}" in
1 )
## Get the first arg as time ID
tistart_time_id="${1}"
;;
2 )
## Get the first arg as time ID
tistart_time_id="${1}"
## Get the second arg as new start time for this track
tistart_time_new_start="${2}"
;;
* )
## Ask the user to choose an ID in time tracking from the yesterday {{{
timew summary from yesterday :ids || return 0
printf '%b' "Enter the ${MAGENTAB}ID${RESET} of the time tracking to modify : "
read -r tistart_time_id
## }}}
;;
esac
# If no time tracking exists with this ID, exit function {{{
if ! timew summary :year :ids | grep --quiet -- " @${tistart_time_id} "; then
printf '%b' "No available time tracking in the last year with ${REDB}${tistart_time_id}${RESET} ID."
return 1
fi
# }}}
# Get time tracking's description from all time tracking of this year
tistart_time_desc=$(timew summary :year :ids | sed --quiet "s/.*@\(${tistart_time_id} .*\)/\1/p" | sed 's/ */ /g')
# Get time tracking's start day from all time tracking
tistart_time_start_day=$(timew export | sed --quiet --regexp-extended "s/^\{\"id\":${tistart_time_id},\"start\":\"([0-9]{4})([0-9]{2})([0-9]{2})T.*end.*/\1-\2-\3/p")
# Check or ask for new start time {{{
if [ -z "${tistart_time_new_start}" ]; then
printf '%b' "Enter the ${MAGENTAB}new start time${RESET} (or new date 'YYYY-MM-DD${REDB}T${RESET}HH:MM:SS'; default day is ${tistart_time_start_day}) for this time tracking : "
read -r tistart_time_new_start
fi
# }}}
printf '%b' "Change start time of \"${MAGENTAB}${tistart_time_desc}${RESET}\" to ${REDB}=> ${tistart_time_new_start} <=${RESET} [Y/n] ? "
read -r tistart_confirmation
# Check confirmation
if printf -- '%s' "${tistart_confirmation:=y}" | grep --quiet --word-regexp -- "y"; then
## If the new start time entered by user contains a "T" (user enter a dateTtime)
if printf -- '%s' "${tistart_time_new_start}" | grep --quiet -- "T"; then
printf '%b' "start time of ${tistart_time_desc} is now ${tistart_time_new_start}."
timew modify start @"${tistart_time_id}" "${tistart_time_new_start}" || return 0
else
printf '%b' "start time of ${tistart_time_desc} is now ${tistart_time_start_day}T${tistart_time_new_start}."
timew modify start @"${tistart_time_id}" "${tistart_time_start_day}T${tistart_time_new_start}" || return 0
fi
fi
}
## }}}
## Modify the end of a time tracking {{{
function tiend() {
# Define new_end empty by default
local tiend_time_new_end=""
local tiend_time_id
local tiend_time_new_end
local tiend_time_desc
local tiend_time_start_day
local tiend_confirmation
# Verify argument
case "${#}" in
1 )
## Get the first arg as time ID
tiend_time_id="${1}"
;;
2 )
## Get the first arg as time ID
tiend_time_id="${1}"
## Get the second arg as new end time for this track
tiend_time_new_end="${2}"
;;
* )
## Ask the user to choose an ID in time tracking from the yesterday {{{
timew summary from yesterday :ids || return 0
printf '%b' "Enter the ${MAGENTAB}ID${RESET} of the time tracking to modify : "
read -r tiend_time_id
## }}}
;;
esac
# If no time tracking exists with this ID, exit function {{{
if ! timew summary :year :ids | grep --quiet -- " @${tiend_time_id} "; then
printf '%b' "No available time tracking in the last year with ${REDB}${tiend_time_id}${RESET} ID."
return 1
fi
# }}}
# Get time tracking's description from all time tracking of this year
tiend_time_desc=$(timew summary :year :ids | sed --quiet "s/.*@\(${tiend_time_id} .*\)/\1/p" | sed 's/ */ /g')
# Get time tracking's start day from all time tracking
tiend_time_start_day=$(timew export | sed --quiet --regexp-extended "s/^\{\"id\":${tiend_time_id},\"start\":\"([0-9]{4})([0-9]{2})([0-9]{2})T.*end.*/\1-\2-\3/p")
# Check or ask for new end time {{{
if [ -z "${tiend_time_new_end}" ]; then
printf '%b' "Enter the ${MAGENTAB}new end time${RESET} (or new date 'YYYY-MM-DD${REDB}T${RESET}HH:MM:SS'; default day is ${tiend_time_start_day}) for this time tracking : "
read -r tiend_time_new_end
fi
# }}}
printf '%b' "Change end time of \"${MAGENTAB}${tiend_time_desc}${RESET}\" to ${REDB}=> ${tiend_time_new_end} <=${RESET} [Y/n] ? "
read -r tiend_confirmation
# Check confirmation
if printf -- '%s' "${tiend_confirmation:=y}" | grep --quiet --word-regexp -- "y"; then
## If the new end time entered by user contains a "T" (user enter a dateTtime)
if printf -- '%s' "${tiend_time_new_end}" | grep --quiet -- "T"; then
timew modify end @"${tiend_time_id}" "${tiend_time_new_end}" || return 0
printf '%b' "End time of ${tiend_time_desc} is now ${tiend_time_new_end}."
else
timew modify end @"${tiend_time_id}" "${tiend_time_start_day}T${tiend_time_new_end}" || return 0
printf '%b' "End time of ${tiend_time_desc} is now ${tiend_time_start_day}T${tiend_time_new_end}."
fi
fi
}
## }}}
## Modify the duration of a time tracking {{{
function tiduration() {
# Define new_duration empty by default
local tiduration_time_new_duration=""
local tiduration_time_id
local tiduration_time_new_duration
local tiduration_time_desc
local tiduration_confirmation
# Verify argument
case "${#}" in
1 )
## Get the first arg as time ID
tiduration_time_id="${1}"
;;
2 )
## Get the first arg as time ID
tiduration_time_id="${1}"
## Get the second arg as new end time for this track
tiduration_time_new_duration="${2}"
;;
* )
## Ask the user to choose an ID in time tracking from the yesterday {{{
timew summary from yesterday :ids || return 0
printf '%b' "Enter the ${MAGENTAB}ID${RESET} of the time tracking to modify : "
read -r tiduration_time_id
## }}}
;;
esac
# If no time tracking exists with this ID, exit function {{{
if ! timew summary :year :ids | grep --quiet -- " @${tiduration_time_id} "; then
printf '%b' "No available time tracking in the last year with ${REDB}${tiduration_time_id}${RESET} ID."
return 1
fi
# }}}
# Get time tracking's description from all time tracking of this year
tiduration_time_desc=$(timew summary :year :ids | sed --quiet "s/.*@\(${tiduration_time_id} .*\)/\1/p" | sed 's/ */ /g')
# Check or ask for new end time {{{
if [ -z "${tiduration_time_new_duration}" ]; then
printf '%b' "Enter the ${MAGENTAB}new duration${RESET} (eg. 25mins, 1hour…) for this time tracking : "
read -r tiduration_time_new_duration
fi
# }}}
printf '%b' "Change duration of \"${MAGENTAB}${tiduration_time_desc}${RESET}\" to ${REDB}=> ${tiduration_time_new_duration} <=${RESET} [Y/n] ? "
read -r tiduration_confirmation
# Check confirmation
if printf -- '%s' "${tiduration_confirmation:=y}" | grep --quiet --word-regexp -- "y"; then
timew resize @"${tiduration_time_id}" "${tiduration_time_new_duration}" || return 0
printf '%b' "Duration of ${tiduration_time_desc} is now ${tiduration_time_new_duration}."
fi
}
## }}}
## Move a time tracking {{{
function timove() {
# Define new_start empty by default
local timove_time_new_start=""
local timove_time_id
local timove_time_new_start
local timove_time_desc
local timove_time_start_day
local timove_confirmation
# Verify argument
case "${#}" in
1 )
## Get the first arg as task ID
timove_time_id="${1}"
;;
2 )
## Get the first arg as task ID
timove_time_id="${1}"
## Get the second arg as new start time for the task
timove_time_new_start="${2}"
;;
* )
## Ask the user to choose an ID in tasks from the yesterday {{{
timew summary from yesterday :ids || return 0
printf '%b' "Enter the ${MAGENTAB}ID${RESET} of the task to move : "
read -r timove_time_id
## }}}
;;
esac
# If no task with this ID exists in the last month, exit function {{{
if ! timew summary :month :ids | grep --quiet -- " @${timove_time_id} "; then
printf '%b' "No available task in the last month with ${REDB}${timove_time_id}${RESET} ID."
return 1
fi
# }}}
# Get task's description from all task of this month
timove_time_desc=$(timew summary :month :ids | sed --quiet "s/.*@\(${timove_time_id} .*\)/\1/p" | sed 's/ */ /g')
# Get time tracking's start day from all time tracking
timove_time_start_day=$(timew export | sed --quiet --regexp-extended "s/^\{\"id\":${timove_time_id},\"start\":\"([0-9]{4})([0-9]{2})([0-9]{2})T.*end.*/\1-\2-\3/p")
# Check or ask for new start time {{{
if [ -z "${timove_time_new_start}" ]; then
printf '%b' "Enter the ${MAGENTAB}new start time${RESET} (or new date 'YYYY-MM-DD${REDB}T${RESET}HH:MM:SS'; default day is ${timove_time_start_day}) for this task : "
read -r timove_time_new_start
fi
# }}}
printf '%b' "Move \"${MAGENTAB}${timove_time_desc}${RESET}\" to ${REDB}=> ${timove_time_new_start} <=${RESET} [Y/n] ? "
read -r timove_confirmation
# Check confirmation
if printf -- '%s' "${timove_confirmation:=y}" | grep --quiet --word-regexp -- "y"; then
## If the new start time entered by user contains a "T" (user enter a dateTtime)
if printf -- '%s' "${timove_time_new_start}" | grep --quiet -- "T"; then
timew move @"${timove_time_id}" "${timove_time_new_start}" || return 0
printf '%b' "${timove_time_desc} was moved to ${timove_time_new_start}."
else
timew move @"${timove_time_id}" "${timove_time_start_day}T${timove_time_new_start}" || return 0
printf '%b' "start time of ${timove_time_desc} is now ${timove_time_start_day}T${timove_time_new_start}."
fi
fi
}
## }}}
# }}}
# DebOps {{{
## Source DebOps user environment file {{{
if [ -f "${HOME}/.config/debops/environment" ]; then
source "${HOME}/.config/debops/environment"
fi
## }}}
## Direct access to DebOps's directories
alias dero="cd ${DEBOPS_VENV_ROLES:-/dev/null}"
alias deplay="cd ${DEBOPS_VENV_PLAYBOOKS:-/dev/null}"
## Apply full config to a define host(s)/group(s) {{{
function debhost() {
if [ ${ANS_HOST} ]; then
debops run site --limit "${ANS_HOST}"
else
printf '%b' "${MAGENTA}ANS_HOST${RESET} vars is ${REDB}not${RESET} define!\n"
fi
}
## }}}
## Apply a role to a define host(s)/group(s) {{{
function debrole() {
if [ ${ANS_HOST} ]; then
debops run site --limit "${ANS_HOST}" --tags "role::${1:-/dev/null}"
else
printf '%b' "${MAGENTA}ANS_HOST${RESET} vars is ${REDB}not${RESET} define!\n"
fi
}
## }}}
## Apply the role from a service to a define host(s)/group(s) {{{
function debserv() {
if [ ${ANS_HOST} ]; then
debops run service/"${1:-/dev/null}" --limit "${ANS_HOST}" --tags "role::${1:-/dev/null}"
else
printf '%b' "${MAGENTA}ANS_HOST${RESET} vars is ${REDB}not${RESET} define!\n"
fi
}
## }}}
## Apply a role from a service to a define host(s)/group(s) {{{
function debservice() {
if [ ${ANS_HOST} ]; then
debops run service/"${1:-/dev/null}" --limit "${ANS_HOST}"
else
printf '%b' "${MAGENTA}ANS_HOST${RESET} vars is ${REDB}not${RESET} define!\n"
fi
}
## }}}
## Apply a playbook to a define host(s)/group(s) {{{
function debplay() {
if [ ${ANS_HOST} ]; then
if [ ! ${2} ]; then
debops run "${1:-/dev/null}" --limit "${ANS_HOST}"
else
debops run "${1:-/dev/null}" --limit "${ANS_HOST}" --tags "role::${2:-/dev/null}"
fi
else
printf '%b' "${MAGENTA}ANS_HOST${RESET} vars is ${REDB}not${RESET} define!\n"
fi
}
## }}}
## Check full config to a define host(s)/group(s) {{{
function debchost() {
if [ ${ANS_HOST} ]; then
debops check site --limit "${ANS_HOST}"
else
printf '%b' "${MAGENTA}ANS_HOST${RESET} vars is ${REDB}not${RESET} define!\n"
fi
}
## }}}
## Check a role to a define host(s)/group(s) {{{
function debcrole() {
if [ ${ANS_HOST} ]; then
debops check site --limit "${ANS_HOST}" --tags "role::${1:-/dev/null}"
else
printf '%b' "${MAGENTA}ANS_HOST${RESET} vars is ${REDB}not${RESET} define!\n"
fi
}
## }}}
## Check the role from a service to a define host(s)/group(s) {{{
function debcserv() {
if [ ${ANS_HOST} ]; then
debops check service/"${1:-/dev/null}" --limit "${ANS_HOST}" --tags "role::${1:-/dev/null}"
else
printf '%b' "${MAGENTA}ANS_HOST${RESET} vars is ${REDB}not${RESET} define!\n"
fi
}
## }}}
## Check a role from a service to a define host(s)/group(s) {{{
function debcservice() {
if [ ${ANS_HOST} ]; then
debops check service/"${1:-/dev/null}" --limit "${ANS_HOST}"
else
printf '%b' "${MAGENTA}ANS_HOST${RESET} vars is ${REDB}not${RESET} define!\n"
fi
}
## }}}
## Check a playbook to a define host(s)/group(s) {{{
function debcplay() {
if [ ${ANS_HOST} ]; then
if [ ! ${2} ]; then
debops run "${1:-/dev/null}" --limit "${ANS_HOST}"
else
debops run "${1:-/dev/null}" --limit "${ANS_HOST}" --tags "role::${2:-/dev/null}"
fi
else
printf '%b' "${MAGENTA}ANS_HOST${RESET} vars is ${REDB}not${RESET} define!\n"
fi
}
## }}}
# }}}
# Web apps {{{
# Get weather
function meteo {
if command -v curl > /dev/null; then
curl http://fr.wttr.in/${*}
elif command -v wget > /dev/null; then
wget --quiet --output-document=- http://wttr.in/${*}
else
printf '%b' "Please ${REDB}install one of this tools :${RESET} curl or wget.\n"
fi
}
# }}}
#######################################
#Ouverture d'un programme en fonction
#de l'extension du fichier
#######################################
alias -s txt='$PAGER '
alias -s odt='libreoffice --writer '
alias -s rtf='libreoffice --writer '
alias -s doc='libreoffice --writer '
alias -s docx='libreoffice --writer '
alias -s ods='libreoffice --calc '
alias -s xls='libreoffice --calc '
alias -s html=$BROWSER
alias -s org=$BROWSER
alias -s php=$BROWSER
alias -s com=$BROWSER
alias -s net=$BROWSER
alias -s png='mirage '
alias -s jpg='mirage '
alias -s gif='mirage '
alias -s mp4='smplayer '
alias -s avi='smplayer '
alias -s flv='smplayer '
alias -s log='tail --follow'
alias -s conf='vim '
alias -s gz='gunzip '
alias -s bz2='bzip2'
#######################################
# Raccourcis pour les dossier
# Pour y accéder, faire ~NOM_DU_RACCOURCIS
#######################################
hash -d apt="/etc/apt"
hash -d zsh="/etc/zsh"
hash -d dl="/media/udata/download/"
hash -d sid="/media/udata/config_debian"
hash -d smb="/etc/samba/"
# Inutile mais fun :p
##Affiche le calendrier et le jour courant en couleur
#alias ccal='var=$(cal -m); echo "${var/$(date +%-d)/$(echo -e "\033[1;31m$(date +%-d)\033[0m")}"'
alias ccal='var=$(cal); echo "${var/$(date +%-d)/$(echo -e "\033[1;31m$(date +%-d)\033[0m")}"'
##Commande utilisant cowsay (ou PONYSAY!!) pour afficher un message
function bonjour() {
local MIN_TIME=$(date +%M)
local MODULO_MIN=$(($MIN_TIME % 2))
if [ $(command -v bash_quote) ] && [ $(command -v cowsay) ]; then
if [ $MODULO_MIN -eq 0 ]; then
#echo Bonjour $USER, nous sommes le `date +"%A %e %B %Y"`, et il est : `date +"%H"` h `date +"%M"` | cowsay -f $(/bin/ls /usr/share/cowsay/cows -1 | head -n $(expr $$$(date +%s) % $(ls /usr/share/cowsay/cows | wc -w) + 1) | tail -n 1)
# Random cow
command bash_quote | cowsay -f $(find /usr/share/cow* -type f -iname "*.cow" | sort --random-sort | head --lines=1)
else
#echo Bonjour $USER, nous sommes le `date +"%A %e %B %Y"`, et il est : `date +"%H"` h `date +"%M"` | ponythink
command bash_quote | ponythink
fi
else
printf '%b' "${WHITEB}bonjour function${RESET}: One of the prerequesites is unavailable.\nFor bash_quote please see: https://git.101010.fr/dotfiles-gardouille/scripts/blob/master/bash_quote\n"
fi
}
##Affiche quelques statistiques à propos de l'ordinateur
alias stat_sys="echo ' ' && uname --all && echo ' '&& uptime &&echo ' '&& df && echo ' '"
#####################################
#####FONCTIONS
######################################
## Verrouiller le shell avec vlock
#function TRAPALRM() { vlock }
##Cree le repertoire et va dedans
function mkcd() {
mkdir -- $1 && cd $_
}
#liste les alias et functions
function listalias(){
cat /etc/zsh/zshrc | egrep "alias|function" | grep --invert-match "^#" -- | $PAGER
}
# Get real address behind a shorten URL {{{
# Require a function because the given argument need to be passed to curl
function unshorten()
{
curl --silent https://unshorten.me/s/"${1-}"
}
# }}}
# Get public IP address {{{
function ippub()
{
#curl ifconfig.me
#wget http://checkip.dyndns.org/ -O - -o /dev/null | cut -d" " -f 6 | cut -d\< -f 1
dig +short myip.opendns.com @resolver1.opendns.com
}
# }}}
# Get all private IP addresses {{{
function ippriv()
{
for interface in $(find /sys/class/net/ ! -name lo -type l -printf "%f\n" | sort);
do
local IP_INTER=$(ip a s ${interface}|grep "inet "|awk '{print $2}')
printf '%b' "${WHITEB}${interface}${RESET}: ${IP_INTER}\n"
done
}
# }}}
# Get main private IP adress {{{
function ipmain()
{
ip route get 1 | awk '{print $(NF-2);exit}'
}
# }}}
# Test if a network connection is available
function is_network()
{
for path_interface in $(find /sys/class/net/ ! -name lo -type l);
do
local IS_UP=$(grep 1 ${path_interface}/carrier)
if [ ${IS_UP} ]; then
return 0
fi
done
printf '%b' "${REDB}Not Online${RESET}\n"
return 1
}
#Renomme les fichiers en minuscule
function lowercase()
{
for file in *; do
local filename=${file##*/}
case "$filename" in
*/*) local dirname==${file%/*} ;;
*) local dirname=.;;
esac
local nf=$(printf $filename | tr A-Z a-z)
local newname="${dirname}/${nf}"
if [ "$nf" != "$filename" ]; then
mv "$file" "$newname"
printf 'lowercase: %s --> %s\n' ${file} ${newname}
else
printf 'lowercase %s not changed\n' ${file}
fi
done
}
##Capture d'écran
function printscreen()
{
scrot --select --exec 'gimp $f ; rm --recursive --force -- $f'
}
## Latex:
##Redéfinition de pdflatex:
# La commande pdflatex est exécutée deux fois pour permettre la construction de l'index
function pdflatex()
{
# On récupère le nom du fichier sans l'extension
local file_name="${1:r}"
# Le fichier avec l'extension pdf
local pdf="${file_name}.pdf"
# Dossier temporaire
local temp_dir="temp"
# On supprime le fichier pdf si il est présent
if [ -f "${pdf}" ]; then
rm --recursive --force -- "${pdf}"
fi
# Si le répertoire temporaire n'existe pas, on le crée
if [ ! -d "${temp_dir}" ]; then
mkdir "${temp_dir}"
fi
# On exécute la commande pour créer le pdf
/usr/bin/pdflatex -output-directory ${temp_dir} $1
/usr/bin/pdflatex -output-directory ${temp_dir} $1
# On place le fichier pdf qui est dans le répertoire temporaire dans le répertoire courant
mv --force -- "${temp_dir}"/*.pdf .
}
#Éteint un pc sous windows à distance
#Nécessite le paquet samba-common
# Arguments:
# ${1}: l'ip de la machine
# ${2}: le nom d'utilisateur
# ${3}: le mot de passe de l'utilisateur
function eteint()
{
net rpc shutdown -f -I $1 -U $2%$3 -t 10 -C "Arrêt en cours..."
}
# Calculatrice en ligne de commande
function calc()
{
echo "${1}" | bc -l
}
# Afficher le code retour de la commande précédente
function cmd_status {
local exit_code=$? # exit code of command
local count=$(jobs | wc --lines) # no. of background jobs
# Report no. of background jobs if >0
if [ $count -gt 0 ]; then
echo -n " %{$fg[cyan]%}⎇ %j "
fi
# Report exit code
if [ $exit_code -ne 0 ]; then
echo -n "%{$fg[yellow]%}%?%{$fg[red]%} ✖%{$reset_color%}"
else
echo -n "%{$fg[green]%}✔%{$reset_color%}"
fi
}
# Affiche un rappel des raccourcis pour se déplacer dans vim
function rappel_vim()
{
echo "\
##########################################
# Rappel basique pour VIM
##########################################
# Déplacements basiques :
H pour se déplacer vers la gauche
J pour se déplacer vers le bas
K pour se déplacer vers la droite
L pour se déplacer vers la droite
# Déplacements avancés sur une ligne :
e pour aller à la fin du mot suivant
w pour aller au début du mot suivant
b pour aller à la fin du mot précédent
0 pour aller en début de ligne
$ pour aller en fin de ligne
^ pour aller au premier caractère de la ligne qui n'est pas un espace ni une tabulation
f<c> pour aller jusqu'au caractère <c> vers l'avant
3f<c> pour aller jusqu'à la 3ème occurence du caractère <c> vers l'avant
F<c> pour aller jusqu'au caractère <c> vers l'arrière
nF<c> pour aller jusqu'à la nème occurence du caractère <c> vers l'arrière
t<c> pour aller jusqu'au caractère <c> vers l'avant en s'arrêtant avant
T<c> pour aller jusqu'au caractère <c> vers l'arrière en s'arrêtant avant
# Déplacement dans le document :
gg pour aller au début du document
G pour aller à la fin du document
nG pour aller à la ligne <n>
:<n> pour aller à la ligne <n>
% pour aller à la parenthèse (acollade, crochet) correspondant
# Copier/coller avancé
\"ayy Copier la ligne courante dans le buffer \"a\"
\"5byy Copier les 5 lignes sous le curseur dans le buffer \"b\"
<MODE_VISUEL>\"ey Copier les lignes sélectionnées dans le buffer \"e\"
# undo & redo
u pour annuler pour annuler la dernière modification
CTRL+R pour refaire la dernière modification
# Gestion du texte
~ pour inverser la casse du texte sélectionné
# Supprimer le texte du curseur à la fin de la ligne
<mode commande> d$
<mode insertion> CTRL-o D
# Supprimer le texte du curseur au début de la ligne
<mode commande> d^
" | $PAGER
}
# Affiche un rappel des raccourcis pour se déplacer dans vim
function rappel_vim_avance()
{
echo "\
##########################################
# Utilisation un peu plus avancée de VIM
##########################################
# nom fichier
# Avec par exemple un fichier qui s'appelle fichier.tex dans /home/limax/Documents/
# est le nom du fichier en cours
:!echo % (renvoie /Documents/fichier.tex )
:!echo %:r (renvoie /Documents/fichier )
:!echo %:e (renvoie tex )
:!echo %:t (renvoie fichier.tex )
:!echo %:p (renvoie /home/limax/Documents/fichier.tex )
:!echo %:t (renvoie fichier.tex )
:!echo %:h (renvoie Documents)
# Par exemple pour ouvrir le pdf avec lesspipe
:!lesspipe %:r.pdf
# Indentation
# Pour réindenter du texte:
mode visuel
- sélectionner toutes les lignes à indenter correctement
touche \"=\"
# Pour décaler plusieurs lignes de plusieurs tabulations:
mode visuel
- sélectionner toutes les lignes à décaler
:>>>
# Commande
# Pour exécuter une seule commande à partir du mode insertion
<mode insertion> CTRL-o suivi de la commande à exécuter
# Code touche
# Pour afficher le code clavier d'une touche spéciale en mode insertion:
<mode insertion> CTRL-V
# Pour afficher le code interne d'une touche spéciale:
<mode insertion> CTRL-K
# Pour obtenir le code ascii d'un caractère:
ga
# Plier/déplier
zm Plier tout le document sur un niveau de plus
zr Déplier tout le document sur un niveau de plus
zc Plier un bloc/fonction/class
zo Déplier un bloc/fonction/class
" | $PAGER
}
# Affiche un rappel pour l'édition de fichier Latex
function rappel_latex()
{
echo "\
-\\/- Permet d'afficher -- et non un tiret cadratin
Ligne vide Permet un retour à la ligne entre deux textes
\\ldots Affiche correctement \"...\"
# itemize
Mettre un \\vspace{0.5cm} après une liste?
Laisser une ligne vide après une commande root dans une liste?
# À faire
Ajouter un style pour les notes d'informations
Ajouter un style pour les notes importantes
" | $PAGER
}
## Vérifier les logins et logouts de tous les comptes incluant le mien.
watch=all
# Vérifie toutes les 30 secondes
logcheck=30
# Change le format de watch pour quelques chose avec plus d'informations
# %n = username, %M = hostname, %a = action, %l = tty, %T = time,
# %W = date
WATCHFMT="%n from %M has %a tty%l at %T %W"
# Crypte le fichier passer en paramètre en utilisant le certificat public
# de l'utilisateur.
# Arguments:
# ${1}: fichier à crypter
# ${2}:
function crypt()
{
openssl smime -encrypt -aes128 -in ${1} -out .${1}.ls ~/.openssl/mycert.crt
}
# Décrypte le fichier passer en paramètre en fonction de la clef ssl de
# l'utilisateur et trouve la ligne contenant le mot rechercher par l'user
# Arguments:
# ${1}: le fichier à décrypter
# ${2}: le paramètre rechercher dans le fichier
function getpdw()
{
openssl smime -decrypt -in ${1} -inkey ~/.openssl/mykey.key | grep ${2}
}
# Décrypte le fichier passer en paramètre en fonction de la clef ssl de
# l'utilisateur et le fichier de sorti est le second paramètre
# Arguments:
# ${1}: le fichier à décrypter
# ${2}: le fichier de sorti
function decrypt()
{
openssl smime -decrypt -in ${1} -out ${2} -inkey ~/.openssl/mykey.key
}
################################################
# 2. Prompt et définition des touches basiques #
################################################
# Prompt couleur (la couleur n'est pas la même pour le root et
# pour les simples utilisateurs)
# Définition des couleurs:
bleu_clair="[36;1m"
bleu_fonce="[34;1m"
rouge="[31m"
jaune="[33m"
blanc="[37m"
vert="[32m"
couleur_normale="[0m"
# Définition du texte du prompt
heure="%{$bleu_clair%}%T"
user="%{$bleu_fonce%}%n"
user_root="%{$rouge%}%n"
at="%{$jaune%}@"
host="%{$blanc%}%m"
repertoire_courant="%{$vert%}%c"
repertoire_absolu="%{$vert%}%d"
# Chemin du répertoire courant en relatif à ~
repertoire_relatif="%{$vert%}%~"
root="%{$jaune%}%#"
noroot="%{$jaune%}%%"
normal="%{$couleur_normale%}"
# Définition du prompt
if [ "`id -u`" -eq 0 ]; then ## Root
export PS1="$heure $user_root$at$host $repertoire_courant$root $normal"
# export PS1="%{$bleu_clair%T %{$rouge%n%{$jaune@%{$blanc%m %{$vert%c%{$jaune%#%{%} "
else ## Simple utilisateur
export PS1="$heure $host $repertoire_courant$noroot $normal"
fi
# Prise en charge des touches [début], [fin] et autres
typeset -A key
key[Home]=${terminfo[khome]}
key[End]=${terminfo[kend]}
key[Insert]=${terminfo[kich1]}
key[Delete]=${terminfo[kdch1]}
key[Up]=${terminfo[kcuu1]}
key[Down]=${terminfo[kcud1]}
key[Left]=${terminfo[kcub1]}
key[Right]=${terminfo[kcuf1]}
key[PageUp]=${terminfo[kpp]}
key[PageDown]=${terminfo[knp]}
[[ -n "${key[Home]}" ]] && bindkey "${key[Home]}" beginning-of-line
[[ -n "${key[End]}" ]] && bindkey "${key[End]}" end-of-line
[[ -n "${key[Insert]}" ]] && bindkey "${key[Insert]}" overwrite-mode
[[ -n "${key[Delete]}" ]] && bindkey "${key[Delete]}" delete-char
[[ -n "${key[Up]}" ]] && bindkey "${key[Up]}" up-line-or-history
[[ -n "${key[Down]}" ]] && bindkey "${key[Down]}" down-line-or-history
[[ -n "${key[Left]}" ]] && bindkey "${key[Left]}" backward-char
[[ -n "${key[Right]}" ]] && bindkey "${key[Right]}" forward-char
[[ -n "${key[PageUp]}" ]] && bindkey "${key[PageUp]}" history-beginning-search-backward
[[ -n "${key[PageDown]}" ]] && bindkey "${key[PageDown]}" history-beginning-search-forward
# ctrl+← and ctrl+→ issue
bindkey "^[[1;5C" vi-forward-word-end
bindkey "^[[1;5D" backward-word
# Titre de la fenêtre d'un xterm
case $TERM in
xterm*)
precmd () {print -Pn "\e]0;%n@%m: %~\a"}
;;
esac
# Gestion de la couleur pour 'ls' (exportation de LS_COLORS)
# First, use vivid {{{
if [ $(command -v vivid) ]; then
#export LS_COLORS="$(vivid generate dracula)"
export LS_COLORS="$(vivid generate one-light)"
# }}}
# Second, use dircolors {{{
elif [ -x /usr/bin/dircolors ]
then
if [ -r ~/.dir_colors ]
then
eval "`dircolors ~/.dir_colors`"
elif [ -r /etc/dir_colors ]
then
eval "`dircolors /etc/dir_colors`"
else
eval "`dircolors`"
fi
fi
# }}}
#######################################
# 3. Comportement ligne de commandes #
#######################################
# La ligne de commande dans zsh peut fonctionner suivant différents schémas (options).
# Les principaux que je vais utiliser sont fait pour la ligne de commande dans zhs se
# comporte à la vim. Il y a donc un mode commande/normal et un mode insertion.
# Afficher le mode courant dans le prompt de droite (normal|insertion)
function zle-line-init zle-keymap-select {
RPS1="$(cmd_status) ${${KEYMAP/vicmd/-CMD-}/(main|viins)/-INS-}"
RPS2=$RPS1
zle reset-prompt
}
# easy color names in this config
autoload -U colors && colors
# Chargement des keymaps
zle -N zle-line-init
zle -N zle-keymap-select
### Raccourcis communs à tous les modes
autoload -U edit-command-line
zle -N edit-command-line
bindkey '' edit-command-line # Ouvrir la commande actuelle dans l'éditeur
bindkey '' history-incremental-search-backward # Recherche incrémentale qui monte dans l'historique
#bindkey '' history-incremental-search-forward # Recherche incrémentale qui descend dans l'historique
### Raccourcis spécifiques au mode insertion
bindkey -M viins '' beginning-of-line # Début de ligne
bindkey -M viins '' vi-forward-blank-word-end # Fin du mot courant
#bindkey -M viins '' vi-forward-blank-word # Début du mot suivant
bindkey -M viins '' vi-backward-word # Début du mot précédent
bindkey -M viins '' vi-find-prev-char # Rechercher la précédente occurence d'une lettre
#bindkey -M viins ' ;' vi-repeat-find # Aller à la prochaine occurence de la lettre recherchée
### Raccourcis spécifiques au mode commande
# Le mode commande dispose déjà de la plupart d'un fonctionnement très semblable
# au mode normal de vim. Seul problème pour le moment, l'absence d'un mode visuel.
###########################################
# 4. Options de zsh (cf 'man zshoptions') #
###########################################
# Je ne veux JAMAIS de beeps
unsetopt beep
unsetopt hist_beep
unsetopt list_beep
# Redirection de la sortie:
# >| doit être utilisés pour pouvoir écraser un fichier déjà existant ;
# le fichier ne sera pas écrasé avec '>'
unsetopt clobber
# Ctrl+D est équivalent à 'logout'
unsetopt ignore_eof
# Affiche le code de sortie si différent de '0'
setopt print_exit_value
# Demande confirmation pour 'rm *'
unsetopt rm_star_silent
# Attend 10 secondes avant d'exécuter une commande rm qui contient un * (asterisk).
setopt rmstarwait
# Correction orthographique des commandes
# Désactivé car, contrairement à ce que dit le "man", il essaye de
# corriger les commandes avant de les hasher
setopt correct
# Si on utilise des jokers dans une liste d'arguments, retire les jokers
# qui ne correspondent à rien au lieu de donner une erreur
setopt nullglob
# Désactivé le raccourcis '='
# Par défaut, `ls -l =vim` indiquera l'emplacement de vim.
# =vim équivaut à `which vim`
#setopt noequals
## Activation des fonctions internes de ZSH:
# Liste des fonctions disponibles:
#zcalc : une calculatrice (plus besoin de bc ou autres expr)
#zargs : un super xargs
#zmv : une commande permettant de faire du renommage/déplaçage en masse de fichiers.
#zftp : un client ftp natif
autoload -U zfinit
zfinit
# Les jobs qui tournent en tâche de fond sont nicé à '0'
unsetopt bg_nice
# N'envoie pas de "HUP" aux jobs qui tourent quand le shell se ferme
unsetopt hup
# Lancer le manuel en se placant sur une commande et en faisant {ESC,ALT}+{H,h}
autoload -U run-help
## Gestion de la pile des dossiers:
# Taille maximale de la pile placé dans zshenv
# L'exécution de "cd" met le répertoire d'où l'on vient sur la pile
setopt auto_pushd
# Ignore les doublons dans la pile
setopt pushd_ignore_dups
# N'affiche pas la pile après un "pushd" ou "popd"
setopt pushd_silent
# Inverse l'action de cd +1 et cd +1
setopt pushdminus
# "pushd" sans argument = "pushd $HOME"
setopt pushd_to_home
## Pour bien utiliser la pile:
# `dirs` va afficher la pile
# `cd -NUMÉRO` ira dans le dossier correspondant au numéro du dossier dans la pile
## Dirstack
DIRSTACKSIZE=20
setopt autopushd pushdsilent pushdtohome
## Remove duplicate entries
setopt pushdignoredups
## This reverts the +/- operators.
setopt pushdminus
#DIRSTACKFILE="$HOME/.zsh/cache/dirs"
#if [[ -f $DIRSTACKFILE ]] && [[ $#dirstack -eq 0 ]]; then
#dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
#[[ -d $dirstack[1] ]] && cd $dirstack[1]
#fi
#chpwd() {
#print -l $PWD ${(u)dirstack} >> $DIRSTACKFILE
#}
###################################
###### Options de complétion ######
###################################
# Schémas de complétion
# - Schéma A :
# 1ère tabulation : complète jusqu'au bout de la partie commune
# 2ème tabulation : propose une liste de choix
# 3ème tabulation : complète avec le 1er item de la liste
# 4ème tabulation : complète avec le 2ème item de la liste, etc...
# -> c'est le schéma de complétion par défaut de zsh.
# Schéma B :
# 1ère tabulation : propose une liste de choix et complète avec le 1er item
# de la liste
# 2ème tabulation : complète avec le 2ème item de la liste, etc...
# Si vous voulez ce schéma, décommentez la ligne suivante :
#setopt menu_complete
# Schéma C :
# 1ère tabulation : complète jusqu'au bout de la partie commune et
# propose une liste de choix
# 2ème tabulation : complète avec le 1er item de la liste
# 3ème tabulation : complète avec le 2ème item de la liste, etc...
# Ce schéma est le meilleur à mon goût !
# Si vous voulez ce schéma, décommentez la ligne suivante :
unsetopt list_ambiguous
# Quand le dernier caractère d'une complétion est '/' et que l'on
# tape 'espace' après, le '/' est effacé
setopt auto_remove_slash
# Ne fait pas de complétion sur les fichiers et répertoires cachés
unsetopt glob_dots
# Traite les liens symboliques comme il faut
setopt chase_links
# Quand l'utilisateur commence sa commande par '!' pour faire de la
# complétion historique, il n'exécute pas la commande immédiatement
# mais il écrit la commande dans le prompt
setopt hist_verify
# Si la commande est invalide mais correspond au nom d'un sous-répertoire
# exécuter 'cd sous-répertoire'
setopt auto_cd
###############################################
# 5. Paramètres de l'historique des commandes #
###############################################
# Définition des variables
SAVEHIST=5000
HISTSIZE=5000
HISTFILE=$HOME/.zsh/history
#export TIMEFMT="%E"
export SAVEHIST HISTSIZE HISTFILE
# Toutes les sessions zsh partage le même historique
#setopt SHARE_HISTORY
# Ajoute l'historique à la fin de l'ancien fichier
#setopt append_history
# Chaque ligne est ajoutée dans l'historique à mesure qu'elle est tapée
setopt inc_append_history
# Ne stocke pas une ligne dans l'historique si elle est identique à la
# précédente
setopt hist_ignore_dups
# Supprime les répétitions dans le fichier d'historique, ne conservant
# que la dernière occurrence ajoutée
#setopt hist_ignore_all_dups
# Supprime les répétitions dans l'historique lorsqu'il est plein, mais
# pas avant
setopt hist_expire_dups_first
# N'enregistre pas plus d'une fois une même ligne, quelles que soient
# les options fixées pour la session courante
#setopt hist_save_no_dups
# La recherche dans l'historique avec l'éditeur de commandes de zsh ne
# montre pas une même ligne plus d'une fois, même si elle a été
# enregistrée plusieurs fois
setopt hist_find_no_dups
# Affichage de la date du début de la commande et sa durée (depuis epoch)
# Culture time: epoch: 1er janvier 1970
setopt extended_history
# Ne pas enregistrer les commandes précédées d'un espace:
setopt hist_ignore_space
###########################################
# 6. Complétion des options des commandes #
###########################################
zstyle ':completion:*' matcher-list '' 'm:{a-z}={A-Z}'
zstyle ':completion:*' max-errors 3 numeric
zstyle ':completion:*' use-compctl false
## Pour la liste des processus que l'on peut kill, avec un menu et couleur
zstyle ':completion:*:*:*:*:processes' menu yes select
#zstyle ':completion:*:*:*:*:processes' force-list always
zstyle ':completion:*:processes' command 'ps -fau$USER'
zstyle ':completion:*:*:kill:*:processes' list-colors "=(#b) #([0-9]#)*=36=31"
## Pour éviter de reproposer un argument déjà utiliser dans la commande lors de la complétion
zstyle ':completion:*:(rm|mv|cp|ls|scp):*' ignore-line yes
## cd ne sélectionnera pas le dossier courant lorsqu'il devra remonter d'un dossier
# cd ../<TAB> ne proposera pas le dossier courant par exemple.
zstyle ':completion:*:cd:*' ignore-parents parent pwd
## Pour la liste des fichiers qu'on peut ouvrir avec vim
zstyle ':completion:*:*:vim:*' menu yes select
## Mettre en cache les résultats de l'auto-complétion car certaines fonctions sont lentes (apt, dpkg, ...)
# Ne pas hésiter à faire un petit aptitude install <TAB> et de lister tous les résultats possibles une première fois, histoire d'avoir tous les paquets en cache (~600ko), ça vaut le coup!
zstyle ':completion:*' use-cache on
zstyle ':completion:*' cache-path ~/.zsh/cache
## Ajout des couleurs pour la complétion
zmodload -i zsh/complist
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
## Complétion de la commande cd avec les répertoires locaux puis ceux de la variable CDPATH
zstyle ':completion:*:*:cd:*' tag-order local-directories path-directories
## Complétion des commandes ssh avec le contenu du fichier ~/.ssh/config et le contenu de host
#local HOSTS
#[[ -f ~/.ssh/config ]] && HOSTS=(`sed --quiet \'s/^Host \(.*\)/\1/p\' ~/.ssh/config`)
#if [ -f ~/.ssh/config ]; then
#HOSTS=(`grep ^Host ~/.ssh/config | sed s/Host\ // | egrep -v ^\*$`)
#fi
#zstyle ':completion:*:(ssh|scp|sftp|sshfs):*' hosts ${HOSTS}
zstyle ':completion:*:hosts' hosts off
# Complétions pour certains programmes en fonction des extensions
zstyle ':completion:*:*:vlc:*' file-patterns '*.(mkv|MKV|avi|AVI|flv|FLV|mp4|MP4|webm|WEBM|mov|MOV|flac|FLAC|mp3|MP3|ogg|OGG|ogv|OGV|wmv|WMV)\ *(-/):directories'
## Ajout de la complétion pour plusieurs fonctions:
autoload -U compinit
autoload -U zutil
autoload -U complist
# Activation
compinit
###########################################
# 7. Création des fichiers et répertoires #
###########################################
# Dossier .zsh dans le répertoire personnel
if [ ! -d ~/.zsh ]; then
mkdir ~/.zsh
fi
# Fichier contenant l'historique pour chaque utilisateur
if [ ! -f ~/.zsh/history ]; then
touch ~/.zsh/history
fi
# Dossier contenant le cache pour chaque utilisateur
if [ ! -d ~/.zsh/cache ]; then
mkdir ~/.zsh/cache
fi
###########################################
############## 8. Globbing ################
###########################################
# Activation du globbing étendu
setopt extendedglob
## '^' inverse la pattern qui suit.
# Exemple:
# `ls ^*.log` listera tous les fichiers exceptés *.log
###########################################
############### 9. Modules ################
###########################################
## IF fzf is AVAILABLE
if [ $(command -v fzf) ]; then
## If local fzf bin is available use it in priority
if [[ ! "$PATH" == *"${HOME}"/.fzf/bin* ]]; then
export PATH="${HOME}/.fzf/bin:${PATH}"
fi
## IF fd is AVAILABLE {{{
if [ -f ~/bin/fd ] ||
[ -f /bin/fd ] ||
[ -f /usr/bin/fd ]; then
export FZF_DEFAULT_COMMAND='fd --type f'
fi
## }}}
autoload is-at-least
# FZF_DEFAULT_OPTS according to fzf version {{{
if is-at-least 0.29.0 $(fzf --version); then
export FZF_DEFAULT_OPTS="--cycle --multi --select-1 --bind 'change:first,shift-tab:down,tab:up'"
else
## change:first is unknown in FZF before 0.29.0
export FZF_DEFAULT_OPTS="--cycle --multi --select-1 --bind 'tab:down,shift-tab:up'"
fi
# }}}
# Auto-completion
# ---------------
[[ $- == *i* ]] && source "${HOME}/.fzf/shell/completion.zsh" 2> /dev/null
# Key bindings
# ------------
test -f "${HOME}/.fzf/shell/key-bindings.zsh" && source "${HOME}/.fzf/shell/key-bindings.zsh"
test -f "/usr/share/fzf/key-bindings.zsh" && source "/usr/share/fzf/key-bindings.zsh"
# ff - cd to selected directory exclude hidden directories and their content {{{
# Search with find (fd|fdfind overkill the CPU for few benefits on small tree)
# Check for symlinked directories too
# Allow to give arguments to prefill fzf request
# Display a preview tree of the directory
# Move to the selected directory
function ff() {
local dir
## Manage argument {{{
if [ "${#}" -eq "0" ]; then
## Default command without args
dir=$(find -L . -xtype d -not -path "*/.*" | fzf --prompt='cd> ' --height=50% --preview 'eza --tree --level 2 {} | head --lines=20' --no-multi) &&
else
## If at least one argument was given, add it to fzf query
dir=$(find -L . -xtype d -not -path "*/.*" | fzf --prompt='cd> ' --height=50% --preview 'eza --tree --level 2 {} | head --lines=20' --no-multi --query "${*} ") &&
fi
## }}}
cd -- "${dir}"
}
# }}}
# ffh - cd to selected directory (hidden only) {{{
# Search with find (fd|fdfind overkill the CPU for few benefits on small tree)
# Check for symlinked directories too
# Allow to give arguments to prefill fzf request
# Display a preview tree of the directory
# Move to the selected directory
function ffh() {
local dir
## Manage argument {{{
if [ "${#}" -eq "0" ]; then
## Default command without args
dir=$(find -L . -xtype d -path "*/.*" | fzf --prompt='cd> ' --height=50% --preview 'eza --tree --level 2 {} | head --lines=20' --no-multi) &&
else
## If at least one argument was given, add it to fzf query
dir=$(find -L . -xtype d -path "*/.*" | fzf --prompt='cd> ' --height=50% --preview 'eza --tree --level 2 {} | head --lines=20' --no-multi --query "${*} ") &&
fi
## }}}
cd -- "${dir}"
}
# }}}
# ffa - cd to any directory from / {{{
# Search with fd (fdfind is perfect to search on /)
# Check for symlinked directories too
# Allow to give arguments to prefill fzf request
# Display a preview tree of the directory
# Move to the selected directory
function ffa() {
local dir
## Manage argument {{{
if [ "${#}" -eq "0" ]; then
## Default command without args
dir=$(fd -uu --search-path / --type d --type symlink --follow | fzf --prompt='cd> ' --height=50% --preview 'eza --tree --level 1 {} | head --lines=20' --no-multi) &&
else
## If at least one argument was given, add it to fzf query
dir=$(fd -uu --search-path / --type d --type symlink --follow | fzf --prompt='cd> ' --height=50% --preview 'eza --tree --level 1 {} | head --lines=20' --no-multi --query "${*} ") &&
fi
## }}}
cd -- "${dir}"
}
# }}}
# ffu - cd to selected parent directory {{{
function ffu() {
local declare dirs=()
local dir
## Function to list parents of the given directory {{{
get_parent_dirs() {
if [[ -d "${1}" ]]; then dirs+=("$1"); else return; fi
if [[ "${1}" == '/' ]]; then
for _dir in "${dirs[@]}"; do echo $_dir; done
else
get_parent_dirs $(dirname "${1}")
fi
}
## }}}
## Manage argument {{{
if [ "${#}" -eq "0" ]; then
## Default command without args
dir=$(get_parent_dirs $(realpath "${PWD}") | fzf --prompt='cd> ' --tac --height=50% --no-multi) &&
else
## If at least one argument was given, add it to fzf query
dir=$(get_parent_dirs $(realpath "${PWD}") | fzf --prompt='cd> ' --tac --height=50% --no-multi --query "${*} ") &&
fi
## }}}
cd -- "${dir}"
}
# }}}
# fff - cd to the directory of the selected file {{{
# Search with fd (after few tests, fdfind is fareway better than find… even on small tree)
# Check for symlinked files too
# Allow to give arguments to prefill fzf request
# Display a directory preview tree of the selected file with eza
# Move to the directory of the selected file
function fff() {
local file
local dir
## Manage argument {{{
if [ "${#}" -eq "0" ]; then
## Default command without args
file=$(fd -uu --type file --type symlink --follow | fzf --prompt='cd> ' --height=50% --preview 'eza --tree --level 2 $(dirname {}) | head --lines=20' --no-multi) &&
else
## If at least one argument was given, add it to fzf query
file=$(fd -uu --type file --type symlink --follow | fzf --prompt='cd> ' --height=50% --preview 'eza --tree --level 2 $(dirname {}) | head --lines=20' --no-multi --query "${*} ") &&
fi
## }}}
dir=$(dirname "${file}")
cd -- "${dir}"
}
# }}}
# cf - fuzzy cd from anywhere {{{
# Search with fd (fdfind is perfect to search on /)
# Allow to give arguments to prefill fzf request
# Display a directory preview tree of the selected file with eza
# Move to the directory of the selected file
function cf() {
local file
## Manage argument {{{
if [ "${#}" -eq "0" ]; then
## Default command without args
file=$(fd -uu --search-path / --follow | fzf --prompt='cd> ' --height=50% --preview 'eza --tree --level 1 $(dirname {}) | head --lines=20' --no-multi) &&
else
## If at least one argument was given, add it to fzf query
file=$(fd -uu --search-path / --follow | fzf --prompt='cd> ' --height=50% --preview 'eza --tree --level 1 $(dirname {}) | head --lines=20' --no-multi --query "${*} ") &&
fi
## }}}
if [[ -n "${file}" ]]
then
if [[ -d "${file}" ]]
then
### If it's a directory, cd
cd -- "${file}"
else
### If it's a file, cd to the directory
cd -- "${file:h}"
fi
fi
}
# }}}
# v - fuzzy open file with vi from current directory {{{
# Search with fd (fdfind is perfect to search more than ~200k files)
# Check for symlinked files too
# Allow to give arguments to prefill fzf request
# Display the 50 first lines of the selected file with bat (batcat)
# Move to the directory of the selected file
# Open the selected file with vi
function v() {
local files
local dir
local file
## Manage argument {{{
if [ "${#}" -eq "0" ]; then
## Default command without args
files=$(fd -uu --type file --type symlink --follow | fzf --prompt='vi> ' --preview 'bat --color=always --line-range 0:50 {}' --no-multi) &&
else
## If at least one argument was given, add it to fzf query
files=$(fd -uu --type file --type symlink --follow | fzf --prompt='vi> ' --preview 'bat --color=always --line-range 0:50 {}' --no-multi --query "${*} ") &&
fi
## }}}
## Move to the directory and open the file {{{
if [[ -n "${files}" ]]
then
dir=$(dirname "${files}")
### Change directory only if not already in the expected dir
test $(realpath "${dir}") != $(realpath .) && cd -- "${dir}"
file=$(basename "${files}")
vi -- "${file}"
fi
## }}}
}
# }}}
# pdf fuzzy open PDF file with "${PDF_VIEWER}" from current directory {{{
# Search with fd (fdfind is better than find with a pattern)
# Allow to give arguments to prefill fzf request
# Display a preview of selected file with lesspipe
# Move to the directory of the selected file
# Open the selected file with "${PDF_VIEWER}"
function pdf() {
local files
local dir
local file
## Manage argument {{{
if [ "${#}" -eq "0" ]; then
## Default command without args
files=$(fd --unrestricted --type file --type symlink --follow "\.pdf$" | fzf --prompt='pdf> ' --preview 'lesspipe {} | less' --no-multi) &&
else
## If at least one argument was given, add it to fzf query
files=$(fd --unrestricted --type file --type symlink --follow "\.pdf$" | fzf --prompt='pdf> ' --preview 'lesspipe {} | less' --no-multi --query "${*} ") &&
fi
## }}}
## Move to the directory and open the file {{{
if [[ -n $files ]]
then
dir=$(dirname "${files}")
### Change directory only if not already in the expected dir
test $(realpath "${dir}") != $(realpath .) && cd -- "${dir}"
file=$(basename "${files}")
"${PDF_VIEWER}" -- "${file}"
fi
## }}}
}
# }}}
# pdfe fuzzy open PDF file with evince from current directory {{{
# Search with fd (fdfind is better than find with a pattern)
# Allow to give arguments to prefill fzf request
# Display a preview of selected file with lesspipe
# Move to the directory of the selected file
# Open the selected file with evince (default rollback to "${PDF_VIEWER}")
function pdfe() {
local files
local dir
local file
local evince_bin
## If evince is available {{{
if [ $(command -v evince) ]; then
evince_bin=$(command -v evince)
else
evince_bin="${PDF_VIEWER}"
fi
## }}}
## Manage argument {{{
if [ "${#}" -eq "0" ]; then
## Default command without args
files=$(fd --unrestricted --type file --type symlink --follow "\.pdf$" | fzf --prompt='pdf> ' --preview 'lesspipe {} | less' --no-multi) &&
else
## If at least one argument was given, add it to fzf query
files=$(fd --unrestricted --type file --type symlink --follow "\.pdf$" | fzf --prompt='pdf> ' --preview 'lesspipe {} | less' --no-multi --query "${*} ") &&
fi
## }}}
## Move to the directory and open the file {{{
if [[ -n $files ]]
then
dir=$(dirname "${files}")
cd "${dir}"
file=$(basename "${files}")
"${evince_bin}" -- "${file}"
fi
## }}}
}
# }}}
# pdfz - fuzzy open with zathura from current directory {{{
# Search with fd (fdfind is better than find with a pattern)
# Allow to give arguments to prefill fzf request
# Display a preview of selected file with lesspipe
# Move to the directory of the selected file
# Open the selected file with zathura (default rollback to "${PDF_VIEWER}")
function pdfz() {
local files
local dir
local file
local zathura_bin
## If zathura is available {{{
if [ $(command -v zathura) ]; then
zathura_bin=$(command -v zathura)
else
zathura_bin="${PDF_VIEWER}"
fi
## }}}
## Manage argument {{{
if [ "${#}" -eq "0" ]; then
## Default command without args
files=$(fd --unrestricted --type file --type symlink --follow "\.pdf$" | fzf --prompt='pdf> ' --preview 'lesspipe {} | less' --no-multi) &&
else
## If at least one argument was given, add it to fzf query
files=$(fd --unrestricted --type file --type symlink --follow "\.pdf$" | fzf --prompt='pdf> ' --preview 'lesspipe {} | less' --no-multi --query "${*} ") &&
fi
## }}}
## Move to the directory and open the file {{{
if [[ -n $files ]]
then
dir=$(dirname "${files}")
cd "${dir}"
file=$(basename "${files}")
"${zathura_bin}" -- "${file}"
fi
## }}}
}
# }}}
# odt fuzzy open text document file with LibreOffice from current directory {{{
# Search with fd (fdfind is better than find with a pattern)
# Search for odt|rtf|doc|docx files
# Allow to give arguments to prefill fzf request
# Move to the directory of the selected file
# Open the selected file with libreoffice --writer
function odt() {
local files
## Manage argument {{{
if [ "${#}" -eq "0" ]; then
## Default command without args
files=$(fd --unrestricted --type file --type symlink --follow "\.(odt|rtf|doc|docx)" | fzf --prompt='odt> ' --no-multi) &&
else
## If at least one argument was given, add it to fzf query
files=$(fd --unrestricted --type file --type symlink --follow "\.(odt|rtf|doc|docx)" | fzf --prompt='odt> ' --no-multi --query "${*} ") &&
fi
## }}}
## Move to the directory and open the file {{{
if [[ -n $files ]]
then
dir=$(dirname "${files}")
### Change directory only if not already in the expected dir
test $(realpath "${dir}") != $(realpath .) && cd -- "${dir}"
file=$(basename "${files}")
command libreoffice --writer "${file}" &
fi
## }}}
}
# }}}
# ods fuzzy open calc document file with LibreOffice from current directory {{{
# Search with fd (fdfind is better than find with a pattern)
# Search for ods|xls|xlsx files
# Allow to give arguments to prefill fzf request
# Move to the directory of the selected file
# Open the selected file with libreoffice --calc
function ods() {
local files
## Manage argument {{{
if [ "${#}" -eq "0" ]; then
## Default command without args
files=$(fd --unrestricted --type file --type symlink --follow "\.(ods|xls|xlsx)" | fzf --prompt='ods> ' --no-multi) &&
else
## If at least one argument was given, add it to fzf query
files=$(fd --unrestricted --type file --type symlink --follow "\.(ods|xls|xlsx)" | fzf --prompt='ods> ' --no-multi --query "${*} ") &&
fi
## }}}
## Move to the directory and open the file {{{
if [[ -n $files ]]
then
dir=$(dirname "${files}")
### Change directory only if not already in the expected dir
test $(realpath "${dir}") != $(realpath .) && cd -- "${dir}"
file=$(basename "${files}")
command libreoffice --calc "${file}" &
fi
## }}}
}
# }}}
# odp fuzzy open presentation document file with LibreOffice from current directory {{{
# Search with fd (fdfind is better than find with a pattern)
# Search for odp|ppt|pptx files
# Allow to give arguments to prefill fzf request
# Move to the directory of the selected file
# Open the selected file with libreoffice --impress
function odp() {
local files
## Manage argument {{{
if [ "${#}" -eq "0" ]; then
## Default command without args
files=$(fd --unrestricted --type file --type symlink --follow "\.(odp|ppt|pptx)" | fzf --prompt='odp> ' --no-multi) &&
else
## If at least one argument was given, add it to fzf query
files=$(fd --unrestricted --type file --type symlink --follow "\.(odp|ppt|pptx)" | fzf --prompt='odp> ' --no-multi "${*} ") &&
fi
## }}}
## Move to the directory and open the file {{{
if [[ -n $files ]]
then
dir=$(dirname "${files}")
### Change directory only if not already in the expected dir
test $(realpath "${dir}") != $(realpath .) && cd -- "${dir}"
file=$(basename "${files}")
command libreoffice --impress "${file}" &
fi
## }}}
}
# }}}
# fopen fuzzy open file with xdg-open from current directory {{{
# Search with fd (fdfind is better than find with a pattern)
# Use first argument as fd pattern
# Other arguments will prefill fzf request
# Move to the directory of the selected file
# Open the selected file with xdg-open
function fopen() {
local files
## Manage argument {{{
if [ "${#}" -le "1" ]; then
## Default command with one argument or default value
files=$(fd --unrestricted --type file --type symlink --follow "${1:-.}" | fzf --prompt='open> ' --no-multi) &&
else
## If at least one argument was given, add it to fzf query
files=$(fd --unrestricted --type file --type symlink --follow "${1:-.}" | fzf --prompt='open> ' --no-multi --query "${*} ") &&
fi
## }}}
## Move to the directory and open the file {{{
if [[ -n $files ]]
then
dir=$(dirname "${files}")
### Change directory only if not already in the expected dir
test $(realpath "${dir}") != $(realpath .) && cd -- "${dir}"
file=$(basename "${files}")
command xdg-open "${file}" &
fi
## }}}
}
# }}}
# dexec Docker exec in a running container {{{
# Display Docker running containers
# Allow to specify the shell (default to bash)
function dexec() {
local images_name
local container_name
local container_id
images_name=$(docker container ls --format "table {{.Image}}\t {{.RunningFor}}\t {{.Ports}}\t {{.Names}}" | fzf --prompt='docker> ' --tac )
## Extract container_name from the selected line
container_name=$(printf '%b' "${images_name}" | awk '{ print $NF }')
## Get container_id from the selected container_name
container_id=$(docker container ls --quiet --filter=name="${container_name}")
printf "%b\n" "Try to enter to Docker container (named : ${container_name})"
docker exec --interactive --tty -- "${container_id:-/dev/null}" "${1:-bash}"
}
# }}}
# passf Edit pass's passwords {{{
# Display existing files in ~/.password-store without .gpg extension
# https://www.passwordstore.org/
function passf() {
local pass_files
pass_file=$(find ~/.password-store -type f -iname "*.gpg" -printf "%P\n" | sed 's/\(.*\)\.gpg$/\1/' | fzf --prompt='pass > ' )
pass edit "${pass_file:-/dev/null}"
}
# }}}
fi
## ENDIF fzf is AVAILABLE
# }}}
# zsh-syntax-highlighting {{{
## Activate if plugin is available
[ -f ~/repos/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ] && source ~/repos/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
## Additionnal highlighters
### The order is important. Put **regexp** before **main** to prioritize
### the double quotation marks
ZSH_HIGHLIGHT_HIGHLIGHTERS=(regexp main brackets pattern)
### Dangerous commands
ZSH_HIGHLIGHT_PATTERNS+=('rm -rf ' 'fg=white,bold,bg=black')
ZSH_HIGHLIGHT_PATTERNS+=('sudo ' 'fg=white,bold,bg=red')
### CLI
ZSH_HIGHLIGHT_REGEXP+=('\ \-[^- ]+' 'fg=202') # short args in orange (-l)
ZSH_HIGHLIGHT_REGEXP+=('\ \--[^ ]+' 'fg=214') # long args in light orange (--all)
### Taskwarrior
ZSH_HIGHLIGHT_REGEXP+=('\ \+[^ ]+' 'fg=202') # tags in orange (+txt)
ZSH_HIGHLIGHT_REGEXP+=('[^ ]+\:' 'fg=135') # metadata in purple (project:)
ZSH_HIGHLIGHT_REGEXP+=('\ \_[^ ]+' 'fg=32') # subcommands in blue (_command)
# }}}