commit 3f61fb4240189814a87a9e15d928d56998ac75bc Author: creio Date: Sun Sep 13 15:29:58 2020 +0300 13.09.2020 Update init diff --git a/.Xresources b/.Xresources new file mode 100755 index 0000000..507fb0f --- /dev/null +++ b/.Xresources @@ -0,0 +1,60 @@ +Xft.dpi: 96 +Xft.antialias: true +Xft.hinting: true +Xft.rgba: rgb +Xft.autohint: false +Xft.hintstyle: hintslight +Xft.lcdfilter: lcddefault + +#include ".colors/dui" + +!URxvt.font: xft:CozetteVector:size=9 +!URxvt.font: xft:Hack Nerd Font Mono:size=9 + +!!! xlsfonts | grep ttyp0 +URxvt.font: -uw-ttyp0-medium-r-normal--13-120-75-75-c-70-iso10646-1,xft:Hack Nerd Font Mono:size=9 +URxvt.boldFont: -uw-ttyp0-medium-r-normal--13-120-75-75-c-70-iso10646-1,xft:Hack Nerd Font Mono:size=9 + +!URxvt.termname: xterm-256color +URxvt.iconFile: /usr/share/icons/Papirus/48x48/apps/urxvt.svg +URxvt.geometry: 84x22 +URxvt.internalBorder: 15 +URxvt.letterSpace: 0 +URxvt.antialias: true +URxvt.pointerBlank: true +URxvt.saveLines: 7000 +URxvt.scrollBar: false +URxvt.cursorBlink: true +URxvt.urgentOnBell: true +URxvt.scrollTtyOutput: true +URxvt.scrollWithBuffer: true +URxvt.scrollTtyKeypress: true +URxvt.transparent:false +URxvt.depth: 32 +URxvt.iso14755: false +URxvt.iso14755_52: false + +URxvt.perl-ext-common: default,matcher,clipboard,keyboard-select,resize-font,url-select +URxvt.url-launcher: /usr/bin/xdg-open +URxvt.url-select.underline: true +URxvt.matcher.button: 1 +URxvt.keysym.C-u: perl:url-select:select_next + +URxvt.keysym.C-Escape: perl:keyboard-select:activate +URxvt.keysym.C-/: perl:keyboard-select:search + +URxvt.clipboard.autocopy: true +URxvt.keysym.Shift-Control-V: eval:paste_clipboard +URxvt.keysym.Shift-Control-C: eval:selection_to_clipboard + +! ctrl + arrows +URxvt.keysym.Control-Up: \033[1;5A +URxvt.keysym.Control-Down: \033[1;5B +URxvt.keysym.Control-Left: \033[1;5D +URxvt.keysym.Control-Right: \033[1;5C + +! urxvt-resize-font-git +URxvt.keysym.C-minus: resize-font:smaller +URxvt.keysym.C-plus: resize-font:bigger +URxvt.keysym.C-equal: resize-font:reset +URxvt.keysym.C-question: resize-font:show diff --git a/.alias_zsh b/.alias_zsh new file mode 100755 index 0000000..c26af36 --- /dev/null +++ b/.alias_zsh @@ -0,0 +1,371 @@ +#!/usr/bin/bash + +# Стеганография +# cat molot-tora.mp4 eraz.zip > data.mp4 +# unzip date.mp4 + +# git.io custom url +# curl -i https://git.io -F "url=https://github.com/creio" -F "code=YOUR_CUSTOM_NAME" + +alias sz="source $HOME/.zshrc" +alias ez="$EDITOR $HOME/.zshrc" +alias ea="$EDITOR $HOME/.alias_zsh" +alias merge="xrdb -merge $HOME/.Xresources" +alias xcolor="xrdb -query | grep" +alias vga="lspci -k | grep -A 2 -E '(VGA|3D)'" +alias upgrub="sudo grub-mkconfig -o /boot/grub/grub.cfg" +alias iip="curl --max-time 10 -w '\n' http://ident.me" +alias tb="nc termbin.com 9999 | xsel -b -i" +alias speed="curl -s https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py | python -" +alias updir="LC_ALL=C xdg-user-dirs-update --force" + +alias dmrun="dmenu_run -l 10 -p 'app>' -fn 'ClearSansMedium 9' -nb '#282c37' -nf '#93a1a1' -sb '#5a74ca' -sf '#fff'" + +doiso() { + rsync -auvCL ~/ctlosiso/out/ cretm@${dev_ctlos_ru}:~/app/dev.ctlos.ru/iso/$1 +} + +# blur img: blur 4 .wall/wl3.jpg blur.jpg +blur() { + convert -filter Gaussian -blur 0x$1 $2 $3 +} + +tbg() { + urxvt -bg '[0]red' -b 0 -depth 32 +sb -name urxvt_bg & +} + +# fzf +zzh() { + du -a ~/ | awk '{print $2}' | fzf | xargs -r $EDITOR +} +zz() { + du -a . | awk '{print $2}' | fzf | xargs -r $EDITOR +} +zzd() { + du -a $1 | awk '{print $2}' | fzf | xargs -r $EDITOR +} +zzb() { + find -H "/usr/bin" "$HOME/.bin" -executable -print | sed -e 's=.*/==g' | fzf | sh +} + +# зависимость source-highlight +hcat () { + /usr/bin/src-hilite-lesspipe.sh "$1" | less -m -N +} + +# share vbox В локальной машине mkdir vboxshare +# в виртуалке uid={имя пользователя} git={группа} +vboxshare () { + mkdir vboxshare + sudo mount -t vboxsf -o rw,uid=1000,gid=1000 vboxshare vboxshare + # sudo mount -t vboxsf -o rw,uid=st,gid=users vboxshare vboxshare +} +# shre qemu +vmshare () { + mkdir vmshare + sudo mount -t 9p -o trans=virtio,version=9p2000.L /vmshare vmshare +} + +# aur pkg +amake () { + git clone https://aur.archlinux.org/"$1".git + # curl -fO https://aur.archlinux.org/cgit/aur.git/snapshot/"$1".tar.gz + cd $1 + makepkg -s + # makepkg -s --sign + cd .. +} + +# aur clean chroot manager +accm () { + git clone https://aur.archlinux.org/"$2".git + # curl -fO https://aur.archlinux.org/cgit/aur.git/snapshot/"$1".tar.gz + # tar -xvf $1.tar.gz + cd $2 + sudo ccm "$1" && + gpg --detach-sign "$2"-*.pkg* + cd .. +} + +# pkg clean chroot manager +lccm () { + sudo ccm "$1" && + gpg --detach-sign *.pkg* +} + +aget () { + git clone https://aur.archlinux.org/"$1".git + # curl -fO https://aur.archlinux.org/cgit/aur.git/snapshot/"$1".tar.gz + # tar -xvf $1.tar.gz + cd $1 +} + +# build and install pkg from aur +abuild () { + cd ~/.build + git clone https://aur.archlinux.org/"$1".git + # curl -fO https://aur.archlinux.org/cgit/aur.git/snapshot/"$1".tar.gz + # tar -xvf $1.tar.gz + cd $1 + makepkg -si --skipinteg + cd ~ + # rm -rf ~/.build/$1 ~/.build/$1.tar.gz + rm -rf ~/.build/$1 +} + + +alias neofetch="neofetch --ascii ~/.config/neofetch/ctlos" +alias neoa="neofetch --ascii ~/.config/neofetch/mario" +alias neo="neofetch --w3m ~/.config/neofetch/cn.jpg" +# alias neo="neofetch --kitty ~/.config/neofetch/cn.jpg" +# alias neo="neofetch --w3m" + +# Погода, не только по городу, но и по месту. Нет привязки к регистру и языку. +# alias wtr="curl 'wttr.in/Москва?M&lang=ru'" +# alias wtr="curl 'wttr.in/Москва?M&lang=ru' | sed -n '1,17p'" +# alias wtr="curl 'wttr.in/?M1npQ&lang=ru'" +wtr () { + # curl "wttr.in/?M$1npQ&lang=ru" + curl "wttr.in/Gomel?M$1npQ&lang=ru" +} +wts () { + curl "wttr.in/$1?M&lang=ru" +} +alias moon="curl 'wttr.in/Moon'" + +alias srm="sudo rm -rf" +alias rm="rm -rf" + +alias dir="dir --color=auto" +alias vdir="vdir --color=auto" +alias grep="grep --color=always" +#alias grep="grep --color=auto" +alias fgrep="fgrep --color=auto" +alias egrep="egrep --color=auto" + +alias ls="ls --color=auto" +alias la="ls -alFh --color=auto" +alias llp="stat -c '%A %a %n' {*,.*}" +alias ll="ls -a --color=auto" +alias l="ls -CF --color=auto" +alias .l="dirs -v" +alias lss="ls -sh | sort -h" +alias duh="du -d 1 -h | sort -h" + +alias mk="mkdir" +mkj () { + mkdir -p "$1" + cd "$1" +} + +alias /="cd /" +alias ~="cd ~" +alias ..="cd .." +alias ...="cd ../.." +# alias ....="cd ../../.." +# alias .....="cd ../../../.." +alias q="exit" +alias gh="cd /media/files/github" +alias ctliso="cd /media/files/github/ctlosiso" +alias wiki="cd /media/files/github/wiki" +alias ghc="cd /media/files/github/creio" +alias dot="cd /media/files/github/creio/dots" + +gc () { + git clone "$1" +} +function gcj () { + git clone "$1" + cd "$2" + # $EDITOR . +} +alias gi="git init" +alias gs="git status" +alias gl="git log --stat --pretty=oneline --graph --date=short" +alias gg="gitg &" +alias ga="git add --all" +gac () { + git add --all + git commit -am "$1" +} +alias gr="git remote" +alias gf="git fetch" +alias gpl="git pull" +alias gp="git push" +alias gpm="git push origin master" +alias ghab="$BROWSER http://github.com/ctlos &" +# yarn global add github-search-repos-cli +alias gsc="github-search-repos -i" + +# tor chromium +alias torc="$BROWSER --proxy-server='socks://127.0.0.1:9050' &" +alias psi="$BROWSER --proxy-server='socks://127.0.0.1:1081' &" + +# full screen flags -fs +alias yt="straw-viewer" +ytv () { + straw-viewer "$1" +} + +# youtube-dl --ignore-errors -o '~/Видео/youtube/%(playlist)s/%(title)s.%(ext)s' https://www.youtube.com/playlist?list=PL-UzghgfytJQV-JCEtyuttutudMk7 +# Загрузка Видео ~/Videos или ~/Видео +# Пример: dlv https://www.youtube.com/watch?v=gBAfejjUQoA +dlv () { + youtube-dl --ignore-errors -o '~/Videos/youtube/%(title)s.%(ext)s' "$1" +} +# dlp https://www.youtube.com/playlist?list=PL-UzghgfytJQV-JCEtyuttutudMk7 +dlp () { + youtube-dl --ignore-errors -o '~/Videos/youtube/%(playlist)s/%(title)s.%(ext)s' "$1" +} + +# Загрузка аудио ~/Music или ~/Музыка +# Пример: mp3 https://www.youtube.com/watch?v=gBAfejjUQoA +mp3 () { + youtube-dl --ignore-errors -f bestaudio --extract-audio --audio-format mp3 --audio-quality 0 -o '~/Music/youtube/%(title)s.%(ext)s' "$1" +} +# mp3p https://www.youtube.com/watch?v=-F7A24f6gNc&list=RD-F7A24f6gNc +mp3p () { + youtube-dl --ignore-errors -f bestaudio --extract-audio --audio-format mp3 --audio-quality 0 -o '~/Music/youtube/%(playlist)s/%(title)s.%(ext)s' "$1" +} + +alias porn="mpv 'http://www.pornhub.com/random'" + +alias mvis="ncmpcpp -S visualizer" +alias m="ncmpcpp" + +pf () { + peerflix "$1" --mpv +} +alias rss="newsboat" +# download web site +wgetw () { + wget -rkx "$1" +} +iso () { + sudo dd bs=4M if="$1" of=/dev/"$2" status=progress && sync +} + +alias -s {mp3,m4a,flac}="mpv" +alias -s {png,jpg,tiff,bmp}="viewnior" +# alias -s {conf,txt}="nvim" +# alias {aurman,pikaur,trizen,yaourt}="yay" + +alias mi="micro" +alias smi="sudo micro" +alias st="subl3" +alias sst="sudo subl3" +alias tm="tmux attach || tmux new -s work" +alias tmd="tmux detach" +alias tmk="tmux kill-server" +alias fm="ranger" +alias sfm="sudo ranger" +alias th="thunar . &" +alias sth="sudo thunar &" +alias na="nautilus . &" +alias sna="sudo nautilus &" +alias h="htop" +# alias {v,vi,vim}="nvim" + +# LANG=C pacman -Sl | awk '/\[installed\]$/ {print $2}' > ~/.pkglist.txt +# LANG=C pacman -Sl | awk '/\[installed\]$/ {print $1 "/" $2 "-" $3}' > ~/.pkglist.txt +alias pkglist="pacman -Qneq > ~/.pkglist.txt" +alias aurlist="pacman -Qmeq > ~/.aurlist.txt" + +alias packey="sudo pacman-key --init && sudo pacman-key --populate && sudo pacman-key --refresh-keys && sudo pacman -Syy" +alias sp="sudo pacman -S" +alias spo="sudo pacman -S --overwrite='*'" +alias spl="sudo pacman -S --noconfirm --needed - < ~/.pkglist.txt" +alias spU="sudo pacman -U" +alias spoU="sudo pacman -U --overwrite='*'" +alias sps="sudo pacman -Ss" +alias spc="sudo pacman -Sc" +alias spcc="sudo pacman -Scc" +alias spy="sudo pacman -Syy" +alias spu="sudo pacman -Syu" +alias spr="sudo pacman -R" +alias pres="pacman -Qqn | sudo pacman -S -" + +alias y="yay -S" +alias yn="yay -S --noconfirm" +alias yl="yay -S --noconfirm --needed - < ~/.aurlist.txt" +alias ys="yay" +alias ysn="yay --noconfirm" +alias yc="yay -Sc" +alias ycc="yay -Scc" +alias yy="yay -Syy" +alias yu="yay -Syu" +alias yun="yay -Syu --noconfirm" +alias yr="yay -R" +alias yrs="yay -Rs" +alias yrsn="yay -Rsn" +alias yrsnp="yay -Rsn $(pacman -Qdtq)" +alias yrn="yay -R --noconfirm" +alias yskip="yay --mflags '--nocheck --skippgpcheck --noconfirm'" +alias ynskip="yay --mflags --skipinteg --noconfirm" + +# systemd +alias sse="sudo systemctl enable" +alias ssd="sudo systemctl disable" +alias ssen="sudo systemctl enable --now" +alias ssdn="sudo systemctl disable --now" +alias ssr="sudo systemctl restart" +alias ssk="sudo systemctl stop" +alias sss="sudo systemctl status" + +# Python +alias ve="virtualenv ve" +alias vea="source ve/bin/activate" +alias ved="deactivate" +alias pipr="pip install -r requirements.txt" + +# распаковать архив не указывая тип распаковщика +function ex { + if [ -z "$1" ]; then + # display usage if no parameters given + echo "Использование: ex ." + else + if [ -f "$1" ] ; then + NAME=${1%.*} + #mkdir $NAME && cd $NAME + case "$1" in + *.tar.bz2) tar xvjf ./"$1" ;; + *.tar.gz) tar xvzf ./"$1" ;; + *.tar.xz) tar xvJf ./"$1" ;; + *.lzma) unlzma ./"$1" ;; + *.bz2) bunzip2 ./"$1" ;; + *.rar) unrar x -ad ./"$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" ;; + *.xz) unxz ./"$1" ;; + *.exe) cabextract ./"$1" ;; + *) echo "ex: '$1' - Не может быть распакован" ;; + esac + else + echo "'$1' - не является допустимым файлом" + fi +fi +} + +# Упаковка в архив командой pk 7z /что/мы/пакуем имя_файла.7z +function pk () { + if [ $1 ] ; then + case $1 in + tbz) tar cjvf $2.tar.bz2 $2 ;; + tgz) tar czvf $2.tar.gz $2 ;; + txz) tar -caf $2.tar.xz $2 ;; + tar) tar cpvf $2.tar $2 ;; + bz2) bzip $2 ;; + gz) gzip -c -9 -n $2 > $2.gz ;; + zip) zip -r $2.zip $2 ;; + 7z) 7z a $2.7z $2 ;; + *) echo "'$1' не может быть упакован с помощью pk()" ;; + esac + else + echo "'$1' не является допустимым файлом" + fi +} diff --git a/.aurlist.txt b/.aurlist.txt new file mode 100644 index 0000000..acf5c63 --- /dev/null +++ b/.aurlist.txt @@ -0,0 +1,37 @@ +blackarch-keyring +caffeine-ng +clean-chroot-manager +colorpicker +cornora-git +downgrade +grub2-theme-preview +hardcode-tray-git +ifuse +imgur.sh +jdk +lib32-opencl-nvidia-390xx +libxnvctrl-390xx +megasync +modprobed-db +n30f-git +netwmpager +ngrok +noip +nvidia-390xx +nvidia-390xx-settings +nvidia-390xx-utils +ob-yml-menu +opencl-nvidia-390xx +picom-tryone-git +pscircle-git +rxvt-unicode-pixbuf +shantz-xwinwrap-bzr +sia-ui +skypeforlinux-preview-bin +sublime-text-dev +toilet +torrserver-bin +ttf-symbola +ttf-weather-icons +urxvt-resize-font-git +ventoy-bin diff --git a/.bin/aliases b/.bin/aliases new file mode 100755 index 0000000..21d2c14 --- /dev/null +++ b/.bin/aliases @@ -0,0 +1 @@ +alias | awk -F'[ =]' '{print $1}' \ No newline at end of file diff --git a/.bin/animatebg b/.bin/animatebg new file mode 100755 index 0000000..98c6dad --- /dev/null +++ b/.bin/animatebg @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +looping=$1 + +if [ -z $looping ] +then + looping=~/.wall/hhh.gif +fi + +#### 20% cpu gif, best result, convert mp4 -> gif: +## ffmpeg -i input.webm -pix_fmt rgb24 output.gif +## ffmpeg -i .wall/heart.mp4 .wall/heart.gif +xwinwrap -b -sp -fs -ov -ni -nf -- mpv -wid WID --no-config --keepaspect=no --loop --no-border --x11-bypass-compositor=no --aid=no --hwdec=auto --really-quiet $looping + +#### 40% cpu mp4 +# xwinwrap -b -sp -fs -ov -ni -nf -- mpv -wid WID --no-config --keepaspect=no --loop --no-border --vd-lavc-fast --x11-bypass-compositor=no --aid=no --vo=xv --hwdec=auto --really-quiet $looping + +#### 60% cpu gif +## gifsicle --resize 1366x768 wl7.gif -o bg.gif +## gifsicle -i .wall/gg.gif --optimize=3 -o ~/.wall/ggo.gif +# xwinwrap -b -sp -fs -ov -ni -nf -- gifview -w WID $looping -a diff --git a/.bin/aur.sh b/.bin/aur.sh new file mode 100755 index 0000000..21fc364 --- /dev/null +++ b/.bin/aur.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# Install script aur pkg +# autor: Alex Creio https://cvc.hashbase.io/ + +pack="oh-my-zsh-git zsh-autosuggestions \ +ttf-clear-sans ttf-roboto-mono capitaine-cursors clipit-gtk3 \ +caffeine-ng python-ewmh \ +sublime-text-dev timeshift engrampa-thunar-gtk2 fsearch-git \ +obmenu-generator perl-linux-desktopfiles \ +xsettingsd qgnomeplatform-git skippy-xd-git betterlockscreen xfce-polkit-git \ +obkey-git tint2-git" + +yay -Sy --noconfirm --needed $pack + +echo "Aur pkg install Complete" \ No newline at end of file diff --git a/.bin/back4.sh b/.bin/back4.sh new file mode 100755 index 0000000..0db1286 --- /dev/null +++ b/.bin/back4.sh @@ -0,0 +1,17 @@ +#!/bin/bash +[ "$#" -lt "1" ] || [ "$#" -gt "2" ] && { echo -e "ERROR : args number invalid \n $0 speed /path/name.gif" ; echo "try 0.010 as speed" ; exit 1 ; } +dir=/tmp/back4 +#example of speed : 0.010 +speed=$1 +name=$2 + + +[[ "$name" == "" ]] && { name=$speed ; speed=${name##*-} ; } + +hash=`md5sum $name | cut -f1 -d" "` + +[[ ! -d $dir ]] && mkdir $dir + +[[ ! -d $dir/$hash ]] && { mkdir $dir/$hash ; echo "spliting .." ; convert -coalesce $name $dir/$hash/$hash.png ; echo ok ; } + +while : ; do for i in ` ls $dir/$hash -v ` ; do xfconf-query -c xfce4-desktop -p /backdrop/screen0/monitorVGA-0/workspace0/last-image -s $dir/$hash/$i ; sleep $speed ; done ; done diff --git a/.bin/bri.sh b/.bin/bri.sh new file mode 100755 index 0000000..ef8e321 --- /dev/null +++ b/.bin/bri.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +if [ -z $1 ]; then + echo "Usage: brighntess BRIGHTNESS" + echo "BRIGHTNESS is a float (0.0-1.0)" +else + xrandr --listmonitors | grep "^ " | cut -f 6 -d' ' | \ + xargs --replace=MONITOR xrandr --output MONITOR --brightness $1 --gamma $2 +fi diff --git a/.bin/btc b/.bin/btc new file mode 100755 index 0000000..0ef8a4b --- /dev/null +++ b/.bin/btc @@ -0,0 +1,25 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import json,sys,urllib.request,time + +if len(sys.argv) != 3: + print("Usage: btc usd,eur,btc nok") + sys.exit() + +currencies = sys.argv[1] +basecurrency = sys.argv[2] + +currencyurl = "http://freecurrencyrates.com/api/action.php?do=cvals&iso=" + currencies.replace(',','') + "&f=" + basecurrency + "&v=1&s=cbr" +f = urllib.request.urlopen(currencyurl) +obj = json.loads(f.read()) +res=""; +for c in currencies.split(','): + res += c.upper() + ":{:,.2f}".format(1/obj[c.upper()]).replace(',',' ') + +# some unicode currency code replacement (optional) +res = res.replace("USD", "$") +res = res.replace("EUR", "€") +res = res.replace("BTC", "") + +print(res); diff --git a/.bin/bud b/.bin/bud new file mode 100755 index 0000000..a5ba217 --- /dev/null +++ b/.bin/bud @@ -0,0 +1,112 @@ +#!/bin/sh -f +# +# pywalesque posix sh alternative. + +img() { + [ -d "$1" ] && { + set +f + set -f -- "$1/"* + shift "$(shuf -i "1-$#" -n 1)" + } + + [ -f "${img:=$1}" ] || exit 1 + + printf '%s\n' "$img" +} + +hex2rgb() { + set -- "${1##\#}" + + r=${1%%????} + g=${1##??} + g=${g%%??} + b=${1##????} + + r=$((0x$r)) + g=$((0x$g)) + b=$((0x$b)) +} + +mod() { + hex2rgb "$2" + + # The operator is stored in a variable + # which makes shellcheck freak out. + # shellcheck disable=1102,2086 + { + r=$((r $3 $4)) + g=$((g $3 $4)) + b=$((b $3 $4)) + } + + r=$((r > 255 ? 255 : r < 0 ? 0 : r)) + g=$((g > 255 ? 255 : g < 0 ? 0 : g)) + b=$((b > 255 ? 255 : b < 0 ? 0 : b)) + + export "$1=$(printf '%02x%02x%02x' "$r" "$g" "$b")" +} + +col() { + cache_file=$(printf %s "$img" | base64) + + # Backticks need to be used here to fix bugs in + # some specific POSIX shells. + # + # Word splitting is also intentional and safe here. + # shellcheck disable=2046,2006 + if [ -f "$cache_dir/$cache_file" ]; then + paleta < "$cache_dir/$cache_file" & + + else + set -- `\ + convert "$img" \ + -alpha off \ + -resize 64x64 \ + -posterize 16 \ + -fill white \ + -colorize 30% \ + -modulate 125,175,100 \ + -unique-colors \ + txt:- | + + while IFS='# ' read -r _ _ col _; do + i=$((i+1)) + + [ "$i" -lt 11 ] && continue + [ "$i" -gt 16 ] && continue + + printf '%s\n' "$col" + done + ` + + # These variables are dynamically defined, + # ignore undeclared variable warnings. + # shellcheck disable=2154 + { + mod bg "$2" / 4 + mod fg "$2" + 150 + mod co "$bg" + 125 + + set -- "$bg" "$@" "$fg" "$co" "$@" "$fg" + } + + printf '%s\n' "$@" | paleta & + printf '%s\n' "$@" > "$cache_dir/$cache_file" + fi +} + +main() { + mkdir -p "${cache_dir:=${XDG_CACHE_HOME:=${HOME}/.cache}/bud}" + + img "$1" + + display \ + -page 3200x \ + -sample 3200x \ + -window root \ + "$img" & + + col & +} + +main "$1" diff --git a/.bin/cache b/.bin/cache new file mode 100755 index 0000000..d8fe90d --- /dev/null +++ b/.bin/cache @@ -0,0 +1,7 @@ +#!/bin/bash + +# fc-cache -vf +sudo pacman -Scc --noconfirm && sudo pacman -Rsn $(pacman -Qdtq) --noconfirm +rm -rf ~/.cache/thumbnails/* +rm -rf ~/.build/* +rm -rf ~/.cache/telegram/* diff --git a/.bin/cast b/.bin/cast new file mode 100755 index 0000000..1f20705 --- /dev/null +++ b/.bin/cast @@ -0,0 +1,42 @@ +#! /bin/bash + +sudo nvidia-settings --assign="0/AllowFlipping=0" &>/dev/null + +RES=$(xdpyinfo | grep dimensions | awk '{print $2;}') +ALSA_OUT="alsa_output.pci-0000_00_14.2.analog-stereo.monitor" + +if [ "$1" = "-m" ]; then + ffmpeg \ + -f x11grab -s $RES -i :0.0 \ + -f alsa -i default \ + -c:v libx264 -pix_fmt yuv420p -r 30 -crf 23 -preset superfast -threads 0 \ + -c:a aac \ + -y ~/Videos/output.mkv +elif [ "$1" = "-n" ]; then + ffmpeg \ + -f x11grab -s $RES -i :0.0 \ + -c:v libx264 -pix_fmt yuv420p -r 30 -preset superfast -qp 0 \ + -y ~/Videos/output.mp4 +elif [ "$1" = "-s" ]; then + slop=$(slop -f "%x %y %w %h %g %i") || exit 1 + read -r X Y W H G ID < <(echo $slop) + ffmpeg \ + -f x11grab -s "$W"x"$H" -i :0.0+$X,$Y \ + -f pulse -i $ALSA_OUT \ + -c:v libx264 -pix_fmt yuv420p -r 30 -crf 23 -preset superfast -qp 0 \ + -y ~/Videos/output.mp4 +# elif [ "$1" = "-g" ]; then +# slop=$(slop -f "%x %y %w %h %g %i") || exit 1 +# read -r X Y W H G ID < <(echo $slop) +# ffmpeg \ +# -f x11grab -s "$W"x"$H" -i :0.0+$X,$Y \ +# -c:v gif \ +# -y ~/Videos/output.gif +else + ffmpeg \ + -f x11grab -video_size $RES -i :0.0 \ + -f pulse -i $ALSA_OUT \ + -c:a libvorbis -b:a 128k \ + -c:v libx264 -pix_fmt yuv420p -crf 23 -preset superfast -s 1920x1080 -r 30 \ + -y ~/Videos/output.mp4 +fi diff --git a/.bin/castm b/.bin/castm new file mode 100755 index 0000000..6ec9562 --- /dev/null +++ b/.bin/castm @@ -0,0 +1,15 @@ +#! /bin/bash +# + +nvidia-settings --assign="0/AllowFlipping=0" &>/dev/null + +# For Pulseaudio with ALSA: +ffmpeg -y \ +-f x11grab \ +-framerate 30 \ +-s $(xdpyinfo | grep dimensions | awk '{print $2;}') \ +-i :0.0 \ +-f alsa -ar 44100 -i default \ +-r 30 \ +-c:v libx264rgb -crf 23 -preset ultrafast -c:a aac \ +-y ~/Videos/output.mkv diff --git a/.bin/cht.sh b/.bin/cht.sh new file mode 100755 index 0000000..26a2e8d --- /dev/null +++ b/.bin/cht.sh @@ -0,0 +1,771 @@ +#!/bin/bash +# shellcheck disable=SC1117,SC2001 +# +# [X] open section +# [X] one shot mode +# [X] usage info +# [X] dependencies check +# [X] help +# [X] yank/y/copy/c +# [X] Y/C +# [X] eof problem +# [X] more +# [X] stealth mode +# +# here are several examples for the stealth mode: +# +# zip lists +# list permutation +# random list element +# reverse a list +# read json from file +# append string to a file +# run process in background +# count words in text counter +# group elements list + +__CHTSH_VERSION=6 +__CHTSH_DATETIME="2019-06-05 18:00:46 +0200" + +# cht.sh configuration loading +# +# configuration is stored in ~/.cht.sh/ (can be overridden by CHTSH_HOME) +# +CHTSH_HOME=${CHTSH:-"$HOME"/.cht.sh} +[ -z "$CHTSH_CONF" ] && CHTSH_CONF=$CHTSH_HOME/cht.sh.conf +# shellcheck disable=SC1090,SC2002 +[ -e "$CHTSH_CONF" ] && source "$CHTSH_CONF" +[ -z "$CHTSH_URL" ] && CHTSH_URL=https://cht.sh + +# currently we support only two modes: +# * lite = access the server using curl +# * auto = try standalone usage first +CHTSH_MODE="$(cat "$CHTSH_HOME"/mode 2> /dev/null)" +[ "$CHTSH_MODE" != lite ] && CHTSH_MODE=auto +CHEATSH_INSTALLATION="$(cat "$CHTSH_HOME/standalone" 2> /dev/null)" + + +export LESSSECURE=1 +STEALTH_MAX_SELECTION_LENGTH=5 + +case "$(uname -s)" in + Darwin) is_macos=yes ;; + *) is_macos=no ;; +esac + +# for KSH93 +# shellcheck disable=SC2034,SC2039,SC2168 +if echo "$KSH_VERSION" | grep -q ' 93' && ! local foo 2>/dev/null; then + alias local=typeset +fi + +fatal() +{ + echo "ERROR: $*" >&2 + exit 1 +} + +_say_what_i_do() +{ + [ -n "$LOG" ] && echo "$(date '+[%Y-%m-%d %H:%M%S]') $*" >> "$LOG" + + local this_prompt="\033[0;1;4;32m>>\033[0m" + printf "\n${this_prompt}%s\033[0m\n" " $* " +} + +cheatsh_standalone_install() +{ + # the function installs cheat.sh with the upstream repositories + # in the standalone mode + local installdir; installdir="$1" + local default_installdir="$HOME/.cheat.sh" + + if [ "$installdir" = help ]; then + cat </dev/null || \ + { echo "DEPENDENCY: \"$dep\" is needed to install cheat.sh in the standalone mode" >&2; _exit_code=1; } + done + [ "$_exit_code" -ne 0 ] && return "$_exit_code" + + while true; do + echo -n "Where should cheat.sh be installed [$default_installdir]? "; read -r installdir + [ -n "$installdir" ] || installdir="$default_installdir" + + if [ "$installdir" = y ] \ + || [ "$installdir" = Y ] \ + || [ "$(echo "$installdir" | tr "[:upper:]" "[:lower:]")" = yes ] + then + echo Please enter the directory name + echo If it was the directory name already, please prepend it with \"./\": "./$installdir" + else + break + fi + done + + if [ -e "$installdir" ]; then + echo "ERROR: Installation directory [$installdir] exists already" + echo "Please remove it first before continuing" + return 1 + fi + + if ! mkdir -p "$installdir"; then + echo "ERROR: Could not create the installation directory \"$installdir\"" + echo "ERROR: Please check the permissions and start the script again" + return 1 + fi + + local space_needed=700 + local space_available; space_available=$(($(df -k "$installdir" | awk '{print $4}' | tail -1)/1024)) + + if [ "$space_available" -lt "$space_needed" ]; then + echo "ERROR: Installation directory has no enough space (needed: ${space_needed}M, available: ${space_available}M" + echo "ERROR: Please clean up and start the script again" + rmdir "$installdir" + return 1 + fi + + _say_what_i_do Cloning cheat.sh locally + local url=https://github.com/chubin/cheat.sh + rmdir "$installdir" + git clone "$url" "$installdir" || fatal Could not clone "$url" with git into "$installdir" + cd "$installdir" || fatal "Cannot cd into $installdir" + + # after the repository cloned, we may have the log directory + # and we can write our installation log into it + mkdir -p "$installdir/log/" + LOG="$installdir/log/install.log" + + # we use tee everywhere so we should set -o pipefail + set -o pipefail + + # currently the script uses python 2, + # but cheat.sh supports python 3 too + # if you want to switch it to python 3 + # set PYTHON2 to NO: + # PYTHON2=NO + # + PYTHON2=YES + if [[ $PYTHON2 = YES ]]; then + python="python2" + pip="pip" + virtualenv_python3_option=() + else + python="python3" + pip="pip3" + virtualenv_python3_option=(-p python3) + fi + + _say_what_i_do Creating virtual environment + "$python" "$(command -v virtualenv)" "${virtualenv_python3_option[@]}" ve \ + || fatal Could not create virtual environment with "python2 $(command -v virtualenv) ve" + + # rapidfuzz does not support Python 2, + # so if we are using Python 2, install fuzzywuzzy instead + if [[ $PYTHON2 = YES ]]; then + sed -i s/rapidfuzz/fuzzywuzzy/ requirements.txt + echo "python-Levenshtein" >> requirements.txt + fi + + _say_what_i_do Installing python requirements into the virtual environment + ve/bin/"$pip" install -r requirements.txt > "$LOG" \ + || { + + echo "ERROR:" + echo "---" + tail -n 10 "$LOG" + echo "---" + echo "See $LOG for more" + fatal Could not install python dependencies into the virtual environment + } + echo "$(ve/bin/"$pip" freeze | wc -l) dependencies were successfully installed" + + _say_what_i_do Fetching the upstream cheat sheets repositories + ve/bin/python lib/fetch.py fetch-all | tee -a "$LOG" + + _say_what_i_do Running self-tests + ( + cd tests || exit + + if CHEATSH_TEST_STANDALONE=YES \ + CHEATSH_TEST_SKIP_ONLINE=NO \ + CHEATSH_TEST_SHOW_DETAILS=NO \ + PYTHON=../ve/bin/python bash run-tests.sh | tee -a "$LOG" + then + printf "\033[0;32m%s\033[0m\n" "SUCCESS" + else + printf "\033[0;31m%s\033[0m\n" "FAILED" + echo "Some tests were failed. Run the tests manually for further investigation:" + echo " cd $PWD; bash run-tests.sh)" + fi + ) + + mkdir -p "$CHTSH_HOME" + echo "$installdir" > "$CHTSH_HOME/standalone" + echo auto > "$CHTSH_HOME/mode" + + _say_what_i_do Done + + local v1; v1=$(printf "\033[0;1;32m") + local v2; v2=$(printf "\033[0m") + + cat < "$CHTSH_HOME/mode" + echo "Configured mode: $mode" + fi + else + echo "Unknown mode: $mode" + echo Supported modes: + echo " auto use the standalone installation first" + echo " lite use the cheat sheets server directly" + fi +} + +get_query_options() +{ + local query="$*" + if [ -n "$CHTSH_QUERY_OPTIONS" ]; then + case $query in + *\?*) query="$query&${CHTSH_QUERY_OPTIONS}";; + *) query="$query?${CHTSH_QUERY_OPTIONS}";; + esac + fi + printf "%s" "$query" +} + +do_query() +{ + local query="$*" + local b_opts= + local uri="${CHTSH_URL}/\"\$(get_query_options $query)\"" + + if [ -e "$HOME/.cht.sh/id" ]; then + b_opts="-b \"\$HOME/.cht.sh/id\"" + fi + + eval curl "$b_opts" -s "$uri" > "$TMP1" + + if [ -z "$lines" ] || [ "$(wc -l "$TMP1" | awk '{print $1}')" -lt "$lines" ]; then + cat "$TMP1" + else + ${PAGER:-$defpager} "$TMP1" + fi +} + +prepare_query() +{ + local section="$1"; shift + local input="$1"; shift + local arguments="$1" + + local query + if [ -z "$section" ] || [ x"${input}" != x"${input#/}" ]; then + query=$(printf %s "$input" | sed 's@ @/@; s@ @+@g') + else + query=$(printf %s "$section/$input" | sed 's@ @+@g') + fi + + [ -n "$arguments" ] && arguments="?$arguments" + printf %s "$query$arguments" +} + +get_list_of_sections() +{ + curl -s "${CHTSH_URL}"/:list | grep -v '/.*/' | grep '/$' | xargs +} + +gen_random_str() +( + len=$1 + if command -v openssl >/dev/null; then + openssl rand -base64 $((len*3/4)) | awk -v ORS='' // + else + rdev=/dev/urandom + for d in /dev/{srandom,random,arandom}; do + test -r "$d" && rdev=$d + done + if command -v hexdump >/dev/null; then + hexdump -vn $((len/2)) -e '1/1 "%02X" 1 ""' "$rdev" + elif command -v xxd >/dev/null; then + xxd -l $((len/2)) -ps "$rdev" | awk -v ORS='' // + else + cd /tmp || { echo Cannot cd into /tmp >&2; exit 1; } + s= + # shellcheck disable=SC2000 + while [ "$(echo "$s" | wc -c)" -lt "$len" ]; do + s="$s$(mktemp -u XXXXXXXXXX)" + done + printf "%.${len}s" "$s" + fi + fi +) + +if [ "$CHTSH_MODE" = auto ] && [ -d "$CHEATSH_INSTALLATION" ]; then + curl() { + # ignoring all options + # currently the standalone.py does not support them anyway + local opt + while getopts "b:s" opt; do + : + done + shift $((OPTIND - 1)) + + local url; url="$1"; shift + PYTHONIOENCODING=UTF-8 "$CHEATSH_INSTALLATION/ve/bin/python" "$CHEATSH_INSTALLATION/lib/standalone.py" "${url#"$CHTSH_URL"}" "$@" + } +elif [ "$(uname -s)" = OpenBSD ] && [ -x /usr/bin/ftp ]; then + # any better test not involving either OS matching or actual query? + curl() { + local opt args="-o -" + while getopts "b:s" opt; do + case $opt in + b) args="$args -c $OPTARG";; + s) args="$args -M -V";; + *) echo "internal error: unsupported cURL option '$opt'" >&2; exit 1;; + esac + done + shift $((OPTIND - 1)) + /usr/bin/ftp "$args" "$@" + } +else + command -v curl >/dev/null || { echo 'DEPENDENCY: install "curl" to use cht.sh' >&2; exit 1; } + _CURL=$(command -v curl) + if [ x"$CHTSH_CURL_OPTIONS" != x ]; then + curl() { + $_CURL "${CHTSH_CURL_OPTIONS}" "$@" + } + fi +fi + +if [ "$1" = --read ]; then + read -r a || a="exit" + printf "%s\n" "$a" + exit 0 +elif [ x"$1" = x--help ] || [ -z "$1" ]; then + + n=${0##*/} + s=$(echo "$n" | sed "s/./ /"g) + + cat </dev/null || echo 'DEPENDENCY: please install "xsel" for "copy"' >&2 +fi +command -v rlwrap >/dev/null || { echo 'DEPENDENCY: install "rlwrap" to use cht.sh in the shell mode' >&2; exit 1; } + +mkdir -p "$HOME/.cht.sh/" +lines=$(tput lines) + +if command -v less >/dev/null; then + defpager="less -R" +elif command -v more >/dev/null; then + defpager="more" +else + defpager="cat" +fi + +cmd_cd() { + if [ $# -eq 0 ]; then + section="" + else + new_section=$(echo "$input" | sed 's/cd *//; s@/*$@@; s@^/*@@') + if [ -z "$new_section" ] || [ ".." = "$new_section" ]; then + section="" + else + valid_sections=$(get_list_of_sections) + valid=no; for q in $valid_sections; do [ "$q" = "$new_section/" ] && { valid=yes; break; }; done + if [ "$valid" = no ]; then + echo "Invalid section: $new_section" + echo "Valid sections:" + echo "$valid_sections" \ + | xargs printf "%-10s\n" \ + | tr ' ' . \ + | xargs -n 10 \ + | sed 's/\./ /g; s/^/ /' + else + section="$new_section" + fi + fi + fi +} + +cmd_copy() { + if [ -z "$DISPLAY" ]; then + echo copy: supported only in the Desktop version + elif [ -z "$input" ]; then + echo copy: Make at least one query first. + else + curl -s "${CHTSH_URL}"/"$(get_query_options "$query"?T)" > "$TMP1" + if [ "$is_macos" != yes ]; then + xsel -bi < "$TMP1" + else + pbcopy < "$TMP1" + fi + echo "copy: $(wc -l "$TMP1" | awk '{print $1}') lines copied to the selection" + fi +} + +cmd_ccopy() { + if [ -z "$DISPLAY" ]; then + echo copy: supported only in the Desktop version + elif [ -z "$input" ]; then + echo copy: Make at least one query first. + else + curl -s "${CHTSH_URL}"/"$(get_query_options "$query"?TQ)" > "$TMP1" + if [ "$is_macos" != yes ]; then + xsel -bi < "$TMP1" + else + pbcopy < "$TMP1" + fi + echo "copy: $(wc -l "$TMP1" | awk '{print $1}') lines copied to the selection" + fi +} + +cmd_exit() { + exit 0 +} + +cmd_help() { + cat < python zip list + cht.sh/python> zip list + cht.sh/go> /python zip list +EOF +} + +cmd_hush() { + mkdir -p "$HOME/.cht.sh/" && touch "$HOME/.cht.sh/.hushlogin" && echo "Initial 'use help' message was disabled" +} + +cmd_id() { + id_file="$HOME/.cht.sh/id" + + if [ id = "$input" ]; then + new_id="" + else + new_id=$(echo "$input" | sed 's/id *//; s/ *$//; s/ /+/g') + fi + if [ "$new_id" = remove ]; then + if [ -e "$id_file" ]; then + rm -f -- "$id_file" && echo "id is removed" + else + echo "id was not set, so you can't remove it" + fi + return + fi + if [ -n "$new_id" ] && [ reset != "$new_id" ] && [ "$(/bin/echo -n "$new_id" | wc -c)" -lt 16 ]; then + echo "ERROR: $new_id: Too short id. Minimal id length is 16. Use 'id reset' for a random id" + return + fi + if [ -z "$new_id" ]; then + # if new_id is not specified check if we have some id already + # if yes, just show it + # if not, generate a new id + if [ -e "$id_file" ]; then + awk '$6 == "id" {print $NF}' <"$id_file" | tail -n 1 + return + else + new_id=reset + fi + fi + if [ "$new_id" = reset ]; then + new_id=$(gen_random_str 12) + else + echo WARNING: if someone gueses your id, he can read your cht.sh search history + fi + if [ -e "$id_file" ] && grep -q '\tid\t[^\t][^\t]*$' "$id_file" 2> /dev/null; then + sed -i 's/\tid\t[^\t][^\t]*$/ id '"$new_id"'/' "$id_file" + else + if ! [ -e "$id_file" ]; then + printf '#\n\n' > "$id_file" + fi + printf ".cht.sh\tTRUE\t/\tTRUE\t0\tid\t$new_id\n" >> "$id_file" + fi + echo "$new_id" +} + +cmd_query() { + query=$(prepare_query "$section" "$input") + do_query "$query" +} + +cmd_stealth() { + if [ "$input" != stealth ]; then + arguments=$(echo "$input" | sed 's/stealth //; s/ /\&/') + fi + trap break INT + if [ "$is_macos" = yes ]; then + past=$(pbpaste) + else + past=$(xsel -o) + fi + printf "\033[0;31mstealth:\033[0m you are in the stealth mode; select any text in any window for a query\n" + printf "\033[0;31mstealth:\033[0m selections longer than $STEALTH_MAX_SELECTION_LENGTH words are ignored\n" + if [ -n "$arguments" ]; then + printf "\033[0;31mstealth:\033[0m query arguments: ?$arguments\n" + fi + printf "\033[0;31mstealth:\033[0m use ^C to leave this mode\n" + while true; do + if [ "$is_macos" = yes ]; then + current=$(pbpaste) + else + current=$(xsel -o) + fi + if [ "$past" != "$current" ]; then + past=$current + current_text="$(echo $current | tr -c '[a-zA-Z0-9]' ' ')" + if [ "$(echo "$current_text" | wc -w)" -gt "$STEALTH_MAX_SELECTION_LENGTH" ]; then + echo "\033[0;31mstealth:\033[0m selection length is longer than $STEALTH_MAX_SELECTION_LENGTH words; ignoring" + continue + else + printf "\n\033[0;31mstealth: \033[7m $current_text\033[0m\n" + query=$(prepare_query "$section" "$current_text" "$arguments") + do_query "$query" + fi + fi + sleep 1; + done + trap - INT +} + +cmd_update() { + [ -w "$0" ] || { echo "The script is readonly; please update manually: curl -s ${CHTSH_URL}/:cht.sh | sudo tee $0"; return; } + TMP2=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) + curl -s "${CHTSH_URL}"/:cht.sh > "$TMP2" + if ! cmp "$0" "$TMP2" > /dev/null 2>&1; then + if grep -q ^__CHTSH_VERSION= "$TMP2"; then + # section was vaildated by us already + args=(--shell "$section") + cp "$TMP2" "$0" && echo "Updated. Restarting..." && rm "$TMP2" && CHEATSH_RESTART=1 exec "$0" "${args[@]}" + else + echo "Something went wrong. Please update manually" + fi + else + echo "cht.sh is up to date. No update needed" + fi + rm -f "$TMP2" > /dev/null 2>&1 +} + +cmd_version() { + insttime=$(ls -l -- "$0" | sed 's/ */ /g' | cut -d ' ' -f 6-8) + echo "cht.sh version $__CHTSH_VERSION of $__CHTSH_DATETIME; installed at: $insttime" + TMP2=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) + if curl -s "${CHTSH_URL}"/:cht.sh > "$TMP2"; then + if ! cmp "$0" "$TMP2" > /dev/null 2>&1; then + echo "Update needed (type 'update' for that)". + else + echo "Up to date. No update needed" + fi + fi + rm -f "$TMP2" > /dev/null 2>&1 +} + +TMP1=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) +trap 'rm -f $TMP1 $TMP2' EXIT +trap 'true' INT + +if ! [ -e "$HOME/.cht.sh/.hushlogin" ] && [ -z "$this_query" ]; then + echo "type 'help' for the cht.sh shell help" +fi + +while true; do + if [ "$section" != "" ]; then + full_prompt="$prompt/$section> " + else + full_prompt="$prompt> " + fi + + input=$( + rlwrap -H "$HOME/.cht.sh/history" -pgreen -C cht.sh -S "$full_prompt" bash "$0" --read | sed 's/ *#.*//' + ) + + cmd_name=${input%% *} + cmd_args=${input#* } + case $cmd_name in + "") continue;; # skip empty input lines + '?'|h|help) cmd_name=help;; + hush) cmd_name=hush;; + cd) cmd_name="cd";; + exit|quit) cmd_name="exit";; + copy|yank|c|y) cmd_name=copy;; + ccopy|cc|C|Y) cmd_name=ccopy;; + id) cmd_name=id;; + stealth) cmd_name=stealth;; + update) cmd_name=update;; + version) cmd_name=version;; + *) cmd_name="query"; cmd_args="$input";; + esac + "cmd_$cmd_name" $cmd_args +done diff --git a/.bin/clean b/.bin/clean new file mode 100755 index 0000000..94ae1da --- /dev/null +++ b/.bin/clean @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +import os +import shutil + +CLEAN_FILES = [ + '~/hostr/', + '~/.bzr.log', + '~/.cache/babl/', + '~/.cache/gegl-0.2/', + '~/.cache/google-chrome/', + '~/.cache/gstreamer-1.0/', + '~/.cache/menu/', + '~/.cache/thumbnails/', + '~/.local/share/gegl-0.2/', + '~/.local/share/recently-used.xbel', + '~/.local/share/Trash/', + '~/.ncmpcpp/error.log', + # '~/.npm/', + # '~/.nv/', + '~/.pki/', + '~/.pylint.d/', + '~/.recently-used', + '~/.thumbnails/', + '~/.w3m/', + '~/.xsession-errors.old' +] + + +def answer(question, default="n"): + prompt = "%s (y/[n]) " % question + ans = input(prompt).strip().lower() + + if not ans: + ans = default + + if ans == "y": + return True + return False + + +def remove_clean(): + found = [] + + print("\n") + for jfile in CLEAN_FILES: + extra = os.path.expanduser(jfile) + if os.path.exists(extra): + found.append(extra) + print(" %s" % jfile) + total = len(found) + + if total == 0: + print("No clean files found :)\n") + return + + if answer("\nRemove all?", default="n"): + for jfile in found: + if os.path.isfile(jfile): + os.remove(jfile) + else: + shutil.rmtree(jfile) + print("\nAll clean cleaned") + + else: + print("\nNo files removed") + + +if __name__ == '__main__': + remove_clean() diff --git a/.bin/clock b/.bin/clock new file mode 100755 index 0000000..05b9685 --- /dev/null +++ b/.bin/clock @@ -0,0 +1,37 @@ +#!/bin/bash +# +# Author: Twily 2014 +# + +unhide_cursor() { printf "\e[?25h"; } +trap unhide_cursor EXIT + +STRW=`expr 6 \* 3 + 2` # String length "00:00:00" in character blocks produced by toilet font +STRH=3 # String height "00:00:00" in character blocks produced by toilet font +SPACEW=3 # "Space" length in character block produced by toilet font + +# This will center the clock, but resizing will leave artifacts +function center { + TW=`tput -S <<< cols` + TH=`tput -S <<< lines` + + A1=`expr $TH - $STRH` + A1=`expr $A1 / 2` + A2=`expr $TW - $STRW` + A2=`expr $A2 / 2` + A2=`expr $A2 / $SPACEW` +} + +clear +center +printf "\e[?25l" +while true; do + printf "\033[;H" + + B2="" + for i in `seq 1 $A1`; do echo ""; done + for i in `seq 1 $A2`; do B2="$B2 "; done + + toilet -f future -t --g <<< "$B2`date +'%H:%M:%S'`" + sleep .1 +done diff --git a/.bin/color b/.bin/color new file mode 100755 index 0000000..01f4f6d --- /dev/null +++ b/.bin/color @@ -0,0 +1,90 @@ +#!/usr/bin/env bash + +# ANSI Color -- use these variables to easily have different color +# and format output. Make sure to output the reset sequence after +# colors (f = foreground, b = background), and use the 'off' +# feature for anything you turn on. + +initializeANSI() +{ + esc="" + + blackf="${esc}[30m"; redf="${esc}[31m"; greenf="${esc}[32m" + yellowf="${esc}[33m" bluef="${esc}[34m"; purplef="${esc}[35m" + cyanf="${esc}[36m"; whitef="${esc}[37m" + + blackb="${esc}[1;30m"; redb="${esc}[1;31m"; greenb="${esc}[1;32m" + yellowb="${esc}[1;33m" blueb="${esc}[1;34m"; purpleb="${esc}[1;35m" + cyanb="${esc}[1;36m"; whiteb="${esc}[1;37m" + + boldon="${esc}[1m"; boldoff="${esc}[22m" + italicson="${esc}[3m"; italicsoff="${esc}[23m" + ulon="${esc}[4m"; uloff="${esc}[24m" + invon="${esc}[7m"; invoff="${esc}[27m" + + reset="${esc}[0m" +} + +color0=$(xrdb -query | egrep -m1 '^\*\.?color0:' | awk '{print $NF}') +color1=$(xrdb -query | egrep -m1 '^\*\.?color1:' | awk '{print $NF}') +color2=$(xrdb -query | egrep -m1 '^\*\.?color2:' | awk '{print $NF}') +color3=$(xrdb -query | egrep -m1 '^\*\.?color3:' | awk '{print $NF}') +color4=$(xrdb -query | egrep -m1 '^\*\.?color4:' | awk '{print $NF}') +color5=$(xrdb -query | egrep -m1 '^\*\.?color5:' | awk '{print $NF}') +color6=$(xrdb -query | egrep -m1 '^\*\.?color6:' | awk '{print $NF}') +color7=$(xrdb -query | egrep -m1 '^\*\.?color7:' | awk '{print $NF}') + +color8=$(xrdb -query | egrep -m1 '^\*\.?color8:' | awk '{print $NF}') +color9=$(xrdb -query | egrep -m1 '^\*\.?color9:' | awk '{print $NF}') +color10=$(xrdb -query | egrep -m1 '^\*\.?color10:' | awk '{print $NF}') +color11=$(xrdb -query | egrep -m1 '^\*\.?color11:' | awk '{print $NF}') +color12=$(xrdb -query | egrep -m1 '^\*\.?color12:' | awk '{print $NF}') +color13=$(xrdb -query | egrep -m1 '^\*\.?color13:' | awk '{print $NF}') +color14=$(xrdb -query | egrep -m1 '^\*\.?color14:' | awk '{print $NF}') +color15=$(xrdb -query | egrep -m1 '^\*\.?color15:' | awk '{print $NF}') +# note in this first use that switching colors doesn't require a reset +# first - the new color overrides the old one. + + + +numbers (){ + echo -en "${blackf} ${color0} ${reset}" + echo -en "${redf} ${color1} ${reset}" + echo -en "${greenf} ${color2} ${reset}" + echo -en "${yellowf} ${color3} ${reset}" + echo -en "${bluef} ${color4} ${reset}" + echo -en "${purplef} ${color5} ${reset}" + echo -en "${cyanf} ${color6} ${reset}" + echo -en "${whiteb} ${color7} ${reset}" + echo -e "\n" + echo -en "${blackf} ${color8} ${reset}" + echo -en "${redf} ${color9} ${reset}" + echo -en "${greenf} ${color10} ${reset}" + echo -en "${yellowf} ${color11} ${reset}" + echo -en "${bluef} ${color12} ${reset}" + echo -en "${purplef} ${color13} ${reset}" + echo -en "${cyanf} ${color14} ${reset}" + echo -en "${whiteb} ${color15} ${reset}" + echo -e "\n" +} + +blocks (){ + +initializeANSI + +cat << EOF + +${blackf}████${reset}${blackb}████${reset} ${redf}████${reset}${redb}████${reset} ${greenf}████${reset}${greenb}████${reset} ${yellowf}████${reset}${yellowb}████${reset} ${bluef}████${reset}${blueb}████${reset} ${purplef}████${reset}${purpleb}████${reset} ${cyanf}████${reset}${cyanb}████${reset} ${whitef}████${reset}${whiteb}████${reset} +${blackf}████${reset}${blackb}████${reset} ${redf}████${reset}${redb}████${reset} ${greenf}████${reset}${greenb}████${reset} ${yellowf}████${reset}${yellowb}████${reset} ${bluef}████${reset}${blueb}████${reset} ${purplef}████${reset}${purpleb}████${reset} ${cyanf}████${reset}${cyanb}████${reset} ${whitef}████${reset}${whiteb}████${reset} +${blackf}████${reset}${blackb}████${reset} ${redf}████${reset}${redb}████${reset} ${greenf}████${reset}${greenb}████${reset} ${yellowf}████${reset}${yellowb}████${reset} ${bluef}████${reset}${blueb}████${reset} ${purplef}████${reset}${purpleb}████${reset} ${cyanf}████${reset}${cyanb}████${reset} ${whitef}████${reset}${whiteb}████${reset} + +EOF + +} + +case $1 in + b) blocks;; + n) numbers;; + a) blocks && numbers;; + *) blocks && numbers;; +esac diff --git a/.bin/cookie b/.bin/cookie new file mode 100755 index 0000000..5808fdd --- /dev/null +++ b/.bin/cookie @@ -0,0 +1,7 @@ +#!/bin/bash +while true +do + sleep 3s + notify-send "$(fortune)" + sleep 5m +done \ No newline at end of file diff --git a/.bin/covid19.sh b/.bin/covid19.sh new file mode 100755 index 0000000..df485bc --- /dev/null +++ b/.bin/covid19.sh @@ -0,0 +1,460 @@ +#!/usr/bin/env bash +# +# Corona Virus (Covid-19) statistics cli, +# +# MIT License +# Copyright (c) 2020 Garry Lachman +# https://github.com/garrylachman/covid19-cli + +VERSION="0.2.0" + +BASE_API="https://corona.lmao.ninja" +API_TOTAL_ENDPOINT="$BASE_API/all" +API_ALL_COUNTRIES_ENDPOINT="$BASE_API/countries" +API_HISTORICAL_COUNTRIES_ENDPOINT="$BASE_API/historical" + +# https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash + +function printTable() +{ + local -r delimiter="${1}" + local -r tableData="$(removeEmptyLines "${2}")" + local -r colorHeader="${3}" + local -r displayTotalCount="${4}" + + if [[ "${delimiter}" != '' && "$(isEmptyString "${tableData}")" = 'false' ]] + then + local -r numberOfLines="$(trimString "$(wc -l <<< "${tableData}")")" + + if [[ "${numberOfLines}" -gt '0' ]] + then + local table='' + local i=1 + + for ((i = 1; i <= "${numberOfLines}"; i = i + 1)) + do + ProgressBar ${i} ${numberOfLines} + local line='' + line="$(sed "${i}q;d" <<< "${tableData}")" + + local numberOfColumns=0 + numberOfColumns="$(awk -F "${delimiter}" '{print NF}' <<< "${line}")" + + # Add Line Delimiter + + if [[ "${i}" -eq '1' ]] + then + table="${table}$(printf '%s#+' "$(repeatString '#+' "${numberOfColumns}")")" + fi + + # Add Header Or Body + + table="${table}\n" + + local j=1 + + for ((j = 1; j <= "${numberOfColumns}"; j = j + 1)) + do + table="${table}$(printf '#| %s' "$(cut -d "${delimiter}" -f "${j}" <<< "${line}")")" + done + + table="${table}#|\n" + + # Add Line Delimiter + + if [[ "${i}" -eq '1' ]] || [[ "${numberOfLines}" -gt '1' && "${i}" -eq "${numberOfLines}" ]] + then + table="${table}$(printf '%s#+' "$(repeatString '#+' "${numberOfColumns}")")" + fi + done + + if [[ "$(isEmptyString "${table}")" = 'false' ]] + then + local output='' + output="$(echo -e "${table}" | column -s '#' -t | awk '/^\+/{gsub(" ", "-", $0)}1')" + + if [[ "${colorHeader}" = 'true' ]] + then + echo -e "\033[1;32m$(head -n 3 <<< "${output}")\033[0m" + tail -n +4 <<< "${output}" + else + echo "${output}" + fi + fi + fi + + if [[ "${displayTotalCount}" = 'true' && "${numberOfLines}" -ge '0' ]] + then + echo -e "\n\033[1;36mTOTAL ROWS : $((numberOfLines - 1))\033[0m" + fi + fi +} + +function isEmptyString() +{ + local -r string="${1}" + + if [[ "$(trimString "${string}")" = '' ]] + then + echo 'true' && return 0 + fi + + echo 'false' && return 1 +} + +function removeEmptyLines() +{ + local -r content="${1}" + + echo -e "${content}" | sed '/^\s*$/d' +} + +function trimString() +{ + local -r string="${1}" + + sed 's,^[[:blank:]]*,,' <<< "${string}" | sed 's,[[:blank:]]*$,,' +} + +function repeatString() +{ + local -r string="${1}" + local -r numberToRepeat="${2}" + + if [[ "${string}" != '' && "$(isPositiveInteger "${numberToRepeat}")" = 'true' ]] + then + local -r result="$(printf "%${numberToRepeat}s")" + echo -e "${result// /${string}}" + fi +} + +function isPositiveInteger() +{ + local -r string="${1}" + + if [[ "${string}" =~ ^[1-9][0-9]*$ ]] + then + echo 'true' && return 0 + fi + + echo 'false' && return 1 +} +function ProgressBar { + let _progress=(${1}*100/${2}*100)/100 + let _done=(${_progress}*4)/10 + let _left=40-$_done + _color=$green + _fill=$(printf "%${_done}s") + _empty=$(printf "%${_left}s") + if [ "$_progress" -gt 0 ]; then + _color="${green}" + fi + if [ "$_progress" -gt 33 ]; then + _color="${yellow}" + fi + if [ "$_progress" -gt 80 ]; then + _color="${red}" + fi + printf "\rProgress : ${_color}[${_fill// /#}${_empty// /-}] ${_progress}%%\r${no_color}" +} +# https://github.com/holman/spark +_echoSP() +{ + if [ "X$1" = "X-n" ]; then + shift + printf "%s" "$*" + else + printf "%s\n" "$*" + fi +} + +spark() +{ + local n numbers= + + # find min/max values + local min=0xffffffff max=0 + + for n in ${@//,/ } + do + # on Linux (or with bash4) we could use `printf %.0f $n` here to + # round the number but that doesn't work on OS X (bash3) nor does + # `awk '{printf "%.0f",$1}' <<< $n` work, so just cut it off + n=${n%.*} + (( n < min )) && min=$n + (( n > max )) && max=$n + numbers=$numbers${numbers:+ }$n + done + + # print ticks + local ticks=(▁ ▂ ▃ ▄ ▅ ▆ ▇ █) + + # use a high tick if data is constant + (( min == max )) && ticks=(▅ ▆) + + local f=$(( (($max-$min)<<8)/(${#ticks[@]}-1) )) + (( f < 1 )) && f=1 + + for n in $numbers + do + _echoSP -n ${ticks[$(( ((($n-$min)<<8)/$f) ))]} + done + _echoSP +} + +# Detect whether output is piped or not. +[[ -t 1 ]] && piped=0 || piped=1 + +# Defaults +args=() + +out() { + ((quiet)) && return + + local message="$@" + if ((piped)); then + message=$(echo $message | sed ' + s/\\[0-9]\{3\}\[[0-9]\(;[0-9]\{2\}\)\?m//g; + s/✖/Error:/g; + s/✔/Success:/g; + ') + fi + printf '%b\n' "$message"; +} +die() { out "$@"; exit 1; } >&2 +err() { out " \033[1;31m✖\033[0m $@"; } >&2 +success() { out " \033[1;32m✔\033[0m $@"; } + +bold=$(tput bold) +normal=$(tput sgr0) + +# colours +green=$(tput setaf 2) +no_color='\033[0m' +red=$(tput setaf 1) +yellow=$(tput setaf 3) + +# Notify on function success +notify() { [[ $? == 0 ]] && success "$@" || err "$@"; } + +# Escape a string +escape() { echo $@ | sed 's/\//\\\//g'; } + +version="v${VERSION}" + +check_dependencies() { + if ! [ -x "$(command -v jq)" ]; then + err 'Error: jq is not installed.\nhttps://stedolan.github.io/jq/' >&2 + die + fi + if ! [ -x "$(command -v curl)" ]; then + err 'Error: curl is not installed.\nhttps://github.com/curl/curl' >&2 + die + fi +} + +# Print usage +usage() { + banner + echo "$(basename $0) [OPTION]... + + Corona Virus (Covid-19) statistics cli. + + MIT License + Copyright (c) 2020 Garry Lachman + https://github.com/garrylachman/covid19-cli + + Options: + -c, --country Specific Country (actual data + historical) + -l, --list-all List all countries + -s, --sort Sort countries list by key (country|cases|active|critical|deaths|recovered|todayCases|todayDeaths|casesPerOneMillion) + -i, --historical List all countries historical trend chart + -h, --help Display this help and exit + -n, --no-banner Hides \"Covid19-CLI\" banner + --version Output version information and exit +" +} + +banner() { + if [[ "$nobanner" != true ]]; then + echo " +${green}_________ .__ ._______ ________ _________ .____ .___ +\_ ___ \ _______ _|__| __| _/_ / __ \ \_ ___ \| | | | +${yellow}/ \ \/ / _ \ \/ / |/ __ | | \____ / ______ / \ \/| | | | +\ \___( <_> ) /| / /_/ | | | / / /_____/ \ \___| |___| | + ${red}\______ /\____/ \_/ |__\____ | |___| /____/ \______ /_______ \___| + \/ \/ \/ \/ +" +printf "${no_color}" + fi +} + + +function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; } + + +main() { + check_dependencies + banner + if [[ -n "$country" && "$list_all" == 1 ]]; then + err "--country (-c) and --list-all (-l) cannot be mixed together" + die + fi; + + if [ "$list_all" == 1 ]; then + # The part can be re-factored in better way... + success "List all Countries" + if [ -n "$sort_by" ]; then + success "Sory by key: $sort_by" + fi + success "Please wait while we: " + success "- Retrieve & preparing the data..." + result=$(curl -s "$API_ALL_COUNTRIES_ENDPOINT/?sort=$sort_by") + cols=(country cases active critical deaths recovered todayCases todayDeaths casesPerOneMillion) + titles=(Country Cases Active Critical Deaths Recovered Today-Cases Today-Deaths Cases-Per-One-Million) + lines=() + lines+=($(join_by , "${titles[@]}")) + cnt=0 + _start=1 + _end=$(echo "${result}" | jq -r 'length') + ((_end=_end-1)) + for row in $(echo "${result}" | jq -r '.[] | @base64'); do + ProgressBar ${cnt} ${_end} + plainRow=$(echo "${row}" | base64 --decode) + line=() + for k in "${cols[@]}"; do + val=$(echo $plainRow | jq -r ".${k}") + line+=("$val") + done + line=$(join_by , "${line[@]}") + lines+=("$line") + ((cnt=cnt+1)) + done + resultStr=$(join_by "\n" "${lines[@]}") + echo "" + success "- Bulding data tables" + printTable "," "$resultStr" + + elif [ -n "$historical_all" ]; then + echo "historical_all" + success "Historical" + result=$(curl -s $API_HISTORICAL_COUNTRIES_ENDPOINT) + + for row in $(echo "${result}" | jq -r '.[] | @base64'); do + plainRow=$(echo "${row}" | base64 --decode) + #echo $plainRow | jq '. | "\(.country)-\(.province)"' + country=$(echo $plainRow | jq -r ".country") + province=$(echo $plainRow | jq -r ".province") + + printf "${bold}${country}" + if [ "$province" != "null" ]; then + printf " (${province})" + fi + printf "${no_color}\n" + + casesHistorical=$(echo $plainRow | jq -r '.timeline .cases | map(.|tostring) | join(",")') + deathsHistorical=$(echo $plainRow | jq -r '.timeline .deaths | map(.|tostring) | join(",")') + recoveredHistorical=$(echo $plainRow | jq -r '.timeline .recovered | map(.|tostring) | join(",")') + + printf "${bold}Cases:\t\t${yellow}$(spark ${casesHistorical})${no_color}\n" + printf "${bold}Deaths:\t\t${red}$(spark ${deathsHistorical})${no_color}\n" + printf "${bold}Recovered:\t${green}$(spark ${recoveredHistorical})${no_color}\n" + + printf "\n" + done + + + + elif [[ -n "$country" && !"$historical_all" ]]; then + success "Country: $country" + result=$(curl -s $API_ALL_COUNTRIES_ENDPOINT/$country) + historicalResult=$(curl -s $API_HISTORICAL_COUNTRIES_ENDPOINT/$country) + + cases=$(echo $result | jq ".cases") + deaths=$(echo $result | jq ".deaths") + recovered=$(echo $result | jq ".recovered") + + casesHistorical=$(echo $historicalResult | jq -r '.timeline .cases | map(.|tostring) | join(",")') + deathsHistorical=$(echo $historicalResult | jq -r '.timeline .deaths | map(.|tostring) | join(",")') + recoveredHistorical=$(echo $historicalResult | jq -r '.timeline .recovered | map(.|tostring) | join(",")') + + printf "\n" + printf "${bold}Cases:\t\t${normal}${yellow}${cases}\t$(spark ${casesHistorical})${no_color}\n" + printf "${bold}Deaths:\t\t${normal}${red}${deaths}\t$(spark ${deathsHistorical})${no_color}\n" + printf "${bold}Recovered:\t${normal}${green}${recovered}\t$(spark ${recoveredHistorical})${no_color}\n" + + else + success "Global Statistics" + result=$(curl -s $API_TOTAL_ENDPOINT) + cases=$(echo $result | jq ".cases") + deaths=$(echo $result | jq ".deaths") + recovered=$(echo $result | jq ".recovered") + + printf "\n" + printf "${bold}Cases:\t\t${normal}${yellow}${cases}${no_color}\n" + printf "${bold}Deaths:\t\t${normal}${red}${deaths}${no_color}\n" + printf "${bold}Recovered:\t${normal}${green}${recovered}${no_color}\n" + fi; + +} + +optstring=h +unset options +while (($#)); do + case $1 in + # If option is of type -ab + -[!-]?*) + # Loop over each character starting with the second + for ((i=1; i < ${#1}; i++)); do + c=${1:i:1} + + # Add current char to options + options+=("-$c") + + # If option takes a required argument, and it's not the last char make + # the rest of the string its argument + if [[ $optstring = *"$c:"* && ${1:i+1} ]]; then + options+=("${1:i+1}") + break + fi + done + ;; + # If option is of type --foo=bar + --?*=*) options+=("${1%%=*}" "${1#*=}") ;; + # add --endopts for -- + --) options+=(--endopts) ;; + # Otherwise, nothing special + *) options+=("$1") ;; + esac + shift +done +set -- "${options[@]}" +unset options + + +# A non-destructive exit for when the script exits naturally. +safe_exit() { + trap - INT TERM EXIT + exit +} + +while [[ $1 = -?* ]]; do + case $1 in + -n|--no-banner) nobanner=true;; + -h|--help) usage >&2; safe_exit ;; + --version) out "$(basename $0) $version"; safe_exit ;; + -c|--country) country=$2; shift ;; + -l|--list-all) list_all=1 ;; + -s|--sort) sort_by=$2 ;; + -i|--historical) historical_all=1 ;; + --endopts) shift; break ;; + *) die "invalid option: $1" ;; + esac + shift +done + +args+=("$@") + +main + +safe_exit diff --git a/.bin/creio.sh b/.bin/creio.sh new file mode 100755 index 0000000..d5d65c9 --- /dev/null +++ b/.bin/creio.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +# Install script for Arch Linux +# https://raw.githubusercontent.com/creio/dots/master/.bin/creio.sh + +# wget git.io/creio.sh && wget git.io/creio2.sh +# nano creio.sh +# nano creio2.sh +# sh creio.sh + +Check for root +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root." >&2 + echo "Try 'sudo sh'" + echo "" + exit 1 +fi + +R_DISK="sda6" +B_DISK="sda2" +# H_DISK="sdb3" +S_DISK="sda3" + +loadkeys ru +setfont cyr-sun16 + +timedatectl set-ntp true + + +### ////// btrfs mbr /////// +mkfs.btrfs -f -L "root" /dev/$R_DISK +mkfs.ext2 /dev/$B_DISK -L boot +mkswap -L "swap" /dev/$S_DISK + +mount /dev/$R_DISK /mnt +btrfs subvolume create /mnt/@ +btrfs subvolume create /mnt/@home +umount /mnt + +mount -o subvol=@,compress=lzo,relatime,space_cache,autodefrag /dev/$R_DISK /mnt +mkdir /mnt/{boot,home} +mount /dev/$B_DISK /mnt/boot +mount -o subvol=@home,compress=lzo,relatime,space_cache,autodefrag /dev/$R_DISK /mnt/home +# // ssd trim +# mount -o subvol=@,compress=lzo,ssd,discard,relatime,space_cache,autodefrag /dev/$R_DISK /mnt +# mount -o subvol=@home,compress=lzo,ssd,discard,relatime,space_cache,autodefrag /dev/$R_DISK /mnt/home +swapon /dev/$S_DISK +### ////// end btrfs mbr /////// + + +### ////// ext4 mbr & efi /////// +# mkfs.ext4 /dev/$R_DISK -L root + +# mkfs.ext2 /dev/$B_DISK -L boot +# mkfs.fat -F32 /dev/$B_DISK -L boot + +# mkfs.ext4 /dev/$H_DISK -L home +# mkswap /dev/$S_DISK -L swap + +# mount /dev/$R_DISK /mnt + +# mkdir /mnt/{boot,home} +# mkdir -p /mnt/{boot/efi,home} + +# mount /dev/$B_DISK /mnt/boot +# mount /dev/$B_DISK /mnt/boot/efi + +# mount /dev/$H_DISK /mnt/home +# swapon /dev/$S_DISK +### ////// end ext4 mbr & efi /////// + + + +pacman -Sy --noconfirm --needed reflector +reflector -c "Russia" -c "Belarus" -c "Ukraine" -c "Poland" -f 20 -l 20 -p https -p http -n 20 --save /etc/pacman.d/mirrorlist --sort rate + +pacstrap /mnt base base-devel linux linux-headers nano + +cp creio2.sh /mnt/creio2.sh +chmod u+x /mnt/creio2.sh + +genfstab -pU /mnt >> /mnt/etc/fstab + +# arch-chroot /mnt sh -c "$(curl -fsSL git.io/creio2.sh)" +arch-chroot /mnt ./creio2.sh diff --git a/.bin/creio2.sh b/.bin/creio2.sh new file mode 100755 index 0000000..fd1c85b --- /dev/null +++ b/.bin/creio2.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +# Install script for Arch Linux +# https://raw.githubusercontent.com/creio/dots/master/.bin/creio2.sh + +# wget git.io/creio2.sh +# nano creio2.sh + +DISK="sda" + +sed -i "/\[multilib\]/,/Include/"'s/^#//' /etc/pacman.conf + +pacman -Sy --noconfirm --needed reflector +reflector -c "Russia" -c "Belarus" -c "Ukraine" -c "Poland" -f 20 -l 20 -p https -p http -n 20 --save /etc/pacman.d/mirrorlist --sort rate + +echo "Arch Linux Virtualbox?" +read -p "yes, no: " virtualbox_setting +if [[ $virtualbox_setting == no ]]; then + virtualbox_install="" +elif [[ $virtualbox_setting == yes ]]; then + virtualbox_install="virtualbox-guest-modules-arch virtualbox-guest-utils" +fi +echo +pacman -S --noconfirm --needed $virtualbox_install + +pack="networkmanager bash-completion \ +reflector htop openssh tmux btrfs-progs \ +curl wget git rsync unzip unrar p7zip gnu-netcat pv" + +pacman -S --noconfirm --needed $pack + +# Root password +passwd + +# user add & password +while true; do + clear + echo -e "add new user" + + printf "\n\nUsername: " + read -r USER + + printf "New user %s. Continue? [y/N]: " "$USER" + read -r answer + + case $answer in + y*|Y*) break + esac +done + +useradd -m -g users -G "adm,audio,log,network,rfkill,scanner,storage,optical,power,wheel" -s /bin/bash "$USER" +passwd "$USER" +echo "%wheel ALL=(ALL) ALL" >> /etc/sudoers + +echo "ctlos" > /etc/hostname + +ln -svf /usr/share/zoneinfo/Europe/Moscow /etc/localtime + +echo "en_US.UTF-8 UTF-8" > /etc/locale.gen +echo "ru_RU.UTF-8 UTF-8" >> /etc/locale.gen +locale-gen + +echo "LANG=ru_RU.UTF-8" > /etc/locale.conf +echo "KEYMAP=ru" >> /etc/vconsole.conf +echo "FONT=cyr-sun16" >> /etc/vconsole.conf + +### rm fsck btrfs +### add keyboard keymap +# HOOKS=(base udev autodetect modconf block filesystems keyboard keymap fsck) +# HOOKS=(base udev autodetect modconf block filesystems keyboard keymap) +nano /etc/mkinitcpio.conf + +mkinitcpio -p linux + +pacman -S --noconfirm --needed grub +# pacman -S --noconfirm --needed grub efibootmgr + +grub-install /dev/$DISK +# grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Arch --force + +grub-mkconfig -o /boot/grub/grub.cfg + +systemctl enable NetworkManager +systemctl enable sshd + +echo "System Setup Complete" diff --git a/.bin/dashboard.sh b/.bin/dashboard.sh new file mode 100755 index 0000000..b27e8fe --- /dev/null +++ b/.bin/dashboard.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +APPS=( + 'conky1' + 'conky2' +) + +APP_conky1_cmd="conky -c $HOME/.conkyrc1" +APP_conky2_cmd="conky -c $HOME/.conkyrc2" + + + +desktop=`$HOME/bin/show_desktop -q` +[ $? -eq 0 ] || exit 1 + +start() { + echo "Starting: $1" + eval "cmd=\$APP_${1}_cmd" + $cmd & + + if [ -n $! ]; then + # Re-position window? + eval "x=\$APP_${1}_winx" + eval "y=\$APP_${1}_winy" + if [ -n "$x" -a -n "$y" ]; then + eval "title=\$APP_${1}_wintitle" + # the sleep gives the window time to show up + $(sleep 1; wmctrl -r $title -e "0,$x,$y,-1,-1") & + + # alternate method which doesn't require the window title + #xdotool getactivewindow windowmove $x $y + fi + fi +} + +stop() { + eval "cmd=\$APP_${1}_cmd" + pid=`pgrep -f "$cmd"` + if [ -n "$pid" ]; then + echo "Killing pid: $pid ($cmd)" + kill $pid + fi +} + +if [ "$desktop" == "visible" ]; then + # Fire up our widget apps + for app in "${APPS[@]}"; do + start "$app" + done +fi + +if [ "$desktop" == "hidden" ]; then + # Kill our widget apps + for app in "${APPS[@]}"; do + stop "$app" + done +fi diff --git a/.bin/delete_files.py b/.bin/delete_files.py new file mode 100644 index 0000000..eadf21d --- /dev/null +++ b/.bin/delete_files.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python + +import os +import shutil + +CLEAN_FILES = [ + #'~/hostr/', + #'~/.bzr.log', + #'~/.cache/babl/', + #'~/.cache/gegl-0.2/', + #'~/.cache/google-chrome/', + #'~/.cache/gstreamer-1.0/', + #'~/.cache/menu/', + #'~/.cache/thumbnails/', + #'~/.local/share/gegl-0.2/', + #'~/.local/share/recently-used.xbel', + #'~/.local/share/Trash/', + #'~/.ncmpcpp/error.log', + # '~/.npm/', + # '~/.nv/', + #'~/.pki/', + #'~/.pylint.d/', + #'~/.recently-used', + #'~/.thumbnails/', + #'~/.w3m/', + #'~/.xsession-errors.old' + '/home/denis/test/2/', + '/home/denis/test/3/' +] + +def answer(question, default="n"): + prompt = "%s (y/[n]) " % question + ans = input(prompt).strip().lower() + + if not ans: + ans = default + + if ans == "y": + return True + return False + + +def remove_clean(): + found = [] + + print("\n") + for jfile in CLEAN_FILES: + extra = os.path.expanduser(jfile) + if os.path.exists(extra): + found.append(extra) + print(" %s" % jfile) + total = len(found) + + if total == 0: + print("No clean files found :)\n") + return + + if answer("\nRemove all?", default="n"): + list_paths = (CLEAN_FILES) + print ('Список путей - {}'.format(list_paths)) + for path in list_paths: + print (path) + for the_file in os.listdir(path): # Смотрим в каждом указанном пути наличие файлов. + file_path = os.path.join(path, the_file) + print(file_path) + try: + if os.path.isfile(file_path): + os.unlink(file_path) + elif os.path.isdir(file_path): shutil.rmtree(file_path) + except Exception as e: + print(e) + + print("\nAll clean cleaned") + + else: + print("\nNo files removed") + + +if __name__ == '__main__': + remove_clean() diff --git a/.bin/dm_search.sh b/.bin/dm_search.sh new file mode 100755 index 0000000..2a1f7f2 --- /dev/null +++ b/.bin/dm_search.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env sh + +# Font +FN='ClearSansMedium:size=11' +# Background Commands +NB='#111113' +# Foreground Commands +NF='#FFF' +# Background Prompt +SB='#5A74CA' +# Foreground Prompt +SF='#FFF' + +# URL='https://www.startpage.com/do/search?hl=pt&q=' +URL='https://duckduckgo.com/?q=' +QUERY=$(echo '' | dmenu -fn $FN -i -p "Search: " -nb $NB -nf $NF -sb $SB -sf $SF) + +if [ -n "$QUERY" ]; then + xdg-open "${URL}${QUERY}" 2> /dev/null +fi diff --git a/.bin/dots b/.bin/dots new file mode 100755 index 0000000..ab79993 --- /dev/null +++ b/.bin/dots @@ -0,0 +1,317 @@ +#!/usr/bin/env bash +# +# Ctlos Linux https://ctlos.github.io +# +# Dot file management script using git & rsync +# Written by Nathaniel Maia, November 2017 - March 2018 + +# Config ~/.dotsrc +# Ignore github ~/.gitignore +# git.io/ctldotsrc +# wget git.io/ctldots + +# immutable values +readonly NAME=$(basename "$0") +readonly CFG="$HOME/.${NAME}rc" + +readonly B='\E[1;34m' +readonly R='\E[1;31m' +readonly G='\E[1;32m' +readonly N='\E[0m' +readonly BLD='\E[1m' + +readonly WRN="${R}[WARN]${N}:" +readonly INF="${B}[INFO]${N}:" +readonly YN="${B}[${R}y${B}/${R}${BLD}N${N}${B}]${N}: " + +readonly MENUTXT="\n Enter number or letter and press [Enter]. 0/q to cancel\n\n> " + +readonly MENU=" +\n\t ${R}1 ${N}| ${R}${BLD}b${N}ackup\t\t-> Backup Files +\t${B}------------------------------------------${N} +\n\t ${R}2 ${N}| ${R}${BLD}r${N}estore\t\t-> Restore Files +\t${B}------------------------------------------${N}" + + +main_menu() { + local choice + + clear + echo -e "$MENU" + draw_box 12 + printf "$MENUTXT" + read -e -r choice + clear + + [[ $choice =~ (v|V) ]] && V="v" + + case "$choice" in + 0|[Qq]|quit) exit 0 ;; + 1*|[Bb]*|backup*) [[ $BASE_DIR ]] && { backup_files; exit 0; } || edit_config ;; + 2*|[Rr]*|restore*) restore_files && exit 0 + esac + + src_cfg + main_menu +} + +draw_box() { + local h=${1:-12} # $1 Box Height + local w=${2:-57} # $2 Box Width + local row=${3:-1} # $3 Starting Row + local col=${4:-2} # $4 Starting Column + local co=${5:-1} # $5 Box Color, 1-7 + ((h--)) # account for corner + ((w--)) # account for corner + local endrow=$((row + h)) # end row + local endcol=$((col + w)) # end column + echo -ne "\E[3${co}m" # foreground colour + + local hz="-" vt="|" cn="+" # horizontal, vertical, and corner chars + + plot_char() { + echo -e "\E[${1};${2}H""$3" + } + + local i=0 + for ((r=row; i/dev/null && hash pacman &>/dev/null; then + echo -e "\n\n\n\tInstalling:\n\t\tgit\n\t\trsync\n\n\tPlease Wait.." + draw_box 8 + sleep 1 + clear + sudo pacman -S git rsync --noconfirm --needed + fi +} + +prep_directory() { + if [[ $REQ != "True" ]]; then + check_reqs + if [[ $BASE_DIR ]]; then # is set in config but might not exist yet + if [[ ! -d $BASE_DIR ]]; then # is not an existing dir + + if [[ $REPO ]] && grep -wq '^https://.*/.*/.*$' <<< "$REPO"; then # is REPO actually and address + git clone "$REPO" "$BASE_DIR" + else + mkdir -p$V "$BASE_DIR" # local backup + fi + fi + + [[ -d $BASE_DIR ]] && REQ="True" + else + echo -e "$WRN BASE_DIR must be set in config to continue. $EXITING" + fi + fi +} + +clean_backup_dirs() { + if [[ ${PREV_BACKUPS[*]} ]] && sub_choice "Perform clean backup (wipe BASE_DIR)" "${R}$BASE_DIR${N}"; then + for dir in "${PREV_BACKUPS[@]}"; do + if [[ -d $dir ]] && sub_choice "Wipe all files in /$(basename "$dir")" "${R}$dir${N}"; then + rm -rf$V "$dir" + [[ $V ]] && sleep 0.5 + fi + done + fi +} + +commit_changes() { + if grep -q 'https://' <<< "$REPO"; then + if sub_choice "Commit and push changes to REPO" "${R}$REPO${N}"; then + + printf "\nEnter commit message below, an example has been provided\n\n> " + read -e -i "$(date +%Y.%m.%d) Update " -r comment + + if grep -wq '[a-zA-Z0-9]*' <<< "$comment"; then + cd "$BASE_DIR/" || return 1 + git add . + git commit -m "$comment" + git push origin "${BRANCH:-HEAD}" + else + echo "Bad commit message" + sleep 1 + commit_changes + fi + fi + fi +} + +backup_files() { + prep_directory + clean_backup_dirs + + if [[ ${USER_PATHS[*]} || ${ROOT_PATHS[*]} ]]; then + + echo -e "$INF ${B}Copying files, please wait..$N\n" + sed -i -e "s/Date:.*/Date: $(date '+%d.%m.%Y,%H:%M:%S')/g" $HOME/README.md + cp $HOME/README.md $HOME/docs/README.md + for f in "${USER_PATHS[@]}"; do + [[ -e $f ]] && rsync -aR$V $f "$BASE_DIR/$USER_DIR/" + [[ $V ]] && sleep 0.5 + done + + for f in "${ROOT_PATHS[@]}"; do + [[ -e $f ]] && rsync -aR$V $f "$BASE_DIR/$ROOT_DIR/" + [[ $V ]] && sleep 0.5 + done + + echo -e "$INF ${G}Backup complete$N" + sleep 1 + else + echo -e "$WRN No valid file paths were found.." + sleep 2 + fi + commit_changes +} + +restore_files() { + prep_directory + if [[ ${PREV_BACKUPS[*]} ]]; then + local msg="" + + for x in "${PREV_BACKUPS[@]}"; do + if [[ -e $x ]] && sub_choice "Restore everything from /$(basename "$x")" "${R}$x${N}"; then + if grep -q "$BASE_DIR/$USER_DIR" <<< "$x"; then + rsync -avPC --filter="exclude $ROOT_DIR" "$BASE_DIR/$USER_DIR/" "$HOME/" + elif grep -q "$BASE_DIR/$ROOT_DIR" <<< "$x"; then + sudo rsync -avn "$BASE_DIR/$ROOT_DIR/" / + else + echo -e "\n\n\n\t$WRN Unable to restore\n\n\t$x" + draw_box 9 + sleep 1 + fi + + fi + + [[ $V ]] && sleep 0.5 + done + + else + echo -e "\n\n\n\t$INF ${R}No Existing backups to restore${N}" + draw_box 9 + sleep 1 + fi +} + +mk_cfg() { + [[ $1 == "new" ]] && edit_config + + for f in "${USER_PATHS[@]}"; do + if [[ -e $f ]] && ! grep "$f" <<< "$u_paths"; then + u_paths="$u_paths\"$f\"\n" + fi + done + + for f in "${ROOT_PATHS[@]}"; do + if [[ -e $f ]] && ! grep "$f" <<< "$r_paths"; then + r_paths="$r_paths\"$f\"\n" + fi + done + + local cfg="# config file for dfm (dotfile manager) +\n# repo https address for cloning & pushing (empty for local backup) +REPO=\"$REPO\" +\n# branch, defaults to current branch (HEAD) +BRANCH=\"$BRANCH\" +\n# location where backup folder or repo will be created or cloned +BASE_DIR=\"$BASE_DIR\" +\n# names for storage directories within BASE_DIR. +# created only if needed, stores files from below arrays +USER_DIR=\"${USER_DIR}\" +ROOT_DIR=\"${ROOT_DIR:-root}\" +\n# file paths which will be backed up into the directories above +USER_PATHS=(\n$u_paths) +\nROOT_PATHS=(\n$r_paths)" + + echo -e "$cfg" > "$CFG" && clear + src_cfg +} + +edit_config() { + $EDITOR "$CFG" + src_cfg +} + +src_cfg() { + PREV_BACKUPS=() + ! . "$CFG" 2>/dev/null && mk_cfg "new" + [[ -d $BASE_DIR/$USER_DIR ]] && PREV_BACKUPS+=("$BASE_DIR/$USER_DIR") + [[ -d $BASE_DIR/$ROOT_DIR ]] && PREV_BACKUPS+=("$BASE_DIR/$ROOT_DIR") +} + +sub_choice() { + local choice + + clear + printf "\n\n\n\t$1? $YN\n\n\t$2" + draw_box 9 + tput cup 3 $((${#1} + 17)) + read -r choice + clear + + grep -q '[yY]' <<< "$choice" && return 0 || return 1 +} + +usage() { + cat </dev/null; then + DIST="${ID,,}" +elif [[ -e /etc/lsb-release ]] && . /etc/lsb-release 2>/dev/null; then + DIST="${DISTRIB_ID,,}" +fi + +# system uptime +# UPT="$(uptime -p)" +# UPT="${UPT/up /}" +# UPT="${UPT/ day?/d}" +# UPT="${UPT/ hour?/h}" +# UPT="${UPT/ minute?/m}" + +# Root / +ROOT=$(df -h / | awk '/[0-9]%/{print $(NF-1)" | "$(NF-2)}') + +# Home /home +HOME=$(df -h /home | awk '/[0-9]%/{print $(NF-1)" | "$(NF-2)}') + +# Home /media +FILES=$(df -h /media/files | awk '/[0-9]%/{print $(NF-1)" | "$(NF-2)}') + +# install date +if [[ -e /var/log/pacman.log ]]; then + INST="$(head -n1 /var/log/pacman.log)" + INST="${INST/ */}" + INST="${INST/\[/}" + INST="${INST//\-/ }" + INST="${INST/\]/}" + INST="${INST/\T/ }" +fi + +# check if root user +[[ $(whoami) != 'root' ]] && USR="${FG4}${USER}" || USR="${FG1}root" + +# login shell +SHLL="$(basename $SHELL)" + +# terminal name +TRM="${TERM/-256color/}" + +# hostname +HOST="${HOST:-$(hostname)}" + +# kernel version +KERN="${KERN:-$(uname -r)}" +KERN="${KERN/-*/}" + +# MEM = used / total +FREE="$(free --mega)" +MB=$(awk 'NR==2 {print $3}' <<< "$FREE") +GB=$(awk 'NR==2 {print $3 / 1000}' <<< "$FREE") +TOT=$(awk 'NR==2 {print $2 / 1000}' <<< "$FREE") +(( MB > 1000 )) && MEM="${GB:0:5}gb / ${TOT/\.*}gb" || MEM="${MB}mb / ${TOT/\.*}gb" + +# C = number of cores +C=$(grep -c "^processor" /proc/cpuinfo) +C=${C:-$(grep -c "^core" /proc/cpuinfo)} +C=${C:-1} + +# CPU = usage / cores +CPU=$(ps aux | awk 'BEGIN {sum = 0} {sum += $3}; END {print sum}') +CPU=${CPU/\.*} + +# wtr +# WTR=$(curl wttr.in?format=1) + +# art +# ART=$(curl -L git.io/unix) +# ART=$(curl -L git.io/coffee) + +# For multi core/thread, CPU needs to be divided by # of cores for average +(( C > 1 )) && CPU=$((CPU / C)) +(( CPU > 100 )) && CPU="$C cores @ 100% avg" || CPU="$C cores @ $CPU% avg" + +rep_char() { + local str char num + char="${1:-=}" + num="${2:-$((${#USR} + 6 + ${#HOST}))}" + str="$(printf "%${num}s")" + echo "${str// /$char}" +} + +pkg_cnt() { + pacman -Qq 2>/dev/null | wc -l +} + +cur_wm() { + if [[ $DISPLAY && ! $WM ]]; then + ID="$(xprop -root -notype _NET_SUPPORTING_WM_CHECK)" + WM="$(xprop -id ${ID##* } -notype -len 100 -f _NET_WM_NAME 8t)" + WM=${WM/*WM_NAME = } WM=${WM/\"} WM=${WM/\"*} WM=${WM,,} + echo "${WM:-$FB}" + else + echo "${WM:-tty$XDG_VTNR}" + fi +} + +clear + + # ${ART} + + # ${FG6}->$FG uptime$FG1: ${FG4}${UPT:-$FB} + # ${FG6}->$FG cpu$FG1: ${FG4}${CPU:-$FB} + # ${FG6}->$FG wtr$FG1: ${FG4}${WTR:-$FB} +cat <<- EOF + + ${FG5}===$FG ${USR}${FG2}@${FG6}${HOST:-$FB} + ${FG5}$(rep_char '=') + ${FG6}->$FG install$FG1: ${FG4}${INST:-$FB} + ${FG6}->$FG distro$FG1: ${FG4}${DIST:-$FB} + ${FG6}->$FG kernel$FG1: ${FG4}${KERN:-$FB} + ${FG6}->$FG shell$FG1: ${FG4}${SHLL:-$FB} + ${FG6}->$FG pkgs$FG1: ${FG4}$(pkg_cnt) + ${FG6}->$FG wm$FG1: ${FG4}$(cur_wm) + ${FG6}->$FG term$FG1: ${FG4}${TRM:-$FB} + ${FG6}->$FG /$FG1: ${FG4}${ROOT:-$FB} + ${FG6}->$FG /home$FG1: ${FG4}${HOME:-$FB} + ${FG6}->$FG /m/files$FG1: ${FG4}${FILES:-$FB} + ${FG6}->$FG ram$FG1: ${FG4}${MEM:-$FB} + + ${FG1}████${FG2}████${FG3}████${FG4}████${FG5}████${FG6}████${FG7}████${FG} + +EOF diff --git a/.bin/findapp b/.bin/findapp new file mode 100755 index 0000000..86f12a1 --- /dev/null +++ b/.bin/findapp @@ -0,0 +1,26 @@ +#!/bin/bash +WMCTRL=`which wmctrl`; +GREP=`which grep`; +APPLICATION=$1; +BASENAME=`basename $APPLICATION | tr "[:upper:]" "[:lower:]"` +FOUND=0; + +function findwindow { + IFS=$'\n'; + MAX_MATCHES=0; + for RUNNING in `$2 -l -x | awk '{print $1, $3}' | tac`; do + MATCH_COUNT=`echo $RUNNING | tr "[:upper:]" "[:lower:]" | $3 -o $1 | wc -l` + if [ $MATCH_COUNT -gt $MAX_MATCHES ]; then + MAX_MATCHES=$MATCH_COUNT + WINDOW_ID=`echo $RUNNING | cut -c1-11` + FOUND=1; + fi; + done +} + +findwindow $BASENAME $WMCTRL $GREP; +if [ $FOUND -eq 0 ]; then + $APPLICATION & +else + $WMCTRL -i -a $WINDOW_ID +fi \ No newline at end of file diff --git a/.bin/finder.sh b/.bin/finder.sh new file mode 100755 index 0000000..7f1cfc4 --- /dev/null +++ b/.bin/finder.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +#PUT THIS FILE IN ~/.local/share/rofi/finder.sh +#USE: rofi -show find -modi find:~/.local/share/rofi/finder.sh +if [ ! -z "$@" ] +then + QUERY=$@ + if [[ "$@" == /* ]] + then + if [[ "$@" == *\?\? ]] + then + coproc ( exo-open "${QUERY%\/* \?\?}" > /dev/null 2>&1 ) + exec 1>&- + exit; + else + coproc ( exo-open "$@" > /dev/null 2>&1 ) + exec 1>&- + exit; + fi + elif [[ "$@" == \!\!* ]] + then + echo "!!-- Type your search query to find files" + echo "!!-- To seach again type !" + echo "!!-- To seach parent directories type ?" + echo "!!-- You can print this help by typing !!" + elif [[ "$@" == \?* ]] + then + while read -r line; do + echo "$line" \?\? + done <<< $(find / -iname *"${QUERY#\?}"* 2>&1 | grep -v 'Permission denied\|Input/output error') + else + find / -iname *"${QUERY#!}"* 2>&1 | grep -v 'Permission denied\|Input/output error' + fi +else + echo "!!-- Type your search query to find files" + echo "!!-- To seach again type !" + echo "!!-- To seach parent directories type ?" + echo "!!-- You can print this help by typing !!" +fi diff --git a/.bin/flameshot.sh b/.bin/flameshot.sh new file mode 100755 index 0000000..44200b6 --- /dev/null +++ b/.bin/flameshot.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# autor Alex Creio + +SCREEN_DIR=$(xdg-user-dir PICTURES)/screen + +[[ ! -d $SCREEN_DIR ]] && mkdir -p $SCREEN_DIR + +if [ "$1" = "-c" ]; then + flameshot full -c -p $SCREEN_DIR +elif [ "$1" = "-d" ]; then + flameshot full -c -d "$2" -p $SCREEN_DIR +else + flameshot gui +fi diff --git a/.bin/fortune.sh b/.bin/fortune.sh new file mode 100755 index 0000000..fef5fc4 --- /dev/null +++ b/.bin/fortune.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +(sleep 20;notify-send --icon="/usr/share/icons/Papirus/48x48/apps/urxvt.svg" "$(fortune)") \ No newline at end of file diff --git a/.bin/fro.sh b/.bin/fro.sh new file mode 100755 index 0000000..cc35331 --- /dev/null +++ b/.bin/fro.sh @@ -0,0 +1,91 @@ +#!/bin/sh +# +# fro: an xmas ascii banner generator for my bro +# MMXV xero (http://xero.nu) + +usage() { +printf "usage: `basename $0` \n\ + [-n --normal normal] \n\ + [-d --dots dots] \n\ + [-c --color color] \n\ + [-h --help help]\n" +} + +dots() { +cat << FRO + + ......................................... + ......................................... + ........ _________ ...................... + ........ \_ \______ .. ______ ..... + ......... / \ / \ .... + ........ / ___ / / /\/ _ /\ ... + ....... / / \/ _/ _/ / / / \ .. + ...... / /__ / \ \ / / / / .. + ..... / _ // // // / / / ... + .... / / \// /_ // / / / .... + .. _/ / /_____/ \ / / ..... + .. \___/ /\ /_____/\_____/ / ...... + ... \ /..\___\ \ / ....... + .... \__/ ...... \______/\_____/ ........ + ......................................... + ......................................... + +FRO +} + +normal() { +cat << FRO + _________ + \_ \______ ______ + / \ / \ + / ___ / / /\/ _ /\ + / / \/ _/ _/ / / / \ + / /__ / \ \ / / / / + / _ // // // / / / + / / \// /_ // / / / +_/ / /_____/ \ / / +\___/ /\ /_____/\_____/ / + \ / \___\ \ / + \__/ \______/\_____/ +FRO +} + +color() { +cat << FRO + + ......................................... + ......................................... + ........ _________ ...................... + ........ \_ \______ .. ______ ..... + ......... / \ / \ .... + ........ / ___ / / /\/ _ /\ ... + ....... / / \/ _/ _/ / / / \ .. + ...... / /__ / \ \ / / / / .. + ..... / _ // // // / / / ... + .... / / \// /_ // / / / .... + .. _/ / /_____/ \ / / ..... + .. \___/ /\ /_____/\_____/ / ...... + ... \ /..\___\ \ / ....... + .... \__/ ...... \______/\_____/ ........ + ......................................... + ......................................... + +FRO +} + +case "$1" in + *-d|--dots|dots*) + dots + ;; + *-c|--color|color*) + color + ;; + *-n|--normal|normal) + normal + ;; + *) + normal + usage + ;; +esac diff --git a/.bin/gap b/.bin/gap new file mode 100755 index 0000000..cf661d1 --- /dev/null +++ b/.bin/gap @@ -0,0 +1,8 @@ +#!/bin/bash + +git add . +echo "Write your commit comment! $(date +%d.%m.%Y) Update:" +read input +git commit -a -m "$(date +%d.%m.%Y) Update $input" +git push +echo "Git Push Done!" diff --git a/.bin/gif-soup b/.bin/gif-soup new file mode 100755 index 0000000..1a63198 --- /dev/null +++ b/.bin/gif-soup @@ -0,0 +1,102 @@ +#!/bin/sh +# +# Uses animated files as wallpapers. +# Requires: mpv(1) and convert(1) + +set -e + +: "${_ext=gif}" + +__usage () { + cat << EOH +$0 path +$0 -h + +$0 will use animated files in "path" and use them as looping wallpapers +$0 -h displays this help text + +We look for files ending in $_ext . +You might set \$_ext to change this behavior. +Use SIGUSR1 to use another random wallpaper (might be the same!) +Use SIGUSR2 to generate the file list again +EOH +} + +# parsing options +case "$1" in + -h|help) __usage ; exit 0 ;; + "") __usage >&2 ; exit 1 ;; + *) _path="$1" ;; +esac + +# simple, stupid check +ls "$_path" >/dev/null + +# We work in a temporary dir +_tmp="$(mktemp -dt "$(basename "$0").XXXX")" + +__cleanup () { + [ -d "$_tmp" ] && rm -rf "${_tmp:?}" +} + +trap __cleanup INT TERM + +__create_list () { + # We list the files and store that have the good extension + : > "$_tmp/list" + for _e in $_ext; do + find "$_path" -name '*.'$_e >> "$_tmp/list" + done +} + +__create_list + +trap __create_list USR2 + +__pick_one () { + # We randomly pick one file and return its path + shuf "$_tmp/list" | head -n 1 +} + +__bg () { + # Select bg color: + # convert(1) to extract the single top-left pixel and extract its color + # throughout the .gif; then grep for its only values that are NOT transparent + # and then take the first one + _solid_color="$(convert "$1" -crop 1x1+0+0 -depth 8 txt: | grep -Eo \ + '#[A-F0-9]{6}(FF|)' | sort -u | head -n 1)" + + # Now $_solid_color contains either #RRGGBB or #RRGGBBAA and we need to + # discard the 'AA' part (where AA = FF anyway, because we used grep earlier), + # hence the '%%FF' + _solid_color="${_solid_color%%FF}" + + printf '%s\n' "${_solid_color}" +} + +__run_mpv () { + mpv --border --video-unscaled --background="$2" --wid=0 "$1" --loop-file=inf --speed=1.0 >/dev/null 2>&1 & +} + +__kill () { + kill "$(pgrep -P "$$" "$1")" 2>/dev/null || : +} + +__set_a_wp () { + _gif="$(__pick_one)" + _bg="$(__bg "$_gif")" + __kill mpv + __run_mpv "$_gif" "$_bg" +} + +__set_a_wp + +trap __set_a_wp USR1 +trap '__kill mpv; __cleanup' INT TERM + +mkfifo "$_tmp/fifo" || exit +chmod 600 "$_tmp/fifo" +read < "$_tmp/fifo" 2>/dev/null + +__cleanup + diff --git a/.bin/grel.sh b/.bin/grel.sh new file mode 100755 index 0000000..38c6005 --- /dev/null +++ b/.bin/grel.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +tag_name="v$1" +target_name="$2" +asset_dir="./out" +cr_date=$(date +%Y%m%d) + +assets=() +for f in "$asset_dir"/*; do [ -f "$f" ] && assets+=(-a "$f"); done + +hub release create "${assets[@]}" -m "Release $tag_name $cr_date" -t "$target_name" "$tag_name" diff --git a/.bin/hide.sh b/.bin/hide.sh new file mode 100755 index 0000000..9c925e2 --- /dev/null +++ b/.bin/hide.sh @@ -0,0 +1,686 @@ +#!/usr/bin/env bash +# +# Automagically hide/show a window by its name when the cursor is +# within a defined region or you mouse over it. +# +# This script was initially written to imitate gnome-shell's systray +# but should be generic enough to do other things as well. +# +# Requirements: +# bash, xdotool, xwininfo, xev +# + +# Global variables used throughout the script +WIN_ID="" +WIN_NAME="" +WIN_CLASS="" +WIN_INSTANCE="" +WAIT=1 + +WIN_WIDTH="" +WIN_HEIGHT="" +WIN_POSX="" +WIN_POSY="" + +SCREEN_WIDTH="" +SCREEN_HEIGHT="" + +MINX="" +MINY="" +MAXX="" +MAXY="" + +HOVER=1 +SIGNAL=1 +INTERVAL=1 +PEEK=3 +DIRECTION="left" +STEPS=3 +NO_TRANS=1 +TOGGLE=1 +TOGGLE_PEEK=1 + +_IS_HIDDEN=1 +_DOES_PEEK=0 +_HAS_REGION=1 +_WAIT_PID="" +_PID_FILE="" + + +usage() { + # Print usage + printf "usage: $0 [options]\n" + printf "\n" + printf "Required (At least on):\n" + printf " -N, --name [pattern]\n" + printf " Match against the window name.\n" + printf " This is the same string that is displayed in the window titlebar.\n" + printf "\n" + printf " -C, --class [pattern]\n" + printf " Match against the window class.\n" + printf "\n" + printf " -I, --instance [pattern]\n" + printf " Match against the window instance.\n" + printf "\n" + printf " --id [window-id]\n" + printf " Explicitly specify a window id rather than searching for one.\n" + printf "\n" + printf "Optional:\n" + printf " -w, --wait\n" + printf " Wait until a matching window was found.\n" + printf " This will check once every second.\n" + printf "\n" + printf " -r, --region [posXxposY+offsetX+offsetY]\n" + printf " Cursor region at which to trigger.\n" + printf " Examples:\n" + printf " --region 0x1080+10+-10 (Bottom left incl. a 10 pixel offset)\n" + printf " --region 1920x1080+0+0 (Bottom right without offset)\n" + printf "\n" + printf " -H, --hover\n" + printf " Show the window when hovering over it.\n" + printf " If --region was defined, --hover will be ignored!\n" + printf " This will only work if --peek is greater 0.\n" + printf " By default, hover is off.\n" + printf "\n" + printf " -S, --signal\n" + printf " Toggle the visibility by sending a 'SIGUSR1' signal.\n" + printf " Both --region and --hover will be ignored.\n" + printf "\n" + printf " -i, --interval [interval]\n" + printf " Interval in seconds to check the cursors location.\n" + printf " Defaults to 1.\n" + printf "\n" + printf " -p, --peek [amount]\n" + printf " When hidden, peek 'amount' of pixels to indicate the window.\n" + printf " Required if --hover is used." + printf " Defaults to 3.\n" + printf "\n" + printf " -d, --direction [left|right|top|bottom]\n" + printf " direction in which to move the window.\n" + printf " Defaults to left.\n" + printf "\n" + printf " -s, --steps [amount]\n" + printf " steps in pixel used to move the window. The higher the value,\n" + printf " the faster it will move at the cost of smoothness.\n" + printf " Defaults to 3.\n" + printf "\n" + printf " -T, --no-trans\n" + printf " Turn of the transition effect.\n" + printf "\n" + printf " -t, --toggle\n" + printf " Send a SIGUSR1 signal to the process matching the same window.\n" + printf " This will toggle the visibility of the window." + printf "\n\n" + printf " -P, --toggle-peek\n" + printf " Send a SIGUSR2 signal to the process matching the same window.\n" + printf " This will toggle the hidden state of the window if --peek is greater 0." + printf "\n\n" + printf "Examples:\n" + printf " Dropdown Terminal:\n" + printf " # Start a terminal with a unique name\n" + printf " # (Make sure yourself it is positioned correctly)\n" + printf " $ termite --title=dropdown-terminal &\n" + printf "\n" + printf " # Hide it and wait for a SIGUSR1 signal\n" + printf " $ hideIt.sh --name '^dropdown-terminal$' --direction top --steps 5 --signal\n" + printf "\n" + printf " # Send a SIGUSR1 signal (This could be mapped to a keyboard shortcut)\n" + printf " $ hideIt.sh --name '^dropdown-terminal$' --toggle\n" +} + + +argparse() { + # Parse system args + + while [ $# -gt 0 ]; do + case $1 in + "-N"|"--name") + WIN_NAME="$2" + shift + ;; + "-C"|"--class") + WIN_CLASS="$2" + shift + ;; + "-I"|"--instance") + WIN_INSTANCE="$2" + shift + ;; + "--id") + if [[ ! $2 =~ [0-9]+ ]]; then + printf "Invalid window id. Should be a number.\n" 1>&2 + exit 1 + fi + + WIN_ID="$2" + shift + ;; + "-w"|"--wait") + WAIT=0 + ;; + "-H"|"--hover") + HOVER=0 + ;; + "-S"|"--signal") + SIGNAL=0 + ;; + "-r"|"--region") + local posX posY offsetX offsetY + read posX posY offsetX offsetY <<<$(echo "$2" | \ + sed -rn 's/^([0-9]+)x([0-9]+)\+(-?[0-9]+)\+(-?[0-9]+)/\1 \2 \3 \4/p') + + # Test if we have proper values by trying + # to add them all together + expr $posX + $posY + $offsetX + $offsetY > /dev/null 2>&1 + if [ $? -ne 0 ]; then + printf "Invalid region. See --help for usage.\n" 1>&2 + exit 1 + fi + + MINX=$posX + MAXX=$((${MINX} + ${offsetX})) + if [ $MINX -gt $MAXX ]; then + read MINX MAXX <<< "$MAXX $MINX" + fi + + MINY=$posY + MAXY=$((${MINY} + ${offsetY})) + if [ $MINY -gt $MAXY ]; then + read MINY MAXY <<< "$MAXY $MINY" + fi + + if [[ ! $MINX =~ [0-9]+ ]] || [[ ! $MINY =~ [0-9]+ ]] \ + || [[ ! $MAXY =~ [0-9]+ ]] || [[ ! $MAXY =~ [0-9]+ ]]; then + printf "Missing or invalid region. See --help for usage.\n" 1>&2 + exit 1 + fi + _HAS_REGION=0 + shift + ;; + "-i"|"--interval") + INTERVAL="$2" + if [[ ! $INTERVAL =~ [0-9]+ ]]; then + printf "Interval should be a number. " 1>&2 + exit 1 + fi + shift + ;; + "-p"|"--peek") + PEEK="$2" + if [[ ! $PEEK =~ [0-9]+ ]]; then + printf "Peek should be a number. " 1>&2 + exit 1 + fi + shift + ;; + "-d"|"--direction") + DIRECTION="$2" + if [[ ! "$DIRECTION" =~ ^(left|right|top|bottom)$ ]]; then + printf "Invalid direction. See --help for usage.\n" 1>&2 + exit 1 + fi + shift + ;; + "-s"|"--steps") + STEPS="$2" + if [[ ! $STEPS =~ [0-9]+ ]]; then + printf "Steps should be a number. " 1>&2 + exit 1 + fi + shift + ;; + "-T"|"--no-trans") + NO_TRANS=0 + ;; + "-t"|"--toggle") + TOGGLE=0 + ;; + "-P"|"--toggle-peek") + TOGGLE_PEEK=0 + ;; + "-h"|"--help") + usage + exit 0 + ;; + **) + printf "Didn't understand '$1'\n" 1>&2 + printf "See --help for usage.\n" + exit 1 + ;; + esac + shift + done + + # Check required arguments + local _names="${WIN_ID}${WIN_NAME}${WIN_CLASS}${WIN_INSTANCE}" + if [ -z "$_names" ] && [ -z "$WIN_ID" ]; then + printf "At least one of --name, --class, --instance or --id" 1>&2 + printf " is required!\n" 1>&2 + exit 1 + fi + + if [ $TOGGLE -ne 0 ] && [ $TOGGLE_PEEK -ne 0 ] && [ $SIGNAL -ne 0 ] \ + && [ $_HAS_REGION -ne 0 ] && [ $HOVER -ne 0 ]; then + printf "At least one of --toggle, --signal, --hover or" 1>&2 + printf " --region is required!\n" 1>&2 + exit 1 + fi +} + + +function fetch_window_id() { + # Sets the values for the following global + # WIN_ID + + # We already have a window id + if [ ! -z "$WIN_ID" ]; then + _PID_FILE="/tmp/hideIt-${WIN_ID}.pid" + return + fi + + local _id=-1 + + # Search all windows matching the provided class + local _tmp1=() + if [ ! -z "$WIN_CLASS" ]; then + _tmp1=($(xdotool search --class "$WIN_CLASS")) + _tmp1=${_tmp1:--1} + fi + + # Search all windows matching the provided instance + local _tmp2=() + if [ ! -z "$WIN_INSTANCE" ]; then + _tmp2=($(xdotool search --classname "$WIN_INSTANCE")) + _tmp2=${_tmp2:--1} + fi + + # Search all windows matching the provided name (title) + local _tmp3=() + if [ ! -z "$WIN_NAME" ]; then + _tmp3=($(xdotool search --name "$WIN_NAME")) + _tmp3=${_tmp3:--1} + fi + + # Shift values upwards + for i in {1..2}; do + if [ -z $_tmp1 ]; then + _tmp1=(${_tmp2[@]}) + _tmp2=() + fi + + if [ -z $_tmp2 ]; then + _tmp2=(${_tmp3[@]}) + _tmp3=() + fi + done + + if [ -z $_tmp2 ]; then + # We only have one list of ids so we pick the first one from it + _id=${_tmp1[0]} + else + # We have multiple lists so we have to find the id that appears + # in all of them + local _oldIFS=$IFS + IFS=$'\n\t' + + local _ids=($(comm -12 \ + <(echo "${_tmp1[*]}" | sort) \ + <(echo "${_tmp2[*]}" | sort))) + + if [ ! -z $_tmp3 ]; then + _ids=($(comm -12 \ + <(echo "${_tmp3[*]}" | sort) \ + <(echo "${_ids[*]}" | sort))) + fi + IFS=$_oldIFS + + _id=${_ids[0]} + fi + + if [[ $_id =~ [0-9]+ ]] && [ $_id -gt 0 ]; then + WIN_ID=$_id + _PID_FILE="/tmp/hideIt-${WIN_ID}.pid" + fi +} + + +function fetch_screen_dimensions() { + # Sets the values for the following globals + # SCREEN_WIDTH, SCREEN_HEIGHT + + local win_info=$(xwininfo -root) + SCREEN_WIDTH=$(echo "$win_info" | sed -rn 's/.*Width: +([0-9]+)/\1/p') + SCREEN_HEIGHT=$(echo "$win_info" | sed -rn 's/.*Height: +([0-9]+)/\1/p') +} + + +function fetch_window_dimensions() { + # Sets the values for the following globals unless no WIN_ID exists + # WIN_WIDTH, WIN_HEIGHT, WIN_POSX, WIN_POSY + + if [[ ! $WIN_ID =~ [0-9]+ ]]; then + return + fi + + local win_info=$(xwininfo -id $WIN_ID) + + WIN_WIDTH=$(echo "$win_info" | sed -rn 's/.*Width: +([0-9]+)/\1/p') + WIN_HEIGHT=$(echo "$win_info" | sed -rn 's/.*Height: +([0-9]+)/\1/p') + + if [ ! -z "$1" ] && [ $1 -eq 0 ]; then + WIN_POSX=$(echo "$win_info" | \ + sed -rn 's/.*Absolute upper-left X: +(-?[0-9]+)/\1/p') + WIN_POSY=$(echo "$win_info" | \ + sed -rn 's/.*Absolute upper-left Y: +(-?[0-9]+)/\1/p') + fi +} + + +function send_signal() { + # Send a SIGUSR1 to an active hideIt.sh instance + # if a pid file was found. + local signal=$1 + if [ ! -f "$_PID_FILE" ]; then + printf "Pid file at \"${_PID_FILE}\" doesn't exist!\n" 1>&2 + exit 1 + fi + + local _pid=`cat $_PID_FILE` + printf "Sending ${signal} to instance...\n" + + if [[ $_pid =~ [0-9]+ ]]; then + kill -${signal} $_pid + exit 0 + else + printf "Invalid pid in \"${_PID_FILE}\".\n" 1>&2 + exit 1 + fi +} + + +function hide_window() { + # Move the window in or out + # Args: + # hide: 0 to hide, 1 to show + + local hide=$1 + + # Make sure window still exists and exit if not. + xwininfo -id $WIN_ID &> /dev/null + if [ $? -ne 0 ]; then + printf "Window doesn't exist anymore, exiting!\n" + exit 0 + fi + + _IS_HIDDEN=$hide + + # Update WIN_WIDTH, WIN_HEIGHT in case they changed + fetch_window_dimensions + + # Activate the window. + # Should bring it to the front, change workspace etc. + if [ $hide -ne 0 ]; then + xdotool windowactivate $WIN_ID > /dev/null 2>&1 + fi + + # Generate the sequence used to move the window + local to=() + local sequence=() + if [ "$DIRECTION" == "left" ]; then + to=-$(($WIN_WIDTH - $PEEK)) + if [ $hide -eq 0 ]; then + sequence=($(seq $WIN_POSX -$STEPS $to)) + sequence+=($to) + else + sequence=($(seq $to $STEPS $WIN_POSX)) + sequence+=($WIN_POSX) + fi + + elif [ "$DIRECTION" == "right" ]; then + to=$(($SCREEN_WIDTH - $PEEK)) + if [ $hide -eq 0 ]; then + sequence=($(seq $WIN_POSX $STEPS $to)) + sequence+=($to) + else + sequence=($(seq $to -$STEPS $WIN_POSX)) + sequence+=($WIN_POSX) + fi + + elif [ "$DIRECTION" == "bottom" ]; then + to=$(($SCREEN_HEIGHT - $PEEK)) + if [ $hide -eq 0 ]; then + sequence=($(seq $WIN_POSY $STEPS $to)) + sequence+=($to) + else + sequence=($(seq $to -$STEPS $WIN_POSY)) + sequence+=($WIN_POSY) + fi + + elif [ "$DIRECTION" == "top" ]; then + to=-$(($WIN_HEIGHT - $PEEK)) + if [ $hide -eq 0 ]; then + sequence=($(seq $WIN_POSY -$STEPS $to)) + sequence+=($to) + else + sequence=($(seq $to $STEPS $WIN_POSY)) + sequence+=($WIN_POSY) + fi + fi + + # Actually move the window + if [ $NO_TRANS -ne 0 ]; then + for pos in ${sequence[@]}; do + if [[ "$DIRECTION" =~ ^(left|right)$ ]]; then + xdotool windowmove $WIN_ID $pos $WIN_POSY + elif [[ "$DIRECTION" =~ ^(top|bottom)$ ]]; then + xdotool windowmove $WIN_ID $WIN_POSX $pos + fi + done + else + pos=${sequence[-1]} + if [[ "$DIRECTION" =~ ^(left|right)$ ]]; then + xdotool windowmove $WIN_ID $pos $WIN_POSY + elif [[ "$DIRECTION" =~ ^(top|bottom)$ ]]; then + xdotool windowmove $WIN_ID $WIN_POSX $pos + fi + fi + + # In case we hid the window, try to give focus to whatever is + # underneath the cursor. + if [ $hide -eq 0 ]; then + eval $(xdotool getmouselocation --shell) + xdotool windowactivate $WINDOW > /dev/null 2>&1 + fi +} + + +function toggle() { + # Toggle the hidden state of the window + + if [ $_IS_HIDDEN -eq 0 ]; then + hide_window 1 + else + hide_window 0 + fi +} + +function toggle_peek() { + # Completely hide/unhide the window in case PEEK is greater 0 + + if [ $PEEK -eq 0 ]; then + return + fi + + local _peek=$PEEK + local _win_posx=$WIN_POSX + local _win_posy=$WIN_POSY + + fetch_window_dimensions 0 + + if [ $_DOES_PEEK -eq 0 ]; then + _DOES_PEEK=1 + PEEK=0 + else + _DOES_PEEK=0 + fi + + hide_window 0 + + PEEK=$_peek + WIN_POSX=$_win_posx + WIN_POSY=$_win_posy +} + +function serve_region() { + # Check the cursors location and act accordingly + + local _hide=0 + while true; do + if [ $_DOES_PEEK -eq 0 ]; then + # Get cursor x, y position and active window + eval $(xdotool getmouselocation --shell) + + # Test if the cursor is within the region + if [ $X -ge $MINX -a $X -le $MAXX ] \ + && [ $Y -ge $MINY -a $Y -le $MAXY ]; then + _hide=1 + else + _hide=0 + fi + + # Don't hide if the cursor is still above the window + if [ $_IS_HIDDEN -ne 0 ] \ + && [ $_hide -eq 0 ] \ + && [ $WINDOW -eq $WIN_ID ]; then + _hide=1 + fi + + # Only do something if necessary + if [ $_IS_HIDDEN -ne $_hide ]; then + hide_window $_hide + fi + fi + + # Cut some slack + sleep $INTERVAL + done +} + + +function serve_xev() { + # Wait for cursor "Enter" and "Leave" events reported by + # xev and act accordingly + + xev -id $WIN_ID -event mouse | while read line; do + if [[ "$line" =~ ^EnterNotify.* ]]; then + hide_window 1 + elif [[ "$line" =~ ^LeaveNotify.* ]]; then + hide_window 0 + fi + done +} + + +function restore() { + # Called by trap once we receive an EXIT + + if [ -n "$_WAIT_PID" ]; then + kill -- "-${_WAIT_PID}" + fi + + if [ -f "$_PID_FILE" ]; then + rm "$_PID_FILE" + fi + + if [ $_IS_HIDDEN -eq 0 ]; then + printf "Restoring original window position...\n" + hide_window 1 + fi + + exit 0 +} + + +function main() { + # Entry point for hideIt + + # Parse all the args! + argparse "$@" + + printf "Searching window...\n" + fetch_window_id + + # If enabled, wait until a window was found. + if [ $WAIT -eq 0 ] && [[ ! $WIN_ID =~ [0-9]+ ]]; then + printf "Waiting for window" + while [[ ! $WIN_ID =~ [0-9]+ ]]; do + printf "." + fetch_window_id + sleep 1 + done + printf "\n" + fi + + if [[ ! $WIN_ID =~ [0-9]+ ]]; then + printf "No window found!\n" 1>&2 + exit 1 + else + printf "Found window with id: $WIN_ID\n" + fi + + if [ $TOGGLE -eq 0 ]; then + send_signal SIGUSR1 + exit 0 + fi + + if [ $TOGGLE_PEEK -eq 0 ]; then + send_signal SIGUSR2 + exit 0 + fi + + printf "Fetching window dimensions...\n" + fetch_window_dimensions 0 + + printf "Fetching screen dimensions...\n" + fetch_screen_dimensions + + trap restore EXIT + + printf "Initially hiding window...\n" + hide_window 0 + + # Save our pid into a file + echo "$$" > /tmp/hideIt-${WIN_ID}.pid + trap toggle_peek SIGUSR2 + + # Start observing + if [ $_HAS_REGION -eq 0 ]; then + printf "Defined region:\n" + printf " X: $MINX $MAXX\n" + printf " Y: $MINY $MAXY\n" + printf "\n" + printf "Waiting for region...\n" + serve_region & + _WAIT_PID=$! + elif [ $SIGNAL -eq 0 ]; then + printf "Waiting for SIGUSR1...\n" + trap toggle SIGUSR1 + sleep infinity & + _WAIT_PID=$! + elif [ $HOVER -eq 0 ]; then + printf "Waiting for HOVER...\n" + serve_xev & + _WAIT_PID=$! + fi + + if [ -n "$_WAIT_PID" ]; then + while true; do + wait "$_WAIT_PID" + printf "Received signal...\n" + done + fi +} + +# Lets do disss! +set -m +main "$@" diff --git a/.bin/i3-logout b/.bin/i3-logout new file mode 100755 index 0000000..9c73803 --- /dev/null +++ b/.bin/i3-logout @@ -0,0 +1,26 @@ +#!/bin/sh + +DIALOG_RESULT=$(echo -e 'exit i3\nsuspend\nhibernate\nreboot\npoweroff\nexit' | rofi -dmenu -i -p "[SYSTEM]" -hide-scrollbar -tokenize -lines 6 -eh 1 -width 25 -location 0 -xoffset 0 -yoffset 0 -padding 20 -disable-history -font "ClearSansMedium 14") + +echo "This result is : $DIALOG_RESULT" +sleep 1; + +if [ "$DIALOG_RESULT" = "exit i3" ]; +then + i3-msg 'exit' +elif [ "$DIALOG_RESULT" = "suspend" ]; +then + exec systemctl suspend +elif [ "$DIALOG_RESULT" = "hibernate" ]; +then + exec systemctl hibernate +elif [ "$DIALOG_RESULT" = "reboot" ]; +then + exec systemctl reboot +elif [ "$DIALOG_RESULT" = "poweroff" ]; +then + exec systemctl poweroff +elif [ "$DIALOG_RESULT" = "exit" ]; +then + exit 0 +fi \ No newline at end of file diff --git a/.bin/i3_empty_workspace.sh b/.bin/i3_empty_workspace.sh new file mode 100755 index 0000000..b4c28dc --- /dev/null +++ b/.bin/i3_empty_workspace.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +MAX_DESKTOPS=20 + +WORKSPACES=$(seq -s '\n' 1 1 ${MAX_DESKTOPS}) + +EMPTY_WORKSPACE=$( (i3-msg -t get_workspaces | tr ',' '\n' | grep num | awk -F: '{print int($2)}' ; \ + echo -e ${WORKSPACES} ) | sort -n | uniq -u | head -n 1) + +i3-msg workspace ${EMPTY_WORKSPACE} diff --git a/.bin/i3_switch_workspace.sh b/.bin/i3_switch_workspace.sh new file mode 100755 index 0000000..5f27aa2 --- /dev/null +++ b/.bin/i3_switch_workspace.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +function gen_workspaces() +{ + i3-msg -t get_workspaces | tr ',' '\n' | grep "name" | sed 's/"name":"\(.*\)"/\1/g' | sort -n +} + + +WORKSPACE=$( (echo Hiden; gen_workspaces) | rofi -dmenu -p "Select workspace") + +if [ x"Hiden" = x"${WORKSPACE}" ] +then + $HOME/.bin/i3_empty_workspace.sh +elif [ -n "${WORKSPACE}" ] +then + i3-msg workspace "${WORKSPACE}" +fi diff --git a/.bin/init-repo.sh b/.bin/init-repo.sh new file mode 100755 index 0000000..f32dc27 --- /dev/null +++ b/.bin/init-repo.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Create and configure repository +git init --bare $HOME/.dots || return 1 +dots config --local status.showUntrackedFiles no + +# Create gitignore and initial commit +echo .dots >> $HOME/.gitignore +dots add $HOME/.gitignore +dots commit -m "Initialize dotfiles repo" \ No newline at end of file diff --git a/.bin/kunst b/.bin/kunst new file mode 100755 index 0000000..0e2446a --- /dev/null +++ b/.bin/kunst @@ -0,0 +1,248 @@ +#!/usr/bin/env bash +# ┬┌─┬ ┬┌┐┌┌─┐┌┬┐ +# ├┴┐│ ││││└─┐ │ +# ┴ ┴└─┘┘└┘└─┘ ┴ +# Created by Siddharth Dushantha +# +# Dependencies: sxiv, imagemagick, bash, ffmpeg, mpc, jq + + +VERSION=1.2.3 +COVER=/tmp/kunst.png +MUSIC_DIR=~/Music/ +SIZE=250x250 +X=50 +Y=50 + + +show_help() { + echo "usage: kunst [-h] [--size "px"] [--music_dir "path/to/dir"] [--silent] [--version]" + echo " " + echo "┬┌─┬ ┬┌┐┌┌─┐┌┬┐" + echo "├┴┐│ ││││└─┐ │" + echo "┴ ┴└─┘┘└┘└─┘ ┴" + echo "Download and display album art or display embedded album art" + echo " " + echo "optional arguments:" + echo " -h, --help show this help message and exit" + echo " --size what size to display the album art in" + echo " --x X" + echo " --y Y" + echo " --music_dir the music directory which MPD plays from" + echo " --silent dont show the output" + echo " --version show the version of kunst you are using" +} + + +# Parse the arguments +options=$(getopt -o h --long size:,x:,y:,music_dir:,version,silent,help -- "$@") +eval set -- "$options" + +while true; do + case "$1" in + --size) + shift; + SIZE=$1 + ;; + --x) + shift; + X=$1 + ;; + --y) + shift; + Y=$1 + ;; + --music_dir) + shift; + MUSIC_DIR=$1 + ;; + -h|--help) + show_help + exit + ;; + --version) + echo $VERSION + exit + ;; + --silent) + SILENT=true + ;; + --) + shift + break + ;; + esac + shift +done + +# This is a base64 endcoded image which will be used if +# the file does not have an emmbeded album art. +# The image is an image of a music note +read -d '' MUSIC_NOTE << EOF +iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAJESURBVGhD7Zg/axRRFMVXAtpYphEVREKClnHfJI0MmReSfAC3tRejhaBgo70fwN7aD2BvEU0gfztbu5AqMxNjoVnvG87KZXy7z5m5dxLI/OCw8Pade+7M3n3Dbq+jo6OjY8RwMJhKk+hhlph3eRJ9w/LF5jCOr1PTj6jpD7mNjkjDkbDl4vFjpX87teZJlkSfSD9501zYfv5QJ1fyZHGexuJtZs12ZqMzX8NlwX4+nK3NXMutWaOm39Nd/u5rMCSUao80fjBNwY+p8Y+krNxQVaGsLsfWzFLYS2r4M30Rf5WbaCJE6OILlhIidPEFSwkRuviCpYQIXXzB1WX26bR6ky4v3OPriNCFB1YRHa079Pr6eKk/h1IFfA+WdOGBk+QeXtT0Ft3pV6e2fxf2f+AeLOnCA8tC0xv09H1xGi/cgWUi3I8lXXigEzX8u3gmWPP8JI5uYdt/w2thSRceSM0/zVfnb+CtWvB6WNJFOlC6XhDpQOl6QaQDpesFkQ6UrhdEOlC6XpA6gcPB/avumKXnxCadXHkha766tTr1GlE18CRZvEmN7nHfOMGiS5XA4mdmYg64Z5Jg06VKYHlEQoKtOVIz6zx8f0iwNUNyZt2F+3zjBFt9pGe22gWYFLb6lEckJNjGUmWEssR8ga0+0jNL9Z75fD7Rp7UOW32kZxb/1u37vFyUu+sODtjqozGzxaFADfprFM3vuD3Y3gytmf17LJPHXbgTNb5BWhe58yNan1lpWp9ZDVqdWS1am9mOjo7LRq/3B1ESKyYUVquzAAAAAElFTkSuQmCC +EOF + + +is_connected() { + # Check if internet is connected. We are using api.deezer.com to test + # if the internet is connected because if api.deezer.com is down or + # the internet is not connected this script will work as expected + if ping -q -c 1 -W 1 api.deezer.com >/dev/null; then + connected=true + else + if [ ! $SILENT ];then + echo "kunst: unable to check online for the album art" + fi + connected=false + fi +} + + +get_cover_online() { + # Check if connected to internet + is_connected + + if [ $connected == false ];then + ARTLESS=true + return + fi + + # Try to get the album cover online from api.deezer.com + API_URL="http://api.deezer.com/search/autocomplete?q=$(mpc current)" && API_URL=${API_URL//' '/'%20'} + + # Extract the albumcover from the json returned + IMG_URL=$(curl -s "$API_URL" | jq -r '.playlists.data[0] | .picture_big') + + if [ "$IMG_URL" = '' ] || [ "$IMG_URL" = 'null' ];then + if [ ! $SILENT ];then + echo "error: cover not found online" + fi + ARTLESS=true + else + if [ ! $SILENT ];then + echo "kunst: cover found online" + fi + curl -o $COVER -s $IMG_URL + ARTLESS=false + fi + +} + + +update_cover() { + # Extract the album art from the mp3 file and dont show the messsy + # output of ffmpeg + ffmpeg -i "$MUSIC_DIR$(mpc current -f %file%)" $COVER -y &> /dev/null + + # Get the status of the previous command + STATUS=$? + + killall n30f + + # Check if the file has a embbeded album art + if [ $STATUS -eq 0 ];then + if [ ! $SILENT ];then + echo "kunst: extracted album art" + fi + ARTLESS=false + else + DIR="$MUSIC_DIR$(dirname "$(mpc current -f %file%)")" + if [ ! $SILENT ];then + echo "kunst: inspecting $DIR" + fi + + # Check if there is an album cover/art in the folder. + # Look at issue #9 for more details + for CANDIDATE in "$DIR/cover."{png,jpg}; do + if [ -f "$CANDIDATE" ]; then + STATUS=0 + ARTLESS=false + convert "$CANDIDATE" $COVER + if [ ! $SILENT ];then + echo "kunst: found cover.png" + fi + fi + done + fi + + if [ $STATUS -ne 0 ];then + if [ ! $SILENT ];then + echo "error: file does not have an album art" + fi + get_cover_online + fi + + # Resize the image to 250x250 + if [ $ARTLESS == false ]; then + convert $COVER -resize $SIZE $COVER + if [ ! $SILENT ];then + echo "kunst: resized album art to $SIZE" + fi + fi + +} + +pre_exit() { + # Get the proccess ID of kunst and kill it. + # We are dumping the output of kill to /dev/null + # because if the user quits sxiv before they + # exit kunst, an error will be shown + # from kill and we dont want that + kill -9 $(cat /tmp/kunst.pid) &> /dev/null +} + +main() { + + # Flag to run some commands only once in the loop + FIRST_RUN=true + + while true; do + + update_cover + notify-send "Now Playing ♫" "$(mpc current)" & + n30f -x $X -y $Y $COVER -t Kunst -c "killall n30f" & + + if [ $ARTLESS == true ];then + # Dhange the path to COVER because the music note + # image is a png not jpg + COVER=/tmp/kunst.png + + # Decode the base64 encoded image and save it + # to /tmp/kunst.png + echo "$MUSIC_NOTE" | base64 --decode > $COVER + fi + + if [ ! $SILENT ];then + echo "kunst: swapped album art to $(mpc current)" + printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - + fi + + if [ $FIRST_RUN == true ]; then + FIRST_RUN=false + + # Display the album art using sxiv + # sxiv -g $SIZE -b $COVER -N "Kunst" & + + notify-send "Now Playing ♫" "$(mpc current)" & + n30f -x $X -y $Y $COVER -t Kunst -c "killall n30f" & + # Save the process ID so that we can kill + # sxiv when the user exits the script + echo $! >/tmp/kunst.pid + fi + + # Waiting for an event from mpd; play/pause/next/previous + # this is lets kunst use less CPU :) + mpc idle &> /dev/null + if [ ! $SILENT ];then + echo "kunst: received event from mpd" + fi + done +} + +# Disable CTRL-Z because if we allowed this key press, +# then the script would exit but, sxiv would still be +# running +trap "" SIGTSTP + +trap pre_exit EXIT +main diff --git a/.bin/kunst.sh b/.bin/kunst.sh new file mode 100755 index 0000000..4303657 --- /dev/null +++ b/.bin/kunst.sh @@ -0,0 +1,248 @@ +#!/usr/bin/env bash +# ┬┌─┬ ┬┌┐┌┌─┐┌┬┐ +# ├┴┐│ ││││└─┐ │ +# ┴ ┴└─┘┘└┘└─┘ ┴ +# Created by Siddharth Dushantha +# +# Dependencies: sxiv, imagemagick, bash, ffmpeg, mpc, jq + + +VERSION=1.2.3 +COVER=/tmp/kunst.png +MUSIC_DIR=~/Music/ +SIZE=250x250 +X=50 +Y=50 + + +show_help() { + echo "usage: kunst [-h] [--size "px"] [--music_dir "path/to/dir"] [--silent] [--version]" + echo " " + echo "┬┌─┬ ┬┌┐┌┌─┐┌┬┐" + echo "├┴┐│ ││││└─┐ │" + echo "┴ ┴└─┘┘└┘└─┘ ┴" + echo "Download and display album art or display embedded album art" + echo " " + echo "optional arguments:" + echo " -h, --help show this help message and exit" + echo " --size what size to display the album art in" + echo " --x X" + echo " --y Y" + echo " --music_dir the music directory which MPD plays from" + echo " --silent dont show the output" + echo " --version show the version of kunst you are using" +} + + +# Parse the arguments +options=$(getopt -o h --long size:,x:,y:,music_dir:,version,silent,help -- "$@") +eval set -- "$options" + +while true; do + case "$1" in + --size) + shift; + SIZE=$1 + ;; + --x) + shift; + X=$1 + ;; + --y) + shift; + Y=$1 + ;; + --music_dir) + shift; + MUSIC_DIR=$1 + ;; + -h|--help) + show_help + exit + ;; + --version) + echo $VERSION + exit + ;; + --silent) + SILENT=true + ;; + --) + shift + break + ;; + esac + shift +done + +# This is a base64 endcoded image which will be used if +# the file does not have an emmbeded album art. +# The image is an image of a music note +read -d '' MUSIC_NOTE << EOF +iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAJESURBVGhD7Zg/axRRFMVXAtpYphEVREKClnHfJI0MmReSfAC3tRejhaBgo70fwN7aD2BvEU0gfztbu5AqMxNjoVnvG87KZXy7z5m5dxLI/OCw8Pade+7M3n3Dbq+jo6OjY8RwMJhKk+hhlph3eRJ9w/LF5jCOr1PTj6jpD7mNjkjDkbDl4vFjpX87teZJlkSfSD9501zYfv5QJ1fyZHGexuJtZs12ZqMzX8NlwX4+nK3NXMutWaOm39Nd/u5rMCSUao80fjBNwY+p8Y+krNxQVaGsLsfWzFLYS2r4M30Rf5WbaCJE6OILlhIidPEFSwkRuviCpYQIXXzB1WX26bR6ky4v3OPriNCFB1YRHa079Pr6eKk/h1IFfA+WdOGBk+QeXtT0Ft3pV6e2fxf2f+AeLOnCA8tC0xv09H1xGi/cgWUi3I8lXXigEzX8u3gmWPP8JI5uYdt/w2thSRceSM0/zVfnb+CtWvB6WNJFOlC6XhDpQOl6QaQDpesFkQ6UrhdEOlC6XpA6gcPB/avumKXnxCadXHkha766tTr1GlE18CRZvEmN7nHfOMGiS5XA4mdmYg64Z5Jg06VKYHlEQoKtOVIz6zx8f0iwNUNyZt2F+3zjBFt9pGe22gWYFLb6lEckJNjGUmWEssR8ga0+0jNL9Z75fD7Rp7UOW32kZxb/1u37vFyUu+sODtjqozGzxaFADfprFM3vuD3Y3gytmf17LJPHXbgTNb5BWhe58yNan1lpWp9ZDVqdWS1am9mOjo7LRq/3B1ESKyYUVquzAAAAAElFTkSuQmCC +EOF + + +is_connected() { + # Check if internet is connected. We are using api.deezer.com to test + # if the internet is connected because if api.deezer.com is down or + # the internet is not connected this script will work as expected + if ping -q -c 1 -W 1 api.deezer.com >/dev/null; then + connected=true + else + if [ ! $SILENT ];then + echo "kunst: unable to check online for the album art" + fi + connected=false + fi +} + + +get_cover_online() { + # Check if connected to internet + is_connected + + if [ $connected == false ];then + ARTLESS=true + return + fi + + # Try to get the album cover online from api.deezer.com + API_URL="http://api.deezer.com/search/autocomplete?q=$(mpc current)" && API_URL=${API_URL//' '/'%20'} + + # Extract the albumcover from the json returned + IMG_URL=$(curl -s "$API_URL" | jq -r '.playlists.data[0] | .picture_big') + + if [ "$IMG_URL" = '' ] || [ "$IMG_URL" = 'null' ];then + if [ ! $SILENT ];then + echo "error: cover not found online" + fi + ARTLESS=true + else + if [ ! $SILENT ];then + echo "kunst: cover found online" + fi + curl -o $COVER -s $IMG_URL + ARTLESS=false + fi + +} + + +update_cover() { + # Extract the album art from the mp3 file and dont show the messsy + # output of ffmpeg + ffmpeg -i "$MUSIC_DIR$(mpc current -f %file%)" $COVER -y &> /dev/null + + # Get the status of the previous command + STATUS=$? + + # killall n30f + + # Check if the file has a embbeded album art + if [ $STATUS -eq 0 ];then + if [ ! $SILENT ];then + echo "kunst: extracted album art" + fi + ARTLESS=false + else + DIR="$MUSIC_DIR$(dirname "$(mpc current -f %file%)")" + if [ ! $SILENT ];then + echo "kunst: inspecting $DIR" + fi + + # Check if there is an album cover/art in the folder. + # Look at issue #9 for more details + for CANDIDATE in "$DIR/cover."{png,jpg}; do + if [ -f "$CANDIDATE" ]; then + STATUS=0 + ARTLESS=false + convert "$CANDIDATE" $COVER + if [ ! $SILENT ];then + echo "kunst: found cover.png" + fi + fi + done + fi + + if [ $STATUS -ne 0 ];then + if [ ! $SILENT ];then + echo "error: file does not have an album art" + fi + get_cover_online + fi + + # Resize the image to 250x250 + if [ $ARTLESS == false ]; then + convert $COVER -resize $SIZE $COVER + if [ ! $SILENT ];then + echo "kunst: resized album art to $SIZE" + fi + fi + +} + +pre_exit() { + # Get the proccess ID of kunst and kill it. + # We are dumping the output of kill to /dev/null + # because if the user quits sxiv before they + # exit kunst, an error will be shown + # from kill and we dont want that + kill -9 $(cat /tmp/kunst.pid) &> /dev/null +} + +main() { + + # Flag to run some commands only once in the loop + FIRST_RUN=true + + while true; do + + update_cover + # notify-send "Now Playing ♫" "$(mpc current)" & + n30f -x $X -y $Y $COVER -t Kunst -c "killall n30f" & + + if [ $ARTLESS == true ];then + # Dhange the path to COVER because the music note + # image is a png not jpg + COVER=/tmp/kunst.png + + # Decode the base64 encoded image and save it + # to /tmp/kunst.png + echo "$MUSIC_NOTE" | base64 --decode > $COVER + fi + + if [ ! $SILENT ];then + echo "kunst: swapped album art to $(mpc current)" + printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - + fi + + if [ $FIRST_RUN == true ]; then + FIRST_RUN=false + + # Display the album art using sxiv + # sxiv -g $SIZE -b $COVER -N "Kunst" & + + # notify-send "Now Playing ♫" "$(mpc current)" & + n30f -x $X -y $Y $COVER -t Kunst -c "killall n30f" & + # Save the process ID so that we can kill + # sxiv when the user exits the script + echo $! >/tmp/kunst.pid + fi + + # Waiting for an event from mpd; play/pause/next/previous + # this is lets kunst use less CPU :) + mpc idle &> /dev/null + if [ ! $SILENT ];then + echo "kunst: received event from mpd" + fi + done +} + +# Disable CTRL-Z because if we allowed this key press, +# then the script would exit but, sxiv would still be +# running +trap "" SIGTSTP + +trap pre_exit EXIT +main \ No newline at end of file diff --git a/.bin/lock b/.bin/lock new file mode 100755 index 0000000..d7dc632 --- /dev/null +++ b/.bin/lock @@ -0,0 +1,6 @@ +#!/bin/bash +scrot /tmp/screen.png +convert /tmp/screen.png -scale 10% -scale 1000% /tmp/screen.png +[[ -f $1 ]] && convert /tmp/screen.png $1 -gravity center -composite -matte /tmp/screen.png +i3lock -u -i /tmp/screen.png +rm /tmp/screen.png diff --git a/.bin/lol.sh b/.bin/lol.sh new file mode 100755 index 0000000..8aca0e7 --- /dev/null +++ b/.bin/lol.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +# pacman -S figlet lolcat + +figlet -c -f slant "$1"|lolcat diff --git a/.bin/macho.sh b/.bin/macho.sh new file mode 100755 index 0000000..2566d7d --- /dev/null +++ b/.bin/macho.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +export FZF_DEFAULT_OPTS=' +--height=30% +--layout=reverse +--prompt="Manual: " +--preview="echo {1} | sed -E \"s/^\((.+)\)/\1/\" | xargs -I{S} man -Pcat {S} {2} 2>/dev/null"' + +while getopts ":s:" opt; do + case $opt in + s ) SECTION=$OPTARG; shift; shift;; + \?) echo "Invalid option: -$OPTARG" >&2; exit 1;; + : ) echo "Option -$OPTARG requires an argument" >&2; exit 1;; + esac +done + +manual=$(apropos -s ${SECTION:-''} ${@:-.} | \ + grep -v -E '^.+ \(0\)' |\ + awk '{print $2 " " $1}' | \ + sort | \ + fzf | \ + sed -E 's/^\((.+)\)/\1/') + +[ -z "$manual" ] && exit 0 +man $manual diff --git a/.bin/mirrors b/.bin/mirrors new file mode 100755 index 0000000..120eb2a --- /dev/null +++ b/.bin/mirrors @@ -0,0 +1,19 @@ +#!/bin/bash +# reflector --list-countries + +if [ "$(which curl)" != "curl not found" ]; then + check_country=$(curl -s https://ipinfo.io/country) +fi + +if [ "$1" = "-lc" ]; then + # mirrors -lc + sudo reflector -c "$check_country" -c "RU" -c "YA" -c "PL" -c "GR" -a 12 -l 50 -f 20 -p https -p http --sort rate --save /etc/pacman.d/mirrorlist +elif [ "$1" = "-c" ]; then + # mirrors -c + sudo reflector -c "$check_country" -f 20 -p https -p http --sort rate --save /etc/pacman.d/mirrorlist +else + # mirrors + sudo reflector --verbose -a 12 -l 50 -f 15 -p https -p http --sort rate --save /etc/pacman.d/mirrorlist +fi + +sudo pacman -Syy diff --git a/.bin/mmv.sh b/.bin/mmv.sh new file mode 100755 index 0000000..2ae0bb7 --- /dev/null +++ b/.bin/mmv.sh @@ -0,0 +1,5 @@ +j=0; +for i in ico_22_*.png; +do let j+=1; +mv $i ico_22_$j.png ; +done \ No newline at end of file diff --git a/.bin/music b/.bin/music new file mode 100755 index 0000000..bd0fc3c --- /dev/null +++ b/.bin/music @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# +# kunst + ncmpcpp = ♥ +# This script launches kunst and ncmpcpp +# at the same time. Saves me from lunching +# them separately + +kunst --music_dir /media/files/mega/music/ --size 250x250+1100+490 --silent & +# kunst.sh --music_dir /media/files/mega/music/ --size 250x250 --x 1100 --y 490 --silent & +echo $! >/tmp/music.pid + +ncmpcpp + +kill -9 $(cat /tmp/kunst.pid) &> /dev/null \ No newline at end of file diff --git a/.bin/ob-theme.sh b/.bin/ob-theme.sh new file mode 100755 index 0000000..1705ebb --- /dev/null +++ b/.bin/ob-theme.sh @@ -0,0 +1,114 @@ +#!/bin/bash + + +sublime_conf="$HOME/.config/sublime-text-3/Packages/User/Preferences.sublime-settings" +qt_conf="$HOME/.config/qt5ct/qt5ct.conf" +ob_rc="$HOME/.config/openbox/rc.xml" +ob_autostart="$HOME/.config/openbox/autostart" +xsettings_d="$HOME/.xsettingsd" + + +# preferences for light theme mode +OB_LIGHT_THEME="obll" +PREF_LIGHT_THEME="ll" +PREF_LIGHT_DECO="ll" +PREF_LIGHT_BG="$HOME/.wall/wl1.jpg" +PREF_LIGHT_BG_OB=".wall\\/wl1.jpg" +PREF_LIGHT_ICO="ll-ico" + +sublime_theme_light="gruvbox" +sublime_colorscheme_light="Packages\\/User\\/Boxy Yesterday.tmTheme" + +sublime_theme_dark="gruvbox" +sublime_colorscheme_dark="Packages\\/One Dark Color Scheme\\/One Dark.tmTheme" + +# preferences for dark theme mode +OB_DARK_THEME="obln" +PREF_DARK_THEME="ln" +PREF_DARK_DECO="ln" +PREF_DARK_BG="$HOME/.wall/wl3.jpg" +PREF_DARK_BG_OB=".wall\\/wl3.jpg" +PREF_DARK_ICO="ln-ico" + + +# Xresources color theme ~/.colors +xresources_conf="$HOME/.Xresources" + +xresources_color_light="colors\\/ll" +xresources_color_dark="colors\\/ln" + + +de_theme="$(xfconf-query -c xsettings -p /Net/ThemeName)" + + +if [[ "$de_theme" == "$PREF_LIGHT_THEME" ]]; then + xfconf-query -c xsettings -p /Net/ThemeName -s $PREF_DARK_THEME + # xfconf-query -c xsettings -p /Gtk/DecorationLayout -s menu: + + gsettings set org.gnome.desktop.interface gtk-theme $PREF_DARK_THEME + # gsettings set org.gnome.desktop.wm.preferences button-layout '"menu:"' + + # sublime text + sed -i -e "s/$sublime_colorscheme_light/$sublime_colorscheme_dark/g" "$sublime_conf" + sed -i -e "s/$sublime_theme_light.sublime-theme/$sublime_theme_dark.sublime-theme/g" "$sublime_conf" + + # ~/.xsettingsd + sed -i -e "s/$PREF_LIGHT_THEME/$PREF_DARK_THEME/g" "$xsettings_d" + sed -i -e "s/$PREF_LIGHT_ICO/$PREF_DARK_ICO/g" "$xsettings_d" + killall xsettingsd + xsettingsd & + + # openbox theme + sed -i -e "s/$OB_LIGHT_THEME/$OB_DARK_THEME/g" "$ob_rc" + sed -i -e "s/$PREF_LIGHT_BG_OB/$PREF_DARK_BG_OB/g" "$ob_autostart" + openbox --reconfigure + + # urxvt color palet + # sed -i -e "s/$xresources_color_light/$xresources_color_dark/g" "$xresources_conf" + # xrdb -merge $HOME/.Xresources + # kill -1 $(pidof urxvt) + + # kitty + # kitty @ set-colors -a $HOME/.config/kitty/night.conf + + # qt5ct + sed -i -e "s/icon_theme=$PREF_LIGHT_ICO/icon_theme=$PREF_DARK_ICO/g" "$qt_conf" + + # wall + hsetroot -fill $PREF_DARK_BG +else + xfconf-query -c xsettings -p /Net/ThemeName -s $PREF_LIGHT_THEME + # xfconf-query -c xsettings -p /Gtk/DecorationLayout -s menu: + + gsettings set org.gnome.desktop.interface gtk-theme $PREF_LIGHT_THEME + # gsettings set org.gnome.desktop.wm.preferences button-layout '"menu:"' + + # sublime text + sed -i -e "s/$sublime_colorscheme_dark/$sublime_colorscheme_light/g" "$sublime_conf" + sed -i -e "s/$sublime_theme_dark.sublime-theme/$sublime_theme_light.sublime-theme/g" "$sublime_conf" + + # ~/.xsettingsd + sed -i -e "s/$PREF_DARK_THEME/$PREF_LIGHT_THEME/g" "$xsettings_d" + sed -i -e "s/$PREF_DARK_ICO/$PREF_LIGHT_ICO/g" "$xsettings_d" + killall xsettingsd + xsettingsd & + + # openbox theme + sed -i -e "s/$OB_DARK_THEME/$OB_LIGHT_THEME/g" "$ob_rc" + sed -i -e "s/$PREF_DARK_BG_OB/$PREF_LIGHT_BG_OB/g" "$ob_autostart" + openbox --reconfigure + + # urxvt color palet + # sed -i -e "s/$xresources_color_light/$xresources_color_dark/g" "$xresources_conf" + # xrdb -merge $HOME/.Xresources + # kill -1 $(pidof urxvt) + + # kitty + # kitty @ set-colors -a $HOME/.config/kitty/light.conf + + # qt5ct + sed -i -e "s/icon_theme=$PREF_DARK_ICO/icon_theme=$PREF_LIGHT_ICO/g" "$qt_conf" + + # wall + hsetroot -fill $PREF_LIGHT_BG +fi \ No newline at end of file diff --git a/.bin/ob_jgmenu b/.bin/ob_jgmenu new file mode 100755 index 0000000..855c0be --- /dev/null +++ b/.bin/ob_jgmenu @@ -0,0 +1,4 @@ +#!/bin/bash + +killall jgmenu +jgmenu --config-file="$HOME/.config/jgmenu/ob-jgmenurc" & diff --git a/.bin/obtgen b/.bin/obtgen new file mode 100755 index 0000000..29c78fa --- /dev/null +++ b/.bin/obtgen @@ -0,0 +1,437 @@ +#!/bin/bash + +# . . +# | | +# ,-. |-. |- ,-: ,-. ;-. +# | | | | | | | |-' | | +# `-' `-' `-' `-| `-' ' ' +# `-' +# Openbox Theme Generator + +file=$HOME/.colors/ln +wb(){ +{ + fill_color + cat < ~/.local/bin/my-obtgen/openbox-3/themerc +cp ~/.local/bin/my-obtgen/openbox-3/* ~/.themes/myobtheme/openbox-3/ +check_theme +} + +nrml(){ + { + fill_color + cat < ~/.local/bin/myobtheme/openbox-3/themerc +cp -r ~/.local/bin/myobtheme/ ~/.themes/ +check_theme +} + +fill_color(){ + get_colors(){ + grep "color$1 *:" $file | awk -F\# '{print $2}' | head -1 + } + get_colors_bg=`grep "background *:" $file | awk -F\# '{print $2}' | head -1` +} + +check_theme(){ + if [[ $(cat $HOME/.config/openbox/rc.xml | grep "myobtheme") ]]; then + notify-send "Done. now you can try your theme :)" + openbox --reconfigure + elif [[ $(find /usr/lib -type d -name lxappearance | xargs ls -R | grep ob) ]]; then + lxappearance >/dev/null 2>&1 + elif [[ $(which obconf) ]]; then + obconf >/dev/null 2>&1 + fi +} + +help(){ + cat <<-EOF + + 888 888 + 888 888 + 888 888 + .d88b. 88888b. 888888 .d88b. .d88b. 88888b. + d88""88b888 "88b888 d88P"88bd8P Y8b888 "88b + 888 888888 888888 888 88888888888888 888 + Y88..88P888 d88PY88b. Y88b 888Y8b. 888 888 + "Y88P" 88888P" "Y888 "Y88888 "Y8888 888 888 + 888 + Y8b d88P + "Y88P" + + Openbox Theme Generator + + Usage : obtgen [options #optional] + + Avaible options + --wal Generate color from pywal cache + --wb Generate borderless theme + --help Show help + + EOF +} + +if [[ "$(echo "$@" | grep '\--wal')" && "$(echo "$@" | grep '\--wb')" ]]; then + file=$HOME/.cache/wal/colors.Xresources + wb +elif [[ "$(echo "$@" | grep '\--wb')" ]]; then + wb +elif [[ "$(echo "$@" | grep '\--wal')" ]]; then + file=$HOME/.cache/wal/colors.Xresources + nrml +elif [[ "$(echo "$@" | grep '\--help')" ]]; then + help +else + nrml +fi \ No newline at end of file diff --git a/.bin/openbox-theme.sh b/.bin/openbox-theme.sh new file mode 100755 index 0000000..46f2ecb --- /dev/null +++ b/.bin/openbox-theme.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +openbox_autostart="$HOME/.config/openbox/autostart" +ob_rc_xml="$HOME/.config/openbox/rc.xml" +xsettingsd_conf="$HOME/.xsettingsd" +qt_conf="$HOME/.config/qt5ct/qt5ct.conf" +sublime_conf="$HOME/.config/sublime-text-3/Packages/User/Preferences.sublime-settings" + + +# preferences for light theme mode +PREF_LIGHT_THEME="lui" +PREF_LIGHT_BG="$HOME/.wall/Crowl.png" +PREF_LIGHT_ICO="lui-ico" + +sublime_theme_light="gruvbox" +sublime_colorscheme_light="Packages\\/User\\/Boxy Yesterday.tmTheme" + +# preferences for dark theme mode +PREF_DARK_THEME="dui" +PREF_DARK_BG="$HOME/.wall/lcrow.png" +PREF_DARK_ICO="dui-ico" + +sublime_theme_dark="gruvbox" +sublime_colorscheme_dark="Packages\\/One Dark Color Scheme\\/One Dark.tmTheme" + + +# wall +hsetroot_autostart_light="hsetroot -fill ~\\/.wall\\/Crowl.png" +hsetroot_autostart_dark="hsetroot -fill ~\\/.wall\\/lcrow.png" + + +# Xresources color theme ~/.colors +xresources_conf="$HOME/.Xresources" + +xresources_color_light="colors\\/lui" +xresources_color_dark="colors\\/dui" + + +ob_theme="$(awk -F "[<,>]" '/ there are warning comments containing "ATTENTION" about this. +# shellcheck disable=SC1117,SC2086 # exclude MANY false-positive shellcheck warnings (see above) + +# This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ======================= +# +# Design based on IceFox script. Heavily modified by pekman, excalibur1234, Chrysostomus, papajoker, and thefallenrat. + +# ANSI Escape sequences used in this script: # ATTENTION: do NOT use \\e[..., because it does not always work! +# \e[31m # red text +# \e[36m # cyan text +# \e[41m # red background +# \e[1m \033[1m # bold text ( \033[1m has to be used in "awk") +# \e[0m \033[0m # non-colored, non-bold text without background color ( \033[0m has to be used in "awk") + +# use unofficial strict mode in order to make bash behave like modern programming languages. this should only be used for debugging during development! +#set -e # exit script immediately, if any command exits with non-zero error code. this is useful for parts of a script, which print an error message when exiting with non-zero value. ATTENTION: when fzf is quit using CTRL+C or ESC, it quits with an error. therefore, "set -e" should not be used around fzf! +#set -E # let traps execute even when "set -e" is used. only use this in conjunction with "set -e" to avoid unexpected behavior +#set -u # only allow previously defined variables. This prevents acces to environment variables! +#set -o pipefail # if one command in a pipe fails, all fail (this is not default behavior!) +#set -x # print every command (with expanded arguments) before execution. can be useful for debugging content of variables and to see in which line the script has failed. ATTENTION: this makes PacUI almost unusable. + + +# ======================= + + +#set +u + +# here, the preferred AUR helper can be set manually by the user. for example, AUR_Helper="trizen" uses Trizen despite any other installed AUR helpers. +AUR_Helper="$PACUI_AUR_HELPER" # global variable, which does not get unset (i.e. cleaned up), because it is needed both in GUI and non-GUI + +#set -u + + +# if $PACUI_AUR_HELPER environment variable is not set, the installed AUR helpers are detected and one is chosen automatically: +if [[ -z "$AUR_Helper" ]] # check, if AUR_Helper variable is empty. more precise: check, if output of "$AUR_Helper" is zero +then + + if [[ -f /usr/bin/yay ]] + then + AUR_Helper="yay" + + elif [[ -f /usr/bin/pikaur ]] + then + AUR_Helper="pikaur" + + elif [[ -f /usr/bin/aurman ]] # check, if /usr/bin/aurman file exists + then + AUR_Helper="aurman" + + elif [[ -f /usr/bin/pakku ]] + then + AUR_Helper="pakku" + + elif [[ -f /usr/bin/trizen ]] + then + AUR_Helper="trizen" + + elif [[ -f /usr/bin/pacaur ]] + then + AUR_Helper="pacaur" + + fi +fi + + +# ======================= + +# all functions of pacui are defined here in the same order as they appear in pacui's UI (including some additional some helper functions): + + +# bug #3: +# "pacui --pacui_tty_clean" helper function. this function is only called from within pacui. +function pacui_tty_clean +{ + if ( tty | grep tty &>/dev/null ) # check, whether output of "tty" contains the string "tty". this is TRUE, if pacui is used within a tty. + then + # in tty, fzf does not clear the screen before and after it runs. this makes a bad visual style in tty. the other code (in the "else bracket") does not help to "clear" the screen before and after fzf runs, either. only the real "clear" command works. + # unfortunately the "clear" command also destroys the terminal history. therefore, the "clear" command should only be used when absolutely necessary (such as in tty)! + clear + fi +} + + +# Update System +# this function provides core functionality of "Update System". the help page provides additional explanations. +function func_u +{ + # define local variable, which indicates whether the installation process was successful or not. + local install_successful + + if [[ "$AUR_Helper" == "yay" ]] # check, if $AUR_Helper variable is set to "aurman". ATTENTION: sometimes, this requires [[ "$AUR_Helper" == "aurman" ]] and sometimes test '$AUR_Helper' = "aurman" . i do not know why this is the case. + then + + # execute "yay -Syu" command: + if ( yay "$argument_flag"-Syu ) # execute command "yay -Syu". if this command fails "false" is returned and the result is: "if ( false )" + then + # only set $install_successful=true, if the command "yay -Syu" was executed without errors + install_successful=true + else + install_successful=false + fi + + elif [[ "$AUR_Helper" == "pikaur" ]] + then + + # execute "pikaur -Syu" command: + if ( pikaur "$argument_flag"-Syu ) + then + # only set $install_successful=true, if the command "pikaur -Syu" was executed without errors + install_successful=true + else + install_successful=false + fi + + elif [[ "$AUR_Helper" == "aurman" ]] + then + + # execute "aurman -Syu" command: + if ( aurman "$argument_flag"-Syu ) + then + # only set $install_successful=true, if the command "aurman -Syu" was executed without errors + install_successful=true + else + install_successful=false + fi + + elif [[ "$AUR_Helper" == "pakku" ]] + then + + # execute "pakku -Syu" command: + if ( pakku "$argument_flag"-Syu ) + then + # only set $install_successful=true, if the command "pakku -Syu" was executed without errors + install_successful=true + else + install_successful=false + fi + + elif [[ "$AUR_Helper" == "trizen" ]] + then + + # execute "trizen -Syu" command: + if ( trizen "$argument_flag"-Syu ) + then + # only set $install_successful=true, if the command "trizen -Syu" was executed without errors + install_successful=true + else + install_successful=false + fi + + elif [[ "$AUR_Helper" == "pacaur" ]] + then + + # execute "pacaur -Syu --color always" command: + if ( pacaur "$argument_flag"-Syu --color always ) + then + # only set $install_successful=true, if the command "pacaur -Syu --color always" was executed without errors + install_successful=true + else + install_successful=false + fi + + else + + # execute "sudo pacman -Syu --color always" command: + if ( sudo pacman "$argument_flag"-Syu --color always ) + then + # only set $install_successful=true, if the command "sudo pacman -Syu --color always" was executed without errors + install_successful=true + else + install_successful=false + fi + + fi + + # if one of the above update commands has failed, the following if-statement is true: + if [[ "$install_successful" == "false" ]] + then + + local server + # extract mirror/repository server url from /etc/pacman.d/mirrorlist file with command: + server="$( grep "^Server =" -m 1 "/etc/pacman.d/mirrorlist" |awk -F '=' '{print $2}' | awk -F '$' '{print $1}' )" + + # if one of the above update commands has failed, there are multiple points of failure. the first one is the internet/repository/mirror connection of the user: + # check, whether there is a connection to the mirror/repository server. this is needed for package download/update! + if ( wget --spider $(echo "$server") &>/dev/null ) # the "wget --spider" command gets executed in any case in order to check its output. + then + + # next, we can force the update, but only for packages from the system repositories and not packages from the AUR. this means, we make sure package updates from system repositories fail: + if ! ( sudo pacman -Syu --color always ) # the "sudo pacman -Syu --color always" command gets executed in any case in order to check its output. + then + + # now, we are sure there is an active connection to the server/mirror/repository and package updates from there have failed. in this case, we can offer the user to forcefully install updates: + local answer + # ask, whether to force update the system and save answer in "answer" variable: + echo -e " \e[1m Updates from system repositories have failed probably because of file conflicts. \e[0m" + echo -e " \e[41m Do you want to forcefully overwrite all conflicting files? [y|N] \e[0m" + read -r -n 1 -e answer # this "read" command only accepts 1 letter as answer. this feels faster and is enough in this situation. + + case ${answer:-n} in # if ENTER is pressed, the variable "answer" is empty. if "answer" is empty, its default value is "n". + y|Y|yes|Yes|YES ) # do this, if "answer" is y or Y or yes or Yes or YES + sudo pacman -Syu --color always --overwrite A-Z,a-z,0-9,-,.,_ + ;; + * ) # do this in all other cases + echo -e " \e[1m Packages have not been updated.\e[0m" + ;; + esac + + fi + + else + + # print error message, if there is no connection to a mirror/repository server and quit + echo + echo -e " \e[41m Either there is something wrong with your internet connection or with your mirror/repository server: $server \e[0m" # writing the $server variables in quotes (" or ') does not work! using ' for echo command does not work either! + echo -e " \e[1;41m Please make sure both are ok and rerun this part of PacUI! \e[0m" + echo + + fi + + fi +} + + +# "pacui --diff" helper function +# this function is not called by pacui or pacui's UI directly. instead, it gets called in func_m (using "pacui --diff") when no DIFFPROG environment variable is found. it provides simple file difference viewer functionality and is essentially a wrapper around the GNU program "diff". therefore, this function expects 2 arguments! +function func_diff +{ + # $(( ... )) does arithmetic evaluation. always use this when dealing with numbers, instead of strings - $[[ ... ]] does sting evaluation! + local {temp,temp2,temp3} # define local variables - these variables will be automatically deleted after the function is finished/exited. + temp2="$( echo "$argument_input" | awk '{print $1}' )" # write second argument of "pacui --diff temp2 temp3" to variable temp2. + temp3="$( echo "$argument_input" | awk '{print $2}' )" # write third argument of "pacui --diff temp2 temp3"to variable temp3. + temp="$(( ( $(tput cols) / 2 ) - ${#temp2} + ${#temp3} ))" # calculate half the width of the terminal window ( $(tput cols)=width of terminal window ; ${#temp2}=width of second argument ) + + # insert extra line with file paths above the diff viewer output: + echo -n -e "\e[31;1m$temp2" # print $temp2 (without \newline at the end) = file path of file1 . use ANSI escape sequence to print file names in this line bold and red. + printf "%*s\n" "$temp" "$temp3" # print (still in the same line) $temp3 ( = file path of file2) with $temp number of spaces in front and \newline at the end. + tput sgr0 # printf does not support any ANSI escape sequences, so output (= red and bold text) has to be reset manually using "tput". + + # use "diff" as a file difference viewer with many options, which make it look good. "diff" takes 2 arguments (=the files, which are supposed to be compared) + diff --side-by-side --suppress-common-lines --ignore-all-space --color=always --width="$(tput cols)" "$temp2" "$temp3" +} + + +# Maintain System +# this function provides core functionality of "Maintain System". it is separated into multiple parts. most parts begin (or contain) an "echo" command, which explains what is being done. the help page explains the core functionality of every part in detail, too. +function func_m +{ + # delete only pacui-related packages in /tmp directory. if other files are deleted, linux starts to act strange! + if ( sudo find /tmp/pacui* &>/dev/null ) # check if "pacui*" file or directory is found in /tmp/ directory + then + echo " deleting PacUI cache ..." + sudo rm --recursive --dir /tmp/pacui* # here the "rm -r" command is needed, because both directories and files have to be removed. "unlink" and "rmdir" do not work here. + echo "" + fi + + + # check for "pacman-mirrors" or "reflector" packages. one of those is needed! + if [[ -f /usr/bin/pacman-mirrors ]] || [[ -f /usr/bin/reflector ]] + then + + echo " choosing fastest mirror (which can take a while) and updating system ..." + if [[ -f /usr/bin/pacman-mirrors ]] # checks, whether file "pacman-mirrors" exists + then + sudo pacman-mirrors -f 0 && sudo pacman -Syyu # choose mirrors server (with up-to-date packages) with lowest ping from all available mirrors and sync database. + + elif [[ -f /usr/bin/reflector ]] # checks, whether file "reflector" exists + then + sudo reflector --verbose --protocol https --age 1 --sort rate --save /etc/pacman.d/mirrorlist && sleep 10 && sudo pacman -Syyu # If it does exists, then the mirror will sort by it + + fi + echo "" + fi + + + echo " searching orphans ..." + if [[ "$AUR_Helper" == "yay" ]] + then + yay -Yc # do orphan cleaning and yay cleaning + + else # do this for all other AUR helpers: + if [[ -n "$(pacman -Qdt)" ]] # only run the following commands, if output of "pacman -Qdt" is not empty. + then + pacman -Qdt --color always # display orphaned packages + # ask, whether to remove the displayed orphaned packages: + echo -e " \e[41m Do you want to remove these orphaned packages? [Y|n] \e[0m" + read -r -n 1 -e answer # save user input in "answer" variable (only accept 1 character as input) + + case ${answer:-y} in # if ENTER is pressed, the variable "answer" is empty. if "answer" is empty, its default value is "y". + y|Y|yes|YES|Yes ) # do this, if "answer" is y or Y or yes or YES or Yes + sudo pacman -Rsn $(pacman -Qqdt) --color always --noconfirm # ATTENTION: (i do not know why but) using quotes (" symbols) around $(...) breaks pacman command for multiple packages + ;; + * ) # do this in all other cases + echo -e " \e[1m Packages have not been removed.\e[0m" + ;; + esac # end of "case" loop + fi + fi + echo "" + + + echo " sudo pacdiff ..." + #set +u # temporarily disable strict mode for environment variables + + if [[ -n "$DIFFPROG" ]] # this if-condition avoids error message when $DIFFPROG is not set/empty + then + sudo pacdiff + else + # use pacdiff to search for .pacnew and .pacsave files. display both the original and the used config file using "pacui_diff" function defined above. + sudo DIFFPROG="pacui --diff" pacdiff + fi + + #set -u + echo "" + + + echo " checking systemctl ..." + # "LC_ALL=C" forces the output to use english language. this is important, if the output is queried. + if [[ "$( LC_ALL=C systemctl --failed | awk 'NR==1 {print $1}' )" == "UNIT" ]] + then + echo -e " \e[41m The following systemd service(s) have failed. Please fix them manually. \e[0m" + echo -e " \e[1m Display detailed information about a systemd service with: systemctl status \e[0m" + echo + systemctl --failed + echo + fi + echo "" + + + echo " checking symlinks ..." + if [[ -n "$(sudo find -xtype l)" ]] # only run, if output of "sudo find -xtype l -print" is not empty + then + echo -e " \e[41m The following symbolic links are broken, please fix them manually: \e[0m" + sudo find -xtype l + fi + echo "" + + + echo " checking consistency of local repository ..." + # check, whether "pacman -Dk" command finishes with errors, but do not output anything when this command runs with "&>/dev/null" + if ! ( pacman -Dk &>/dev/null ) + then + echo -e " \e[41m The following inconsistencies have been found in your local packages: \e[0m" + echo -e "$( pacman -Dk )" # encapsulate "pacman -Dk" in echo command. without this, the strict bash mode would quit pacui whenever "pacman -Dk" encounters an error! + fi + echo "" + + + if [[ -n "$AUR_Helper" ]] # check, if output of "$AUR_Helper" is non-zero + then + echo " checking AUR packages (which can take a while) ..." + # download AUR package list to /tmp/pacui-aur/packages. + + #wget -P "/tmp/pacui-aur/" "https://aur.archlinux.org/packages.gz" &>/dev/null + wget -P "/tmp/pacui-aur/" "https://aur.archlinux.org/packages.gz" &>/dev/null && gunzip -f "/tmp/pacui-aur/packages.gz" + # now, file /tmp/pacui-aur/packages contains an unsorted list of all packages from the AUR with the download date on top (in a commented line). + + # check, if /tmp/pacui-aur/packages exists. /tmp/pacui-aur/packages does not exist, if there is no internet connection or something went wrong during the download of the list of AUR packages. + #if [[ -f /tmp/pacui-aur/packages.gz ]] + if [[ -f /tmp/pacui-aur/packages ]] + then + + local pkg + # the "comm" command compares 2 files and outputs the differences between them. both files have to be sorted! + # "pacman -Qqm | sort" outputs a list of all installed packages from the AUR + #pkg=$( comm -23 <(pacman -Qqm | sort) <(sort -u /tmp/pacui-aur/packages.gz) ) + pkg="$( comm -23 <(pacman -Qqm | sort) <(sort -u /tmp/pacui-aur/packages) )" + + # only run the command inside the if-statement, if $pkg variable is not empty + if [[ -n "$pkg" ]] # checks, if length of string is non-zero ("-n" conditional bash expression is the opposite of "-z" (check, whether length of string is zero)) + then + echo -e " \e[1m The following packages are neither in your package repository nor the AUR. \e[0m" + echo -e " \e[1m They are orphaned and will never be updated. \e[0m" + echo -e " \e[41m It is recommended to remove these packages carefully: \e[0m" + echo "$pkg" + echo "" + fi + + fi + fi + echo "" + + + echo " checking for packages moved to the AUR ..." + local pkg + # "pacman -Qqm" lists all packages, which are not from the system repositories. "pacman -Qqem" lists all files, which were explicitly installed, but are not present in the system repositories. + # comm -23 only outputs unique packages from the 1. list (not present in the 2. list) + pkg="$( comm -23 <(pacman -Qqm | sort) <(pacman -Qqem | sort) )" + + # only run the command inside the if-statement, if $pkg variable is not empty + if [[ -n "$pkg" ]] # checks, if length of string is non-zero ("-n" conditional bash expression is the opposite of "-z" (check, whether length of string is zero)) + then + echo -e " \e[1m The following packages were not explicitly installed and are not part of your system repository. \e[0m" + echo -e " \e[41m If no important packages depend on them, it is recommended to remove these packages carefully: \e[0m" + echo "$pkg" + echo "" + fi + echo "" + + + if [[ "$(cat /proc/1/comm)" == "systemd" ]] # if init system is systemd + then + echo " cleaning systemd log files ..." + # limit logs in journalctl to an age of 30 days and a combined size of 50mb + sudo journalctl --vacuum-size=100M --vacuum-time=30days + fi + echo "" + + + echo " cleaning package cache ..." + # remove all packages, which are not installed on this system, except the latest versions (this is a back up, in case somebody removes networkmanager) + sudo paccache -rvu -k 1 + echo "" + # remove all package versions, except the latest 3 + sudo paccache -rv -k 3 + echo "" + # general comment: "pacaur" is currently the only aur helper, which creates its own download directory for aur packages. the content of this download folder can be cleaned with "pacaur -Sc". But "pacaur -Sc" removes too many files and is therefore not used here. + + + echo " checking installed kernels ..." + local {installed_kernels,available_kernels,eol_kernels} # declare local variables + # filter installed kernels from boot sector and determine, which package owns that file. this yields the package name of all installed kernels (including kernels from the AUR): + installed_kernels="$( + for p in $( command ls -1 /boot | grep -E '^vmlinuz' ) # ATTENTION: (i do not know why but) using quotes (" symbols) around $(...) breaks for-loop + do + pacman -Qqo /boot/"$p" + done | sort -u )" + # Check if installed kernels are available in repositories and forward it/them to available_kernels variable: + available_kernels="$( + for p in $( echo "$installed_kernels" ) # ATTENTION: (i do not know why but) using quotes (" symbols) around $(...) breaks for-loop + do + pacman -Ssq "^$p$" + done | sort -u )" + # filter kernels to $eol_kernels variable, which are installed but no longer available: + eol_kernels="$( comm -13 <(echo "$available_kernels") <(echo "$installed_kernels") )" + # print warning message, if end-of-life kernel(s) are found: + if [[ -n "$eol_kernels" ]] + then + echo + echo -e " \e[41m The following Linux kernel(s) are no longer available in your repositories. \e[0m" + echo -e " \e[1m Do not expect any security or stability fixes for the(se) kernel(s) anymore. \e[0m" + echo -e " \e[1m Kernel modules are likely to break. It is recommended to remove the kernel(s).\e[0m" + echo -e " \e[1m If one or more of the following kernel(s) are taken from AUR, you may safely ignore this warning. \e[0m" + echo "$eol_kernels" + fi + echo "" +} + + +# Install Packages +# this function provides core functionality of "Install Packages". the help page provides additional explanations. +function func_i +{ + local {pacui_list_install,pkg} # declare local variables + + # write package list of system repositories (package name and description) to $pacui_list_install. %-33n uses printf support in expac to format output nicely (reserve a 33 character wide field for package name %n). + pacui_list_install="$( expac -S "%-33n\t%d" )" # here the parenthesis in "$(...)" are essential to write multiple lines to a variable! without parenthesis the variable will contain only a single line (space separated)! + + + # for performance reasons, there are multiple files of package lists created in the following code. a comparison to local files is much faster than checking, whether a selected package is part of an online repository. + # the use of variables instead of files can give more performance (and security) gains, but variables cannot be called from within fzf's preview, because it needs to be used with ' symbols (e.g. --preview '...') + # these files do not need a trap (for security reasons), because they are only used for comparison. if tampered with, the comparison (which is done in "comm" without root privileges) simply fails and no package info is shown. + expac -Q "%n" > /tmp/pacui-list-installed # get locally installed packages (equivalent to "pacman -Qq", but faster). + + if [[ ! -f /tmp/pacui-list-install-repo ]] # check, if file does not exist. + then + echo "$pacui_list_install" | cut -d " " -f 1 > /tmp/pacui-list-install-repo # get the content of $pacui_list_install variable and save (only a list of package names) to /tmp/pacui-list-install-repo file. + fi + + # add a list of package groups in the system repositories to $pacui_list_install variable + pacui_list_install+="\n" # by default, the "+=" operator adds all stuff directly to the end of a variable (but without a newline!). therefore, an additional "\n" (newline) is needed before adding stuff to a list. + + if [[ ! -f /tmp/pacui-list-install-groups ]] + then + # "pacman -Sgq" is equivalent to "expac -Sg %G | sort -u | sed 's/ /\n/g' | sort -u | awk 'NF != 0'", but much faster + # split output of "pacman -Sgq" using "tee" to $pacui_list_install variable and /tmp/pacui-list-install-groups file. this saves a little time. + pacui_list_install+="$( pacman -Sgq | tee /tmp/pacui-list-install-groups )" + else + pacui_list_install+="$( cat /tmp/pacui-list-install-groups )" # if /tmp/pacui-list-install-groups file already exists, its content is added to $pacui_list_install variable. this is insecure, but because the same is done below (which i do not know how to do differently) with a list of AUR packages, i think it is an acceptable performance optimization. + #pacui_list_install+="$( pacman -Sgq )" # secure solution needs a bit of extra time. + fi + + + + if [[ -n "$AUR_Helper" ]] # check, if output of "$AUR_Helper" is non-zero + then + + # download AUR package list (only when not already downloaded) and add it to $pacui_list_install + #if [[ ! -f /tmp/pacui-aur/packages.gz ]] + if [[ ! -f /tmp/pacui-aur/packages ]] + then + echo " downloading list of AUR packages (which can take a while) ..." + + #wget -P "/tmp/pacui-aur/" "https://aur.archlinux.org/packages.gz" &>/dev/null + wget -P "/tmp/pacui-aur/" "https://aur.archlinux.org/packages.gz" &>/dev/null && gunzip -f "/tmp/pacui-aur/packages.gz" + fi + + # check, if /tmp/pacui-aur/packages exists. /tmp/pacui-aur/packages does not exist, if there is no internet connection or something went wrong during the download of the list of AUR packages. + #if [[ -f /tmp/pacui-aur/packages.gz ]] + if [[ -f /tmp/pacui-aur/packages ]] + then + pacui_list_install+="\n" + # remove line with download date from list of AUR packages with "grep" and add content of /tmp/pacui-aur/packages file to $pacui_list_install variable. this is insecure, but i do not know how to download the list of AUR packages directly into a variable. doing this with temporary files and traps would be a (quite slow!) secure solution, which i am not willing to implement yet. + #pacui_list_install+="$( grep -v '#' '/tmp/pacui-aur/packages.gz' | tr -d ' ' )" # delete all trailing spaces with "tr". command equivalent to "awk '{print $1}'" + pacui_list_install+="$( grep -v '#' '/tmp/pacui-aur/packages' )" + fi + + fi + + + pacui_tty_clean # clear terminal + #set +e # prevent PacUI to quit, if fzf is quit using CTRL+C or ESC (which exits fzf with an error code) + #set +E + + # fzf lets you search and select a given list. "man fzf" lists all its arguments beautifully. "fzf" commands in this script are typically in a convoluted form. here, a long "fzf" command is listed in maximum readable form. + # the package list in $pacui_list_install gets sorted and displayed by fzf. then it is filtered by awk and saved in pkg variable. + pkg="$( + echo -e "$pacui_list_install" | # load list of package names from $pacui_list_install_all variable. "-e" interprets the added newlines. + sort -k1,1 -u | # sort list: only first column gets used for sorting + # the "--multi" flag makes it possible to select multiple list items + # $argument_input variable gets defined after function definitions --> search for "argument_input=" + # the "--preview" flag displays information about the currently selected line in fzf's preview window + fzf -i \ + --multi \ + --exact \ + --no-sort \ + --select-1 \ + --query="$argument_input" \ + --cycle \ + --reverse \ + --bind=right:half-page-down,left:half-page-up \ + --margin="4%,1%,1%,2%" \ + --info=inline \ + --no-unicode \ + --preview ' + if [[ $(comm -12 <(echo {1}) <(sort /tmp/pacui-list-install-groups)) ]] # check, if 1. field of selected line (in fzf) is a package group + then + echo -e "\e[1m{1} group has the following members: \e[0m" + pacman -Sgq {1} # display package name of group members in preview window of fzf + + else + + if [[ $(comm -12 <(echo {1}) <(sort /tmp/pacui-list-installed)) ]] # check, if 1. field of selected line (in fzf) is a locally installed package. + then + echo -e "\e[1mInstalled package info: \e[0m" + pacman -Qi {1} --color always # display local package information in preview window of fzf + echo + fi + + if [[ $(comm -12 <(echo {1}) <(sort /tmp/pacui-list-install-repo)) ]] # check, if 1. field of selected line (in fzf) is a package from system repositories + then + echo -e "\e[1mRepository package info: \e[0m" + pacman -Si {1} --color always # display repository package information in preview window of fzf + + elif ( test -n '$AUR_Helper' ) # preview window of fzf requires checking with "test": check whether internet connection is up. + then + echo -e "\e[1mAUR package info: \e[0m" + + if test '$AUR_Helper' = "yay" + then + yay -Si {1} | grep -v "::" # grep command removes all errors displayed by yay + + elif test '$AUR_Helper' = "pikaur" + then + pikaur -Si {1} + + elif test '$AUR_Helper' = "aurman" # if {1} is neither locally installed nor a group, it is from the AUR. display info with AUR helper + then + aurman -Si {1} | grep -v "::" # grep command removes all errors displayed by aurman + + elif test '$AUR_Helper' = "pakku" + then + pakku -Si {1} + + elif test '$AUR_Helper' = "trizen" + then + trizen -Si {1} + + elif test '$AUR_Helper' = "pacaur" + then + pacaur -Si {1} --color always | grep -v "::" # grep command removes all errors displayed by pacaur + + fi + fi + + fi' \ + "$( + if (( $(tput cols) >= 125 )) + then + echo "--preview-window=right:55%:wrap" # depending on the terminal width (determined by "tput cols"), the preview window is either shown on the right or the bottom + else + echo "--preview-window=bottom:55%:wrap" + fi + )" \ + --header="TAB key to (un)select. ENTER to install. ESC to quit." \ + --prompt="Enter string to filter list > " | + awk '{print $1}' # use "awk" to filter output of "fzf" and only get the first field (which contains the package name). "fzf" should output a separated (by newline characters) list of all chosen packages! + )" + + #set -e + #set -E + pacui_tty_clean # clear terminal + + # $pkg contains package names below each other (=separated by \n), but we need a list in 1 line (which is space separated): + pkg="$( echo "$pkg" | paste -sd " " )" + + + # only run the command inside the if-statement, if variable $pkg is not empty (this happens when fzf is quit with ESC or CTRL+C) + if [[ -n "$pkg" ]] + then + + if [[ "$AUR_Helper" == "yay" ]] + then + yay "$argument_flag"-S $pkg # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkg variable breaks AUR helper and pacman + + elif [[ "$AUR_Helper" == "pikaur" ]] + then + pikaur "$argument_flag"-S $pkg # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkg variable breaks AUR helper and pacman + + elif [[ "$AUR_Helper" == "aurman" ]] + then + aurman "$argument_flag"-S $pkg # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkg variable breaks AUR helper and pacman + + elif [[ "$AUR_Helper" == "pakku" ]] + then + pakku "$argument_flag"-S $pkg # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkg variable breaks AUR helper and pacman + + elif [[ "$AUR_Helper" == "trizen" ]] + then + trizen "$argument_flag"-S $pkg # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkg variable breaks AUR helper and pacman + + elif [[ "$AUR_Helper" == "pacaur" ]] + then + pacaur "$argument_flag"--color always -S $pkg # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkg variable breaks AUR helper and pacman + + else + sudo pacman "$argument_flag"--color always -Syu $pkg # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkg variable breaks AUR helper and pacman + + fi + + fi +} + + +# Remove Packages +# this function provides core functionality of "Remove Packages". the help page provides additional explanations. +function func_r +{ + # write package list of local repository to /tmp/pacui-packages-group. + #pacman -Qq | tr -d " " > /tmp/pacui-packages-group + expac -Q "%-33n\t%d" > /tmp/pacui-packages-group + # use expac command to print a list of installed package groups (of installed packages. then extract installed package groups from all of them) and add it to the bottom of /tmp/pacui-packages-group + # awk 'NF != 0' only displays lines where the number of fields is not zero (i.e. non-empty lines) + expac -Qg %G | sort -u | sed 's/ /\n/g' | sort -u | awk 'NF != 0' >> /tmp/pacui-packages-group + + local {pkg,pkg_remove,pkg_remove_backup} # declare local variables + + pacui_tty_clean # clear terminal + #set +e + #set +E + + # take a sorted package (and group) list from /tmp/pacui-packages-group, then make the resulting list available to fzf. see above for a "fzf" command with good readability and many comments + pkg="$( sort -k1,1 -u /tmp/pacui-packages-group | fzf -i --multi --exact --no-sort --select-1 --query="$argument_input" --cycle --reverse --bind=right:half-page-down,left:half-page-up --margin="4%,1%,1%,2%" --info=inline --no-unicode --preview ' + if ( pacman -Qq {1} &>/dev/null ) # check, if selected line is a locally installed package + then + echo -e "\e[1mInstalled package info: \e[0m" + pacman -Qi {1} --color always + + else + echo -e "\e[1m{1} group has the following members: \e[0m" + pacman -Sgq {1} + + fi + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:55%:wrap"; else echo "--preview-window=bottom:55%:wrap"; fi )" --header="TAB key to (un)select. ENTER to remove. ESC to quit." --prompt='Enter string to filter list > ' | awk '{print $1}' )" + + #set -e + #set -E + pacui_tty_clean # clear terminal + + if [[ -n "$pkg" ]] # check, whether $pkg variable is not empty. this happens when fzf is quit with CTRL+C. + then + # $pkg contains package names below each other, but we need a list (in 1 line, space separated): + pkg="$( echo "$pkg" | paste -sd " " )" + pkg_remove="$( echo "$pkg" )" + + # wrap the "sudo pacman -Rns" command in an if-statement, which checks, whether the removal of packages works. the removal of packages does not work, if the user tries to remove a dependency. + # the failure of "sudo pacman -Rns" is especially annoying, if many packages has been chose for removal and 1 package is a dependency. by default, the list of packages (which are supposed to be removed) is NOT saved! + # "sudo pacman -Rsn $pkg_remove --color always" always gets executed! + if ! ( sudo pacman "$argument_flag"-Rsn $pkg_remove --color always ) # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkg_remove variable breaks AUR helper and pacman + then + + # now, "sudo pacman -Rsn $pkg_remove --color always" has failed. this means that a dependency was selected. Print error message below the error output of pacman. + echo + echo -e " \e[1m Package removal has failed. Most likely you have tried to remove a dependency.\e[0m" + echo + echo -e " \e[41m Do you want to forcefully remove all selected packages anyway? [y|N] \e[0m" + echo -e " \e[1m Choose one of the following options: \e[0m" + echo + echo -e "\e[1;31m y Forcefully remove package(s) without checking their dependencies first. \e[0m" + echo -e "\e[1;31m Attention: This command can break packages on your system or even your entire system. \e[0m" + echo + echo -e "\e[1m N Try again. \e[0m" + echo -e "\e[1m Read the error message(s) above carefully and try not to select dependencies next time. \e[0m" + echo + echo -e "\e[1m ESC Exit without removing any packages. \e[0m" + echo + # save answer in "answer" variable: + read -r -n 1 -e answer + + case ${answer:-n} in # if ENTER is pressed, the variable "answer" is empty. if "answer" is empty, its default value is "n". + + y|Y|yes|YES|Yes ) # do this, if "answer" is y or Y or yes or YES or Yes + + sudo pacman -Rdd $pkg_remove --color always # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkg_remove variable breaks AUR helper and pacman + ;; + + n|N|no|NO|No ) # do this, if "answer" is n or N or no or NO or No + + # continue here only if "sudo pacman -Rns" has failed: + # 1. save list of packages to variable + pkg_remove_backup="$( echo "$pkg_remove" | tr " " "\n" )" # tr " " "\n" is needed to convert the list of package names (in 1 line) back to multiple lines. otherwise, fzf cannot work with it. + + # 2. try again with a limited list of packages in fzf. this loop is dependent on the pkg_remove_backup variable! + while [[ -n "$pkg_remove_backup" ]] + do + + local {pkg,pkg_remove} # declare local variables + + pacui_tty_clean # clear terminal + #set +e + #set +E + + # fzf lets you search and select the given list in a fast way. see above for a "fzf" command with good readability and many comments + pkg="$( echo "$pkg_remove_backup" | fzf -i --multi --exact --no-sort --query="$argument_input" --reverse --bind=right:half-page-down,left:half-page-up --margin="4%,1%,1%,2%" --info=inline --no-unicode --preview ' + if ( pacman -Qq {1} &>/dev/null ) # check, if selected line is a locally installed package + then + echo -e "\e[1mInstalled package info: \e[0m" + pacman -Qi {1} --color always + + else + echo -e "\e[1m{1} group has the following members: \e[0m" + pacman -Sgq {1} + + fi + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:55%:wrap"; else echo "--preview-window=bottom:55%:wrap"; fi )" --header="TAB key to (un)select. ENTER to remove. ESC to quit." --prompt='Enter string to filter list > ' | awk '{print $1}' )" + + #set -e + #set -E + pacui_tty_clean # clear terminal + + if ! [[ -n "$pkg" ]] # check, whether $pkg variable is empty. this happens when fzf is quit with CTRL+C. + then + break # break while-loop, if fzf was quit using CTRL+C + fi + + # $pkg contains package names below each other, but we need a list (in 1 line, space separated): + pkg_remove="$(echo "$pkg" | paste -sd " ")" + + if ! ( sudo pacman -Rsn $pkg_remove --color always ) # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkg_remove variable breaks AUR helper and pacman + then + # continue here only if "sudo pacman -Rns" has failed (again): + # a) save list of packages to backup variable + pkg_remove_backup="$( echo "$pkg_remove" | tr " " "\n" )" # here, do NOT write selection to file. this enables the user to guess which packages are dependencies. + + # b) Print error message. the user can read all error messages (of pacman) and decide what to do next. + echo + echo -e " \e[41m Package removal failed because at least one dependency was selected. \e[0m" + echo -e " \e[1m Press ENTER to try again or CTRL+C to quit. \e[0m" + read -r + # now, start at the top of the while-loop again... + else + # removing the pkg_remove_backup variable quits the while-loop + unset pkg_remove_backup + fi + + done + ;; + + * ) # do this in all other cases + echo -e " \e[1m No input recognized. Removal of packages has been cancelled. \e[0m" + ;; + + esac + + fi + fi +} + + +# Dependency Tree +# this function provides core functionality of "Dependency Tree". the help page provides additional explanations. +function func_t +{ + # write list of all installed packages to file /tmp/pacui-packages-local . then add list of packages in system repositories to the bottom of /tmp/pacui-packages-local. + #pacman -Qq | tr -d " " > /tmp/pacui-packages-local + expac -Q "%-33n\t%d" > /tmp/pacui-packages-local + #pacman -Slq | tr -d " " >> /tmp/pacui-packages-local + expac -S "%-33n\t%d" >> /tmp/pacui-packages-local + + local pkg + + pacui_tty_clean # clear terminal + #set +e + #set +E + + pkg="$( sort -k1,1 -u /tmp/pacui-packages-local | fzf -i --exact --no-sort --select-1 --query="$argument_input" --cycle --reverse --bind=right:half-page-down,left:half-page-up --margin="4%,1%,1%,2%" --info=inline --no-unicode --preview ' + if ( pacman -Qq {1} &>/dev/null ) # check, if 1. element of selected line is a locally installed package + then + echo -e "\e[1mInstalled package info: \e[0m" + pacman -Qi {1} --color always + + else + echo -e "\e[1mRepository package info: \e[0m" + pacman -Si {1} --color always # do this, if package is not locally installed + + fi + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:55%:wrap"; else echo "--preview-window=bottom:55%:wrap"; fi )" --header="ENTER for dependency tree. ESC to quit." --prompt='Enter string to filter list > ' | awk '{print $1}' )" + + pacui_tty_clean # clear terminal + + + if [[ -n "$pkg" ]] + then + if ( pacman -Qq "$pkg" &>/dev/null ) # check, if (in fzf) selected package is locally installed + then + + # explain the " echo {} | sed 's/^[|`- ]*//g' | cut -d ' ' -f 1 " command used below: + # first echo selected line in fzf. then, remove all symbols from the beginning of the line, which does not belong to the package name. if there are multiple package names (e.g. with "provides") in 1 line all other (except for the first package name) are cut from the result. + pactree --color --ascii "$pkg" | fzf -i --multi --exact --no-sort --ansi --reverse --bind=right:half-page-down,left:half-page-up --margin=4%,1%,1%,1% --info=inline --no-unicode --preview ' + echo -e "\e[1mInstalled package info: \e[0m" + pacman -Qi "$( echo -e {} | sed "s/[\|\`\ -]*//" | cut -d " " -f 1 )" --color always + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:55%:wrap"; else echo "--preview-window=bottom:55%:wrap"; fi )" --header="Local Dependency Tree of \"$pkg\". ESC to quit." --prompt='Enter string to filter list > ' > /tmp/pacui-t + + else + + # if $pkg is not a locally installed package, "pactree --sync" shows reverse dependency tree of repository packages: + pactree --color --ascii --sync "$pkg" | fzf -i --multi --exact --no-sort --ansi --reverse --bind=right:half-page-down,left:half-page-up --margin=4%,1%,1%,1% --info=inline --no-unicode --preview ' + if ( pacman -Qq "$( echo -e {} | sed "s/[\|\`\ -]*//" | cut -d " " -f 1 )" &>/dev/null ) # check, if selected line contains a locally installed package. + then + echo -e "\e[1mInstalled package info: \e[0m" + pacman -Qi "$( echo -e {} | sed "s/[\|\`\ -]*//" | cut -d " " -f 1 )" --color always # display local package information in preview window of fzf + + else + echo -e "\e[1mRepository package info: \e[0m" + pacman -Si "$( echo -e {} | sed "s/[\|\`\ -]*//" | cut -d " " -f 1 )" --color always # display package info from repository, if package is not locally installed + + fi + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:55%:wrap"; else echo "--preview-window=bottom:55%:wrap"; fi )" --header="Repository Dependency Tree of \"$pkg\". ESC to quit." --prompt='Enter string to filter list > ' > /tmp/pacui-t + + fi + + pacui_tty_clean # clear terminal + + fi + + #set -e + #set -E +} + + +# Reverse Dependency Tree +# this function provides core functionality of "Reverse Dependency Tree". the help page provides additional explanations. +function func_rt +{ + # write list of all installed packages to file /tmp/pacui-packages-local . then add list of packages in system repositories to the bottom of /tmp/pacui-packages-local. + #pacman -Qq | tr -d " " > /tmp/pacui-packages-local + expac -Q "%-33n\t%d" > /tmp/pacui-packages-local + #pacman -Slq | tr -d " " >> /tmp/pacui-packages-local + expac -S "%-33n\t%d" >> /tmp/pacui-packages-local + + local pkg + + pacui_tty_clean # clear terminal + #set +e + #set +E + + pkg="$( sort -k1,1 -u /tmp/pacui-packages-local | fzf -i --exact --no-sort --select-1 --query="$argument_input" --cycle --reverse --bind=right:half-page-down,left:half-page-up --margin="4%,1%,1%,2%" --info=inline --no-unicode --preview ' + if ( pacman -Qq {1} &>/dev/null ) # check, if 1. element of selected line is a locally installed package + then + echo -e "\e[1mInstalled package info: \e[0m" + pacman -Qi {1} --color always + + else + echo -e "\e[1mRepository package info: \e[0m" + pacman -Si {1} --color always # do this, if package is not locally installed + + fi + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:55%:wrap"; else echo "--preview-window=bottom:55%:wrap"; fi )" --header="ENTER for reverse dependency tree. ESC to quit." --prompt='Enter string to filter list > ' | awk '{print $1}' )" + + pacui_tty_clean # clear terminal + + + if [[ -n "$pkg" ]] + then + if ( pacman -Qq "$pkg" &>/dev/null ) # check, if (in fzf) selected package is locally installed + then + + # explain the " echo {} | sed 's/^[|`- ]*//g' | cut -d ' ' -f 1 " command used below: + # first echo selected line in fzf. then, remove all symbols from the beginning of the line, which does not belong to the package name. if there are multiple package names (e.g. with "provides") in 1 line all other (except for the first package name) are cut from the result. + pactree --color --ascii --reverse "$pkg" | fzf -i --multi --exact --no-sort --ansi --reverse --bind=right:half-page-down,left:half-page-up --margin=4%,1%,1%,1% --info=inline --no-unicode --preview ' + echo -e "\e[1mInstalled package info: \e[0m" + pacman -Qi "$( echo -e {} | sed "s/[\|\`\ -]*//" | cut -d " " -f 1 )" --color always + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:55%:wrap"; else echo "--preview-window=bottom:55%:wrap"; fi )" --header="Local Reverse Dependency Tree of \"$pkg\". ESC to quit." --prompt='Enter string to filter list > ' > /tmp/pacui-rt + + else + + # if $pkg is not a locally installed package, "pactree --sync" shows reverse dependency tree of repository packages: + pactree --color --ascii --sync --reverse "$pkg" | fzf -i --multi --exact --no-sort --ansi --reverse --bind=right:half-page-down,left:half-page-up --margin=4%,1%,1%,1% --info=inline --no-unicode --preview ' + if ( pacman -Qq "$( echo -e {} | sed "s/[\|\`\ -]*//" | cut -d " " -f 1 )" &>/dev/null ) # check, if selected line contains a locally installed package. + then + echo -e "\e[1mInstalled package info: \e[0m" + pacman -Qi "$( echo -e {} | sed "s/[\|\`\ -]*//" | cut -d " " -f 1 )" --color always # display local package information in preview window of fzf + + else + echo -e "\e[1mRepository package info: \e[0m" + pacman -Si "$( echo -e {} | sed "s/[\|\`\ -]*//" | cut -d " " -f 1 )" --color always # display package info from repository, if package is not locally installed + + fi + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:55%:wrap"; else echo "--preview-window=bottom:55%:wrap"; fi )" --header="Repository Reverse Dependency Tree of \"$pkg\". ESC to quit." --prompt='Enter string to filter list > ' > /tmp/pacui-rt + + fi + + pacui_tty_clean # clear terminal + + fi + + #set -e + #set -E +} + + +# List Package Files +# this function provides core functionality of "List Package Files". the help page provides additional explanations. +function func_l +{ + # write list of all installed packages to file /tmp/pacui-packages-local . then add list of packages in system repositories to the bottom of /tmp/pacui-packages-local. + #pacman -Qq | tr -d " " > /tmp/pacui-packages-local + expac -Q "%-33n\t%d" > /tmp/pacui-packages-local + #pacman -Slq | tr -d " " >> /tmp/pacui-packages-local + expac -S "%-33n\t%d" >> /tmp/pacui-packages-local + + local pkg + + pacui_tty_clean # clear terminal + #set +e + #set +E + + pkg="$( sort -k1,1 -u /tmp/pacui-packages-local | fzf -i --exact --no-sort --select-1 --query="$argument_input" --cycle --reverse --bind=right:half-page-down,left:half-page-up --margin="4%,1%,1%,2%" --info=inline --no-unicode --preview ' + if ( pacman -Qq {1} &>/dev/null ) # check, if selected line is a locally installed package + then + echo -e "\e[1mInstalled package info: \e[0m" + pacman -Qi {1} --color always # for local packages, local query is sufficient. + + else + echo -e "\e[1mRepository package info: \e[0m" + pacman -Si {1} --color always # do this, if package is not locally installed + + fi + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:55%:wrap"; else echo "--preview-window=bottom:55%:wrap"; fi )" --header="ENTER to list files. ESC to quit." --prompt='Enter string to filter list > ' | awk '{print $1}' )" + + pacui_tty_clean # clear terminal + + if [[ -n "$pkg" ]] + then + # next, it is checked, whether "pkg" is part of a list of all installed packages (pacman -Qq): the if-statement checks the exit code of the command "pacman -Qq $pkg &>/dev/null". + if ( pacman -Qq "$pkg" &>/dev/null ) + then + + # "pacman -Ql" shows sometimes more files than "pacman -Fl". therefore, both commands have to be used! + # take the output of command "pacman -Qlq $pkg" and make it searchable with fzf. for all used fzf flags see "man fzf". store all marked lines in file /tmp/pacui-list. + pacman -Ql "$pkg" --color always 2>/dev/null | grep -a -v "/$" | awk '{print $NF}' | fzf -i --multi --exact --no-sort --query="usr/bin/" --reverse --bind=right:half-page-down,left:half-page-up --margin=4%,1%,1%,1% --info=inline --header="List of files of local package \"$pkg\". Press ESC to quit." --prompt='Manipulate string to filter list > ' > /tmp/pacui-l + + else + + local server + # extract mirror/repository server url from /etc/pacman.d/mirrorlist file with command: + server="$( grep "^Server =" -m 1 "/etc/pacman.d/mirrorlist" | awk -F '=' '{print $2}' | awk -F '$' '{print $1}' )" + + # check, whether there is a connection to the mirror/repository server. this is needed for package download/update! + if ( wget --spider $(echo "$server") &>/dev/null ) # the "wget --spider" command gets executed in any case in order to check its output. + then + # update local package database. this needs a long time when internet connection is slow. + # in some cases, the local database has to be initialized first with "sudo pacman -Fyy" + sudo pacman -Fy + fi + + pacui_tty_clean # clear terminal + + # search in system repositories with "pacman -Fl" --> machine readable version of output is easier to read for awk! + # grep -a is used, because "pacman -Fl --machinereadable" returns a file starting with non-text data. the "-a" option ignores that. + # the awk command is used to format output: "-F '\0'" set "\0" as separator. this makes it possible to easily use $1,$2,$3,$4 as syntax later. + # "{print $1 "/" $2 " " $4}" prints output nicely formatted. + pacman -Fl --machinereadable "$pkg" | grep -a -v "/$" | awk -F '\0' '{print $4}' | fzf -i --multi --exact --no-sort --query="usr/bin/" --reverse --bind=right:half-page-down,left:half-page-up --margin=4%,1%,1%,1% --info=inline --header="List of files of remote package \"$pkg\". Press ESC to quit." --prompt='Manipulate string to filter list > ' > /tmp/pacui-l + + fi + + pacui_tty_clean # clear terminal + + fi + + #set -e + #set -E +} + + +# Search Package Files +# this function provides core functionality of "Search Package Files". the help page provides additional explanations. +function func_s +{ + # define local variables - all get deleted automatically when the function is exited + local file + + if [[ -n "$argument_input" ]] + then + # do this if variable "input" is not empty: + file="$argument_input" + else + # do this if pacui is used with UI or no argument is specified in "pacui s" command: + echo -e " \e[41m Enter (parts of) the file name to be searched. Press ENTER to start search. \e[0m" + echo -e " \e[1m Using regular expressions can narrow the search result dramatically: \e[0m" + read -r file + echo + fi + + if [[ -n "$file" ]] + then + + # use as many local variables as possible. unfortunately, it is still necessary to use a couple of temporary files (i have done a lot of tests and this current form of 'pacui s' seems to be the fastest): + local {pacui_search_temp_local,pacui_search_temp_repo2,pacui_search_temp_only_in_repo2,server} + + + echo -e "\n\e[1mLocal package files: \e[0m" > /tmp/pacui-search + # list all files of all installed local packages using "pacman -Ql --color always" + # awk -v VAR="$file" '$NF ~ VAR' searches for $file (using regex) in the last field/column only. write resulting list to /tmp/pacui-search + pacman -Ql --color always | awk -v VAR="$file" -F '/' '$NF ~ VAR' >> /tmp/pacui-search + # write a list of package names (which install files containing "$file" string) to variable $pacui_search_temp_local + pacui_search_temp_local="$( pacman -Ql | awk -v VAR="$file" -F '/' '$NF ~ VAR' | awk -F '/' '{print $1}' | sort -u | tr -d ' ' )" + + # extract mirror/repository server url from /etc/pacman.d/mirrorlist file with command: + server="$( grep "^Server =" -m 1 "/etc/pacman.d/mirrorlist" | awk -F '=' '{print $2}' | awk -F '$' '{print $1}' )" + # check, whether there is a connection to the mirror/repository server. this is needed for package download/update! + if ( wget --spider $(echo "$server") &>/dev/null ) # the "wget --spider" command gets executed in any case in order to check its output. + then + # update local package database. this needs a long time when internet connection is slow. + # in some cases, the local database has to be initialized first with "sudo pacman -Fyy" + sudo pacman -Fy + fi + + echo -e "\n\e[1mPackage files in system repositories: \e[0m" >> /tmp/pacui-search + # search in system repositories with "pacman -Fsx" --> machine readable version of output is easier to read for awk! + # comment: possible improvement: use "pv -ptb" to show progress bar (useful for large searches) + # the awk command is used to format output: "-F '\0'" set "\0" as separator. this makes it possible to easily use $1,$2,$3,$4 as syntax later. + + # store raw output of "pacman -Fsx" in file /tmp/pacui-search-temp-repo, because this process is quite slow + pacman -Fsx --machinereadable "$file" > "/tmp/pacui-search-temp-repo" + + # create new variable $pacui_search_temp_repo2 ,which only contains package names + pacui_search_temp_repo2="$( awk -F '\0' '{print $2}' "/tmp/pacui-search-temp-repo" | sort -u | tr -d ' ' )" + + # compare list of package names and only keep package names in system repository (in variable $pacui_search_temp_repo2): + pacui_search_temp_only_in_repo2="$( comm -13 <(echo "$pacui_search_temp_local") <(echo "$pacui_search_temp_repo2") )" + + # grep all package names from variable $pacui_search_temp_only_in_repo2 and search for them in file /tmp/pacui-search-temp-repo (leave "cat" and "grep" in their current order for better code readability) + # next, awk formats the list to the desired style + grep -a -f <(echo "$pacui_search_temp_only_in_repo2") "/tmp/pacui-search-temp-repo" | awk -F '\0' '{print $1 "/" "\033[1m" $2 "\033[0m " $4}' >> /tmp/pacui-search + + ### the last command (above) is REALLY fast, but the result is much less exact than desired!!! if an exact result is needed, the following command at the end of this comment block can provide it. + # "system( "grep -q " $2 " /tmp/pacui-search-temp-local" ) == 1" check exit status of "grep -q /tmp/pacui-search-temp-local"(checks, if is part of list /tmp/pacui-search-temp-local). if error occurs (==1), the package is printed to /tmp/pacui-search-temp + # "{print $1 "/" $2, $4}" prints output nicely formatted to /tmp/pacui-search. + # instead of regular ANSI escape sequences, i need to use \033[1m instead of \e[1m inside the awk command. + #pacman -Fsx --machinereadable "$file" | awk -F '\0' 'system("grep -q " $2 " /tmp/pacui-search-temp-local") == 1 {print $1 "/" "\033[1m" $2 "\033[0m " $4}' >> /tmp/pacui-search + + + pacui_tty_clean # clear terminal + #set +e + #set +E + + # display results from file /tmp/pacui-search in fzf. + cat /tmp/pacui-search | fzf -i --multi --exact --no-sort --ansi --reverse --bind=right:half-page-down,left:half-page-up --margin=4%,1%,1%,1% --info=inline --header="Package file names and paths containing \"$file\". Press ESC to quit." --prompt='Enter string to filter list > ' > /tmp/pacui-s + + #set -e + #set -E + pacui_tty_clean # clear terminal + + fi +} + + +# ======================= + + +# Roll Back System +# this function provides core functionality of "Roll Back System". the help page provides additional explanations. +function func_b +{ + # declare local variables + local {cache,logpath,cachePACAUR,pkgR,pkgI,pkgD,pkgU,line,temp1,temp2,temp3,pacui_cache_packages,pacui_cache_install,pacui_aur_install,pacui_cache_downgrade,pacui_cache_downgrade_counted,pacui_tmp_downgrade,pacui_aur_install,pacui_install,pacui_downgrade,pacui_cache_upgrade,pacui_cache_upgrade_counted,pacui_tmp_upgrade,pacui_upgrade} + pacui_aur_install="" # needed to avoid "unbound variable error" + + # get cache directory from file /etc/pacman.conf (without any white spaces) and write results to variable $cache: + cache="$( awk -F '=' '/^CacheDir/ {gsub(" ","",$2); print $2}' '/etc/pacman.conf' )" + # set variable $cache to default directory, if variable $cache is empty: + if [[ -z "$cache" ]] # if "cache" variable is empty (exact: if output of $cache is zero) + then + cache="/var/cache/pacman/pkg/" + fi + + # get log file path from file /etc/pacman.conf (without any white spaces) and write results to variable $logpath: + logpath="$( awk -F '=' '/^LogFile/ {gsub(" ","",$2); print $2}' '/etc/pacman.conf' )" + # set variable $logpath to default directory, if variable $logpath is empty: + if [[ -z "$logpath" ]] # if "logpath" variable is empty (exact: if output of $logpath is zero) + then + logpath="/var/log/pacman.log" + fi + + if [[ "$AUR_Helper" == "pacaur" ]] # checks, whether file "pacaur" exists, i.e. pacaur is installed + then + #set +u # temporarily disable strict mode for environment variables + + # the cache location of pacaur is important for downgrading packages installed from the AUR or reinstalling removed packages from the AUR: + if [[ -z $AURDEST ]] # $AURDEST is environment variable for changing pacaur's default cache directory. check, if "AURDEST" variable is empty + then + cachePACAUR="$HOME/.cache/pacaur/" + else + cachePACAUR="$AURDEST" + fi + + #set -u + fi + + + pacui_tty_clean # clear terminal + #set +e + #set +E + + # 1. get list of last installs/upgrades/removals/downgrades from pacman log and display result in fzf. + # when fzf quits, only selected package names (including the words " installed/upgraded/removed/downgraded") are saved to variable $pacui_cache_packages + # the space in front of "installed" prevents reinstallations being displayed (otherwise, they would be removed)! the ] in "] installed" prevents config file changes being displayed, e.g. "warning: /etc/sddm.conf installed as /etc/sddm.conf.pacnew" + # awk '{ $3="" ; $5="\033[1m" $5 "\033[0m" ; print }': this simply prints everything, but hides the third column and marks the 5th column as bold text. + pacui_cache_packages="$( tail -8000 "$logpath" | grep "] installed\|removed\|upgraded\|downgraded" | awk '{ $2="" ; $4="\t\033[1m" $4 " \033[0m" ; print }' | fzf -i --multi --exact --no-sort --select-1 --ansi --query="$argument_input" --cycle --tac --reverse --bind=right:half-page-down,left:half-page-up --margin="4%,1%,1%,2%" --info=inline --header="Press TAB key to (un)select. ENTER to roll back. ESC to quit." --prompt='Enter string to filter displayed list of recent Pacman changes > ' | sed 's/ ([^)]*)//g' | awk '{print $3 " " $4}' )" + + #set -e + #set -E + pacui_tty_clean # clear terminal + + # only run the command inside the if-statement, if variable $pacui_cache_packages is not empty and exists - this happens when fzf is quit with ESC or CTRL+C + if [[ ! -z "$pacui_cache_packages" ]] + then + + + # 2. in case of conflicting packages, packages have to be first removed (with the force option, because other packages might still depend on them). + # filter variable $pacui_cache_packages for the word "installed" and write package names to variable $pkgR + pkgR="$( echo "${pacui_cache_packages}" | awk '/installed/ {print $2}' | sort -u | paste -sd " " )" + + if [[ ! -z "$pkgR" ]] # this if-condition avoids error message when no package gets removed (and $pkgR is empty) + then + # remove packages with pacman command. use parameter substitution with ${...} (without quotes!!!) for it, because otherwise the pacman command fails! + sudo pacman "$argument_flag"-R ${pkgR} --color always # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkgR variable breaks AUR helper and pacman + fi + + + # 3. in case an "upgraded" package needs a package as dependency, the "removed" packages have to be installed. + # filter variable $pacui_cache_packages for the word "removed" and write package names to variable $pacui_cache_install + pacui_cache_install="$( echo "${pacui_cache_packages}" | awk '/removed/ {print $2}' )" + + if [[ ! -z "$pacui_cache_install" ]] # this if-condition avoids error messages when no package gets installed (and variable $pacui_cache_install is empty) + then + + if [[ "$AUR_Helper" == "pacaur" ]] # checks, whether file "pacaur" exists, i.e. pacaur is installed + then + # the while-loop here is needed to read the content of every line of $pacui_cache_install variable and save that line to variable $line. + pacui_aur_install="$( + while IFS='' read -r line || [[ -n "$line" ]] + do + ## the problem here is that AUR packages are not named/numbered in a constant and easy sortable way. therefore, we search for all files and output their modification date in an easy searchable format (and then, the file name). + ## then, "grep" is used to get only package files. then, the list is sorted (by the modification date). + ## awk gets rid of the modification date. grep filters for the file name $line. sed only chooses the first/top line. + find "$cachePACAUR" -maxdepth 2 -mindepth 2 -type f -printf "%T+\t%p\n" | grep ".pkg.tar.[gx]z$" | sort -rn | awk '{print $2}' | grep "$line""-" | sed -n '1p' + done < <(echo "${pacui_cache_install}") + )" + fi + + # read line by line from variable $pacui_cache_install in while loop and save that line to variable $line + pacui_install="$( + while IFS='' read -r line || [[ -n "$line" ]] + do + # write name of latest version in cache into variable $pacui_install ("sort" puts latest version on top, which is then selected): + find "$cache" -name "${line}-[0-9a-z.-_]*.pkg.tar.[gx]z" | sort -r | sed -n '1p' + done < <(echo "${pacui_cache_install}") + )" + + # sort output to suit pacman's syntax. pacman needs a list of package names separated by single spaces. + if [[ ! -z "$pacui_aur_install" ]] + then + # if AUR packages should be installed, the lists of package names are first combined before they get sorted and rearranged to space separated lists. + # use parameter substitution to combine 2 lists of packages. + pkgI="$( printf "${pacui_install}\n${pacui_aur_install}" | sort -u | paste -sd " " )" + else + pkgI="$( echo "${pacui_install}" | sort -u | paste -sd " " )" + fi + + # finally, all packages get installed manually using "pacman -U": + if [[ ! -z "$pkgI" ]] + then + # install cannot be done as dependency, because sometimes packages are simply replaced by other packages. in this case, installing as dependency would be bad! + sudo pacman "$argument_flag"-U ${pkgI} --color always # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkgI variable breaks AUR helper and pacman + fi + + fi + + + # 4. filter variable $pacui_cache_packages file for the word "upgraded" and write package names to variable $pacui_cache_downgrade + # variable $pacui_cache_packages contains list of package names to be downgraded! + pacui_cache_downgrade="$( echo "${pacui_cache_packages}" | awk '/upgraded/ {print $2}' )" + + if [[ ! -z "$pacui_cache_downgrade" ]] # this if-condition avoids error messages when no package gets downgraded (and variables $pacui_cache_downgrade is empty) + then + + # here, it is impossible to use variables instead of temporary files. therefore, the temporary files should be as tamper-proof as possible. + # Create temp file with mktemp command (Important for security). the XXXXXXXX indicates numbers assigned by "mktemp" command. + # the XXXXXXXXX numbers make it necessary to call the temporary file in the code below with ${pacui_tmp_downgrade} ! + pacui_tmp_downgrade="$( mktemp /tmp/pacui-tmp-downgrade.XXXXXXXX )" + + # add trap command to immediately remove upon ctrl+c (or any other case this function quits in the middle) for security purposes + # this is the normal syntax for "trap" command. + trap "unlink ${pacui_tmp_downgrade}" EXIT + + # first, count the number of times the package name appears in file ${pacui_cache_downgrade}: + pacui_cache_downgrade_counted="$( echo "${pacui_cache_downgrade}" | sort | uniq -c )" + # "uniq" command: first argument in variable $pacui_cache_downgrade_counted is the number of times the package name appears and the second is the package name. + + # read line by line from variable $pacui_cache_downgrade_counted in while loop and save that line to variable $line + pacui_downgrade="$( + while read -r line && [[ -n "$line" ]] + do + + # attention, the following variables can be empty: + temp1="$( echo "$line" | awk '{print $1}' )" # this variable is the no. of times a package has to be downgraded + temp2="$( echo "$line" | awk '{print $2}' )" # this variable is the package name to be downgraded + + if [[ -n "$temp2" ]] # checks, if length of string is non-zero ("-n" conditional bash expression is the opposite of "-z" (check, whether length of string is zero)) + then + # write list with all versions of package in cache into file ${pacui_tmp_downgrade} (sorted - newest package version is on top) + find "$cache" -name "${temp2}-[0-9a-z.-_]*.pkg.tar.[gx]z" | sort -r > ${pacui_tmp_downgrade} + + if [[ "$AUR_Helper" == "pacaur" ]] # checks, whether file "pacaur" exists, i.e. pacaur is installed + then + # do the same as below for files from pacaur's cache directory. + # the problem here is that AUR packages are not named/numbered in a constant and easy sortable way. therefore, we search for all files and output their modification date in an easy searchable format (and then, the file name). + # then, "grep" is used to get only package files. then, the list is sorted (by the modification date). + # awk gets rid of the modification date. grep filters for the file name $temp2. + find "$cachePACAUR" -maxdepth 2 -mindepth 2 -type f -printf "%T+\t%p\n" | grep ".pkg.tar.[gx]z$" | sort -rn | awk '{print $2}' | grep "$temp2""-" >> ${pacui_tmp_downgrade} + fi + + # temp3 is supposed to be "2p" when temp1=1 and "3p" when temp1=2 ... --> needed for "sed" command below + temp3="$(( temp1 + 1 ))p" + + # the next line moves the $((temp3-1))-th version below the currently installed package version to file ${pacui_downgrade}. if no such old version is available, nothing happens. + # this command determines the currently installed verions of package $temp2: pacman -Q "$temp2" | awk '{print $2}' + grep "$( pacman -Q "$temp2" | awk '{print $2}' )" -A 100 "$pacui_tmp_downgrade" | sed -n "$temp3" + fi + + done < <(echo "${pacui_cache_downgrade_counted}") )" + + # remove temporary file. it is no longer needed and should not be left on the system. + unlink ${pacui_tmp_downgrade} + + # sort output to suit pacman's syntax. pacman needs a list of package names separated by single spaces. + pkgD="$( echo "${pacui_downgrade}" | sort -u | paste -sd " ")" + + # the following if-statement prevents the following error, in case there is no older package version available: "error: no targets specified (use -h for help)" + if [[ ! -z "$pkgD" ]] # checks, if variable is not empty + then + # downgrade packages by manually installing them: (sudo pacman -U --noconfirm --color always ) + sudo pacman "$argument_flag"-U ${pkgD} --color always # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkgD variable breaks AUR helper and pacman + fi + + fi + + + # 5. filter variable $pacui_cache_packages file for the word "downgraded" and write package names to variable $pacui_cache_upgrade + # variable $pacui_cache_packages contains list of package names to be downgraded! + pacui_cache_upgrade="$( echo "${pacui_cache_packages}" | awk '/downgraded/ {print $2}' )" + + if [[ ! -z "$pacui_cache_upgrade" ]] # this if-condition avoids error messages when no package gets upgraded (and variables $pacui_cache_upgrade is empty) + then + + # here, it is impossible to use variables instead of temporary files. therefore, the temporary files should be as tamper-proof as possible. + # Create temp file with mktemp command (Important for security). the XXXXXXXX indicates numbers assigned by "mktemp" command. + # the XXXXXXXXX numbers make it necessary to call the temporary file in the code below with "${pacui_tmp_upgrade}" (without ")! + pacui_tmp_upgrade="$( mktemp /tmp/pacui-tmp-upgrade.XXXXXXXX )" + + # add trap command to immediately remove upon ctrl+c (or any other case this function quits in the middle) for security purposes + # this is the normal syntax for "trap" command. + trap "unlink ${pacui_tmp_upgrade}" EXIT + + # first, count the number of times the package name appears in file ${pacui_cache_upgrade}: + pacui_cache_upgrade_counted="$( echo "${pacui_cache_upgrade}" | sort | uniq -c )" + # "uniq" command: first argument in variable $pacui_cache_upgrade_counted is the number of times the package name appears and the second is the package name. + + # read line by line from variable $pacui_cache_upgrade_counted in while loop and save that line to variable $line + pacui_upgrade="$( + while read -r line && [[ -n "$line" ]] + do + + # attention, the following variables can be empty: + temp1="$( echo "$line" | awk '{print $1}' )" # this variable is the no. of times a package has to be upgraded + temp2="$( echo "$line" | awk '{print $2}' )" # this variable is the package name to be upgraded + + if [[ -n "$temp2" ]] # checks, if length of string is non-zero: "-n" conditional bash expression is the opposite of "-z", which checks whether length of string is zero + then + # write list with all versions of package in cache into file ${pacui_tmp_upgrade} - sorted by newest package version + find "$cache" -name "${temp2}-[0-9a-z.-_]*.pkg.tar.[gx]z" | sort -r > ${pacui_tmp_upgrade} + + if [[ "$AUR_Helper" == "pacaur" ]] # checks, whether file "pacaur" exists, i.e. pacaur is installed + then + # do the same as below for files from pacaur's cache directory. + # the problem here is that AUR packages are not named/numbered in a constant and easy sortable way. therefore, we search for all files and output their modification date in an easy searchable format (and then, the file name). + # then, "grep" is used to get only package files. then, the list is sorted (by the modification date). + # awk gets rid of the modification date. grep filters for the file name $temp2. + find "$cachePACAUR" -maxdepth 2 -mindepth 2 -type f -printf "%T+\t%p\n" | grep ".pkg.tar.[gx]z$" | sort -rn | awk '{print $2}' | grep "$temp2""-" >> ${pacui_tmp_upgrade} + fi + + # temp3 is supposed to be "2p" when temp1=1 and "3p" when temp1=2 ... --> needed for "sed" command below + temp3="$(( temp1 + 1 ))p" + + # the next line moves the $((temp3-1))-th version below the currently installed package version to file $pacui_upgrade. if no such old version is available, nothing happens. + # this command determines the currently installed versions of package $temp2: pacman -Q "$temp2" | awk '{print $2}' + grep "$( pacman -Q "$temp2" | awk '{print $2}' )" -B 100 "$pacui_tmp_upgrade" | tac | sed -n "$temp3" + fi + + done < <(echo "${pacui_cache_upgrade_counted}") )" + + # remove temporary file. it is no longer needed an should not be left on the system. + unlink ${pacui_tmp_upgrade} + + # sort output to suit pacman's syntax. pacman needs a list of package names separated by single spaces. + pkgU="$( echo "${pacui_upgrade}" | sort -u | paste -sd " " )" + + # the following if-statement prevents the following error, in case there is no older package version available: "error: no targets specified (use -h for help)" + if [[ ! -z "$pkgU" ]] # checks, if variable is not empty + then + # upgrade packages by manually installing them: (sudo pacman -U --noconfirm --color always ) + sudo pacman "$argument_flag"-U ${pkgU} --color always # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkgU variable breaks AUR helper and pacman + fi + + fi + + + fi +} + + +# Fix Pacman Errors +# this function provides core functionality of "Fix Pacman Errors". it is separated into multiple parts. most parts begin (or contain) an introducing "echo" command or comment, which explains what is being done. the help page explains the core functionality of every part in detail, too. +function func_f +{ + # delete only pacui-related packages in /tmp directory. if other files are deleted, linux starts to act strange! + if ( sudo find /tmp/ -iname 'pacui*' -print -quit | grep pacui -q ) # check if "pacui*" file or directory is found in /tmp/ directory and print its first path. use a quiet "grep" to have a success condition. + then + echo " deleting PacUI cache ..." + sudo rm -r /tmp/pacui* # here the "rm -r" command is needed, because both directories and files have to be removed. "unlink" and "rmdir" do not work here. + echo "" + fi + + + # remove pacman database lock file + local dbpath="$( awk -F '=' '/^DBPath/ {gsub(" ","",$2); print $2}' '/etc/pacman.conf' )" # extract path of database file from pacman.conf + if [[ -z "$dbpath" ]] # if "dbpath" variable is empty (exact: if output of $dbpath is zero) + then + dbpath="/var/lib/pacman/" # default database path + fi + + if [[ -f "$dbpath"db.lck ]] # check, if pacman database lock file "db.lck" exists + then + echo " removing pacman database lock ..." + sudo unlink "$dbpath"db.lck # remove file + echo "" + fi + unset dbpath + + + # check for "pacman-mirrors" or "reflector" packages. one of those is needed! + if [[ -f /usr/bin/pacman-mirrors ]] || [[ -f /usr/bin/reflector ]] + then + echo " fixing mirrors (which can take a while) ..." + # do this, if system uses pacman-mirrors (default in Manjaro) + if [[ -f /usr/bin/pacman-mirrors ]] + then + sudo pacman-mirrors -f 0 && sudo pacman -Syy # choose mirrors server (with up-to-date packages) with lowest ping from all available mirrors and sync database. + # here, "pacman -Syy" is used to sync to the (potentially new) repository server. this is important! + # but "pacman -Syy" (when pacman -S is executed later on) can result in a partially updated system. this cannot be prevented here, because it is possible the user's keys are corrupted and he is no longer able to install/update any packages. + fi + # do this, if system uses reflector (default on Arch Linux or distributions using Arch Linux mirrors/repo servers) + if [[ -f /usr/bin/reflector ]] + then + sudo reflector --verbose --protocol https --age 1 --sort rate --save /etc/pacman.d/mirrorlist && sleep 10 && sudo pacman -Syy + fi + echo "" + fi + + + local server + # extract mirror/repository server url from /etc/pacman.d/mirrorlist file with command: + server="$( grep "^Server =" -m 1 "/etc/pacman.d/mirrorlist" |awk -F '=' '{print $2}' | awk -F '$' '{print $1}' )" + + # check, whether there is a connection to the mirror/repository server. this is needed for package download/update! + if ! ( wget --spider $(echo "$server") &>/dev/null ) # the "wget --spider" command gets executed in any case in order to check its output. + then + + # print error message, if there is no connection to a mirror/repository server and quit + echo + echo -e " \e[41m Either there is something wrong with your internet connection or with your mirror/repository server: $server \e[0m" # writing the $server variables in quotes (" or ') does not work! using ' for echo command does not work either! + echo -e " \e[1;41m Please make sure both are ok and rerun this part of PacUI. \e[0m" + echo + + else + + # the following command sometimes prevents an error connecting to the key server + echo + echo " sudo dirmngr /dev/null" + if ! ( sudo dirmngr /dev/null ) # check, if any critical errors occurred in command in parenthesis + then + echo + echo -e " \e[41m The following dirmngr errors have occured: \e[0m" + sudo dirmngr /dev/null ) # check, whether string "/etc/pacman.d/gnupg/pubring.gpg" is already present in file "$HOME/.gnupg/gpg.conf". + then + + echo " trusting keys from system developers ..." + + # sometimes, people get a "missing key" error about keys they have already installed. this can be confusing + # automatically trust all keys from arch linux trusted users (and manjaro developers) - both for packages from the repositories and packages from the AUR. + # there are 2 different places on system for keys to be stored. include pacman's keys in your private collection of keys, which is used when installing (i.e. veritying) packages from the AUR. + echo "# " >> "$HOME/.gnupg/gpg.conf" + echo "# Automatically trust all keys in Pacman's keyring: " >> "$HOME/.gnupg/gpg.conf" + echo "keyring /etc/pacman.d/gnupg/pubring.gpg" >> "$HOME/.gnupg/gpg.conf" + echo + + fi + fi + #set -u + + + echo " trying to update system conventionally ..." + if ! ( sudo pacman -Syu --noconfirm) + then + + echo + echo -e " \e[41m Conventional update(s) failed. Please read the error message(s) above. \e[0m" + echo -e " \e[1;41m Did the update fail because of key or keyring errors? [y|N] \e[0m" + read -r -n 1 -e answer # save user input in "answer" variable (only accept 1 character as input) + + case ${answer:-n} in # if ENTER is pressed, the variable "answer" is empty. if "answer" is empty, its default value is "n". + + y|Y|yes|YES|Yes ) # do this, if "answer" is y or Y or yes or YES or Yes + + echo + echo -e " Lowering pacman securities (in case keyring is broken) ..." + # first, make a backup of /etc/pacman.conf, which preserves all file permissions and other attributes. "cp -f" overwrites the target file, if it already exists. + # the second command replaces all "SigLevel = ....." strings with "SigLevel = Never" in the /etc/pacman.conf file. This change deactivates all key signature checks in pacman. + # general comment about "sed" usage in scripts: in order to avoid breakage, it is recommended to escape all the following characters /\.*[]^$ with a \ character! + sudo cp --preserve=all -f /etc/pacman.conf /etc/pacman.conf.backup && sudo sed -i 's/SigLevel[ ]*=[A-Za-z ]*/SigLevel = Never/' '/etc/pacman.conf' + # if something goes wrong in the following code, the SigLevel is never raised back and we would mess on a user's system. THIS HAS TO BE PREVENTED! solution: use trap, which reverses our changes in /etc/pacman.conf file whenever pacui quits unexpectedly: + trap "sudo cp --preserve=all -f /etc/pacman.conf.backup /etc/pacman.conf && sudo rm /etc/pacman.conf.backup" EXIT + echo "" + + + echo " trying to update system manually without checking keys ..." + # if keyring is broken, updates (without checking keys) can be manually installed now. + if ! ( sudo pacman -Syu ) # this last update attempt does not use "--noconfirm" and allows user intervention + then + + echo + echo -e " \e[41m Update still not successful. PacUI is unable to fix the system automatically. \e[0m" + echo -e " \e[41m Read all error messages carefully and try to fix them yourself. \e[0m" + echo + + echo " raising pacman securities back ..." + # This command will revert the change from above: overwrite (modified) /etc/pacman.conf file with its (unmodified) backup. then, the backup file is deleted. + sudo cp --preserve=all -f /etc/pacman.conf.backup /etc/pacman.conf && sudo rm /etc/pacman.conf.backup + # now, the trap is longer needed. reset trap: + trap − EXIT + echo "" + + else + + echo + echo -e " \e[41m It seems the update succeded because of the temporary lack of key checks. \e[0m" + echo -e " \e[1;41m Should PacUI prevent all future key / keyring errors? [y|N] \e[0m" + read -r -n 1 -e answer2 # save user input in "answer2" variable (only accept 1 character as input) + + case ${answer2:-n} in # if ENTER is pressed, the variable "answer2" is empty. if "answer2" is empty, its default value is "n". + + y|Y|yes|YES|Yes ) # do this, if "answer2" is y or Y or yes or YES or Yes + + # remove gnupg including all keys + if [[ -f /etc/pacman.d/gnupg ]] + then + echo + echo " sudo rm -r /etc/pacman.d/gnupg ..." + sudo rm -r /etc/pacman.d/gnupg &>/dev/null + fi + + echo + echo " reinstalling gnupg ..." + sudo pacman -Syu gnupg --noconfirm + echo "" + + + echo " installing all necessary keyrings ..." + # This command will install all keyrings from avialable current repository + sudo pacman -Syu $( pacman -Qsq '(-keyring)' | grep -v -i -E '(gnome|python|debian)' | paste -sd " " ) --noconfirm # ATTENTION: (i do not know why but) using quotes (" symbols) around $(...) does not work! + echo "" + + + echo " raising pacman securities back ..." + # This command will revert the change from above: overwrite (modified) /etc/pacman.conf file with its (unmodified) backup. then, the backup file is deleted. + sudo cp --preserve=all -f /etc/pacman.conf.backup /etc/pacman.conf && sudo rm /etc/pacman.conf.backup + # now, the trap is longer needed. reset trap: + trap − EXIT + echo "" + + + echo " initializing and populating keyring ..." + sudo pacman-key --init && echo "" && sudo pacman-key --populate $( pacman -Qsq '(-keyring)' | grep -v -i -E '(gnome|python|debian)' | sed 's/-keyring//' | paste -sd " " ) # ATTENTION: (i do not know why but) using quotes (" symbols) around $(...) does not work! + echo "" + + + echo " updating file database ..." + sudo pacman -Fyy + echo "" + ;; + + + n|N|no|NO|No ) # do this, if "answer2" is n or N or no or NO or No + + echo + echo " do not fix keyring(s) ..." + echo + + + echo " raising pacman securities back ..." + # This command will revert the change from above: overwrite (modified) /etc/pacman.conf file with its (unmodified) backup. then, the backup file is deleted. + sudo cp --preserve=all -f /etc/pacman.conf.backup /etc/pacman.conf && sudo rm /etc/pacman.conf.backup + # now, the trap is longer needed. reset trap: + trap − EXIT + echo "" + + + echo " updating file database ..." + sudo pacman -Fyy + echo "" + ;; + + + * ) # do this, if "answer2" is neither "no" nor "yes". + echo + echo -e " \e[41m Answer not recognized. Please try again with a valid answer. \e[0m" + echo -e " \e[41m All attempts to fix your system were stopped. \e[0m" + echo + + + echo " raising pacman securities back ..." + # This command will revert the change from above: overwrite (modified) /etc/pacman.conf file with its (unmodified) backup. then, the backup file is deleted. + sudo cp --preserve=all -f /etc/pacman.conf.backup /etc/pacman.conf && sudo rm /etc/pacman.conf.backup + # now, the trap is longer needed. reset trap: + trap − EXIT + echo "" + ;; + esac + fi + ;; + + + n|N|no|NO|No ) # do this, if "answer" is n or N or no or NO or No + + if [[ "$(cat /proc/1/comm)" == "systemd" ]] # if init system is systemd + then + + # set almost correct time (while ignoring time zone and daylight saving time): + # 1. stop running NTPD service (and ignore output in case NTPD is not installed): + echo + echo " sudo systemctl stop ntpd.service ..." + sudo systemctl stop ntpd.service &>/dev/null + echo "" + + + # 2. download and install ntp: + echo " installing ntp ..." + sudo pacman -S ntp --noconfirm + # if "sudo pacman -Syu --noconfirm" (above) was not completed successfully, a partial update is done here in order to try to fix the update machanism. + # if "sudo pacman -Syu --noconfirm" (without checking keys) (below) is successful, the system will not be left in a partially updated state! + echo "" + + + # 3. start NTP daemon and set system clock + # 4. wait for 10 seconds (maximum time needed for system clock to set to new time) + # 5. write time from system clock to hardware clock + echo " setting clock (which can take a while) ..." + sudo ntpd -qg && sleep 10 && sudo hwclock -w + echo "" + + fi + + + echo " trying to update system manually again ..." + if ! ( sudo pacman -Syu ) # this last update attempt does not use "--noconfirm" and allows user intervention + then + echo + echo -e " \e[41m Update still not successful. PacUI is unable to fix the system automatically. \e[0m" + echo -e " \e[41m Read all error messages carefully and try to fix them yourself. \e[0m" + echo + + else + echo + echo " updating file database ..." + sudo pacman -Fyy + echo "" + + fi + ;; + + + * ) # do this, if "answer" is neither "no" nor "yes". + echo + echo -e " \e[41m Answer not recognized. Please try again with a valid answer. \e[0m" + echo -e " \e[41m All attempts to fix your system were stopped. \e[0m" + ;; + esac # end of "case" loop + + else + + # do this, if conventional system update was successful + echo + echo " updating file database ..." + sudo pacman -Fyy + echo "" + + fi + + fi +} + + +# Edit Config Files +# this function provides core functionality of "Edit Config Files". the help page provides additional explanations. +function func_c +{ + # here, it is impossible to use variables instead of temporary files. therefore, the temporary files should be as tamper-proof as possible. + # Create temp file with mktemp command (Important for security). the XXXXXXXX indicates numbers assigned by "mktemp" command. + # the XXXXXXXXX numbers make it necessary to call the temporary file in the code below with ${pacui_config} ! + pacui_config="$( mktemp /tmp/pacui-config.XXXXXXXX )" + + # add trap command to immediately remove upon ctrl+c (or any other case this function quits in the middle) for security purposes + # this is the normal syntax for "trap" command: + trap "unlink ${pacui_config}" EXIT + + #set +u + + # if file /etc/default/tlp exists, push string "/etc/default/tlp Configure power management." into ${pacui_config} file. there are enough spaces added to avoid users seeing file/folder description: + [[ -f /etc/default/tlp ]] && echo -e "/etc/default/tlp Configure power management in file:" >> ${pacui_config} + [[ -f /etc/default/cpupower ]] && echo -e "/etc/default/cpupower Configure CPU power management in file:" >> ${pacui_config} + [[ -f /etc/profile.d/freetype2.sh ]] && echo -e "/etc/profile.d/freetype2.sh Configure TrueType interpreter (including Infinality mode) in file:" >> ${pacui_config} + [[ -f /etc/pulse/daemon.conf ]] && echo -e "/etc/pulse/daemon.conf Configure global PulseAudio daemon in file:" >> ${pacui_config} + [[ -f /etc/pulse/default.pa ]] && echo -e "/etc/pulse/default.pa Configure PulseAudio modules in file:" >> ${pacui_config} + [[ -f /etc/asound.conf ]] && echo -e "/etc/asound.conf Configure ALSA in file:" >> ${pacui_config} + [[ -f $HOME/.gnupg/gpg.conf ]] && echo -e "\e[31m$HOME/.gnupg/gpg.conf Configure GnuPG user settings in file:\e[0m" >> ${pacui_config} + [[ -f /etc/pacman.conf ]] && echo -e "\e[31m/etc/pacman.conf Configure Pacman in file:\e[0m" >> ${pacui_config} + [[ -f /etc/pacman-mirrors.conf ]] && echo -e "/etc/pacman-mirrors.conf Configure Manjaro's pacman-mirrors in file:" >> ${pacui_config} + [[ -f /etc/pacman.d/mirrorlist ]] && echo -e "/etc/pacman.d/mirrorlist Configure mirror list manually in file:" >> ${pacui_config} + [[ -f $HOME/.config/trizen/trizen.conf ]] && echo -e "$HOME/.config/trizen/trizen.conf Configure Trizen in file:" >> ${pacui_config} + [[ -f $HOME/.config/yay/config.json ]] && echo -e "$HOME/.config/yay/config.json Configure Yay in file:" >> ${pacui_config} + [[ -f $XDG_CONFIG_DIRS/pacaur/config ]] && echo -e "$XDG_CONFIG_DIRS/pacaur/config Configure Pacaur in file:" >> ${pacui_config} + [[ -f $HOME/.config/pikaur.conf ]] && echo -e "$HOME/.config/pikaur.conf Configure Pikaur in file:" >> ${pacui_config} + [[ -f /etc/pakku.conf ]] && echo -e "/etc/pakku.conf Configure Pakku in file:" >> ${pacui_config} + [[ -f $XDG_CONFIG_HOME/aurman/aurman_config ]] && echo -e "$XDG_CONFIG_HOME/aurman/aurman_config Configure Aurman in file:" >> ${pacui_config} + [[ -f $HOME/.config/aurman/aurman_config ]] && echo -e "$HOME/.config/aurman/aurman_config Configure Aurman in fallback file:" >> ${pacui_config} + [[ -f /etc/makepkg.conf ]] && echo -e "/etc/makepkg.conf Configure package compilation in file:" >> ${pacui_config} + [[ -d /usr/lib/NetworkManager/conf.d ]] && echo -e "/usr/lib/NetworkManager/conf.d/ Configure NetworkManager in files:" >> ${pacui_config} + [[ -f /etc/resolv.conf ]] && echo -e "/etc/resolv.conf Configure DNS servers in file:" >> ${pacui_config} + [[ -f /etc/hostname ]] && echo -e "/etc/hostname Configure your network hostname in file:" >> ${pacui_config} + [[ -f /etc/hosts ]] && echo -e "/etc/hosts Configure local DNS in file:" >> ${pacui_config} + [[ -f /etc/environment ]] && echo -e "/etc/environment Configure system-wide environment variables in file:" >> ${pacui_config} + [[ -f /etc/locale.conf ]] && echo -e "/etc/locale.conf Configure regional standards in file:" >> ${pacui_config} + [[ -f /etc/slim.conf ]] && echo -e "/etc/slim.conf Configure slim display manager in file:" >> ${pacui_config} + [[ -f /etc/lightdm.conf ]] && echo -e "/etc/lightdm.conf Configure lightdm display manager in file:" >> ${pacui_config} + [[ -f /etc/sddm.conf ]] && echo -e "/etc/sddm.conf Configure sddm display manager in file:" >> ${pacui_config} + [[ -f /etc/mdm/mdm.conf ]] && echo -e "/etc/mdm/mdm.conf Configure mdm display manager in file:" >> ${pacui_config} + [[ -f /etc/lxdm/lxdm.conf ]] && echo -e "/etc/lxdm/lxdm.conf Configure lxdm display manager in file:" >> ${pacui_config} + [[ -f /etc/gdm/custom.conf ]] && echo -e "/etc/gdm/custom.conf Configure gdm display manager in file:" >> ${pacui_config} + [[ -f /etc/entrance/entrance.conf ]] && echo -e "/etc/entrance/entrance.conf Configure entrance display manager in file:" >> ${pacui_config} + [[ -f /etc/conf.d/xdm ]] && echo -e "/etc/conf.d/xdm Configure xdm display manager in file:" >> ${pacui_config} + [[ -f /etc/updatedb.conf ]] && echo -e "/etc/updatedb.conf Configure database of locate in file:" >> ${pacui_config} + [[ -f $HOME/.bashrc ]] && echo -e "$HOME/.bashrc Configure bash shell in file:" >> ${pacui_config} + [[ -f $HOME/.zshrc ]] && echo -e "$HOME/.zshrc Configure zsh shell in file:" >> ${pacui_config} + [[ -f $HOME/.config/fish ]] && echo -e "$HOME/.config/fish/ Configure fish shell in file:" >> ${pacui_config} + [[ -f $HOME/.xinitrc ]] && echo -e "\e[31m$HOME/.xinitrc Configure X server startup in file:\e[0m" >> ${pacui_config} + [[ -f $HOME/.Xresources ]] && echo -e "\e[31m$HOME/.Xresources Configure X client applications in file:\e[0m" >> ${pacui_config} + [[ -f /etc/fstab ]] && echo -e "\e[31m/etc/fstab Configure file system mount table in file:\e[0m" >> ${pacui_config} + [[ -f /etc/crypttab ]] && echo -e "\e[31m/etc/crypttab Configure encrypted file system mount table in file:\e[0m" >> ${pacui_config} + [[ -f /etc/sudoers ]] && echo -e "\e[31m/etc/sudoers Configure sudo in file:\e[0m" >> ${pacui_config} + [[ -d /etc/udev/rules.d/ ]] && echo -e "/etc/udev/rules.d/ Configure device manager for Linux kernel in these files:" >> ${pacui_config} + [[ -f /etc/systemd/swap.conf ]] && echo -e "/etc/systemd/swap.conf Configure systemd swap in file:" >> ${pacui_config} + [[ -f /etc/systemd/logind.conf ]] && echo -e "/etc/systemd/logind.conf Configure systemd user logins in file:" >> ${pacui_config} + [[ -f /etc/systemd/journald.conf ]] && echo -e "/etc/systemd/journald.conf Configure systemd logging in file:" >> ${pacui_config} + [[ -f /etc/systemd/coredump.conf ]] && echo -e "/etc/systemd/coredump.conf Configure systemd coredumps in file:" >> ${pacui_config} + [[ -f /etc/systemd/system.conf ]] && echo -e "/etc/systemd/system.conf Configure systemd system in file:" >> ${pacui_config} + [[ -f /etc/systemd/timesyncd.conf ]] && echo -e "/etc/systemd/timesyncd.conf Configure systemd-timesyncd in file:" >> ${pacui_config} + [[ -f /etc/systemd/user.conf ]] && echo -e "/etc/systemd/user.conf Configure systemd user units in file:" >> ${pacui_config} + [[ -d /usr/lib/systemd/system ]] && echo -e "/usr/lib/systemd/system/ Configure systemd in these files:" >> ${pacui_config} + [[ -d /usr/lib/systemd/network ]] && echo -e "/usr/lib/systemd/network/ Configure systemd-networkd in these files:" >> ${pacui_config} + [[ -d /etc/X11/xorg.conf.d ]] && echo -e "\e[31m/etc/X11/xorg.conf.d/ Configure Xorg display server in these files:\e[0m" >> ${pacui_config} + [[ -f $HOME/.config/weston.ini ]] && echo -e "$HOME/.config/weston.ini Configure Weston compositor in file:" >> ${pacui_config} + [[ -d /usr/lib/sysctl.d ]] && echo -e "/usr/lib/sysctl.d/ Configure kernel parameter files at runtime:" >> ${pacui_config} + [[ -d /etc/modules-load.d ]] && echo -e "\e[31m/etc/modules-load.d/ Configure Kernel module loading during boot in files:\e[0m" >> ${pacui_config} + [[ -f /etc/mkinitcpio.conf ]] && echo -e "\e[31m/etc/mkinitcpio.conf Configure initial ramdisk environment in file:\e[0m" >> ${pacui_config} + [[ -f /etc/default/grub ]] && echo -e "\e[31m/etc/default/grub Configure GRUB boot loader in file:\e[0m" >> ${pacui_config} + [[ -f /boot/grub/custom.cfg ]] && echo -e "/boot/grub/custom.cfg Configure custom GRUB entries in file:" >> ${pacui_config} + [[ -f /boot/loader/loader.conf ]] && echo -e "\e[31m/boot/loader/loader.conf Configure systemd-boot boot loader in file:\e[0m" >> ${pacui_config} + [[ -f /etc/sdboot-manage.conf ]] && echo -e "\e[31m/etc/sdboot-manage.conf Configure systemd-boot-manager in file:\e[0m" >> ${pacui_config} + [[ -f /boot/loader/entries ]] && echo -e "\e[31m/boot/loader/entries/ Configure systemd-boot boot loader entries:\e[0m" >> ${pacui_config} + [[ -f /boot/refind_linux.conf ]] && echo -e "\e[31m/boot/refind_linux.conf Configure rEFInd boot loader in file:\e[0m" >> ${pacui_config} + [[ -f /boot/EFI/refind/refind.conf ]] && echo -e "\e[31m/boot/EFI/refind/refind.conf Configure rEFInd boot loader in file:\e[0m" >> ${pacui_config} + [[ -f /boot/EFI/CLOVER/config.plist ]] && echo -e "\e[31m/boot/EFI/CLOVER/config.plist Configure Clover boot loader in file:\e[0m" >> ${pacui_config} + [[ -f /boot/syslinux/syslinux.cfg ]] && echo -e "\e[31m/boot/syslinux/syslinux.cfg Configure syslinux boot loaders in file:\e[0m" >> ${pacui_config} + + #set -u + + # create local variables + local {file,check} + + pacui_tty_clean # clear terminal + #set +e + #set +E + + # echo -e "$( cat ${pacui_config} )" -- this command interprets the ANSI escape sequences contained in ${pacui_config}. + file="$( echo -e "$( cat ${pacui_config} )" | fzf -i --exact --no-sort --select-1 --ansi --cycle --query="$argument_input" --reverse --bind=right:half-page-down,left:half-page-up --margin="4%,1%,1%,2%" --info=inline --no-unicode --preview ' + echo -e "\e[1m$(echo {2..}) $(echo {1})\e[0m" # display file/folder description ( {2..} = second to last field in selected line) + echo + if ( echo {1} | grep "/$" &>/dev/null ) # check, if 1. field ends with a "/"" (= is a directory) + then + ls {1} # if directory is selected in fzf, display list of files in that directory + + elif ( cat {1} &>/dev/null ) + then + cat {1} # display file content, if no directory is selected. an error is displayed, when root privilges are required (because "sudo cat {1}" breaks fzf when password entry is required !!!) + + else + echo "{1}: Read permission denied" + + fi + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:60%:wrap"; else echo "--preview-window=bottom:60%:wrap"; fi )" --header="ENTER to continue. ESC to quit." --prompt='Enter string to filter list > ' | awk '{print $1}' )" + # the output of fzf is saved in the $file variable. $file can contain a filename (with its full path) or a directory (with its full path). + + pacui_tty_clean # clear terminal + + # we need a method to check, whether fzf is quit with ESC. if this happens, we should NOT open a text editor! + check=1 # set initial value + + # only run the command inside the if-statement, if $file variable is not empty <-- this happens when fzf is quit with ESC or CTRL+C + if [[ -n "$file" ]] # checks, if length of string is non-zero ("-n" conditional bash expression is the opposite of "-z" (check, whether length of string is zero)) + then + # if $file contains a directory, another instance of fzf is opened to let the user choose the file (within the directory) he wants to edit: + if ( echo "$file" | grep "/$" &>/dev/null ) + then + + # set $check to 0. 0 means a text editor will NOT open. + check=0 + + # attention: currently $file contains directory path and NOT the file name! + # find $file -maxdepth 1 -xtype f -- this command displays a list of files (including their full path) and symlinks to files (including their full path) in a directory given by $file. + file="$( find "$file" -maxdepth 1 -xtype f | sort -u | fzf -i --exact --no-sort --select-1 --reverse --bind=right:half-page-down,left:half-page-up --margin="4%,1%,1%,2%" --info=inline --no-unicode --preview ' + echo -e "\e[1mFile preview: \e[0m" + cat {1} # {1} is the first field of the marked line in fzf. the file given by {1} is shown in the preview window. + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:55%:wrap"; else echo "--preview-window=bottom:55%:wrap"; fi )" --header="ENTER to edit file in text editor. ESC to quit." --prompt='Enter string to filter list > ' )" + + pacui_tty_clean # clear terminal + + if [[ -n "$file" ]] # $file is empty when fzf is quit with ESC. + then + check=1 # only set $check variable back to 1, if fzf is not quit with ESC. + fi + + fi + fi + + #set -e + #set -E + + # because not all files should be opened the same way, multiple if-statements are needed to specify special conditions for opening files in a text editor: + # only run the command inside the if-statement, if $file variable is not empty <-- this happens when fzf is quit with ESC or CTRL+C + if [[ -n "$file" ]] && (( check == 1 )) # here $check variable needs to be 1 in order to continue normally and display files in a text editor. + then + + #set +u # temporarily disable strict mode for environment variables. "$EDITOR" and "$SUDO_EDITOR" variable gets used extensibly in the following code! + + if [[ "$( echo "$file" | cut -c -6 )" == "/home/" ]] # check, if "file"'s first characters is "/home/" + then + # if $file starts with "/home/", open it in "EDITOR" (without root privileges). + # "${EDITOR:-/usr/bin/nano}" outputs the content of the $EDITOR environment variable. if it is not set, '/usr/bin/nano' gets used. + "${EDITOR:-/usr/bin/nano}" "$file" + + elif [[ "$file" == "/etc/sudoers" ]] + then + # the sudoers file should never be edited directly! if something goes wrong, sudo stops working. instead, visudo should be used. this is much safer. + # if $SUDO_EDITOR variable does not exist, use 'nano'. visudo uses $SUDO_EDITOR variable by default! + sudo SUDO_EDITOR="${SUDO_EDITOR:-/usr/bin/nano}" visudo + + elif [[ "$file" == "/etc/pacman.d/mirrorlist" ]] || [[ "$file" == "/etc/pacman.conf" ]] + then + sudo "${EDITOR:-/usr/bin/nano}" "$file" + sudo pacman "$argument_flag"-Syyu # apply changes + + elif [[ "$file" == "/etc/pacman-mirrors.conf" ]] + then + sudo "${EDITOR:-/usr/bin/nano}" "$file" + sudo pacman-mirrors -f 0 && sudo pacman "$argument_flag"-Syyu + + elif [[ "$file" == "/etc/fstab" ]] || [[ "$file" == "/etc/crypttab" ]] + then + sudo "${EDITOR:-/usr/bin/nano}" "$file" + sudo mount -a # mount all drives/partitions in /etc/fstab file. this shows immediately mistakes in your /etc/fstab file and prevents non-working systems. + + elif [[ "$file" == "/etc/mkinitcpio.conf" ]] + then + sudo "${EDITOR:-/usr/bin/nano}" "$file" + + echo -e " \e[1;41m Do you want to regenerate the initramfs and update /boot/grub/grub.cfg? [y|N] \e[0m" + read -r -n 1 -e answer # save user input in "answer" variable (only accept 1 character as input) + + case ${answer:-n} in # if ENTER is pressed, the variable "answer" is empty. if "answer" is empty, its default value is "n". + y|Y|yes|YES|Yes ) + sudo mkinitcpio -P && sudo grub-mkconfig -o /boot/grub/grub.cfg # apply changes # "grub-mkconfig -o /boot/grub/grub.cfg" == "udpate-grub" (in manjaro) + ;; + + * ) + echo -e " \e[1m Changes in /etc/mkinitcpio.conf will only be applied after initramfs and boot loader configuration have been regenerated! \e[0m" + ;; + esac + + elif [[ "$file" == "/etc/default/grub" ]] || [[ "$file" == "/boot/grub/custom.cfg" ]] + then + sudo "${EDITOR:-/usr/bin/nano}" "$file" + sudo grub-mkconfig -o /boot/grub/grub.cfg # apply changes # "grub-mkconfig -o /boot/grub/grub.cfg" == "udpate-grub" (in manjaro) + + else + # start "sudo nano $file" for all other files (not mentioned separately in elif-statements above) + sudo "${EDITOR:-/usr/bin/nano}" "$file" + fi + + #set -u + + fi + + # cleanup + unlink ${pacui_config} # remove temporary file ${pacui_config} + trap - EXIT # disable trap, which was set above +} + + +# List Packages by Size +# this function provides core functionality of "List Packages by Size". the help page provides additional explanations. +function func_ls +{ + pacui_tty_clean # clear terminal + #set +e + #set +E + + # list all packages on local system sorted by their installed size using "expac" and "sort". + # $( comm -23 <(pacman -Qq | sort) <(pacman -Qqg base | sort) ) only shows packages, which are not part of "base" group. + # "sort -n -r" sorts list by number (with which every element begins). + # ATTENTION: (i do not know why but) using quotes (" symbols) around $( comm ...) breaks expac + expac -H M -Q "%12m - \e[1m%n\e[0m %v" $( comm -23 <(pacman -Qq | sort) <(pacman -Qqg base | sort) ) | sort -n -r | fzf -i --multi --exact --no-sort --ansi --reverse --bind=right:half-page-down,left:half-page-up --margin=4%,1%,1%,1% --info=inline --no-unicode --preview ' + echo -e "\e[1mInstalled package info: \e[0m" + pacman -Qi {4} --color always + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:60%:wrap"; else echo "--preview-window=bottom:60%:wrap"; fi )" --header="Navigate with PageUp / PageDown. ESC to quit." --prompt='Enter string to filter list > ' > /tmp/pacui-ls + # alternative command to "expac" and "sort": package-query -Qe --rsort 2 -f "%2 - \e[1m%n \e[0m%v" | numfmt --to=iec + + #set -e + #set -E + pacui_tty_clean # clear terminal +} + + +# ======================= + + +# Force Update AUR +# this function provides core functionality of "Force Update AUR". the help page provides additional explanations. +function func_ua +{ + if [[ "$AUR_Helper" == "yay" ]] + then + yay "$argument_flag"-Syu --devel --needed + + elif [[ "$AUR_Helper" == "pikaur" ]] + then + pikaur "$argument_flag"-Syu --devel --needed + + elif [[ "$AUR_Helper" == "aurman" ]] + then + aurman "$argument_flag"-Syu --devel --needed + + elif [[ "$AUR_Helper" == "pakku" ]] + then + pakku "$argument_flag"-Syu --needed # does not support "--devel" flag + + elif [[ "$AUR_Helper" == "trizen" ]] + then + trizen "$argument_flag"-Syu --devel --needed + + elif [[ "$AUR_Helper" == "pacaur" ]] + then + pacaur "$argument_flag"-Syua --devel --needed --color always + + else + echo -e " \e[41m No AUR helper has been found. Please install at least one supported AUR helper manually: \e[0m" + echo -e " \e[1m yay \e[0m" + echo -e " \e[1m pikaur \e[0m" + echo -e " \e[1m aurman \e[0m" + echo -e " \e[1m pakku \e[0m" + echo -e " \e[1m trizen \e[0m" + echo -e " \e[1m pacaur \e[0m" + + fi +} + + +# List Installed from AUR +# this function provides core functionality of "List Installed from AUR". the help page provides additional explanations. +function func_la +{ + pacui_tty_clean # clear terminal + #set +e + #set +E + + # check, whether there is a connection to AUR server. this is needed for AUR package information. If there is no connection to AUR server, no AUR package info get displayed. + if ( wget --spider "https://aur.archlinux.org" &>/dev/null ) # the "wget --spider" command gets executed in any case in order to check its output. + then + AurSserverIsUp="true" + else + AurSserverIsUp="false" + fi + + # this command shows all packages from external, i.e. not in system repositories, sources: + # packages from the AUR and manually installed packages + # "pacman -Qm --color always" + pacman -Qqm --color always | fzf -i --multi --exact --no-sort --ansi --reverse --bind=right:half-page-down,left:half-page-up --margin="4%,1%,1%,2%" --info=inline --no-unicode --preview ' + echo -e "\e[1mInstalled package info: \e[0m" + pacman -Qi {} --color always + echo + + if ( $(test '$AurSserverIsUp' = true) ) && ( $(test -n '$AUR_Helper') ) # preview window of fzf requires checking with "test": first, check whether internet connection is up. second, check if any AUR helper is installed. + then + echo -e "\e[1mAUR package info: \e[0m" + + if test '$AUR_Helper' = "yay" + then + yay -Si {1} | grep -v "::" # grep command removes all errors displayed by yay + + elif test '$AUR_Helper' = "pikaur" + then + pikaur -Si {1} + + elif test '$AUR_Helper' = "aurman" # if {1} is neither locally installed nor a group, it is from the AUR. display info with AUR helper + then + aurman -Si {1} | grep -v "::" # grep command removes all errors displayed by aurman + + elif test '$AUR_Helper' = "pakku" + then + pakku -Si {1} + + elif test '$AUR_Helper' = "trizen" + then + trizen -Si {1} + + elif test '$AUR_Helper' = "pacaur" + then + pacaur -Si {1} --color always | grep -v "::" # grep command removes all errors displayed by pacaur + + fi + fi + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:60%:wrap"; else echo "--preview-window=bottom:60%:wrap"; fi )" --header="List of manually installed packages. ESC to quit." --prompt='Enter string to filter list > ' > /tmp/pacui-la + + #set -e + #set -E + pacui_tty_clean # clear terminal +} + + +# ======================= +# the following functions are hidden from the UI. + + +# Downgrade Packages +# this function provides core functionality of "Downgrade Packages". the help page provides additional explanations. +function func_d +{ + # check for "downgrade" package + if [[ ! -f /usr/bin/downgrade ]] + then + + echo -e " \e[41m No 'downgrade' package has been found. Please install it. Alternatively, use PacUI's 'Roll Back System' option. \e[0m" + + else + + # write list of all installed packages to file /tmp/pacui-packages-local . then add list of packages in system repositories to the bottom of /tmp/pacui-packages-local. + expac -Q "%-33n\t%d" > /tmp/pacui-packages-local + expac -S "%-33n\t%d" >> /tmp/pacui-packages-local + + local {pkg,pkg_downgrade} + + pacui_tty_clean # clear terminal + #set +e + #set +E + + pkg="$( sort -k1,1 -u /tmp/pacui-packages-local | fzf -i --multi --exact --no-sort --select-1 --bind=right:half-page-down,left:half-page-up --query="$argument_input" --cycle --reverse --margin="4%,1%,1%,2%" --info=inline --no-unicode --preview ' + if ( pacman -Qq {1} &>/dev/null ) # check, if selected line is a locally installed package + then + echo -e "\e[1mInstalled package info: \e[0m" + pacman -Qi {1} --color always # for local packages, local query is sufficient. + + else + echo -e "\e[1mRepository package info: \e[0m" + pacman -Si {1} --color always # do this, if package is not locally installed + + fi + ' "$( if (( $(tput cols) >= 125 )); then echo "--preview-window=right:55%:wrap"; else echo "--preview-window=bottom:55%:wrap"; fi )" --header="TAB to (un)select. ENTER to downgrade. ESC to quit." --prompt='Enter string to filter list > ' | awk '{print $1}' )" + + #set -e + #set -E + pacui_tty_clean # clear terminal + + # $pkg contains package names below each other, but we need a list (in 1 line, space separated): + pkg_downgrade="$(echo "$pkg" | paste -sd " ")" + + if [[ -n "$pkg" ]] + then + downgrade "$argument_flag"$pkg_downgrade # ATTENTION: (i do not know why but) using quotes (" symbols) around $pkg_downgrade variable breaks AUR helper and pacman + fi + + fi +} + + +# Search + Install from AUR +# this function provides core functionality of "Search + Install from AUR". the help page provides additional explanations. +function func_a +{ + local pkg + + if [[ -n "$argument_input" ]] # checks, if length of string is non-zero ("-n" conditional bash expression is the opposite of "-z" (check, whether length of string is zero)) + then + # do this if variable "$argument_input" is not empty: + + if [[ "$AUR_Helper" == "yay" ]] + then + yay "$argument_input" + + elif [[ "$AUR_Helper" == "pikaur" ]] + then + pikaur -Ss "$argument_input" + + elif [[ "$AUR_Helper" == "aurman" ]] + then + aurman "$argument_input" + + elif [[ "$AUR_Helper" == "pakku" ]] + then + pakku -Ss "$argument_input" + + elif [[ "$AUR_Helper" == "trizen" ]] + then + trizen "$argument_input" + + elif [[ "$AUR_Helper" == "pacaur" ]] + then + pacaur -Ss "$argument_input" --color always | grep -v "::" # grep command removes errors being displayed in pacaur + + else + echo -e " \e[41m No AUR helper has been found. Please install at least one supported AUR helper manually: \e[0m" + echo -e " \e[1m yay \e[0m" + echo -e " \e[1m pikaur \e[0m" + echo -e " \e[1m aurman \e[0m" + echo -e " \e[1m pakku \e[0m" + echo -e " \e[1m trizen \e[0m" + echo -e " \e[1m pacaur \e[0m" + + fi + + else + + # do this if pacui is used with UI or no argument is specified in "pacui a" command: + echo -e " \e[41m Enter (parts of) name and/or description of package to be searched. Then press ENTER. \e[0m" + read -r pkg + + if [[ "$AUR_Helper" == "yay" ]] + then + yay "$pkg" + + elif [[ "$AUR_Helper" == "pikaur" ]] + then + pikaur -Ss "$pkg" + + elif [[ "$AUR_Helper" == "aurman" ]] + then + aurman "$pkg" + + elif [[ "$AUR_Helper" == "pakku" ]] + then + pakku -Ss "$pkg" + + elif [[ "$AUR_Helper" == "trizen" ]] + then + trizen "$pkg" + + elif [[ "$AUR_Helper" == "pacaur" ]] + then + pacaur -Ss "$pkg" --color always | grep -v "::" # grep command removes errors being displayed in pacaur + + else + echo -e " \e[41m No AUR helper has been found. Please install at least one supported AUR helper manually: \e[0m" + echo -e " \e[1m yay \e[0m" + echo -e " \e[1m pikaur \e[0m" + echo -e " \e[1m aurman \e[0m" + echo -e " \e[1m pakku \e[0m" + echo -e " \e[1m trizen \e[0m" + echo -e " \e[1m pacaur \e[0m" + + fi + + fi +} + + +# ======================= +# 2 different help functions + + +# Help +# this function provides core functionality of "Help" page: Helpful text (including ANSI escapes) is written to /tmp/pacui-help file and read with "less". +function func_help +{ + # this "heredoc" command pushes all the following lines into "cat" (and "cat pushes it to file /tmp/pacui-help) until a line containing the "EOF" keyword is encountered + cat > /tmp/pacui-help <<- "EOF" + +\e[1mWelcome to PacUIs Help Page + +PacUI is an interactive package manager for your command line terminal. It provides an easy user interface and uses Pacman and Yay/Pikaur/Aurman/Pakku/Trizen/Pacaur as back ends. + +Navigate this help page with your Arrow Keys, PageUp/PageDown Keys, SpaceBar, or your Mouse Wheel. To search this Help Page, enter / and press ENTER. For example, enter the following (without quotes " ") in order to search for the word "update": "/update". Press N key to continue searching for other occurrences of "/update". Search is not case sensitive. To exit this Help Page, press your Q key. +PacUI uses Fuzzy Finder (fzf) to display selectable lists, which can be easily searched by starting to type. Advanced users can even use regular expressions to search in fzf. Navigate fzf's list the same way you navigate this help page. + + +\e[1mHOME SCREEN +PacUI's home screen is split into three parts: +The first part focuses on updates, maintenance, installations, and removals of packages from system repositories and the Arch User Repository (AUR). It includes useful tools for these actions, too. +The second part includes options for fixing and configuring your system. Options, which can break your system, are marked in red. +The last part offers options exclusive to Arch User Repository (AUR) management. + + +\e[1m99 - HELP +Display this help page. A very shot summary of this help page can be displayed in your terminal with "pacui -h" or "pacui h". +Quit this help page by pressing the Q key. + + +\e[1m0 - QUIT +\e[36m"clear && exit" +This will quit PacUI and clear your terminal. Scroll up to see all terminal output of your last PacUI session. + + +\e[1m1 - UPDATE SYSTEM +\e[36m"sudo pacman -Syu" +\e[36m"yaourt -Syua" +The first command compares a list of all installed packages with package database on your system repository mirror/server. If an updated package is available from your system repositories, it will get downloaded and installed on your system. +The second command does the same as the first part, but with one exception: It also downloads, compiles, and installs all packages from the Arch User Repository (AUR), which have an updated PKGBUILD file. The first command is still needed occasionally, because major Pacman updates require "pacman -Syu" and will fail when started with an AUR helper. +If updates from system repositories fail, the user is offered the choice to update packages using \e[36m"sudo pacman -Syu --overwrite A-Z,a-z,0-9,-,.,_"\e[0m. +\e[1mAttention\e[0m: When a new version of an AUR package is available, sometimes the PKGBUILD file is not updated. If you want to install the latest version of a single AUR package, (re-)install it with INSTALL PACKAGES. If you want to install the latest versions of ALL AUR packages use FORCE UPDATE AUR. + + +\e[1m2 - MAINTAIN SYSTEM +\e[36m"sudo rm -r /tmp/pacui*" +This command deletes all PacUI files in /tmp directory. PacUI uses this temporary directory to cache package lists and fzf selections. By deleting the /tmp directory, PacUI behaves exactly as after a reboot: Its first usage probably feels slower but any strange bugs and incompatibilities, e.g. originating from PacUI updates, should be gone. + +\e[36m"sudo pacman-mirrors -f 0 && sudo pacman -Syyu" \e[0m(for Manjaro) +This command generates a new mirrorlist of all available Manjaro repository mirrors/servers and sorts it by ping of up-to-date mirrors/servers. Additionally, the latest package database is downloaded from the chosen Manjaro repository mirror and the system is updated. If you want to speed up this command, it is recommended to only test your connection quality to Manjaro mirrors/servers near you. Example: You have noticed the pings to German and French mirrors are always best for you. Then, you can run: "sudo pacman-mirrors -f 0 -c Germany,France". In order to prevent partial updates, the whole system needs to be updated after the change to another repository mirror/server. +Here a short explanation of partial updates and why a complete system update is needed: Assume you switch to another (updated) repository mirror/server with "sudo pacman-mirrors -f 0". Afterwards, a sync of the local package database and the package database on the server is needed using "sudo pacman -Syy" (and updates are found). It is now possible you install a package using "sudo pacman -S", which also installs a new (and no longer compatible) version of "bash" as a dependency. This means that all other (and not updated) packages, which depend on "bash", are broken. + +\e[36m"sudo reflector --verbose --protocol https --age 1 --sort rate --save /etc/pacman.d/mirrorlist && sudo pacman -Syyu" \e[0m(for Arch and other Arch-based distros) +This command generates a new mirrorslist of secure and fast repository mirrors/servers. Then it resyncs database to match the mirrors and updates the system. + +\e[36m"sudo pacman -Rsn $(pacman -Qqdt)" +This option lists all orphaned packages on your system. Orphaned packages are old and no longer needed dependencies (packages not explicitly installed by you), which were never removed from your system. + +\e[36m"sudo pacdiff" +A .pacnew file may be created during a package upgrade to avoid overwriting a file (e.g. a config file) which already exists and was previously modified by the user. A .pacsave file may be created during a package removal, or by a package installation (the package must be removed first). These files require manual intervention from the user and it is good practice to handle them regularly - ideally everytime a .pacnew/.pacsave file has been created. +This command offers you a choice, whether you want to keep the original file (and delete the .pacnew/.pacsave file) or overwrite the original file with the .pacnew/.pacsave file (the original file is backed up automatically with an added dash "-" to the end of its file name). +It is strongly recommended to view and compare both files by choosing "v" before making a decision. +If you keep the original config file, the new program version could not recognize the old syntax in the original config file anymore. In the worst case, your program could break or stop working. If you remove the original file and use the new file without any changes, all your configuration settings might be reset to the default values. This can result in changed system behavior, including missing passwords or even sudo capability. +In most cases, the syntax does not change and you can simply remove the .pacnew file. However, if you notice a syntax change, it is highly recommended to solve this conflict in another way (e.g. by manually editing one of those files and deleting the other). +\e[1mAttention\e[0m: This command requires a default file difference viewer by setting the environment variable DIFFPROG. for example by adding "DIFFPROG=meld" to your /etc/environment file. If this variable is not set, a minimal default is provided by PacUI based on "diff". +\e[1mAttention\e[0m: In severe and rare cases, removing your old config file (and using the new .pacnew config file) OR keeping your old config file (and deleting the .pacnew config file) can result in a broken system. PLEASE BE CAUTIOUS WHEN USING THIS COMMAND! + +\e[36m"systemctl --failed" +This command checks for systemd services in a failed state. It is possible the systemd service will no longer be failed after a reboot. But if a systemd service still fails after a reboot, you should manually fix the problem. Start by using the command "systemctl status ". + +\e[36m"sudo find -xtype l" \e[0m(only if there are broken symlinks) +This command displays a list of broken symbolic links on your system. These links are not deleted by default. You have to decide yourself what to do with them. When you have doubt about deleting them, leave them on your system. They can sometimes cause problems, but they use almost no hard drive space. +Symbolic links can be removed manually or "sudo find -xtype l -delete" can be used to remove all broken symbolic links. + +\e[36m"pacman -Dk" +This command checks your local package repository for consistency and shows missing packages, dependencies, or other errors. Please refer to "man pacman" for a more detailed explanation. + +\e[36m"comm -23 <(pacman -Qqm | sort) <(curl https://aur.archlinux.org/packages.gz | gzip -cd | sort)" +This command compares 2 lists: The first list contains packages, which were not installed from your system repository. The second list contains all AUR package names. By comparing these 2 lists, it is possible to find EOL packages, which will never receive any updates. +These EOL packages were either installed manually by the user or from the AUR (and have been removed from there in the meantime). +Unless you know exactly what you are doing, it is recommended to remove these EOL packages. + +\e[36m"comm -23 <(pacman -Qqm | sort) <(pacman -Qqem | sort)" +This command compares 2 lists: The first list contains packages, which were not installed from your system repository. The second list contains explicitly installed packages, which were not installed from your system repository. Packages unique to the first list are output. +Sometimes, packages from the system repository are no longer maintained. Typically, they get put into the AUR instead of deleting them. Such packages get filtered by this command. +These packages can cause really long update times and are generally a security risk. Unless important packages depend on them, it is recommended to remove these packages manually. You can check, which packages depend on them by using REVERSE DEPENDENCY TREE. + +\e[36m"sudo journalctl --vacuum-size=100M --vacuum-time=30days" +This command limits all log files in journalctl to a combined size of 250 megabytes and a maximum age of 30 days. This leaves plenty of log files behind to analyze systematic and reoccurring errors while preventing excessive amounts of log files. + +\e[36m"paccache -ruvk1" +\e[36m"paccache -rvk3" +By default Pacman uses this cache directory for downloading packages: /var/cache/pacman/pkg/ . No cached packages get deleted automatically. The package cache of an old and actively used installation can become quite large. Clean it to regain space on your root partition. +The first command removes all old packages from cache, which are not installed (anymore) on your system (except the latest version of that package). +The second command removes all old packages from cache except the 3 latest versions: The version you have currently installed on your system and 2 previous versions. Old package versions are kept to enable you to use ROLL BACK SYSTEM (or to manually downgrade packages) even without a working internet connection. + +\e[36m"comm -13 <(echo "$available_kernels") <(echo "$installed_kernels")" +This long "comm" command compares the output of 2 lists: The first list of contains (still) available kernels in your repository (which are also installed on your system) and the second list of contains installed kernels. +By comparing both lists, it is possible to extract of so called end-of-live kernels. These installed kernels are no longer supported and do not receive updates anymore. Kernel modules are likely to break. It is highly recommended to remove these kernels. +Kernels from the AUR are also listed by the "comm" command and trigger a warning. Please decide for yourself, whether you want to keep them or not. + + +\e[1m3 - INSTALL PACKAGES +\e[36m"yaourt -Sy " +This option first updates your system and then downloads and installs on your system. The list of packages shows packages from your system repository with their description while package groups or packages from the AUR are only shown with their name. +\e[1mAttention\e[0m: Experienced users can install packages from the AUR without the need to answer questions all the time by using the command "yaourt -S --noconfirm". The "--noconfirm" flag is great for quick and dirty installations of AUR packages on non-secure systems. Please keep always in mind that the AUR can contain any sort of packages - including malicious and destructive (parts of) packages. Therefore, it is recommended to always check the PKGBUILD and .INSTALL file manually before installing a package from the AUR. + + +\e[1m4 - REMOVE PACKAGES AND DEPS +\e[36m"sudo pacman -Rsn " +This command removes from your system including all dependencies, which are no longer needed by other packages. A copy of will be kept in your package cache: Run MAINTAIN SYSTEM to remove it. +Please note that folders in your home (~) directory and created by the program will not get removed from your system. Look for such folders in these places and remove them manually: +~/ +~/.config/ +~/.local/share/ +\e[1mAttention\e[0m: If you want to display a list of all your installed packages (including their version number and description) use this PacUI option. Simply do not select to be removed, but quit the list view with ESC or CTRL+C. +If package removal fails, the user is offered the choice to either try again or remove packages using \e[36m"pacman -Rdd "\e[0m. +\e[1mAttention\e[0m: \e[36m"pacman -Rdd "\e[0m does not check for dependencies before removing packages. In severe cases, this can leave your system without essential packages and thus unbootable! + + +\e[1m5 - DEPENDENCY TREE +\e[36m"pactree " +\e[36m"pactree -s "\e[0m(only for packages not installed on your system) +This command will display a complete tree of all dependencies of . can be an installed package or a package from your system repositories. Dependencies are packages required by in order to function. When you install , all its dependencies get installed, too. +Please note that all selected lines (toggle selection with your TAB key) will get added to file /tmp/pacui-t. + + +\e[1m6 - REVERSE DEPENDENCY TREE +\e[36m"pactree -r " +\e[36m"pactree -r -s "\e[0m(only for packages not installed on your system) +This command will display a tree of installed packages, which depend on . In other words: All displayed packages require in order to function (properly). +Use this command when you want to know why you cannot remove from your system. +Please note that all selected lines (toggle selection with your TAB key) will get added to file /tmp/pacui-rt. + + +\e[1m7 - LIST PACKAGE FILES +\e[36m"pacman -Ql " +\e[36m"sudo pacman -Fyl " \e[0m(only for packages not installed on your system) +These commands list all files contained in including their path. The second command syncs the file database with your system repositories and then searches the file database for files, which get installed by . +As a result the complete path to the files get displayed. +Have you ever installed a program and did not know with which command it can be started/executed? Just look for files (and their names) in your /usr/bin/ directory using LIST PACKAGE FILES. +By default, the results are filtered for files located in usr/bin/, but you can enter any filter term you want to. Delete the default filter term with BACKSPACE to see a complete list of files of . Please note that all selected lines (toggle selection with your TAB key) will get added to file /tmp/pacui-l. +\e[1mAttention\e[0m: On some systems, the file database has not been downloaded which results in an error message instead of search results from your system repositories. You can fix it by running "sudo pacman -Fyy" and restarting LIST PACKAGE FILES. + + +\e[1m8 - SEARCH PACKAGE FILES +\e[36m"pacman -Ql | grep " +\e[36m"sudo pacman -Fysx " \e[0m(only for packages not installed on your system) +In some situations, Pacman (e.g. during UPDATE SYSTEM) cannot find a file, for example a shared library. An error message is shown about . Use SEARCH PACKAGE FILES to find out, which package has installed . In most cases, you can fix the Pacman error by using one of the following options on that package: UPDATE SYSTEM, ROLL BACK SYSTEM, REMOVE PACKAGES, and INSTALL PACKAGES, or FORCE UPDATE AUR. +SEARCH PACKAGE FILES is in many ways a reverse LIST PACKAGE FILES. You can use it to find out which package you have to install in order to use the command in your terminal. +The first command searches for in all your installed packages. can be a part of an actual file name or contain regular expressions. +The second command syncs the file database with your system repositories and then searches the file database for . +As a result, / and the complete path to gets displayed using fzf. is always printed in a bold font. only gets displayed for packages, which are not installed on your system. Please note that all selected lines (toggle selection with your TAB key) will get added to file /tmp/pacui-s. +\e[1mAttention\e[0m: On some systems, the file database has not been downloaded which results in an error message instead of search results from your system repositories. You can fix it by running "sudo pacman -Fyy" and restarting SEARCH PACKAGE FILES. + + +\e[1m9 - ROLL BACK SYSTEM +\e[36m"sudo pacman -R --noconfirm" \e[0m(only for rolling back package installations) +\e[36m"sudo pacman -U --noconfirm" \e[0m(only for rolling back package removals, upgrades, or downgrades.) +Manjaro and Arch Linux use a rolling release development model. This means ALL packages on your system continuously get updated to the latest version. Sometimes, things go wrong during UPDATE SYSTEM and you should roll back the last update. In case the latest version of a single package is broken, rolling back (a.k.a. downgrading) that package can work. +This command shows you a list of all recent Pacman actions sorted by date (using parts of this command: "tail -8000 /var/log/pacman.log"). Please select all Pacman actions you want to roll back. Installed packages will be removed from your system. Removed packages will be reinstalled as the latest version available in your Pacman/Pacaur cache. Upgraded packages will be downgraded to the previous version (if this version is available in your local Pacman/Pacaur cache). Downgraded packages will be Upgraded to a later version. If you select multiple upgrades/downgrades of the same package, the package gets downgraded/upgraded multiple times (if this version is available in your local Pacman/Pacaur cache). +\e[1mAttention\e[0m: It is strongly recommended to always roll back including ALL its dependencies. Otherwise, your system could be left in a broken state. If you are in doubt about that, rolling back all changes made on your system in a short time intervall should be sufficient. +\e[1mAttention\e[0m: After downgrading a broken package to a working version, it is recommended to add the package name to your Ignore List ( "IgnorePkg" option in /etc/pacman.conf ). This will prevent Pacman from showing any available updates for this package. The package needs to be removed manually from your Ignore List in order to receive automatic updates again. Alternatively, you can run future updates with the command "sudo pacman -Syu --ignore " until a fixed version of that package gets released. + + +\e[31;1m10 - FIX PACMAN ERRORS +Multiple commands attempt to fix the most common issues Manjaro users have with Pacman. +Please make sure that your root partition is not full. If you have doubts about this, run MAINTAIN SYSTEM before FIX PACMAN ERRORS. + +\e[36m"sudo rm -r /tmp/pacui*" +This command deletes all PacUI files in /tmp directory. PacUI uses this temporary directory to cache package lists and fzf selections. By deleting the /tmp directory, PacUI behaves exactly as after a reboot: Its first usage probably feels slower but any strange bugs and incompatibilities, e.g. originating from PacUI updates, should be gone. + +\e[36m"sudo unlink /var/lib/pacman/db.lck" +This command removes Pacmans database lock. The database lock prevents multiple Pacman instances from running at the same time and interfering with each other. +\e[1mAttention\e[0m: Only run this command when no other Pacman instance (e.g. Pacman, Yaourt, Pamac, Octopi, PacmanXG4, ...) is running. + +\e[36m"sudo pacman-mirrors -f 0 && sudo pacman -Syy" \e[0m(for Manjaro) +This command generates a new mirrorslist of all available Manjaro repository mirrors/servers and sorts it by ping of up-to-date mirrors/servers. Additionally, the latest package database is downloaded from the chosen Manjaro repository mirror. If you want to speed up this command, it is recommended to only test your connection quality to Manjaro mirrors/servers near you. Example: You have noticed the pings to German and French mirrors are always best for you. Then, you can run: "sudo pacman-mirrors -c Germany,France". +Here, the risk of a (temporarily) partially updated system has to be considered against the effort to fix all systems, including systems on which it is no longer possible to install any packages. The system can be put in a partially updated state during the course of FIX PACMAN ERRORS, but at the end of FIX PACMAN ERRORS the complete system is updated. + +\e[36m"sudo reflector --verbose --protocol https --age 1 --sort rate --save /etc/pacman.d/mirrorlist && sudo pacman -Syy" \e[0m(For Arch and other Arch-based distributions) +This command generates a new mirrorlist of secure and fast repository mirrors/servers. Then it resynchronizes the database to match the mirrors. + +\e[36m"sudo dirmngr > $HOME/.gnupg/gpg.conf" +There are 2 different places in Arch Linux and Manjaro to store keys: One place is used by Pacman and the other gets used by GPG. +This command imports all keys for Pacman into GPG. This essentially means that the user trusts all Arch Linux Trusted Users and your distribution's developers. After that, you will be able to install AUR packages from Arch Linux Trusted Users and your distribution's developers without the need to import those keys (again) manually. + +\e[36m"sudo pacman -Syu --noconfirm" +This command forces a redownload of the latest package database from the best repository mirror. Then, all your installed packages are checked against this latest package database. If an updated package is available from your system repositories, it will get downloaded and installed on your system. If an installed package is newer than the same package in your system repositories, it will not be installed. This behavior ensures your packages are always in sync with (or newer than) your system repositories. + +\e[36m"sudo cp --preserve=all -f /etc/pacman.conf /etc/pacman.conf.backup && sudo sed -i 's/SigLevel[ ]*=[A-Za-z ]*/SigLevel = Never/' '/etc/pacman.conf' " +The following commands delete and reinstall some essential packages. If your keyring is broken, no packages could be installed because of a key mismatch. Therefore, it is important to disable Pacman's key check before continuing. +This command disables the signature key check of packages in Pacman. + +\e[36m"sudo systemctl stop ntpd.service" +This command stops (temporarily) the Network Time Protocol daemon service NTPD (if it is installed and running). In case NTPD is not installed, the output is ignored. +This is the first command of a series of commands, which try to set the system and hardware clock on your computer (ignoring time zone and daylight saving time). An (almost) correct system time is needed for checking and importing keys or fingerprints later on in the fixing process! + +\e[36m"sudo pacman -S ntp" +This command (re-)installs the "ntp" package. +Because the keyring is not checked, in certain situations your system could be left in a partially updated state. However, if you follow PacUI's instructions, this does not happen. + +\e[36m"sudo ntpd -qg && sleep 10 && sudo hwclock -w" +The first command starts the just (re-)installed Network Time Protocol daemon (ntpd.service). Next, your system clock is set. Finally, the ntpd.service is quit. +The second command makes your system wait for 60 seconds. This is done as precaution to ensure your system has enough time to connect to an internet or network server and set the system clock. +The third command is only run when the first and second command have been successfully finished. It writes the time from your system clock to your hardware clock. +\e[1mAttention\e[0m: The last command is needed in order to prevent other services on your system to set your system clock according to your hardware clock in regular intervals. This may result in a hardware clock, which is not set to UTC anymore and/or a system clock, which shows the wrong time. If you encounter this problem read the Arch Linux Wiki article about time: "https://wiki.archlinux.org/index.php/Time" + +\e[36m"sudo pacman -Syu" +This command makes abolutely sure all packages get updated. No keyring check is performed here. +If manual intervention is necessary, the user can do it here. Please follow Pacman and/or PacUI instructions, which appear during this update. It is important that this step completes without any errors in order to continue FIX PACMAN ERRORS. + +The following steps are only run, when the previous update attempt was successful. They reinitialize the key database: + +\e[36m"sudo rm -r /etc/pacman.d/gnupg" +This command deletes your key database. It does not output an error in case the package "gnupg" is not installed on your system. +\e[1mAttention\e[0m: This command will remove all keys from your system, including manually installed keys (with "sudo pacman-key --lsign-key "). Please remember to reinstall those keys again after FIX PACMAN ERRORS has completed! + +\e[36m"sudo pacman -Syu gnupg $(pacman -Qsq '(-keyring)' | grep -v -i -E '(gnome|python|debian)' | paste -sd " " )" --noconfirm +This command (re-)installs the gnupg and keyring packages. + +\e[36m"sudo cp --preserve=all -f /etc/pacman.conf.backup /etc/pacman.conf && sudo rm /etc/pacman.conf.backup " +This command enables the signature check of packages in Pacman again. + +\e[36m"sudo pacman-key --init && sudo pacman-key --populate $(pacman -Qsq '(-keyring)' | grep -v -i -E '(gnome|python|debian)' | sed 's/-keyring//' | paste -sd " " )" +These two commands create a fresh key for you and import and (re-)install all keyrings. This will solve problems with your local key database and your distribution's and Arch's key database. Such problems can occur when new Arch Linux or your distribution packagers get added, for example. +\e[1mAttention\e[0m: This command might take a long time to complete. If your system appears to stop or hang, it searches for entropy in order to generate a new key for you. In this case, it might help to do file operations with a lot of reads and/or writes per minute (such as searching for files, copying large directories, etc.). Alternatively, you can open a browser and do some heavy surfing (with a lot of mouse movements, mouse clicks, and keyboard key presses): This can help to generate entropy much faster. + +\e[36m"sudo pacman -Fyy" +This command forces a sync of the file database of your system repository with your used repository mirror server. The file database is separate from the package database. The file database enables SEARCH PACKAGE FILES and LIST PACKAGE FILES of packages, which are not installed on your system but only available on your system repository. + + +\e[1m11 - EDIT CONFIG FILES +\e[36m"$EDITOR " +This command opens in your default text editor. You can choose between multiple important system configuration files. Files in the root directory are opened with root privileges. The "sudoers" file is edited with \e[36m"sudo visudo"\e[0m (which uses the $SUDO_EDITOR environment variable by default). For some configuration files, additional commands are executed after the text editor is closed in order to avoid system breakage. +By default the text editor Nano gets used, except custom $EDITOR and $SUDO_EDITOR environment variables have been set. In the text editor Nano, Press CTRL+O to save your changes, ENTER to choose a directory, and CTRL+X to quit Nano. +\e[1mAttention\e[0m: Changing system configuration files can harm or even destroy your system. In some cases, this can happen with a single mistake. Be extremely careful and always double check your changes before saving and rebooting - especially when editing the files marked in red! It is recommended to search the Arch Wiki for the configuration file you want to edit and read about available and recommended settings. + + +\e[1m12 - LIST PACKAGES BY SIZE +\e[36m"expac -Q '%m - %n %v' | sort -n -r " +This command lists packages on your system sorted by their installation size. Both explicitly installed packages and dependencies are displayed. Important system packages part of the "base" group are not displayed. Please note that all selected lines (toggle selection with your TAB key) will get added to file /tmp/pacui-ls. + +EOF + # only write the following paragraph to file, if an AUR helper is installed + if [[ -n "$AUR_Helper" ]] + then + cat >> /tmp/pacui-help <<- "EOF" +\e[1m13 - FORCE UPDATE AUR +\e[36m"yaourt -Syua --devel --needed" +The Arch User Repository (AUR) is a repository of (mostly) PKGBUILD files. Everybody can create such a PKGBUILD file and upload it to the AUR. A PKGBUILD file contains simple and human readable instructions like where to download the source code from, what dependencies are needed, where to copy files for installation, etc. Your AUR helper can interpret PKGBUILD files and download the source code, install dependencies, build files on your system, and copy these files to the right location (a.k.a. installing a program). +By checking a PKGBUILD file (and .INSTALL file) you can make sure the source code is loaded from an official download server, no harmful dependencies get installed, and the installation instructions do not contain harmful code. +A lot of PKGBUILD files contain variables (e.g. program version) in download addresses; this makes them download always the latest source code (e.g. from Github) during installation. Some PKGBUILD files contain no variables: These PKGBUILD files need to be changed manually every time a new program version is released. +This command updates both regular and AUR packages. Some AUR helpers need the "--devel" flag in order to update development versions (i.e. all git, svn, and cvs-packages) from the AUR as well. +\e[1mAttention\e[0m: This might take a long time! Some AUR helpers pause by default after every 15min and ask again for your password. + +EOF + fi + + cat >> /tmp/pacui-help <<- "EOF" +\e[1m14 - LIST INSTALLED FROM AUR +\e[36m"pacman -Qm" +This command lists all installed packages, which are from the AUR or which were manually installed. Packages, which are installed on your local system, but are no longer available in remote system repositories are listed here, too. They are orphaned and can get removed with MAINTAIN SYSTEM. Please note that all selected lines (toggle selection with your TAB key) will get added to file /tmp/pacui-la. +If you want a list of all installed packages use REMOVE PACKAGES AND DEPS as described in this Help Page. + +EOF + # only write the following paragraph to file, if "downgrade" is installed + if [[ -f /usr/bin/downgrade ]] + then + cat >> /tmp/pacui-help <<- "EOF" +\e[1mDOWNGRADE PACKAGES +\e[36m"downgrade " +Manjaro and Arch Linux use a rolling release development model. This means ALL packages on your system continuously get updated to the latest version. If the latest version of a packages does not work on your system, you can downgrade that package to an earlier, working version. +This command downgrades and offers you a list of old versions to choose from. This list includes all old versions from your local package cache and online sources (if you have a working internet connection). +After a successful downgrade, you can add to your Ignore List ( "IgnorePkg" option in /etc/pacman.conf ). This will prevent Pacman from showing any available updates for . needs to be removed manually from your Ignore List in order to receive automatic updates of again. +Alternatively, you can run future updates with the command "sudo pacman -Syu --ignore " until a fixed version of gets released. +\e[1mAttention\e[0m: Be careful when using Manjaro and downgrading to from online sources, because these are old versions from the Arch Linux repositories only: In the worst case, this can brake your system! Therefore, it is recommended to limit downgrading to (old versions of) local packages, if possible. +\e[1mAttention\e[0m: Downgrading to a working version of can break your system in in rare cases like the following: The latest system update has replaced a dependency of with a different package and is an important system package. Downgrading will NOT reinstall the dependency of , because it conflicts with the already installed different package. This can result in a broken system. Please keep these kind of conflicts in mind when using DOWNGRADE PACKAGES. +\e[1mAttention\e[0m: DOWNGRADE PACKAGES will show you a selection of packages you can downgrade. If you are using Pacaur to install AUR packages, you will not be able to downgrade AUR packages using DOWNGRADE PACKAGES! instead, the ROLL BACK SYSTEM option is recommended. + +EOF + fi + + # only write the following paragraph to file, if an AUR helper is installed + if [[ -n "$AUR_Helper" ]] + then + cat >> /tmp/pacui-help <<- "EOF" +\e[1mSEARCH AND INSTALL FROM AUR +\e[36m"yaourt " +This command searches for in all system repositories and the Arch User Repository (AUR). It searches for package names and package descriptions. +Example: You can search for "web browser" and you will find Firefox and other web browsers. One or multiple search results can be installed on your system. +If you want to exit this mode without installing any packages, simply press CTRL+C or ENTER. + +EOF + fi + + cat >> /tmp/pacui-help <<- "EOF" + +Press "q" to quit this Help Page. + +EOF + + # display /tmp/pacui-help file in "less" and interpret all ANSI escape sequences in it (which only works with "echo -e ..."): + echo -e "$( cat '/tmp/pacui-help' )" | less -RMi +} + + +# Help +# this function provides short Help. +function func_h +{ + echo -e " pacui - \e[1mPac\e[0mUI with \e[1mU\e[0mser \e[1mI\e[0mnterface" + echo + echo -e " 1 pacui u - \e[1mU\e[0mpdate System" + echo -e " 2 pacui m - \e[1mM\e[0maintain System" + echo -e " 3 pacui i - \e[1mI\e[0mnstall Packages" + echo -e " 4 pacui r - \e[1mR\e[0memove Packages and Deps" + echo -e " 5 pacui t - Dependency \e[1mT\e[0mree" + echo -e " 6 pacui rt - \e[1mR\e[0meverse Dependency \e[1mT\e[0mree" + echo -e " 7 pacui l - \e[1mL\e[0mist Package Files" + echo -e " 8 pacui s - \e[1mS\e[0mearch Package Files" + echo + echo -e " 9 pacui b - Roll \e[1mB\e[0mack System" + echo -e " \e[31m 10 pacui f - \e[1mF\e[0;31mix Pacman Errors\e[0m" + echo -e " 11 pacui c - Edit \e[1mC\e[0monfig Files" + echo -e " 12 pacui ls - \e[1mL\e[0mist Packages by \e[1mS\e[0mize" + echo + [[ -n "$AUR_Helper" ]] && echo -e " 13 pacui ua - Force \e[1mU\e[0mpdate \e[1mA\e[0mUR" + echo -e " 14 pacui la - \e[1mL\e[0mist Installed from \e[1mA\e[0mUR" + [[ -n "$AUR_Helper" ]] && echo + [[ -f /usr/bin/downgrade ]] && echo -e " pacui d - \e[1mD\e[0mowngrade Packages" + [[ -n "$AUR_Helper" ]] && echo -e " pacui a - Search and Install from \e[1mA\e[0mUR" + echo + echo -e " pacui h - This short \e[1mH\e[0melp." + echo -e " 99 pacui help - Full \e[1mHelp\e[0m page. 'q' key quits." +} + + + +# all functions of pacui end here. + +# ======================= + +# section for general bug fixes + + +# bug #2: +# when used with tmux and pacaur and $EDITOR variable is not set and vi is not installed ("vi" is the default editor used by pacaur): +# pacaur sometimes does not find an editor to use and the --preview window in fzf does not show any package information. +# instead, it shows "::editor variable unset". + +#set +u # temporarily disable strict mode for environment variables + +# check, whether pacaur is installed, user config file exists, $EDITOR variable is empty, "vi" is not installed: +if [[ "$AUR_Helper" == "pacaur" ]] && [[ ! -f $HOME/.config/pacaur/config ]] && [[ ! -n $EDITOR ]] && [[ ! -f /usr/bin/vi ]] +then + # export "editor='${EDITOR:-nano}'" to config file. '${EDITOR:-nano}'" outputs "nano", if there is no $EDITOR variable set. + mkdir -p "$HOME/.config/pacaur/" + echo "editor='${EDITOR:-nano}'" >> "$HOME/.config/pacaur/config" +fi + +#set -u + + +# bug #4 : +# when database of system repositories has not been saved, it is impossible to use pacman (or expac) in any meaningful way. +# therefore, the existence of the "core" database is tested here. if it does not exist, a repository server is chosen and the repository database synced to the user's system + +dbpath="$( awk -F '=' '/^DBPath/ {gsub(" ","",$2); print $2}' '/etc/pacman.conf' )" # extract path of database file from pacman.conf +if [[ -z "$dbpath" ]] # if "dbpath" variable is empty (exact: if output of $dbpath is zero) +then + dbpath="/var/lib/pacman/" # default database path +fi + +if ! [[ -f "$dbpath"sync/core.db ]] # check, whether repository database file "core.db" exists +then + + # check for "pacman-mirrors" or "reflector" packages. one of those is needed! + if [[ -f /usr/bin/pacman-mirrors ]] || [[ -f /usr/bin/reflector ]] + then + + echo " choosing fastest mirror (which can take a while) and updating system ..." + if [[ -f /usr/bin/pacman-mirrors ]] # checks, whether file "pacman-mirrors" exists + then + sudo pacman-mirrors -f 0 && sudo pacman -Syyu # choose mirrors server (with up-to-date packages) with lowest ping from all available mirrors and sync database. + + elif [[ -f /usr/bin/reflector ]] # checks, whether file "reflector" exists + then + sudo reflector --verbose --protocol https --age 1 --sort rate --save /etc/pacman.d/mirrorlist && sleep 10 && sudo pacman -Syyu # If it does exists, then the mirror will sort by it + + fi + fi + +fi +unset dbpath + + +# ======================= + +# the following section of code is executed when pacui gets called directly from a terminal/tty without using the UI + + +# the 'pacui' command gets called (mostly) with arguments. in the following while-loop, all arguments are assigned to their designated variables: + +# save number of arguments in a variable for later usage, because the following while-loop destroys all original arguments and therefore, the number of arguments is always 0 after it: +argument_number="${#:-}" # we have to use "${#:-}" instead of "$#", because of strict bash mode! # '$#' is the number of arguments with which 'pacui' got called + +# save the argument, which contains a function name to this variable: +function_call="" +function_call_previous="" # this variable is not really necessary, but its usage saves many lines of code + +# save all unknown input in this variable: +argument_input="" + +# variable for 'flag' input, which gets directly passed to the AUR-helper or pacman +argument_flag="" + + +while (( ${#:-} > 0 )) +do + + key="${1:-}" # we have to use "${1:-}" instead of "$1", because of strict bash mode! # '$1' is the first argument with which 'pacui' got called + # comment: when entering regex as parameter for pacui, it has to be put in brackets. otherwise, "${1:-}" will somehow interpret it and output strange stuff. + + # remove leading white spaces from $key: + key="$( echo "$key" | sed 's/^ *//g' )" + + # remove trailing white spaces: + key="$( echo "$key" | sed 's/ *$//g' )" + + # remove leading dash(es): + key="$( echo "$key" | sed 's/^-*//g' )" + + # convert content of "key" variable to lowercase + key="$( echo "$key" | tr '[:upper:]' '[:lower:]' )" + + + # test, whether 'key' fits any of the following strings listed inside this 'case' command: + case "$key" in + + 1|u|update|update-system) # the following commands will get executed if $key is "1" or "u" or "update" until a code line containing only ";;" is encountered + function_call="u" + shift # shift to next argument (which is currently known as '$2'), and make it first argument ( referred to as '$1'). this command throws away the current argument, because we have done everything with it we wanted to do and it is no longer needed. + ;; + 2|m|maintain|maintain-system ) + function_call="m" + shift + ;; + 3|i|install|install-packages ) + function_call="i" + shift + ;; + 4|r|remove|remove-packages-and-deps ) + function_call="r" + shift + ;; + 5|t|tree|dependency-tree ) + function_call="t" + shift + ;; + 6|rt|reversetree|reverse-dependency-tree ) + function_call="rt" + shift + ;; + 7|l|list|list-package-files ) + function_call="l" + shift + ;; + 8|s|search|search-package-files ) + function_call="s" + shift + ;; + 9|b|back|roll-back-system ) + function_call="b" + shift + ;; + 10|f|fix|fix-pacman-errors ) + function_call="f" + shift + ;; + 11|c|conf|config|edit-config-files ) + function_call="c" + shift + ;; + 12|ls|listsize|list-packages-by-size ) + function_call="ls" + shift + ;; + 13|ua|fua|forceupdateaur|updateaur|force-update-aur ) + function_call="ua" + shift + ;; + 14|la|listaur|list-installed-from-aur ) + function_call="la" + shift + ;; + d|down|downgrade|downgrade-packages ) + function_call="d" + shift + ;; + a|aur|search-and-install-from-aur ) + function_call="a" + shift + ;; + h ) + function_call="h" # call short help + shift + ;; + 99|help|man ) + function_call="help" # call full help page + shift + ;; + + # next, all other possible arguments pacui can be called with are listed: + + diff ) + function_call="diff" # call "diff" helper function + shift + ;; + flag=* ) # this means 'flag=' string and every following string (no matter how long it is or what characters (except for " ") it contains) + argument_flag="${key#*=}" # replace '*=' (i.e. everything in front of = sign and = sign itself) in 'key' variable with nothing. save result in $argument_flag. + shift + ;; + flag ) + # assign next argument (which follows directly the 'flag' argument) to $argument_flag variable + argument_flag="${2:-}" # please note that only '$1' has been trimmed, dash(es) removed, and switched to lowercase. but nothing is done yet to '$2'. # we have to use "${2:-}" instead of "$2", because of strict bash mode! + shift # shift over 'flag' argument + shift # shift over argument, which follows 'flag' argument, i.e. the string which got just saved to $argument_flag + ;; + * ) # do this, if $key variable contains anything else not listed above. this is (hopefully) all stuff, which is supposed to be passed on to fzf. + argument_input+="$key" + argument_input+=" " # all 'key' arguments should be space separated. problem: there will be a space at the end of $argument_input variable. + shift + ;; + + esac + + + # print error message when more than 1 argument is recognized as a argument calling a pacui function + if [[ -n "$function_call_previous" && "$function_call_previous" != "$function_call" ]] + then + + echo -e " \e[41m Only one PacUI option can be called at the same time. Please try again. \e[0m" + exit + + fi + # save $function_call in $function_call_previous variable, because $function_call can get overwritten when the loop runs the next time. + function_call_previous="$function_call" + + +done + +# add trailing space to content of $argument_flag variable, because pacman and AUR helpers react in a strange way when an extra space is added. +if [[ -n "$argument_flag" ]] # check, whether output of "$argument_flag" is not-zero, i.e. $argument_flag contains something +then + argument_flag+=" " +fi + +# remove trailing white spaces from $argument_input variable. this is needed e.g. for 'func_s' to not search for "" but "" +argument_input="$( echo "$argument_input" | sed 's/ *$//g' )" + + +# the following code checks, whether a prefix (func_) + variable "function_call" is a valid function defined above. +if [[ "$( type -t "func_$function_call")" == "function" ]] +then + + "func_$function_call" # call pacui function + + # unset global variables: + unset function_call + unset function_call_previous + unset argument_input + unset argument_flag + + exit "$?" # exit pacui here and return error code if present. this "exit" command is needed to prevent the UI from loading! + +elif (( argument_number > 0 )) # if "func_$function_call" is no valid function AND if any arguments are given. this condition is needed to exclude the "pacui" command (note, there are NO arguments. "pacui" is supposed to start the UI) from running this section. +then + + unset function_call + unset function_call_previous + unset argument_input + unset argument_flag + + # display error, if $function_call does not refer to a valid function. the UI will be started by default. + echo -e " \e[41m Bad console command. Press ENTER to start PacUI or CTRL+C to abort. \e[0m" + read -r + # now, continue this script without exiting, i.e. load pacui's UI. + +fi + +unset argument_number # this global variable is no longer needed + + + +# logic code is above +# ======================= +# ======================= +# ======================= +# UI code is below + + + +# bug #1: +# "pacui --pacui_clean" helper function. this function is only called from within pacui's UI. +function pacui_clean +{ + # the traditional "clear" command does not work as expected on all systems. problem: the terminal history of all previous commands is deleted when the "clear" command is used. solution: do everything i expect from "clear" manually. this keeps the terminal history: + + local lines + # number of lines of the user's terminal. + lines="$( tput lines )" + for (( i=1; i