summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaymaekers Luca <raymaekers.luca@gmail.com>2024-06-22 02:05:44 +0200
committerRaymaekers Luca <raymaekers.luca@gmail.com>2024-06-22 02:05:44 +0200
commit36d2972c60ec86b873fa496d1f5ea95cf748cf49 (patch)
treea6d6750fa17c2964cd241afa8e963cac6106b390
parent4914b43f642e2772a140a8f9b1f26b4e555ed88b (diff)
parent32256e087aaf7744348a5ba33e802d5c8d9d97dd (diff)
Merge branch 'main' of db:dotfiles
-rwxr-xr-xbin/common/askpass13
-rwxr-xr-xbin/common/gt121
-rwxr-xr-xbin/extra/aivpn30
-rwxr-xr-xbin/extra/clock64
-rwxr-xr-xbin/extra/ddsurf4
-rwxr-xr-xbin/extra/igdl21
-rwxr-xr-xbin/extra/mtr23
-rwxr-xr-xbin/extra/muz-sync10
-rwxr-xr-xbin/extra/myalscore.sh7
-rwxr-xr-xbin/extra/spschedule2
-rwxr-xr-xbin/extra/trl4
-rwxr-xr-xbin/extra/trmv13
-rwxr-xr-xbin/extra/ytplay2
-rw-r--r--bin/guiscripts/mega.sh67
-rwxr-xr-xbin/guiscripts/osurf2
-rwxr-xr-xbin/guiscripts/osurf-fill127
-rwxr-xr-xbin/guiscripts/osurf-txt18
-rwxr-xr-xbin/guiscripts/osurfls8
-rwxr-xr-xbin/guiscripts/osurftabs12
-rwxr-xr-xbin/guiscripts/osurftxts22
-rwxr-xr-xbin/guiscripts/record100
-rwxr-xr-xbin/guiscripts/setbg5
-rwxr-xr-xbin/guiscripts/startw4
-rwxr-xr-xbin/guiscripts/yt4
-rwxr-xr-xbin/menuscripts/keyadd2
-rwxr-xr-xbin/menuscripts/mpass2
-rwxr-xr-xbin/menuscripts/mpass-otp2
-rwxr-xr-xbin/menuscripts/tsh21
-rwxr-xr-xconfig/X/x11/xinitrc2
-rw-r--r--config/common/mpd/mpd.conf2
-rwxr-xr-xconfig/common/mpv/mpv.conf5
m---------config/common/mpv/scripts/mpv-skipsilence0
-rw-r--r--config/common/newsraft/feeds12
-rwxr-xr-xconfig/common/tmux/tmux.conf2
-rw-r--r--config/essentials/shell/aliases.sh10
-rw-r--r--config/essentials/shell/functions.sh20
-rw-r--r--config/essentials/vis/Makefile6
-rw-r--r--config/essentials/vis/backup.lua47
-rw-r--r--config/essentials/vis/build.lua66
-rw-r--r--config/essentials/vis/commentary.lua251
-rw-r--r--config/essentials/vis/complete-line.lua141
-rw-r--r--config/essentials/vis/cursors.lua105
-rw-r--r--config/essentials/vis/format.lua134
-rw-r--r--config/essentials/vis/fzf-mru.lua75
-rw-r--r--config/essentials/vis/fzf-open.lua81
-rw-r--r--config/essentials/vis/themes/nord.lua123
-rw-r--r--config/essentials/vis/title.lua16
-rw-r--r--config/essentials/vis/vis-go.lua102
-rw-r--r--config/essentials/vis/vis-ultisnips/init.lua149
-rw-r--r--config/essentials/vis/vis-ultisnips/snipmate-parser.lua128
-rw-r--r--config/essentials/vis/vis-ultisnips/testlpeg-snipmate.lua160
-rw-r--r--config/essentials/vis/vis-ultisnips/testlpeg-ultisnips.lua230
-rw-r--r--config/essentials/vis/vis-ultisnips/ultisnips-parser.lua211
-rw-r--r--config/essentials/vis/visrc.lua152
-rw-r--r--config/essentials/vis/yank-highlight.lua37
-rw-r--r--config/essentials/zsh/.zshrc17
-rw-r--r--config/extra/mutt/.gitignore2
-rw-r--r--config/extra/mutt/muttrc1
-rw-r--r--config/home/.zshenv7
-rw-r--r--config/wayland/gammastep/config.ini2
-rw-r--r--config/wayland/hypr/hyprland.conf2
61 files changed, 2948 insertions, 60 deletions
diff --git a/bin/common/askpass b/bin/common/askpass
new file mode 100755
index 0000000..2725dbf
--- /dev/null
+++ b/bin/common/askpass
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# We can figure out the password for the key based on $1
+# which is in the following form:
+# Enter passphrase for key 'path/to/key':
+# The point is to retrieve the path and use the final name of the key
+# find the according password.
+key="$(printf '%s\n' "$1" |
+ cut -f 2 -d \' |
+ awk -F '/' '{print $NF}')"
+pass="keys/$(hostname)/ssh/$key"
+
+pass show "$pass" | head -n 1
diff --git a/bin/common/gt b/bin/common/gt
new file mode 100755
index 0000000..c679b23
--- /dev/null
+++ b/bin/common/gt
@@ -0,0 +1,121 @@
+#!/bin/sh
+
+# Git Trach, track the state of multiple repos from a single file.
+
+# dependencies:
+# - git
+# - $EDITOR: -e
+
+repos=$HOME/sync/share/git-track.txt
+# prevent file not found errors
+touch "$repos"
+
+help() {
+ >&2 cat <<EOF
+usage: gt [OPTION]
+-a PATH add repo
+-s update and show status of each repo
+-c COMMAND run 'git COMMAND' in each repo
+-h show this help
+-l list repos
+-e edit repos in $EDITOR
+EOF
+}
+
+# fetch repository prettily, outputs nothing if failed
+fetch() {
+ # fetch with one-line printing of progress
+ git fetch --progress 2>/dev/null | while read -r line
+ # \r\033[0K : clear current line
+ do >&2 printf '\r\033[0K%s' "$line"
+ done
+}
+
+# Print repositories prettily
+# This function function prints animations (eg. clearing the line)
+# to stderr and the final status line is outputted to stdout.
+status() {
+ while read -r repo
+ do
+ repo_pretty="$(printf '%s' "$repo" | sed "s@$HOME@~@" )"
+
+ # absolute path
+ cd "$repo"
+
+ # replace line with status
+ >&2 printf '\r\033[0K'
+
+ status="$(git status --porcelain 2> /dev/null | awk '{print $1}' | uniq | tr -d '\n')"
+ remote="$(git branch -v 2>/dev/null |
+ sed '/^*/!d;s/ahead/↑/;s/behind/↓/;s/[^↓↑]*//g')"
+
+ printf '%s %s %s\n' "$repo_pretty" "$status" "$remote"
+ done < "$repos"
+}
+
+# run git command in each repo
+# $1: command
+repos_cmd() {
+ while read -r repo
+ do
+ repo_pretty="$(printf '%s' "$repo" | sed "s@$HOME@~@" )"
+ printf ''\''%s'\'' in %s' "$1" "$repo_pretty"
+ (
+ cd "$repo"
+ git "$1" > /dev/null 2>&1
+ [ $? -gt 0 ] && s="x" || s="o"
+ printf '\r\033[0K%s: %s\n' "$repo_pretty" "$s"
+ )
+ done < "$repos"
+}
+
+# no options
+if [ -z "$1" ]
+then
+ help
+ exit 1
+fi
+
+while getopts ":a:c:f:lshe" opt
+do
+ case "$opt" in
+ a)
+ cd "$OPTARG" || exit 1
+ r="$(git rev-parse --show-toplevel)"
+ [ "$r" ] || exit 2
+
+ if grep "$r" "$repos" > /dev/null 2>&1
+ then
+ >&2 printf 'added already.\n'
+ exit 2
+ fi
+
+ printf '%s\n' "$r" >> "$repos"
+
+ >&2 printf 'added.\n' ;;
+ c) f_command=1; f_arg="$OPTARG" ;;
+ s) f_status=1 ;;
+ l) cat "$repos" ;;
+ e) $EDITOR "$repos" ;;
+ f) repos="$OPTARG" ;;
+ h) help ;;
+ :) >&2 printf -- '-%s requires argument\n' "$OPTARG"; exit 1 ;;
+ ?) >&2 printf -- 'Invalid option: -%s\n' "$OPTARG"; exit 1 ;;
+ esac
+done
+
+# commands hereafter must happen in order
+
+[ "$(wc -l < "$repos")" -gt 0 ] || exit 0
+
+if [ "$f_command" ]
+then
+ repos_cmd "$f_arg"
+fi
+
+if [ "$f_status" ]
+then
+ status
+fi
+
+# eval "herbe $(status | sed 's/"/\"/g;s/.*/"&"/' | tr '\n' ' ')"
diff --git a/bin/extra/aivpn b/bin/extra/aivpn
new file mode 100755
index 0000000..841d926
--- /dev/null
+++ b/bin/extra/aivpn
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+err() { printf "%s\n" "$@"; }
+
+if [ "$1" = "-k" ]
+then
+ pgrep -f -- "ssh.*-L.*vm" | xargs kill
+ exit
+fi
+
+err "I: Waiting for connectivity..."
+while ! ssh -o ConnectTimeout=1 -o BatchMode=yes vm 2>&1 | grep "Permission denied" > /dev/null
+do sleep 1
+done
+
+
+export SSH_ASKPASS="sshpass"
+export SSH_ASKPASS_REQUIRE="prefer"
+export PASSWORD="zot/quickemu"
+
+err "I: Activating vpn"
+ssh vm "rasdial \"vpn.student.ehb.be\""
+
+keyadd ehb/ai
+ssh -f -N -L 2222:10.2.160.41:22 vm
+
+keyadd ehb/vm_int
+ssh -f -N -L 2223:10.2.160.9:22 vm
+ssh -f -N -L 2224:10.2.160.10:22 vm
+ssh -f -N -L 2225:10.2.160.11:22 vm
diff --git a/bin/extra/clock b/bin/extra/clock
new file mode 100755
index 0000000..bd6efd2
--- /dev/null
+++ b/bin/extra/clock
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+clocks="${XDG_DATA_HOME:-$HOME}"/clocks.csv
+
+if [ ! -f "$clocks" ]
+then
+ printf 'start,end,message\n' > "$clocks"
+fi
+
+# print clocks file prettily
+if [ "$1" = "-p" ]
+then
+ # empty
+ [ "$(wc -l < "$clocks")" -eq 1 ] && exit
+
+ timefmt="%y%m%d-%T"
+ IFS=","
+ # skip csv header
+ tail -n +2 "$clocks" |
+ while read -r start end message
+ do
+ printf "%s - %s | %s\n" "$(date -d "@$start" +"$timefmt" )" "$(date -d "@$end" +"$timefmt")" "$message"
+ done
+ exit
+fi
+
+# edit clocks file in $EDITOR
+if [ "$1" = "-e" ]
+then
+ $EDITOR "$clocks"
+ exit
+fi
+
+trap 'exit 0' INT # The proper way to exit
+
+while true
+do
+ >&2 printf ' > '
+ message="$(head -n 1)"
+
+ [ "$message" ] || exit 1
+ printf '\033[1A' # move cursor up once: https://en.wikipedia.org/wiki/ANSI_escape_code
+
+ start_time="$(date +%s)"
+ start_time_pretty="$(date -d "@$start_time" +%R)"
+ >&2 printf -- '\r%s- > %s' "$start_time_pretty" "$message"
+
+ # Wait for EOF
+ cat > /dev/null 2>&1
+
+ end_time="$(date +%s)"
+ end_time_pretty="$(date -d "@$end_time" +%R)"
+ >&2 printf -- '\r%s-%s > %s\n' "$start_time_pretty" "$end_time_pretty" "$message"
+
+ if printf '%s' "$message" | grep ',' > /dev/null
+ then
+ # escape potential double quotes
+ message="$(printf '%s' "$message" | sed -e 's/"/""/g')"
+ message="\"$message\""
+ fi
+
+ # save clocked time and message
+ printf '%s,%s,%s\n' "$start_time" "$end_time" "$message" >> "$clocks"
+done
diff --git a/bin/extra/ddsurf b/bin/extra/ddsurf
new file mode 100755
index 0000000..a3ae0d1
--- /dev/null
+++ b/bin/extra/ddsurf
@@ -0,0 +1,4 @@
+#!/bin/sh
+f="$(mktemp)"
+awk '!x[$2]++' ~/.config/surf/history.txt > "$f"
+mv "$f" ~/.config/surf/history.txt
diff --git a/bin/extra/igdl b/bin/extra/igdl
new file mode 100755
index 0000000..1973187
--- /dev/null
+++ b/bin/extra/igdl
@@ -0,0 +1,21 @@
+#!/bin/sh
+lock="/tmp/igdl.lock"
+
+if [ -f "$lock" ]
+then
+ herbe "already downloading."
+ exit 1
+fi
+
+
+url="$(clipo)"
+out="/tmp/igdl.mp4"
+
+touch "$lock"
+herbe "igdl" "downloading: $url" &
+yt-dlp "$url" -o "$out" || rm "$lock"
+
+printf '%s' "$out" | clipp
+herbe "igdl" "copied path."
+
+rm "$lock"
diff --git a/bin/extra/mtr b/bin/extra/mtr
new file mode 100755
index 0000000..486a9b8
--- /dev/null
+++ b/bin/extra/mtr
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+list_categories()
+{
+ cat <<EOF
+music
+anime
+movies
+shows
+other
+software
+games
+isos
+books
+EOF
+}
+
+category="$(list_categories | commander -cl)"
+[ "$category" ] || exit 1
+
+transmission-remote debuc.com -a "$(clipo)" -w "/downloads/$category"
+
+notify-send "mtr" "added to <b>$category</b>"
diff --git a/bin/extra/muz-sync b/bin/extra/muz-sync
new file mode 100755
index 0000000..a81ef74
--- /dev/null
+++ b/bin/extra/muz-sync
@@ -0,0 +1,10 @@
+#!/bin/sh
+trap "exit 1" INT
+
+music="$(xdg-user-dir MUSIC)"
+>&2 printf "music: %s\n" "$music"
+
+# recursive, links, fuzzy, partial, progress
+while ! rsync -rlyP --size-only db:/media/basilisk/music/sorted/ "$music"
+do :
+done
diff --git a/bin/extra/myalscore.sh b/bin/extra/myalscore.sh
new file mode 100755
index 0000000..ef68bcc
--- /dev/null
+++ b/bin/extra/myalscore.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+[ "$1" ] || exit 1
+query="$(printf '%s' "$*" | sed 's/\s/%20/g')"
+curl -s "https://myanimelist.net/search/prefix.json?type=all&keyword=$query&v=1" \
+ -H 'Accept: application/json, text/javascript, */*; q=0.01' |
+ jq -r '.categories[].items[] | [.payload.score, .name] | join(" ")'
diff --git a/bin/extra/spschedule b/bin/extra/spschedule
new file mode 100755
index 0000000..b0dd70a
--- /dev/null
+++ b/bin/extra/spschedule
@@ -0,0 +1,2 @@
+#!/bin/sh
+curl -s 'https://subsplease.org/api/?f=schedule&tz=UTC' | jq -r ".schedule.$(date +%A).[] | [.time, .title] | join(\" \")"
diff --git a/bin/extra/trl b/bin/extra/trl
index bd4c2c5..55d65ee 100755
--- a/bin/extra/trl
+++ b/bin/extra/trl
@@ -41,10 +41,10 @@ then
fi
[ "$word" ] || exit 1
-primary="$(languages | fzf)"
+primary="$(languages | fzf --prompt="from:")"
[ "$primary" ] || exit 1
-secondary="$(languages | fzf)"
+secondary="$(languages | fzf --prompt="to:")"
[ "$secondary" ] || exit 1
curl -s "https://context.reverso.net/translation/$primary-$secondary/$word" \
diff --git a/bin/extra/trmv b/bin/extra/trmv
new file mode 100755
index 0000000..22d9e48
--- /dev/null
+++ b/bin/extra/trmv
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+trr() { transmission-remote 192.168.178.79 "$@"; }
+
+id="$(trr -t all -l | tail -n +2 | head -n -1 | fzf | awk '{print $1}')"
+[ "$id" ] || exit 1
+name="$(trr -t "$id" -i | grep '^\s*Name:' | cut -f 4- -d ' ')"
+location="$(trr -t "$id" -i | grep '^\s*Location:' | cut -f 4- -d ' ')"
+
+>&2 printf '#%s\n' "$id"
+>&2 printf "old name: %s\n" "$name"
+>&2 printf 'new name: '
+trr -t "$id" --path "$name" --rename "$(head -n 1)"
diff --git a/bin/extra/ytplay b/bin/extra/ytplay
index 66204c4..5243364 100755
--- a/bin/extra/ytplay
+++ b/bin/extra/ytplay
@@ -1,4 +1,4 @@
#!/bin/sh
url="$(ytlink)"
-notify-send "playing: $url" &
+herbe "playing: $url" &
yt-dlp -o - "$url" | mpv -
diff --git a/bin/guiscripts/mega.sh b/bin/guiscripts/mega.sh
new file mode 100644
index 0000000..cafca0a
--- /dev/null
+++ b/bin/guiscripts/mega.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+URL=""
+
+if [[ $1 =~ ^https?:\/\/mega(\.co)?\.nz ]]; then
+ URL="$1"
+fi
+
+if [[ ! $URL ]]; then
+ echo "Usage: ${0##*/} url" >&2
+ exit 1
+fi
+
+CURL="curl -Y 1 -y 10"
+
+missing=false
+for cmd in openssl; do
+ if [[ ! $(command -v "$cmd" 2>&1) ]]; then
+ missing=true
+ echo "${0##*/}: $cmd: command not found" >&2
+ fi
+done
+if $missing; then
+ exit 1
+fi
+
+if [[ $URL =~ .*/file/[^#]*#[^#]* ]]; then
+ id="${URL#*file/}"; id="${id%%#*}"
+ key="${URL##*file/}"; key="${key##*#}"
+else
+ id="${URL#*!}"; id="${id%%!*}"
+ key="${URL##*!}"
+fi
+
+raw_hex=$(echo "${key}=" | tr '\-_' '+/' | tr -d ',' | base64 -d -i 2>/dev/null | od -v -An -t x1 | tr -d '\n ')
+hex=$(printf "%016x" \
+ $(( 0x${raw_hex:0:16} ^ 0x${raw_hex:32:16} )) \
+ $(( 0x${raw_hex:16:16} ^ 0x${raw_hex:48:16} ))
+)
+
+json=$($CURL -s -H 'Content-Type: application/json' -d '[{"a":"g", "g":"1", "p":"'"$id"'"}]' 'https://g.api.mega.co.nz/cs?id=&ak=') || exit 1; json="${json#"[{"}"; json="${json%"}]"}"
+file_url="${json##*'"g":'}"; file_url="${file_url%%,*}"; file_url="${file_url//'"'/}"
+
+json=$($CURL -s -H 'Content-Type: application/json' -d '[{"a":"g", "p":"'"$id"'"}]' 'https://g.api.mega.co.nz/cs?id=&ak=') || exit 1
+at="${json##*'"at":'}"; at="${at%%,*}"; at="${at//'"'/}"
+
+json=$(echo "${at}==" | tr '\-_' '+/' | tr -d ',' | openssl enc -a -A -d -aes-128-cbc -K "$hex" -iv "00000000000000000000000000000000" -nopad | tr -d '\0'); json="${json#"MEGA{"}"; json="${json%"}"}"
+file_name="${json##*'"n":'}"
+if [[ $file_name == *,* ]]; then
+ file_name="${file_name%%,*}"
+fi
+file_name="${file_name//'"'/}"
+
+aria2c -x 15 -o "$file_name" "$file_url"
+cat "$file_name" | openssl enc -d -aes-128-ctr -K "$hex" -iv "${raw_hex:32:16}0000000000000000" > "temp.new"
+mv -f temp.new "$file_name"
+
+echo "$file_url"
+echo "$file_name"
+echo "$hex"
+echo "${raw_hex:32:16}0000000000000000"
+sleep 5
+echo "Downloading... (press Ctrl + C to Cancel)"
+
+aria2c -x 16 -s 16 -o "$file_name" "$file_url"
+cat "$file_name" | openssl enc -d -aes-128-ctr -K "$hex" -iv "${raw_hex:32:16}0000000000000000" > "temp.new"
+mv -f temp.new "$file_name"
diff --git a/bin/guiscripts/osurf b/bin/guiscripts/osurf
new file mode 100755
index 0000000..6923848
--- /dev/null
+++ b/bin/guiscripts/osurf
@@ -0,0 +1,2 @@
+#!/bin/sh
+tabbed -c -dn tabbed-surf -r 2 surf -e '' "$1"
diff --git a/bin/guiscripts/osurf-fill b/bin/guiscripts/osurf-fill
new file mode 100755
index 0000000..43af807
--- /dev/null
+++ b/bin/guiscripts/osurf-fill
@@ -0,0 +1,127 @@
+#!/bin/sh
+
+# Fills a password for a given website
+# original script by Avalon Williams (avalonwilliams@protonmail.com)
+# This version uses the window id to know the url of the surf window
+# and to know which fifo it must use. Then it injects javascript code.
+# that will fill the forms with the credentials
+
+# dependencies:
+# - surf fifo patch (http://surf.suckless.org/patches/fifo/)
+# - xprop
+# - 'pass' with password store in form dir/url/pass.gpg
+
+# $1: winid
+
+fifodir="$HOME/.config/surf/fifo"
+if [ -z "${winid:=$1}" ]
+then
+ winid="$(osurfls | dmenu -c -F -i | cut -f1 -d' ')"
+fi
+[ "$winid" ] || exit 1
+fifo="$fifodir/$winid"
+[ -p "$fifo" ] || exit 2
+
+# Get only domain name + top-level domain
+url="$(xprop -id "$winid" _SURF_URI |
+ cut -f 2 -d'"' |
+ sed 's,^.*://\([^/]*\)/.*,\1,' |
+ sed -r -e 's/^([^.]+)\.([^.]+)\.([^.]+)$/\2.\3/')"
+[ "$url" ] || exit 3
+>&2 printf 'url: %s\n' "$url"
+
+# get pass with url and ask if multiple are found
+pass="$({ find $PASSWORD_STORE_DIR/websites/ -type f -name '*.gpg' |
+ grep "$url/" || echo; } | head -n 1 |
+ sed "s,$PASSWORD_STORE_DIR/,,;s/\.gpg$//" |
+ dmenu -c)"
+# if dmenu was stopped, exit
+[ $? -gt 0 ] && exit 4
+
+# if no password was found, search through password store manually with dmenu
+if [ -z "$pass" ]
+then
+ store="${PASSWORD_STORE_DIR:-$HOME/.password-store}"
+ while [ -d "$store/$file" ]
+ do
+ choice="$(find "$store/$file" \
+ -maxdepth 1 -mindepth 1 \
+ -not -name '.*' -type d -printf "%y\t%f\n" -o \
+ -not -name '.*' -not -type d -printf "%y\t%f\n" |
+ sort -k1 -k2 |
+ cut -f 2 | sed 's/\.gpg$//' |
+ dmenu -c)"
+ [ "$choice" ] || exit 1
+ [ -z "$file" ] && file="$choice" || file="$file/$choice"
+ done
+ pass="$file"
+fi
+>&2 printf 'pass: %s\n' "$pass"
+herbe "filling ${pass#websites/}" &
+
+# Get password and username in variables with only one call to 'pass'
+# escape single quotes
+eval "$(pass show "$pass" |
+ sed -n "1s/'/'\\\\''/g;1s/.*/password='&'/p;s/^login: \?\(.\+\)/username='\1'/p")"
+printf '%s : %s\n' "$username" "$password"
+
+# Escape quotes and backslashes for javascript
+javascript_escape() {
+ printf '%s' "$1" | sed -s 's,['\''"\\\\],\\\\&,g'
+}
+
+js() {
+cat <<EOF
+ function isVisible(elem) {
+ var style = elem.ownerDocument.defaultView.getComputedStyle(elem, null);
+ if (style.getPropertyValue("visibility") !== "visible" ||
+ style.getPropertyValue("display") === "none" ||
+ style.getPropertyValue("opacity") === "0") {
+ return false;
+ }
+ return elem.offsetWidth > 0 && elem.offsetHeight > 0;
+ };
+ function hasPasswordField(form) {
+ var inputs = form.getElementsByTagName("input");
+ for (var j = 0; j < inputs.length; j++) {
+ var input = inputs[j];
+ if (input.type == "password" || input.autocomplete == "password" || input.name == "password") {
+ return true;
+ }
+ }
+ return false;
+ };
+ function loadData2Form (form) {
+ var inputs = form.getElementsByTagName("input");
+ for (var j = 0; j < inputs.length; j++) {
+ var input = inputs[j];
+ if (isVisible(input) && (input.type == "text" || input.type == "email")) {
+ input.focus();
+ input.value = "$(javascript_escape "$username")";
+ input.blur();
+ console.log("user: $(javascript_escape "$username")")
+ }
+ if (input.type == "password" || input.name == "password" || input.autocomplete == "password" || input.id == "password" ) {
+ input.focus();
+ input.value = "$(javascript_escape "$password")";
+ input.blur();
+ console.log("password: $(javascript_escape "$password")")
+ }
+ console.log(input)
+ }
+ };
+ var forms = document.getElementsByTagName("form");
+ for (i = 0; i < forms.length; i++) {
+ if (hasPasswordField(forms[i])) {
+ loadData2Form(forms[i]);
+ // forms[i].submit();
+ }
+ }
+EOF
+}
+
+printjs() {
+ js | sed 's,//.*$,,' | tr '\n' ' '
+}
+
+echo "inject $(printjs)" >> "$fifo"
diff --git a/bin/guiscripts/osurf-txt b/bin/guiscripts/osurf-txt
new file mode 100755
index 0000000..9a1d4f4
--- /dev/null
+++ b/bin/guiscripts/osurf-txt
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# open a link from a txt file in surf
+
+# dependencies: surf, osurf, dmenu
+
+winid="$1"
+>&2 printf 'winid: %s\n' "$winid"
+tabs="$HOME/dl/txtabs"
+
+f="$(find "$tabs" -type f -printf '%f\n' | dmenu -c)"
+[ "$f" ] || exit 1
+f="$tabs"/"$f"
+>&2 printf 'f: %s\n' "$f"
+
+url="$(dmenu -c < "$f")"
+
+printf 'loaduri %s' "$url" > $HOME/.config/surf/fifo/$winid
diff --git a/bin/guiscripts/osurfls b/bin/guiscripts/osurfls
new file mode 100755
index 0000000..0abdd35
--- /dev/null
+++ b/bin/guiscripts/osurfls
@@ -0,0 +1,8 @@
+#!/bin/sh
+find "$HOME/.config/surf/fifo" -type p -printf '%f\n' |
+while read -r winid
+do
+ title="$(xprop -id "$winid" 2> /dev/null | awk -F'"' '/^_NET_WM_NAME/ {print $2}')"
+ [ "$title" ] || continue
+ printf '%s %s\n' "$winid" "$title"
+done \ No newline at end of file
diff --git a/bin/guiscripts/osurftabs b/bin/guiscripts/osurftabs
new file mode 100755
index 0000000..d41424b
--- /dev/null
+++ b/bin/guiscripts/osurftabs
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# list surf tabbed windows
+
+# dependencies: lsw, dmenu, xprop
+# expects the tabbed windows to be named 'tabbed-surf'
+lsw | cut -f1 -d' ' |
+ while read -r winid
+ do
+ [ "tabbed-surf" = "$(xprop -id "$winid" WM_CLASS | cut -f2 -d'"')" ] &&
+ printf '%s %s\n' "$winid" "$(xprop -id "$winid" WM_NAME | cut -f2 -d'"')"
+ done
diff --git a/bin/guiscripts/osurftxts b/bin/guiscripts/osurftxts
new file mode 100755
index 0000000..ef60166
--- /dev/null
+++ b/bin/guiscripts/osurftxts
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# open all links in txt file into one tabbed surf
+
+# dependencies: surf, osurf, dmenu
+
+# $1: file path for non interactive use
+if [ -z "$1" ]
+then
+ d="$HOME/dl/txtabs"
+ f="$(find "$d" -type f -printf '%f\n' | dmenu)"
+ [ "$f" ] || exit 1
+ f="$d"/"$f"
+else
+ [ -f "$1" ] || exit 1
+ f="$1"
+fi
+
+winid="$(osurf "$(head -n 1 "$f")")"
+tail -n +2 "$f" | while read -r url;
+ do surf -e "$winid" "$url" &
+ done
diff --git a/bin/guiscripts/record b/bin/guiscripts/record
new file mode 100755
index 0000000..df4b6e6
--- /dev/null
+++ b/bin/guiscripts/record
@@ -0,0 +1,100 @@
+#!/bin/sh
+
+# record - record an area of the screen
+
+lock="/tmp/record.lock"
+
+# dependencies: ffmpeg, hacksaw (part), xwininfo & lsw (window), xdotool (active)
+# optional:
+# - hacksaw: part
+# - xwininfo, lsw, commander: window
+# - xdotool: active
+# - xdg-user-dir
+
+audio=
+
+# $1: width
+# $2: height
+# $3: x
+# $4: y
+# $5: output dir
+# $6: output name
+record_cmd()
+{
+ if [ -f "$lock" ]
+ then
+ >&2 printf 'already recording, please stop recording first\n'
+ exit 1
+ else
+ touch "$lock"
+ fi
+
+ herbe "started recording." &
+ w=$(($3 + $3 % 2))
+ h=$(($4 + $4 % 2))
+ ffmpeg $audio \
+ -v 16 \
+ -r 30 \
+ -f x11grab \
+ -s "${w}x${h}" \
+ -i ":0.0+$1,$2" \
+ -preset slow \
+ -c:v h264 \
+ -pix_fmt yuv420p \
+ -crf 20 \
+ "$5/$6.mp4"
+ printf '%s\n' "$5/$6.mp4"
+ rm -f "$lock"
+ herbe "stopped recording." &
+}
+
+if [ -d "$1" ]
+then
+ dir="$1"
+ shift
+else
+ dir="$(which xdg-user-dir > /dev/null 2>&1 && xdg-user-dir VIDEOS)"
+ [ "$dir" ] && dir="$dir/records" || dir="$HOME/vids/records"
+fi
+mkdir -p "$dir"
+
+if [ "$1" = "-a" ]
+then
+ audio="-f pulse -ac 2 -i default"
+ shift
+fi
+
+if [ "$1" = "-l" ]
+then
+ find vids/records/ -type f | sort | tail -n 1
+ exit
+fi
+
+current=$(date +%F_%H-%M-%S)
+
+[ "$1" ] && option="$1" || option="$(printf 'active\nwindow\npart\nstop\nfull\naudio' | commander -c)"
+case "$option" in
+ active)
+ record_cmd $(xwininfo -id "$(xdotool getactivewindow)" |
+ sed -e '/Absolute\|Width:\|Height:/!d;s/.*:\s*//' | tr '\n' ' ') $dir $current
+ ;;
+
+ window)
+ winid="$(lsw | commander -cxl | cut -d' ' -f1)"
+ [ "$winid" ] || exit 1
+ values="$(xwininfo -id "$winid" | sed -e '/Absolute\|Width:\|Height:/!d;s/.*:\s*//' | tr '\n' ' ')"
+ [ "$values" ] || exit 1
+ record_cmd $values $dir $current
+ ;;
+
+ part)
+ hacksaw | {
+ IFS=+x read -r w h x y
+ record_cmd $w $h $x $y $dir $current
+ }
+ ;;
+ stop) kill "$(pgrep ffmpeg | xargs ps | grep 'x11grab' | awk '{print $1}')"; rm -f "$lock" ;;
+ full) record_cmd 0 0 1920 1080 $dir $current ;;
+ audio) $0 -a; exit ;;
+ help|*) >&2 printf 'record [dir] (active|window|part|stop|full)\n' ;;
+esac
diff --git a/bin/guiscripts/setbg b/bin/guiscripts/setbg
new file mode 100755
index 0000000..a4109ab
--- /dev/null
+++ b/bin/guiscripts/setbg
@@ -0,0 +1,5 @@
+#!/bin/sh
+cd "$HOME/pics/wallpapers" || exit 1
+bg="$(find . -type f -printf '%f\n' | sed 's@^\./@@' | dmenu -c -x)"
+[ "$bg" ] || exit 1
+feh --no-fehbg --bg-scale "$bg"
diff --git a/bin/guiscripts/startw b/bin/guiscripts/startw
index 0383f48..dbf4450 100755
--- a/bin/guiscripts/startw
+++ b/bin/guiscripts/startw
@@ -1,8 +1,4 @@
#!/bin/sh
-
eval "$(keychain --dir "$XDG_CONFIG_HOME/keychain" --eval --quiet --agents gpg,ssh)"
eval "$(keychain --dir "$XDG_CONFIG_HOME/keychain" --eval --quiet --agents gpg 3A626DD20A32EB2E5DD9CE71CFD9ABC97158CD5D 2> /dev/null)"
-
-(cd ~/.config/waybar/ && ln -sf hyprland.jsonc config.jsonc)
-
Hyprland
diff --git a/bin/guiscripts/yt b/bin/guiscripts/yt
new file mode 100755
index 0000000..72f6e92
--- /dev/null
+++ b/bin/guiscripts/yt
@@ -0,0 +1,4 @@
+#!/bin/sh
+link="$(ytfzf -D -I l)"
+[ "$link" ] || exit 1
+yt-dlp $@ -o - "$link" | mpv -
diff --git a/bin/menuscripts/keyadd b/bin/menuscripts/keyadd
index 12519ec..4e7949f 100755
--- a/bin/menuscripts/keyadd
+++ b/bin/menuscripts/keyadd
@@ -2,7 +2,7 @@
log()
{
- notify-send -t 1000 "keyadd" "$1"
+ notify-send -t 1000 "keyadd" "$1" &
>&2 printf '%s\n' "$1"
}
diff --git a/bin/menuscripts/mpass b/bin/menuscripts/mpass
index 7348321..f513b16 100755
--- a/bin/menuscripts/mpass
+++ b/bin/menuscripts/mpass
@@ -14,7 +14,7 @@ list_pswds()
while [ -d "$store/$file" ]
do
- choice="$(list_pswds "$store/$file" | dmenu -c -g 4 -l 4)"
+ choice="$(list_pswds "$store/$file" | commander -c)"
[ "$choice" ] || exit 1
[ -z "$file" ] && file="$choice" || file="$file/$choice"
done
diff --git a/bin/menuscripts/mpass-otp b/bin/menuscripts/mpass-otp
index 52d1341..2be6186 100755
--- a/bin/menuscripts/mpass-otp
+++ b/bin/menuscripts/mpass-otp
@@ -1,7 +1,7 @@
#!/bin/sh
pass="$(find "$PASSWORD_STORE_DIR"/keys/otp -iname "*.gpg" |
sed "/^\./d;s#^$PASSWORD_STORE_DIR/keys/otp/##;s/\.gpg$//" |
- commander -c)"
+ dmenu -c)"
[ "$pass" ] || exit 1
pass otp -c keys/otp/"$pass"
notify-send -t 1000 "mpass" "copied $pass"
diff --git a/bin/menuscripts/tsh b/bin/menuscripts/tsh
index aac27ee..0c57ee0 100755
--- a/bin/menuscripts/tsh
+++ b/bin/menuscripts/tsh
@@ -5,8 +5,8 @@ PROG="$(basename "$0")"
# copy command and deps variable
deps="pup curl $MENUCMD"
-LIBPFX=/home/aluc/.local/share/tsh
-module='1337x.sh' # default module
+MODULES_PATH=$HOME/.local/share/tsh
+module='nyaa.sh' # default module
# Files
export tmp="/tmp/$PROG"
@@ -83,7 +83,7 @@ cleanup ()
done
}
-list_modules () { find -L "$LIBPFX" -type f -printf "%f\n"; }
+list_modules () { find -L "$MODULES_PATH" -type f -printf "%f\n"; }
# get a query from user based on MENUCMD
get_query ()
@@ -121,14 +121,6 @@ show_files()
rm -f "$tmp"/.torrent
}
-# Select a type after having displayed them with 'show_types'
-select_type()
-{
- for type in $categories
- do printf "%s\n" "$type"
- done | fzf
-}
-
trap "exit 1" INT
trap "cleanup" EXIT
@@ -179,7 +171,7 @@ then
# Get results
rm -f "$results" "$links"
# shellcheck source=/usr/local/lib/$PROG/nyaa.sh disable=SC1091
- . "$LIBPFX/$module"
+ . "$MODULES_PATH/$module"
[ -f "$results" ] || die "No results."
# Save which module was used
@@ -190,7 +182,7 @@ fi
# acquire get_magnet function
# shellcheck source=/usr/local/lib/$PROG/nyaa.sh disable=SC1091
-getfunctions=1 . "$LIBPFX/$module"
+getfunctions=1 . "$MODULES_PATH/$module"
# select result from "$results"
for choice in $(select_result | xargs)
@@ -205,7 +197,8 @@ do
if [ "$noaskdownload" ] || confirm 'download?'
then
- [ "${category:-$(select_type)}" ] || exit 1
+ [ "$category" ] || category="$(printf '%s' "$categories" | tr ' ' '\n' | fzf)"
+ [ "$category" ] || exit 2
transmission-remote debuc.com -a "$magnet" -w "/downloads/$category"
elif confirm "copy?"
then
diff --git a/config/X/x11/xinitrc b/config/X/x11/xinitrc
index bc1824a..8b3cf2b 100755
--- a/config/X/x11/xinitrc
+++ b/config/X/x11/xinitrc
@@ -22,7 +22,7 @@ export MENUCMD="dmenu"
export IMAGE="feh"
xcompmgr &
feh --no-fehbg --bg-scale ~/pics/wallpaper
-setxkbmap us -option ctrl:swapcaps,altwin:menu_win -variant colemak
+setxkbmap colemak -option ctrl:swapcaps,altwin:menu_win
# xautolock -locker slock &
gammastep -m randr &
# dunst &
diff --git a/config/common/mpd/mpd.conf b/config/common/mpd/mpd.conf
index 095b345..889b458 100644
--- a/config/common/mpd/mpd.conf
+++ b/config/common/mpd/mpd.conf
@@ -1,4 +1,4 @@
-music_directory "/media/manthe/music"
+music_directory "~/music"
playlist_directory "~/.config/mpd/playlists"
db_file "~/.config/mpd/database"
pid_file "~/.config/mpd/pid"
diff --git a/config/common/mpv/mpv.conf b/config/common/mpv/mpv.conf
index 1fd96da..2e7318e 100755
--- a/config/common/mpv/mpv.conf
+++ b/config/common/mpv/mpv.conf
@@ -17,10 +17,11 @@ ytdl-raw-options=extractor-args="youtube:player-client=android"
# Default demuxer is 150/75 MB, note that this uses RAM so set a reasonable amount.
# 150MB, Max pre-load for network streams (1 MiB = 1048576 Bytes).
-demuxer-max-bytes=150000000
+demuxer-max-bytes=150MiB
+demuxer-readahead-secs=20
# 75MB, Max loaded video kept after playback.
-demuxer-max-back-bytes=75000000
+demuxer-max-back-bytes=75MiB
# Force stream to be seekable even if disabled.
force-seekable=yes
diff --git a/config/common/mpv/scripts/mpv-skipsilence b/config/common/mpv/scripts/mpv-skipsilence
new file mode 160000
+Subproject 2d6fd04dca3c70edf816e9af6fc30b302eb1c7a
diff --git a/config/common/newsraft/feeds b/config/common/newsraft/feeds
index 77e5420..683490c 100644
--- a/config/common/newsraft/feeds
+++ b/config/common/newsraft/feeds
@@ -25,8 +25,12 @@ https://arthurmelton.com/blogs.rss "Arthur Melton's blog'"
@ Linux
https://www.youtube.com/feeds/videos.xml?channel_id=UC-V8FVQCUpRRUPNClviki3w "Luke Smith"
-https://youtube.com/feeds/video.xml?channel_id=UCngn7SVujlvskHRvRKc1cTw "Bugswriter"
-https://youtube.com/feeds/video.xml?channel_id=UCVls1GmFKf6WlTraIb_IaJg "DistroTube"
+https://www.youtube.com/feeds/videos.xml?channel_id=UCngn7SVujlvskHRvRKc1cTw "Bugswriter"
+https://www.youtube.com/feeds/videos.xml?channel_id=UCVls1GmFKf6WlTraIb_IaJg "DistroTube"
+https://www.youtube.com/feeds/videos.xml?channel_id=UCuGS5mN1_CpPzuOUAu2LluA "NixHero"
+https://www.youtube.com/feeds/videos.xml?channel_id=UCWQaM7SpSECp9FELz-cHzuQ "Dreams of Code"
+https://www.youtube.com/feeds/videos.xml?channel_id=UCCuoqzrsHlwv1YyPKLuMDUQ "Jonathan Blow"
+
@ Entertainment
https://www.youtube.com/feeds/videos.xml?channel_id=UCi8C7TNs2ohrc6hnRQ5Sn2w "Programmers are also human"
@@ -37,5 +41,5 @@ https://www.youtube.com/feeds/videos.xml?channel_id=UCVk4b-svNJoeytrrlOixebQ "Th
https://www.youtube.com/feeds/videos.xml?channel_id=UCd3dNckv1Za2coSaHGHl5aA "TJ DeVries"
@ News
-https://rss.rtbf.be/article/rss/highlight_rtbf_info.xml?source=internal
-https://news.ycombinator.com/rss
+https://rss.rtbf.be/article/rss/highlight_rtbf_info.xml?source=internal "RTBF"
+https://news.ycombinator.com/rss "HackerNews"
diff --git a/config/common/tmux/tmux.conf b/config/common/tmux/tmux.conf
index 9300c97..8cf10e5 100755
--- a/config/common/tmux/tmux.conf
+++ b/config/common/tmux/tmux.conf
@@ -120,7 +120,7 @@ set -g status on
#+--- Layout ---+
set -g set-titles-string "[#S: #W] #T"
set -g set-titles on
-set -g status-position top
+set -g status-position bottom
set -g window-status-current-style "underscore"
set -g status-justify left
set -g status-left-length 16
diff --git a/config/essentials/shell/aliases.sh b/config/essentials/shell/aliases.sh
index a8b9036..ddc605a 100644
--- a/config/essentials/shell/aliases.sh
+++ b/config/essentials/shell/aliases.sh
@@ -3,7 +3,8 @@
# The most important one
alias vi='vis'
-alias cd='z'
+which z > /dev/null 2>&1 &&
+ alias cd='z'
# Zsh specific aliases
if [ $SHELL = "/bin/zsh" ]
@@ -53,7 +54,8 @@ alias pf='profanity'
alias f='fg'
-alias gurk='pgrep gurk > /dev/null && printf "Already Running.\n" || gurk'
+which gurk > /dev/null 2>&1 &&
+ alias gurk='pgrep gurk > /dev/null && printf "Already Running.\n" || gurk'
alias arduino-cli='arduino-cli --config-file $XDG_CONFIG_HOME/arduino15/arduino-cli.yaml'
@@ -162,9 +164,6 @@ alias wtip='wt ip -c -brief addr'
alias fusephone='sshfs myphone: /media/phone'
alias ttyper='ttyper -l english1000'
-alias wgup='doas wg-quick up wg0'
-alias wgdown='doas wg-quick down wg0'
-
# NPM
alias npi="npm init --yes"
@@ -339,6 +338,7 @@ alias ddeps='pactree -r -d 1'
alias update-mirrors='reflector -p https | rankmirrors -n 10 -p -w - | doas tee /etc/pacman.d/mirrorlist'
alias tmpd='cd $(mktemp -d)'
+alias tmpf='$EDITOR $(mktemp)'
alias brs='$BROWSER'
which bat > /dev/null 2>&1 &&
alias cat="bat -p"
diff --git a/config/essentials/shell/functions.sh b/config/essentials/shell/functions.sh
index b69b775..27eb33e 100644
--- a/config/essentials/shell/functions.sh
+++ b/config/essentials/shell/functions.sh
@@ -241,6 +241,7 @@ pacsize()
mime-default ()
{
+ mime=
[ "${mime:=$1}" ] ||
mime="$(find /usr/share/applications/ -iname '*.desktop' -printf '%f\n' |
sed 's/\.desktop$//' |
@@ -305,7 +306,7 @@ gdown () {
}
# toggle wireguard vpn on $1 -> interface
-wgtoggle() {
+wgt() {
d="${1:-wg0}"
ip -br a | awk '{print $1}' | grep "$d" > /dev/null &&
doas wg-quick down "$d" ||
@@ -317,17 +318,10 @@ serve() {
if [ "$1" ]
then
logn "Serving $1"
- docker container run \
- --rm \
- --volume "$(readlink -f "$1")":/data \
- --publish 80:5000 sigoden/dufs /data
+ dufs "$1"
else
-
logn "Receiving files.."
- docker container run \
- --rm \
- --volume /tmp/data:/data \
- --publish 80:5000 sigoden/dufs /data --allow-upload
+ dufs /tmp/data --alow-upload
fi
}
@@ -364,3 +358,9 @@ ssh_port()
ssh -f -N -L 0.0.0.0:"$3":localhost:"$1" "$2"
>&2 printf "Forwarded port '%s' on '%s' to '%s'.\n" "$1" "$2" "$3"
}
+ffconcat () {
+ tmp=$(mktemp -p . ffconcat.XXXXX)
+ sed 's/.*/file &/' > "$tmp"
+ ffmpeg -y -f concat -safe 0 -i $tmp -c copy "$1"
+ rm $tmp
+}
diff --git a/config/essentials/vis/Makefile b/config/essentials/vis/Makefile
new file mode 100644
index 0000000..f2d386b
--- /dev/null
+++ b/config/essentials/vis/Makefile
@@ -0,0 +1,6 @@
+.PHONY: check
+
+LUA_FILES := $(shell find . -type f -name "*.lua")
+
+check:
+ luacheck --no-color --globals=vis -- $(LUA_FILES)
diff --git a/config/essentials/vis/backup.lua b/config/essentials/vis/backup.lua
new file mode 100644
index 0000000..f48895f
--- /dev/null
+++ b/config/essentials/vis/backup.lua
@@ -0,0 +1,47 @@
+local backup = {}
+
+-- Return the backup path concatenated with the filename, replace / with %
+backup.entire_path_with_double_percentage_signs =
+ function(backup_dir, path)
+ return backup_dir .. "/" .. string.gsub(path, "/", "%%")
+ end
+
+-- Return the backup path concatenated with the filename, replace / with %
+-- and append the current time using time_format
+backup.entire_path_with_double_percentage_signs_and_timestamp = function(
+ backup_dir, path)
+ return backup_dir .. "/" .. os.date(backup.time_format) ..
+ string.gsub(path, "/", "%%")
+end
+
+-- Before saving the file, copy the current contents of the file to a backup file
+vis.events.subscribe(vis.events.FILE_SAVE_PRE, function(file, path)
+ if file.size > backup.byte_limit then return end
+
+ -- E.g. when editing stdin as an interactive filter
+ -- `vis -`
+ if path == nil then return end
+
+ local backup_path = backup.get_fname(backup.directory, path)
+
+ local backup_file = io.open(backup_path, "w")
+ local current_file = io.open(path)
+ if backup_file == nil or current_file == nil then return end
+
+ for line in current_file:lines() do backup_file:write(line .. "\n") end
+
+ backup_file:close()
+end)
+
+-- Set defaults
+backup.directory = os.getenv("XDG_DATA_HOME") .. "/Trash/vis-backups"
+
+backup.get_fname = backup.entire_path_with_double_percentage_signs
+
+backup.time_format = "%H-%M-"
+
+-- Do not make backups if the file is greater than this
+-- 1MB by default
+backup.byte_limit = 1000000
+
+return backup
diff --git a/config/essentials/vis/build.lua b/config/essentials/vis/build.lua
new file mode 100644
index 0000000..8a062cd
--- /dev/null
+++ b/config/essentials/vis/build.lua
@@ -0,0 +1,66 @@
+-- Copyright (c) 2024 Florian Fischer. All rights reserved.
+--
+-- vis-build 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 3 of the License, or (at your option) any later
+-- version.
+--
+-- vis-build 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
+-- vis-build found in the LICENSE file.
+-- If not, see <https://www.gnu.org/licenses/>.
+local M = {}
+M.get_default_build_cmd = function() return 'make' end
+
+local build_id = 0
+local builds = {}
+
+M.new_build = function(cmd)
+ build_id = build_id + 1
+ local build_name = 'build' .. build_id
+ local build_fd = vis:communicate(build_name, cmd)
+ local build = {fd = build_fd, out = '', err = '', cmd = cmd}
+ builds[build_name] = build
+end
+
+vis.events.subscribe(vis.events.PROCESS_RESPONSE,
+ function(name, event, code, msg)
+ local build = builds[name]
+ if not build then return end
+
+ if event == 'EXIT' or event == 'SIGNAL' then
+ if code ~= 0 then
+ vis:message('build: ' .. name .. ' cmd: ' .. build.cmd)
+ if event == 'EXIT' then
+ vis:message('failed with: ' .. code)
+ else
+ vis:message('got signal: ' .. code)
+ end
+ vis:message('stdout:\n' .. build.out)
+ vis:message('stderr:\n' .. build.err)
+ else
+ vis:message(name .. ':\n' .. build.out)
+ end
+ builds[name] = nil
+ end
+
+ if event == 'STDOUT' then
+ build.out = build.out .. msg
+ elseif event == 'STDERR' then
+ build.err = build.err .. msg
+ end
+end)
+
+vis:command_register('build', function(argv)
+ M.new_build(argv[1] or M.get_default_build_cmd())
+end, 'Asynchronously build the current file or project')
+
+vis:map(vis.modes.NORMAL, '<M-b>', function()
+ vis:command('build')
+ return 0
+end, 'Asynchronously build the current file or project')
+
+return M
diff --git a/config/essentials/vis/commentary.lua b/config/essentials/vis/commentary.lua
new file mode 100644
index 0000000..26d06b5
--- /dev/null
+++ b/config/essentials/vis/commentary.lua
@@ -0,0 +1,251 @@
+--
+-- vis-commentary
+--
+local comment_string = {
+ actionscript = '//',
+ ada = '--',
+ ansi_c = '/*|*/',
+ antlr = '//',
+ apdl = '!',
+ apl = '#',
+ applescript = '--',
+ asp = '\'',
+ autoit = ';',
+ awk = '#',
+ b_lang = '//',
+ bash = '#',
+ batch = ':',
+ bibtex = '%',
+ boo = '#',
+ chuck = '//',
+ cmake = '#',
+ coffeescript = '#',
+ context = '%',
+ cpp = '//',
+ crystal = '#',
+ csharp = '//',
+ css = '/*|*/',
+ cuda = '//',
+ dart = '//',
+ desktop = '#',
+ django = '{#|#}',
+ dmd = '//',
+ dockerfile = '#',
+ dot = '//',
+ eiffel = '--',
+ elixir = '#',
+ erlang = '%',
+ faust = '//',
+ fennel = ';;',
+ fish = '#',
+ forth = '|\\',
+ fortran = '!',
+ fsharp = '//',
+ gap = '#',
+ gettext = '#',
+ gherkin = '#',
+ glsl = '//',
+ gnuplot = '#',
+ go = '//',
+ groovy = '//',
+ gtkrc = '#',
+ haskell = '--',
+ html = '<!--|-->',
+ icon = '#',
+ idl = '//',
+ inform = '!',
+ ini = '#',
+ Io = '#',
+ java = '//',
+ javascript = '//',
+ json = '/*|*/',
+ jsp = '//',
+ latex = '%',
+ ledger = '#',
+ less = '//',
+ lilypond = '%',
+ lisp = ';',
+ logtalk = '%',
+ lua = '--',
+ makefile = '#',
+ markdown = '<!--|-->',
+ matlab = '#',
+ moonscript = '--',
+ myrddin = '//',
+ nemerle = '//',
+ nsis = '#',
+ objective_c = '//',
+ pascal = '//',
+ perl = '#',
+ php = '//',
+ pico8 = '//',
+ pike = '//',
+ pkgbuild = '#',
+ prolog = '%',
+ props = '#',
+ protobuf = '//',
+ ps = '%',
+ pure = '//',
+ python = '#',
+ rails = '#',
+ rc = '#',
+ rebol = ';',
+ rest = '.. ',
+ rexx = '--',
+ rhtml = '<!--|-->',
+ rstats = '#',
+ ruby = '#',
+ rust = '//',
+ sass = '//',
+ scala = '//',
+ scheme = ';',
+ smalltalk = '"|"',
+ sml = '(*)',
+ snobol4 = '#',
+ sql = '#',
+ tcl = '#',
+ tex = '%',
+ text = '',
+ toml = '#',
+ vala = '//',
+ vb = '\'',
+ vbscript = '\'',
+ verilog = '//',
+ vhdl = '--',
+ wsf = '<!--|-->',
+ xml = '<!--|-->',
+ yaml = '#',
+ zig = '//',
+ nim = '#',
+ julia = '#',
+ rpmspec = '#'
+}
+
+-- escape all magic characters with a '%'
+local function esc(str)
+ if not str then return "" end
+ return (str:gsub('%%', '%%%%'):gsub('^%^', '%%^'):gsub('%$$', '%%$'):gsub(
+ '%(', '%%('):gsub('%)', '%%)'):gsub('%.', '%%.')
+ :gsub('%[', '%%['):gsub('%]', '%%]'):gsub('%*', '%%*')
+ :gsub('%+', '%%+'):gsub('%-', '%%-'):gsub('%?', '%%?'))
+end
+
+-- escape '%'
+local function pesc(str)
+ if not str then return "" end
+ return str:gsub('%%', '%%%%')
+end
+
+local function rtrim(s)
+ local n = #s
+ while n > 0 and s:find("^%s", n) do n = n - 1 end
+ return s:sub(1, n)
+end
+
+local function comment_line(lines, lnum, prefix, suffix)
+ if suffix ~= "" then suffix = " " .. suffix end
+ lines[lnum] = string.gsub(lines[lnum], "(%s*)(.*)",
+ "%1" .. pesc(prefix) .. " %2" .. pesc(suffix))
+end
+
+local function uncomment_line(lines, lnum, prefix, suffix)
+ local match_str = "^(%s*)" .. esc(prefix) .. "%s?(.*)" .. esc(suffix)
+ local m = table.pack(lines[lnum]:match(match_str))
+ lines[lnum] = m[1] .. rtrim(m[2])
+end
+
+local function is_comment(line, prefix)
+ return (line:match("^%s*(.+)"):sub(0, #prefix) == prefix)
+end
+
+local function toggle_line_comment(lines, lnum, prefix, suffix)
+ if not lines or not lines[lnum] then return end
+ if not lines[lnum]:match("^%s*(.+)") then return end -- ignore empty lines
+ if is_comment(lines[lnum], prefix) then
+ uncomment_line(lines, lnum, prefix, suffix)
+ else
+ comment_line(lines, lnum, prefix, suffix)
+ end
+end
+
+-- if one line inside the block is not a comment, comment the block.
+-- only uncomment, if every single line is comment.
+local function block_comment(lines, a, b, prefix, suffix)
+ local uncomment = true
+ for i = a, b do
+ if lines[i]:match("^%s*(.+)") and not is_comment(lines[i], prefix) then
+ uncomment = false
+ end
+ end
+
+ if uncomment then
+ for i = a, b do
+ if lines[i]:match("^%s*(.+)") then
+ uncomment_line(lines, i, prefix, suffix)
+ end
+ end
+ else
+ for i = a, b do
+ if lines[i]:match("^%s*(.+)") then
+ comment_line(lines, i, prefix, suffix)
+ end
+ end
+ end
+end
+
+vis:map(vis.modes.NORMAL, "gcc", function()
+ local win = vis.win
+ local lines = win.file.lines
+ local comment = comment_string[win.syntax]
+ if not comment then return end
+ local prefix, suffix = comment:match('^([^|]+)|?([^|]*)$')
+ if not prefix then return end
+
+ for sel in win:selections_iterator() do
+ local lnum = sel.line
+ local col = sel.col
+
+ toggle_line_comment(lines, lnum, prefix, suffix)
+ sel:to(lnum, col) -- restore cursor position
+ end
+
+ win:draw()
+end, "Toggle comment on a the current line")
+
+local function visual_f(i)
+ return function()
+ local win = vis.win
+ local lines = win.file.lines
+
+ local comment = comment_string[win.syntax]
+ if not comment then return end
+
+ local prefix, suffix = comment:match('^([^|]+)|?([^|]*)$')
+ if not prefix then return end
+
+ for sel in win:selections_iterator() do
+ local r = sel.range
+ local lnum = sel.line -- line number of cursor
+ local col = sel.col -- column of cursor
+
+ if sel.anchored and r then
+ sel.pos = r.start
+ local a = sel.line
+ sel.pos = r.finish
+ local b = sel.line - i
+
+ block_comment(lines, a, b, prefix, suffix)
+
+ sel:to(lnum, col) -- restore cursor position
+ end
+ end
+
+ win:draw()
+ vis.mode = vis.modes.NORMAL -- go to normal mode
+ end
+end
+
+vis:map(vis.modes.VISUAL_LINE, "gc", visual_f(1),
+ "Toggle comment on the selected lines")
+vis:map(vis.modes.VISUAL, "gc", visual_f(0),
+ "Toggle comment on the selected lines")
diff --git a/config/essentials/vis/complete-line.lua b/config/essentials/vis/complete-line.lua
new file mode 100644
index 0000000..93728a3
--- /dev/null
+++ b/config/essentials/vis/complete-line.lua
@@ -0,0 +1,141 @@
+-- SPDX-License-Identifier: GPL-3.0-or-later
+-- © 2020 Georgi Kirilov
+local progname = ...
+
+local lpeg = require("lpeg")
+local R, C, Cmt = lpeg.R, lpeg.C, lpeg.Cmt
+
+-- copied from vis.h
+local VIS_MOVE_NOP = 64
+
+local cont = R("\128\191")
+
+local charpattern = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont *
+ cont + R("\240\244") * cont * cont * cont
+
+local function concat_keys(tbl)
+ local keys = {}
+ for k in pairs(tbl) do table.insert(keys, k) end
+ return table.concat(keys, "\n"), #keys
+end
+
+local function line_complete()
+ local file = vis.win.file
+ local sel = vis.win.selection
+ local cur_line = file.lines[sel.line]
+ local indent_patt = "^[ \t\v\f]+"
+ local prefix = cur_line:sub(1, sel.col - 1):gsub(indent_patt, "")
+ local candidates = {}
+ for l in file:lines_iterator() do
+ local unindented = l:gsub(indent_patt, "")
+ local start, finish = unindented:find(prefix, 1, true)
+ if start == 1 and finish < #unindented then
+ candidates[unindented] = true
+ end
+ end
+ local candidates_str, n = concat_keys(candidates)
+ if n < 2 then
+ if n == 1 then vis:insert(candidates_str:sub(#prefix + 1)) end
+ return
+ end
+ -- XXX: with too many candidates this command will become longer that the shell can handle:
+ local command = string.format("vis-menu -l %d <<'EOF'\n%s\nEOF\n",
+ math.min(n, math.ceil(vis.win.height / 2)),
+ candidates_str)
+ local status, output = vis:pipe(nil, nil, command)
+ if n > 0 and status == 0 then
+ vis:insert(output:sub(#prefix + 1):gsub("\n$", ""))
+ end
+end
+
+local function selection_by_pos(pos)
+ for s in vis.win:selections_iterator() do
+ if s.pos == pos then return s end
+ end
+end
+
+local function charwidth(cells_so_far, char)
+ if char == "\t" then
+ local tw = vis.tabwidth or 8
+ local trail = cells_so_far % tw
+ return tw - trail
+ else
+ return 1
+ end
+end
+
+local function virtcol(line, col)
+ local ncells = 0
+ local nchars = 0
+ local function upto(_, _, char)
+ if nchars < col - 1 then
+ ncells = ncells + charwidth(ncells, char)
+ nchars = nchars + 1
+ return true
+ end
+ end
+ (Cmt(C(charpattern), upto) ^ 0):match(line)
+ return ncells + 1
+end
+
+local function neighbor(lines, ln, col, direction)
+ local line = ln + direction > 0 and lines[ln + direction]
+ if not line then return end
+ local column = virtcol(lines[ln], col)
+ local ncells = 0
+ local function upto(_, _, char)
+ ncells = ncells + charwidth(ncells, char)
+ return ncells < column
+ end
+ return
+ (Cmt(C(charpattern), upto) ^ (-column + 1) / 0 * C(charpattern)):match(
+ line)
+end
+
+local function dup_neighbor(direction)
+ return function(file, _, pos)
+ local sel = selection_by_pos(pos)
+ local char = neighbor(file.lines, sel.line, sel.col, direction)
+ if not char then return pos end
+ file:insert(pos, char)
+ return pos + #char
+ end
+end
+
+local function dup_neighbor_feedkeys(direction)
+ local sel = vis.win.selection
+ local file = vis.win.file
+ local char = neighbor(file.lines, sel.line, sel.col, direction)
+ if not char then return end
+ vis:feedkeys(char)
+end
+
+local function operator(handler)
+ local id = vis:operator_register(handler)
+ return id >= 0 and function()
+ vis:operator(id)
+ vis:motion(VIS_MOVE_NOP)
+ end
+end
+
+vis.events.subscribe(vis.events.INIT, function()
+ local function h(msg) return string.format("|@%s| %s", progname, msg) end
+
+ local function column_complete(direction)
+ local binding = operator(dup_neighbor(direction))
+ return function()
+ if #vis.win.selections == 1 then
+ dup_neighbor_feedkeys(direction)
+ else
+ return binding()
+ end
+ end
+ end
+
+ vis:map(vis.modes.INSERT, "<C-y>", column_complete(-1),
+ h "Insert the character which is above the cursor")
+ vis:map(vis.modes.INSERT, "<C-e>", column_complete(1),
+ h "Insert the character which is below the cursor")
+ vis:map(vis.modes.INSERT, "<C-x><C-l>", line_complete,
+ h "Complete the current line")
+end)
diff --git a/config/essentials/vis/cursors.lua b/config/essentials/vis/cursors.lua
new file mode 100644
index 0000000..5b3d43b
--- /dev/null
+++ b/config/essentials/vis/cursors.lua
@@ -0,0 +1,105 @@
+local M = {}
+local cursors = {}
+local files = {}
+
+-- default maxsize
+M.maxsize = 1000
+
+-- get the default system cache directory
+local function get_default_cache_path()
+ local HOME = os.getenv('HOME')
+ local XDG_CACHE_HOME = os.getenv('XDG_CACHE_HOME')
+ local BASE = XDG_CACHE_HOME or HOME
+ return BASE .. '/.vis-cursors'
+end
+
+-- default save path
+M.path = get_default_cache_path()
+
+local function read_files()
+
+ -- read file
+ local file = io.open(M.path)
+ if file == nil then return end
+
+ files = {}
+
+ -- read positions per file path
+ for line in file:lines() do
+ for path, pos in string.gmatch(line, '(.+)[,%s](%d+)') do
+ cursors[path] = pos
+ table.insert(files, path)
+ end
+ end
+
+ file:close()
+end
+
+-- read cursors from file on init
+local function on_init() read_files() end
+
+-- apply cursor pos on win open
+local function on_win_open(win)
+
+ if win.file == nil or win.file.path == nil then return end
+
+ -- init cursor path if nil
+ local pos = cursors[win.file.path]
+ if pos == nil then
+ cursors[win.file.path] = win.selection.pos
+ return
+ end
+
+ -- set current cursor
+ win.selection.pos = tonumber(pos)
+
+ -- center view around cursor
+ vis:feedkeys("zz")
+end
+
+-- set cursor pos on close
+local function on_win_close(win)
+
+ if win.file == nil or win.file.path == nil then return end
+
+ -- re-read files in case they've changed
+ read_files()
+
+ -- remove old occurences of current path
+ for i, path in ipairs(files) do
+ if path == win.file.path then table.remove(files, i) end
+ end
+
+ -- ignore files with cursor at the beginning
+ if win.selection.pos == 0 then return end
+
+ -- insert current path to top of files
+ table.insert(files, 1, win.file.path)
+
+ -- set cursor pos for current file path
+ cursors[win.file.path] = win.selection.pos
+end
+
+-- write cursors to file on quit
+local function on_quit()
+
+ local file = io.open(M.path, 'w+')
+ if file == nil then return end
+
+ -- buffer cursors string
+ local buffer = {}
+ for _, path in ipairs(files) do
+ table.insert(buffer, string.format('%s,%d', path, cursors[path]))
+ if M.maxsize and #buffer >= M.maxsize then break end
+ end
+ local output = table.concat(buffer, '\n')
+ file:write(output)
+ file:close()
+end
+
+vis.events.subscribe(vis.events.INIT, on_init)
+vis.events.subscribe(vis.events.WIN_OPEN, on_win_open)
+vis.events.subscribe(vis.events.WIN_CLOSE, on_win_close)
+vis.events.subscribe(vis.events.QUIT, on_quit)
+
+return M
diff --git a/config/essentials/vis/format.lua b/config/essentials/vis/format.lua
new file mode 100644
index 0000000..e39320e
--- /dev/null
+++ b/config/essentials/vis/format.lua
@@ -0,0 +1,134 @@
+local global_options = { check_same = true }
+
+local function stdio_formatter(cmd, options)
+ local function apply(win, range, pos)
+ local size = win.file.size
+ local all = { start = 0, finish = size }
+ if range == nil then
+ range = all
+ end
+ local command = type(cmd) == "function" and cmd(win, range, pos) or cmd
+ local check_same = (options and options.check_same ~= nil) and options.check_same or global_options.check_same
+ local check = check_same == true or (type(check_same) == "number" and check_same >= size)
+ local status, out, err = vis:pipe(win.file, all, command)
+ if status ~= 0 then
+ vis:message(err)
+ elseif out == nil or out == "" then
+ vis:info("No output from formatter")
+ elseif not check or win.file:content(all) ~= out then
+ local start, finish = range.start, range.finish
+ win.file:delete(range)
+ win.file:insert(start, out:sub(start + 1, finish + (out:len() - size)))
+ end
+ return pos
+ end
+ return {
+ apply = apply,
+ options = options or { ranged = type(cmd) == "function" },
+ }
+end
+
+local function with_filename(win, option)
+ if win.file.path then
+ return option .. "'" .. win.file.path:gsub("'", "\\'") .. "'"
+ else
+ return ""
+ end
+end
+
+local formatters = {}
+formatters = {
+ bash = stdio_formatter(function(win)
+ return "shfmt " .. with_filename(win, "--filename ") .. " -"
+ end),
+ csharp = stdio_formatter("dotnet csharpier"),
+ go = stdio_formatter("gofmt"),
+ lua = {
+ pick = function(win)
+ local _, out = vis:pipe(
+ win.file,
+ { start = 0, finish = win.file.size },
+ "test -e .lua-format && echo luaformatter || echo stylua"
+ )
+ return formatters[out:gsub("\n$", "")]
+ end,
+ },
+ luaformatter = stdio_formatter("lua-format"),
+ markdown = stdio_formatter(function(win)
+ if win.options and win.options.colorcolumn ~= 0 then
+ return "prettier --parser markdown --prose-wrap always "
+ .. ("--print-width " .. (win.options.colorcolumn - 1) .. " ")
+ .. with_filename(win, "--stdin-filepath ")
+ else
+ return "prettier --parser markdown " .. with_filename(win, "--stdin-filepath ")
+ end
+ end, { ranged = false }),
+ powershell = stdio_formatter([[
+ "$( (command -v powershell.exe || command -v pwsh) 2>/dev/null )" -c '
+ Invoke-Formatter -ScriptDefinition `
+ ([IO.StreamReader]::new([Console]::OpenStandardInput()).ReadToEnd())
+ ' | sed -e :a -e '/^[\r\n]*$/{$d;N;};/\n$/ba'
+ ]]),
+ rust = stdio_formatter("rustfmt"),
+ stylua = stdio_formatter(function(win, range)
+ if range and (range.start ~= 0 or range.finish ~= win.file.size) then
+ return "stylua -s --range-start "
+ .. range.start
+ .. " --range-end "
+ .. range.finish
+ .. with_filename(win, " --stdin-filepath ")
+ .. " -"
+ else
+ return "stylua -s " .. with_filename(win, "--stdin-filepath ") .. " -"
+ end
+ end),
+ text = stdio_formatter(function(win)
+ if win.options and win.options.colorcolumn ~= 0 then
+ return "fmt -w " .. (win.options.colorcolumn - 1)
+ else
+ return "fmt"
+ end
+ end, { ranged = false }),
+}
+
+local function getwinforfile(file)
+ for win in vis:windows() do
+ if win and win.file and win.file.path == file.path then
+ return win
+ end
+ end
+end
+
+local function apply(file_or_keys, range, pos)
+ local win = type(file_or_keys) ~= "string" and getwinforfile(file_or_keys) or vis.win
+ local ret = type(file_or_keys) ~= "string" and function()
+ return pos
+ end or function()
+ return 0
+ end
+ pos = pos or win.selection.pos
+ local formatter = formatters[win.syntax]
+ if formatter and formatter.pick then
+ formatter = formatter.pick(win)
+ end
+ if formatter == nil then
+ vis:info("No formatter for " .. win.syntax)
+ return ret()
+ end
+ if range ~= nil and not formatter.options.ranged and range.start ~= 0 and range.finish ~= win.file.size then
+ vis:info("Formatter for " .. win.syntax .. " does not support ranges")
+ return ret()
+ end
+ pos = formatter.apply(win, range, pos) or pos
+ vis:redraw()
+ win.selection.pos = pos
+ return ret()
+end
+
+return {
+ formatters = formatters,
+ options = global_options,
+ apply = apply,
+ stdio_formatter = stdio_formatter,
+ with_filename = with_filename,
+}
diff --git a/config/essentials/vis/fzf-mru.lua b/config/essentials/vis/fzf-mru.lua
new file mode 100644
index 0000000..6c2510d
--- /dev/null
+++ b/config/essentials/vis/fzf-mru.lua
@@ -0,0 +1,75 @@
+local module = {}
+module.fzfmru_filepath = os.getenv("XDG_CACHE_HOME") .. "/vis-fzf-mru"
+module.fzfmru_path = "fzf"
+module.fzfmru_args = "--height=40%"
+module.fzfmru_history = 20
+
+local function read_mru()
+ local mru = {}
+ local f = io.open(module.fzfmru_filepath)
+ if f == nil then return end
+ for line in f:lines() do table.insert(mru, line) end
+ f:close()
+
+ return mru
+end
+
+local function write_mru(win)
+ local file_path = win.file.path
+ local mru = read_mru()
+
+ -- check if mru data exists
+ if mru == nil then mru = {} end
+ -- check if we opened any file
+ if file_path == nil then return end
+ -- check duplicate
+ if file_path == mru[1] then return end
+
+ local f = io.open(module.fzfmru_filepath, "w+")
+ if f == nil then return end
+
+ table.insert(mru, 1, file_path)
+
+ for i, k in ipairs(mru) do
+ if i > module.fzfmru_history then break end
+ if i == 1 or k ~= file_path then
+ f:write(string.format("%s\n", k))
+ end
+ end
+
+ f:close()
+end
+
+vis.events.subscribe(vis.events.WIN_OPEN, write_mru)
+
+vis:command_register("fzfmru", function(argv)
+ local command = "cat " .. module.fzfmru_filepath .. " | " ..
+ module.fzfmru_path .. " " .. module.fzfmru_args .. " " ..
+ table.concat(argv, " ")
+
+ local file = io.popen(command)
+ local output = file:read()
+ local _, _, status = file:close()
+
+ if status == 0 then
+ vis:command(string.format("e '%s'", output))
+ elseif status == 1 then
+ vis:info(string.format(
+ "fzf-open: No match. Command %s exited with return value %i.",
+ command, status))
+ elseif status == 2 then
+ vis:info(string.format(
+ "fzf-open: Error. Command %s exited with return value %i.",
+ command, status))
+ elseif status ~= 130 then
+ vis:info(string.format(
+ "fzf-open: Unknown exit status %i. command %s exited with return value %i",
+ status, command, status, status))
+ end
+
+ vis:redraw()
+
+ return true
+end)
+
+return module
diff --git a/config/essentials/vis/fzf-open.lua b/config/essentials/vis/fzf-open.lua
new file mode 100644
index 0000000..1c9d1e6
--- /dev/null
+++ b/config/essentials/vis/fzf-open.lua
@@ -0,0 +1,81 @@
+-- Copyright (C) 2017 Guillaume Chérel
+-- Copyright (C) 2023 Matěj Cepl
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Lesser General Public License as
+-- published by the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+local M = {}
+
+M.fzf_path = "fzf"
+M.fzf_args = "--height=40%"
+
+vis:command_register("fzf", function(argv)
+ local fzf_path = M.fzf_path
+ if argv[1] == "--search-path" then
+ table.remove(argv, 1)
+ local dir = table.remove(argv, 1)
+ fzf_path = ([[FZF_DEFAULT_COMMAND="$FZF_DEFAULT_COMMAND --search-path ]] .. dir .. [[" fzf]])
+ end
+
+ local command = string.gsub(
+ [[
+ $fzf_path \
+ --header="Enter:edit,^s:split,^v:vsplit" \
+ --expect="ctrl-s,ctrl-v" \
+ $fzf_args $args
+ ]],
+ "%$([%w_]+)",
+ {
+ fzf_path = fzf_path,
+ fzf_args = M.fzf_args,
+ args = table.concat(argv, " "),
+ }
+ )
+
+ local file = io.popen(command)
+ local output = {}
+ for line in file:lines() do
+ table.insert(output, line)
+ end
+ local _, _, status = file:close()
+
+ if status == 0 then
+ local action = "e"
+
+ if output[1] == "ctrl-s" then
+ action = "split"
+ elseif output[1] == "ctrl-v" then
+ action = "vsplit"
+ end
+
+ vis:feedkeys(string.format(":%s '%s'<Enter>", action, output[2]))
+ elseif status == 1 then
+ vis:info(string.format("fzf-open: No match. Command %s exited with return value %i.", command, status))
+ elseif status == 2 then
+ vis:info(string.format("fzf-open: Error. Command %s exited with return value %i.", command, status))
+ elseif status ~= 130 then
+ vis:info(
+ string.format(
+ "fzf-open: Unknown exit status %i. command %s exited with return value %i",
+ status,
+ command,
+ status
+ )
+ )
+ end
+
+ vis:redraw()
+
+ return true
+end, "Select file to open with fzf")
+
+return M
diff --git a/config/essentials/vis/themes/nord.lua b/config/essentials/vis/themes/nord.lua
new file mode 100644
index 0000000..71635cf
--- /dev/null
+++ b/config/essentials/vis/themes/nord.lua
@@ -0,0 +1,123 @@
+-- base16-vis (https://github.com/pshevtsov/base16-vis)
+-- by Petr Shevtsov
+-- Nord scheme by arcticicestudio
+local lexers = vis.lexers
+
+local colors = {
+ ['bg'] = '#2E3440',
+ ['black'] = '#3B4252',
+ ['light_black'] = '#434C5E',
+ ['dark_gray'] = '#4C566A',
+ ['gray'] = '#D8DEE9',
+ ['light_gray'] = '#616E88',
+ ['fg'] = '#E5E9F0',
+ ['white'] = '#ECEFF4',
+ ['turquoise'] = '#8FBCBB',
+ ['light_cyan'] = '#88C0D0',
+ ['cyan'] = '#81A1C1',
+ ['blue'] = '#5E81AC',
+ ['red'] = '#BF616A',
+ ['orange'] = '#D08770',
+ ['yellow'] = '#EBCB8B',
+ ['green'] = '#A3BE8C',
+ ['magenta'] = '#B48EAD'
+}
+
+lexers.colors = colors
+
+local fg = 'fore:' .. colors.fg
+local bg = 'back:' .. colors.bg
+
+lexers.STYLE_DEFAULT = bg .. ',' .. fg
+lexers.STYLE_NOTHING = bg
+lexers.STYLE_CLASS = 'fore:' .. colors.blue
+lexers.STYLE_COMMENT = 'fore:' .. colors.light_gray .. ',italics'
+lexers.STYLE_CONSTANT = 'fore:' .. colors.cyan
+lexers.STYLE_DEFINITION = 'fore:' .. colors.green
+lexers.STYLE_ERROR = 'fore:' .. colors.light_cyan .. ',italics'
+lexers.STYLE_FUNCTION = 'fore:' .. colors.light_cyan .. ',bold'
+lexers.STYLE_HEADING = 'fore:' .. colors.bg .. ',back:' .. colors.yellow
+lexers.STYLE_KEYWORD = 'fore:' .. colors.cyan .. ',bold'
+lexers.STYLE_LABEL = 'fore:' .. colors.blue
+lexers.STYLE_NUMBER = 'fore:' .. colors.magenta
+lexers.STYLE_OPERATOR = 'fore:' .. colors.light_cyan
+lexers.STYLE_REGEX = 'fore:' .. colors.orange
+lexers.STYLE_STRING = 'fore:' .. colors.green
+lexers.STYLE_PREPROCESSOR = 'fore:' .. colors.blue
+lexers.STYLE_TAG = 'fore:' .. colors.blue
+lexers.STYLE_TYPE = 'fore:' .. colors.cyan
+lexers.STYLE_VARIABLE = 'fore:' .. colors.cyan .. ',bold'
+lexers.STYLE_WHITESPACE = 'fore:' .. colors.light_black
+lexers.STYLE_EMBEDDED = 'fore:' .. colors.magenta
+lexers.STYLE_IDENTIFIER = fg .. ',bold'
+
+lexers.STYLE_LINENUMBER = 'fore:' .. colors.light_black .. ',back:' .. colors.bg
+lexers.STYLE_CURSOR = 'fore:' .. colors.bg .. ',back:' .. colors.fg
+lexers.STYLE_CURSOR_PRIMARY = 'fore:' .. colors.bg .. ',back:' .. colors.fg
+lexers.STYLE_CURSOR_LINE = 'back:' .. colors.black
+lexers.STYLE_COLOR_COLUMN = 'back:' .. colors.black
+lexers.STYLE_SELECTION = 'back:' .. colors.light_black
+lexers.STYLE_STATUS = 'fore:' .. colors.gray .. ',back:' .. colors.black
+lexers.STYLE_STATUS_FOCUSED = 'fore:' .. colors.cyan .. ',back:' .. colors.black
+lexers.STYLE_SEPARATOR = lexers.STYLE_DEFAULT
+lexers.STYLE_INFO = 'fore:default,back:default,bold'
+lexers.STYLE_EOF = ''
+
+-- lexer specific styles
+
+-- Diff
+lexers.STYLE_ADDITION = 'back:' .. colors.green .. ',fore:' .. colors.bg
+lexers.STYLE_DELETION = 'back:' .. colors.red .. ',fore:' .. colors.bg
+lexers.STYLE_CHANGE = 'back:' .. colors.yellow .. ',fore:' .. colors.bg
+
+-- CSS
+lexers.STYLE_PROPERTY = lexers.STYLE_ATTRIBUTE
+lexers.STYLE_PSEUDOCLASS = ''
+lexers.STYLE_PSEUDOELEMENT = ''
+
+-- HTML
+lexers.STYLE_TAG_UNKNOWN = lexers.STYLE_TAG .. ',italics'
+lexers.STYLE_ATTRIBUTE_UNKNOWN = lexers.STYLE_ATTRIBUTE .. ',italics'
+
+-- Latex, TeX, and Texinfo
+lexers.STYLE_COMMAND = lexers.STYLE_KEYWORD
+lexers.STYLE_COMMAND_SECTION = lexers.STYLE_CLASS
+lexers.STYLE_ENVIRONMENT = lexers.STYLE_TYPE
+lexers.STYLE_ENVIRONMENT_MATH = lexers.STYLE_NUMBER
+
+-- Makefile
+lexers.STYLE_TARGET = ''
+
+-- Markdown
+lexers.STYLE_HR = ''
+lexers.STYLE_HEADING_H1 = 'fore:' .. colors.orange .. ',bold'
+lexers.STYLE_HEADING_H2 = 'fore:' .. colors.red .. ',bold'
+for i = 3, 6 do
+ lexers['STYLE_HEADING_H' .. i] = 'fore:' .. colors.magenta .. ',bold'
+end
+lexers.STYLE_BOLD = 'bold'
+lexers.STYLE_ITALIC = 'italics'
+lexers.STYLE_LIST = lexers.STYLE_KEYWORD
+lexers.STYLE_LINK = 'fore:' .. colors.yellow .. ',italics'
+lexers.STYLE_REFERENCE = 'fore:' .. colors.blue
+lexers.STYLE_CODE = 'back:' .. colors.black .. ',fore:' .. colors.turquoise
+
+-- Output
+lexers.STYE_FILENAME = 'bold'
+lexers.STYLE_LINE = 'fore:' .. colors.green
+lexers.STYLE_COLUMN = 'underline'
+lexers.STYLE_MESSAGE = ''
+
+-- Python
+lexers.STYLE_KEYWORD_SOFT = ''
+
+-- YAML
+lexers.STYLE_ERROR_INDENT = 'back:' .. colors.red
+
+-- GO
+lexers.STYLE_CONSTANT_BUILTIN = 'fore:' .. colors.yellow
+lexers.STYLE_FUNCTION_METHOD = 'fore:' .. colors.light_cyan
+lexers.STYLE_FUNCTION_BUILTIN = 'fore:' .. colors.light_cyan .. ',bold'
+
+-- Lua
+lexers.STYLE_ATTRIBUTE = 'fore:' .. colors.yellow .. ',bold'
diff --git a/config/essentials/vis/title.lua b/config/essentials/vis/title.lua
new file mode 100644
index 0000000..d743b63
--- /dev/null
+++ b/config/essentials/vis/title.lua
@@ -0,0 +1,16 @@
+require('vis')
+
+local function set_title(title)
+ -- print() cannot be used here as it will mess up vis
+ vis:command(string.format(":!printf '\\033]2;vis %s\\007'", title))
+end
+
+vis.events.subscribe(vis.events.INIT, function() print('\27[22;2t') end)
+
+vis.events.subscribe(vis.events.WIN_OPEN,
+ function(win) set_title(win.file.name or '[No Name]') end)
+
+vis.events.subscribe(vis.events.FILE_SAVE_POST,
+ function(file) set_title(file.name) end)
+
+vis.events.subscribe(vis.events.QUIT, function() print('\27[23;2t') end)
diff --git a/config/essentials/vis/vis-go.lua b/config/essentials/vis/vis-go.lua
new file mode 100644
index 0000000..b0b383f
--- /dev/null
+++ b/config/essentials/vis/vis-go.lua
@@ -0,0 +1,102 @@
+local function jump_to(path, line, col)
+ if path then
+ vis:command(string.format("e %s", path))
+ end
+ vis.win.selection:to(line, col)
+end
+
+local Gostack = { s = {}, i = 1 }
+
+function Gostack:push(v)
+ self.s[self.i] = v
+ self.i = self.i + 1
+end
+
+function Gostack:pop()
+ if self.i == 1 then
+ return nil
+ end
+ self.i = self.i - 1
+ return self.s[self.i]
+end
+
+local function godef()
+ local win = vis.win
+ if win.syntax ~= "go" then
+ return 0
+ end
+
+ local file = win.file
+ local pos = win.selection.pos
+ local cmd = string.format("godef -i -o %d", pos)
+ local status, out, err = vis:pipe(file, { start = 0, finish = file.size }, cmd)
+ if status ~= 0 or not out then
+ if err then
+ vis:info(err)
+ end
+ return status
+ end
+
+ Gostack:push({ path = file.path, line = win.selection.line, col = win.selection.col })
+
+ local path, line, col = string.match(out, "([^:]+):([^:]+):([^:]+)")
+ if not path then
+ -- same file
+ line, col = string.match(out, "([^:]+):([^:]+)")
+ end
+ jump_to(path, line, col)
+end
+
+local function godef_back()
+ if vis.win.syntax ~= "go" then
+ return 0
+ end
+
+ local pos = Gostack:pop()
+ if pos then
+ jump_to(pos.path, pos.line, pos.col)
+ end
+end
+
+vis:map(vis.modes.NORMAL, "gd", godef, "Jump to Go symbol/definition")
+vis:map(vis.modes.NORMAL, "gD", godef_back, "Jump back to previous Go symbol/definition")
+
+local function gorename(argv, force, win, selection)
+ if win.syntax ~= "go" then
+ return true
+ end
+
+ local name = argv[1]
+ if not name then
+ vis:info("empty new name provided")
+ return false
+ end
+
+ local forceFlag = ""
+ if force then
+ forceFlag = "-force"
+ end
+
+ local pos = selection.pos
+ local f =
+ io.popen(string.format("gorename -offset %s:#%d -to %s %s 2>&1", win.file.path, pos, name, forceFlag), "r")
+ local out = f:read("*all")
+ local success, _, _ = f:close()
+ if not success then
+ vis:message(out)
+ return false
+ end
+
+ -- refresh current file
+ vis:command("e")
+ win.selection.pos = pos
+
+ vis:info(out)
+ return true
+end
+
+vis:command_register(
+ "gorename",
+ gorename,
+ "Perform precise type-safe renaming of identifiers in Go source code: :gorename newName"
+)
diff --git a/config/essentials/vis/vis-ultisnips/init.lua b/config/essentials/vis/vis-ultisnips/init.lua
new file mode 100644
index 0000000..52faa55
--- /dev/null
+++ b/config/essentials/vis/vis-ultisnips/init.lua
@@ -0,0 +1,149 @@
+--------------------------------------------------------------------------------
+-- Modules
+
+local M = {}
+local cwd = ...
+local SnipMate = require(cwd .. '.snipmate-parser')
+local UltiSnips = require(cwd .. '.ultisnips-parser')
+
+
+
+--------------------------------------------------------------------------------
+-- Config
+
+M.snipmate = ''
+M.ultisnips = ''
+
+
+
+--------------------------------------------------------------------------------
+-- Helper functions
+
+-- Takes list of snippets and concatenates them into the string suitable
+-- for passing to dmenu (or, very probably, vis-menu)
+local function snippetslist(snippets)
+ local list = ''
+
+ for k,v in pairs(snippets) do
+ if not v.description then
+ list = list .. k .. '\n'
+ else
+ list = list .. k .. ' - ' .. v.description .. '\n'
+ end
+ end
+
+ return list
+end
+
+
+
+local function load_ultisnips()
+ local snippetfile = M.ultisnips .. vis.win.syntax .. '.snippets'
+ local snippets, success = UltiSnips.load_snippets(snippetfile)
+ if not success then
+ vis:info('Failed to load a correct UltiSnip: ' .. snippetfile)
+ end
+ return snippets, success
+end
+
+
+
+local function load_snipmate()
+ local snippetfile = M.snipmate .. vis.win.syntax .. '.snippets'
+ local snippets, success = SnipMate.load_snippets(snippetfile)
+ if not success then
+ vis:info('Failed to load a correct SnipMate: ' .. snippetfile)
+ end
+ return snippets, success
+end
+
+
+
+-- Second will append to first using suffix for distinguishing
+local function merge_and_override(snips1, snips2, suffix)
+ for k,v in pairs(snips2) do
+ snips1[k .. suffix] = v
+ end
+ return snips1
+end
+
+
+
+--------------------------------------------------------------------------------
+-- Plugging it all in
+
+vis:map(vis.modes.INSERT, "<C-x><C-j>", function()
+ local snippets = merge_and_override(load_snipmate(), load_ultisnips(), '_us')
+
+ local win = vis.win
+ local file = win.file
+ local pos = win.selection.pos
+
+ if not pos then
+ return
+ end
+ -- TODO do something clever here
+
+ -- Use prefix W if exists
+ local initial = ' '
+ local range = file:text_object_longword(pos > 0 and pos - 1 or pos)
+ if range then
+ initial = initial .. file:content(range)
+ end
+
+ -- Note, for one reason or another, using vis-menu corrupts my terminal
+ -- (urxvt) for exact amount of lines that vis-menu takes
+ -- dmenu has no such problems, but can't take initial input :-\
+ --local stdout = io.popen("echo '" .. snippetslist(snippets) .. "' | dmenu -l 5", "r")
+ local stdout = io.popen("echo '" .. snippetslist(snippets) .. "' | vis-menu " .. initial, "r")
+ local chosen = stdout:lines()()
+ local _, msg, status = stdout:close()
+ if status ~= 0 or not chosen then
+ vis:message(msg)
+ return
+ end
+
+ local trigger = chosen:gmatch('[^ ]+')()
+ local snipcontent = snippets[trigger].content
+ if range then
+ file:delete(range)
+ -- Update position after deleting the range
+ pos = pos - (range.finish - range.start)
+ vis:redraw()
+ end
+
+ vis:insert(snipcontent.str)
+
+
+ if #snipcontent.tags > 0 then
+ vis:info("Use 'g>' and 'g<' to navigate between anchors.")
+
+ -- Create selections iteratively using `:#n,#n2 p` command and `gs` to
+ -- save it in the jumplist
+ for _,v in ipairs(snipcontent.tags) do
+ -- Can't use 'x' command because it'd select stuff across
+ -- whole file
+ vis:command('#' .. pos + v.selstart ..',#' .. pos + v.selend .. ' p')
+ --vis:feedkeys('gs') -- Tested, works without this too, but just in case
+ --vis:message('Command: ' .. cmd)
+ end
+
+ -- Backtrack through all selections we've made first
+ -- (so that we can use g> to move us forward)...
+ for _ in ipairs(snipcontent.tags) do
+ vis:feedkeys('g<')
+ end
+
+ -- ... then set us on the first selection
+ vis:feedkeys('g>')
+ else
+ win.selection.pos = pos + #snipcontent.str
+ end
+end, "Insert a snippet")
+
+
+
+--------------------------------------------------------------------------------
+-- End module
+
+return M \ No newline at end of file
diff --git a/config/essentials/vis/vis-ultisnips/snipmate-parser.lua b/config/essentials/vis/vis-ultisnips/snipmate-parser.lua
new file mode 100644
index 0000000..9d735f1
--- /dev/null
+++ b/config/essentials/vis/vis-ultisnips/snipmate-parser.lua
@@ -0,0 +1,128 @@
+--------------------------------------------------------------------------------
+-- Module table
+
+local M = {}
+
+local lpeg = require('lpeg')
+
+
+
+--------------------------------------------------------------------------------
+-- lpeg rules
+
+-- Base definitions
+-- local tws = lpeg.S' ' ^ 1
+local tnewline = lpeg.S'\n'
+-- local tlowcasedword = lpeg.R'az' ^ 1
+local tdigit = lpeg.locale()['digit']
+local talphanum = lpeg.locale()['alnum']
+local tanyprintable = lpeg.locale()['print']
+-- local tcontrol = lpeg.locale()['cntrl']
+local ttabtrigger = tanyprintable ^ 1
+local ttag = lpeg.Cg(lpeg.Cp(), 'selstart')
+ * lpeg.P'${'
+ * lpeg.Cg(tdigit^1, 'tag-order')
+ * (
+ (lpeg.S':' * lpeg.Cg(talphanum^1, 'default-value') * lpeg.S'}')
+ + lpeg.S'}'
+ )
+ * lpeg.Cg(lpeg.Cp(), 'selend')
+local tsnippetdecl = lpeg.P'snippet' * lpeg.S' ' * lpeg.Cg(ttabtrigger, 'tabtrigger') * tnewline
+local tsnippetcontent = lpeg.C(
+ lpeg.Cp() *
+ (lpeg.S'\t '^1
+ * (lpeg.Ct(ttag) + tanyprintable)^1
+ * tnewline
+ )^1
+ )
+
+-- Constructs
+local tsnippet = tsnippetdecl * tsnippetcontent
+local tcomment = lpeg.S'#' * tanyprintable^0 * tnewline
+
+-- The way grammar captures:
+-- Every snippet gets its own table, and every table has:
+-- 'tabtrigger' - the tabtrigger
+-- [1] - full content
+-- [2] - start of snippet content (need to subtract from selstart/selend
+-- [3..n] - tags
+local tsnippetsfile = lpeg.Ct((tcomment + lpeg.Ct(tsnippet) + tnewline) ^1)
+
+--------------------------------------------------------------------------------
+-- Functions
+
+local function trim_tabs(content)
+ local trim = function (s)
+ return (string.gsub(s, "^\t(.-)$", "%1"))
+ end
+
+ local ret=''
+ for str in string.gmatch(content, '([^\n]+)') do
+ ret = ret .. trim(str) .. '\n'
+ end
+ return ret
+end
+
+-- Tags are on the top level of th table,
+-- defined starting with index '3'
+-- Index '2' is start of the content
+-- Structure:
+-- { tag-order: int
+-- , selstart: int
+-- , selend: int
+-- , default-value: str
+-- }
+local function extract_tags(tableau)
+ local tags = {}
+ for k,v in ipairs(tableau) do
+ if k >= 3 then -- Only process starting with ix 2
+ tags[k - 2] = { selstart = v.selstart - tableau[2] - 1
+ , selend = v.selend - tableau[2] - 1
+ , default = v['default-value']
+ , order = v['tag-order']
+ }
+-- vis:message('snippet ' .. tableau.tabtrigger .. ' tag ' ..
+-- tostring(tags[k - 1].order) .. ' has start/end: ' ..
+-- tostring(tags[k - 1].selstart) .. '/' ..
+-- tostring(tags[k - 1].selend))
+ end
+ end
+ return tags
+end
+
+M.load_snippets = function(snippetfile)
+ local snippets = {}
+
+ local f = io.open(snippetfile, 'r')
+ if f then
+ local content = f:read("*all")
+
+ -- TODO hmmm, this'll make whole file unsuable, when it could
+ -- in fact have usable snippets
+ local m = tsnippetsfile:match(content)
+ if not m then
+ vis:info('Failed to parse SnipMate file: '.. snippetfile)
+ return nil
+ else
+ -- k is index of snippet definition, v is table of snippet def
+ for _,v in pairs(m) do
+ snippets[v.tabtrigger] = { description = nil
+ , options = {}
+ , content = { str = trim_tabs(v[1])
+ , tags = extract_tags(v)
+ }
+ }
+ end
+ end
+
+ f:close()
+ return snippets, true
+ else
+ return snippets, false
+ end
+end
+
+--------------------------------------------------------------------------------
+-- End module
+
+return M
diff --git a/config/essentials/vis/vis-ultisnips/testlpeg-snipmate.lua b/config/essentials/vis/vis-ultisnips/testlpeg-snipmate.lua
new file mode 100644
index 0000000..997365f
--- /dev/null
+++ b/config/essentials/vis/vis-ultisnips/testlpeg-snipmate.lua
@@ -0,0 +1,160 @@
+local lpeg = require("lpeg")
+
+--------------------------------------------------------------------------------
+
+-- Base definitions
+-- local tws = lpeg.S(" ") ^ 1
+local tnewline = lpeg.S("\n")
+-- local tlowcasedword = lpeg.R("az") ^ 1
+local tdigit = lpeg.locale()["digit"]
+local talphanum = lpeg.locale()["alnum"]
+local tanyprintable = lpeg.locale()["print"]
+-- local tcontrol = lpeg.locale()["cntrl"]
+local ttabtrigger = tanyprintable ^ 1
+local ttag = lpeg.Cg(lpeg.Cp(), "selstart")
+ * lpeg.P("${")
+ * lpeg.Cg(tdigit ^ 1, "tag-order")
+ * ((lpeg.S(":") * lpeg.Cg(talphanum ^ 1, "default-value") * lpeg.S("}")) + lpeg.S("}"))
+ * lpeg.Cg(lpeg.Cp(), "selend")
+local tsnippetdecl = lpeg.P("snippet") * lpeg.S(" ") * lpeg.Cg(ttabtrigger, "tabtrigger") * tnewline
+local tsnippetcontent = lpeg.C(lpeg.Cp() * (lpeg.S("\t ") ^ 1 * (lpeg.Ct(ttag) + tanyprintable) ^ 1 * tnewline) ^ 1)
+
+-- Constructs
+local tsnippet = tsnippetdecl * tsnippetcontent
+local tcomment = lpeg.S("#") * tanyprintable ^ 0 * tnewline
+
+-- The way grammar captures:
+-- Every snippet gets its own table, and every table has:
+-- 'tabtrigger' - the tabtrigger
+-- [1] - full content
+-- [2..n] - tags
+local tsnippetsfile = lpeg.Ct((tcomment + lpeg.Ct(tsnippet) + tnewline) ^ 1)
+--------------------------------------------------------------------------------
+
+-- local testsingle = [[
+-- snippet sim
+-- ${1:public} static int Main(string[] args)
+-- {
+-- ${0}
+-- return 0;
+-- }
+-- ]]
+
+-- local testmulti = [[
+-- snippet sim
+-- ${1:public} static int Main(string[] args)
+-- {
+-- ${0}
+-- return 0;
+-- }
+-- snippet simc
+-- public class Application
+-- {
+-- ${1:public} static int Main(string[] args)
+-- {
+-- ${0}
+-- return 0;
+-- }
+-- }
+-- snippet svm
+-- ${1:public} static void Main(string[] args)
+-- {
+-- ${0}
+-- }
+-- ]]
+
+local testfile = [[
+# I'll most propably add more stuff in here like
+# * List/Array constructio
+# * Mostly used generics
+# * Linq
+# * Funcs, Actions, Predicates
+# * Lambda
+# * Events
+#
+# Feedback is welcome!
+#
+# Main
+snippet sim
+ ${1:public} static int Main(string[] args)
+ {
+ ${0}
+ return 0;
+ }
+snippet simc
+ public class Application
+ {
+ ${1:public} static int Main(string[] args)
+ {
+ ${0}
+ return 0;
+ }
+ }
+snippet svm
+ ${1:public} static void Main(string[] args)
+ {
+ ${0}
+ }
+# if condition
+snippet if
+ if (${1:true})
+ {
+ ${0:${VISUAL}}
+ }
+snippet el
+ else
+ {
+ ${0:${VISUAL}}
+ }
+]]
+
+--------------------------------------------------------------------------------
+-- Test
+
+local function print_table(tableau, tabwidth)
+ if tabwidth == nil then
+ tabwidth = 0
+ end
+
+ -- Iterate
+ for k, v in pairs(tableau) do
+ local tabs = ("\t"):rep(tabwidth)
+
+ print(tabs .. k .. ':"' .. tostring(v) .. '"')
+ if type(v) == "table" then
+ print_table(v, tabwidth + 1)
+ end
+ end
+end
+
+--print("------------ header ------------------------------------")
+--p = lpeg.Ct(tsnippetdecl)
+--t = p:match([[
+--snippet classy
+--]])
+--print_table(t)
+--print("--------------------------------------------------------------")
+
+--print("------------ tag ------------------------------------")
+--print_table(
+-- lpeg.Ct(ttag):match('${0:VISUAL}')
+--)
+--print_table(
+-- lpeg.Ct(ttag):match('${12:Badonkadong}')
+--)
+--print_table(
+-- lpeg.Ct(ttag):match('${1}')
+--)
+--print("--------------------------------------------------------------")
+
+--print("------------ single snippet test ------------------------------------")
+--print_table(lpeg.Ct(tsnippet):match(testsingle))
+--print("--------------------------------------------------------------")
+
+--print("------------ multi snippet test ------------------------------------")
+--print_table(lpeg.Ct(tsnippetsfile):match(testmulti))
+--print("--------------------------------------------------------------")
+
+print("------------ file with comments -------------------------------------")
+print_table(tsnippetsfile:match(testfile))
+print("--------------------------------------------------------------")
diff --git a/config/essentials/vis/vis-ultisnips/testlpeg-ultisnips.lua b/config/essentials/vis/vis-ultisnips/testlpeg-ultisnips.lua
new file mode 100644
index 0000000..79df900
--- /dev/null
+++ b/config/essentials/vis/vis-ultisnips/testlpeg-ultisnips.lua
@@ -0,0 +1,230 @@
+local lpeg = require("lpeg")
+
+--------------------------------------------------------------------------------
+
+local tsep = lpeg.S(" ")
+local tws = tsep ^ 1
+local tnewline = lpeg.S("\n")
+local tlowcasedword = lpeg.R("az") ^ 1
+local tdigit = lpeg.locale()["digit"]
+-- local talphanum = lpeg.locale()['alnum']
+local tanyprintable = lpeg.locale()["print"]
+local tcontrol = lpeg.locale()["cntrl"]
+local function quoted(p)
+ return lpeg.S('"') * p * lpeg.S('"')
+end
+local function anythingbut(ch)
+ return (tanyprintable + tcontrol) - lpeg.S(ch)
+end
+
+local ttabtriggercomplex = quoted(tlowcasedword * lpeg.S("()[]?0123456789-") ^ 1)
+-- TODO This is just retarded
+local ttabtriggerweird = lpeg.S("!") * (lpeg.R("az") + lpeg.S("?()")) ^ 1 * lpeg.S("!")
+local ttabtriggerweird2 = lpeg.P("#!")
+local ttabtrigger = ttabtriggercomplex + ttabtriggerweird + ttabtriggerweird2 + tlowcasedword
+local tdescription = quoted(lpeg.Cg((tanyprintable - lpeg.S('"')) ^ 1, "description"))
+local toption = lpeg.R("az")
+
+local tstartsnippet = lpeg.P("snippet")
+ * tws
+ * lpeg.Cg(ttabtrigger, "tabtrigger")
+ * tws
+ * tdescription
+ * tws ^ 0
+ * lpeg.Cg(toption ^ 0, "options")
+local tendsnippet = lpeg.P("endsnippet")
+
+-- The content parsing needs cleanup, its really convoluted due to me learning
+-- lpeg while using it
+--tcontent = ((tanyprintable + tcontrol)^1 - tendsnippet) * tnewline
+local tcontent = ((lpeg.S(" \t") + tanyprintable) ^ 1 - tendsnippet) * tnewline
+local tsnippet = tstartsnippet * tnewline * ((tendsnippet * tnewline) + lpeg.Cg(tcontent ^ 1, "content"))
+
+local tcomment = lpeg.S("#") * tanyprintable ^ 0 * tnewline
+local tpriority = lpeg.P("priority") * tws * lpeg.Cg(lpeg.S("-") ^ 0 * tdigit ^ 1, "priority")
+
+-- TODO doesn't work
+local tsnippetsfile = (lpeg.Ct(tsnippet) + tpriority + tcomment + tnewline) ^ 1
+
+-- TODO does parse values correctly, but parsing out nested tags will
+-- require recursion at the callsite since I have no clue how to do it
+local ttag = {
+ "T",
+ Expr = lpeg.C((lpeg.V("T") + anythingbut("}")) ^ 1),
+ Tnum = lpeg.Cg(tdigit ^ 1, "tagnum"),
+ Ps = lpeg.Cg(lpeg.Cp(), "selstart"),
+ Pe = lpeg.Cg(lpeg.Cp(), "selend"),
+ Tc = lpeg.V("Ps")
+ * lpeg.P("${")
+ * lpeg.V("Tnum")
+ * lpeg.S(":")
+ * lpeg.Cg(lpeg.V("Expr"), "expr")
+ * lpeg.V("Pe")
+ * lpeg.S("}"),
+ Ts = lpeg.V("Ps") * lpeg.S("$") * lpeg.V("Pe") * lpeg.V("Tnum"),
+ T = lpeg.V("Tc") + lpeg.V("Ts"),
+}
+
+--------------------------------------------------------------------------------
+
+-- local testheader = [[
+-- snippet #! "#!/usr/bin/env lua" b
+-- ]]
+
+local testcontent = [[
+for ${1:idx},${2:val} in ipairs(${3:table_name}) do
+ $0
+end
+]]
+
+local testsnippet = [[
+snippet fori "ipair for foop" b
+for ${1:idx},${2:val} in ipairs(${3:table_name}) do
+ $0
+end
+endsnippet
+]]
+
+local luasnippetfile = [[
+priority -50
+
+#################################
+# Snippets for the Lua language #
+#################################
+snippet #! "#!/usr/bin/env lua" b
+#!/usr/bin/env lua
+$0
+endsnippet
+
+snippet !fun(ction)?! "New function" br
+local function ${1:new_function}(${2:args})
+ $0
+end
+endsnippet
+
+snippet forp "pair for loop" b
+for ${1:name},${2:val} in pairs(${3:table_name}) do
+ $0
+end
+endsnippet
+
+snippet fori "ipair for foop" b
+for ${1:idx},${2:val} in ipairs(${3:table_name}) do
+ $0
+end
+endsnippet
+
+snippet for "numeric for loop" b
+for ${1:i}=${2:first},${3:last}${4/^..*/(?0:,:)/}${4:step} do
+ $0
+end
+endsnippet
+
+snippet do "do block"
+do
+ $0
+end
+endsnippet
+
+snippet repeat "repeat loop" b
+repeat
+ $1
+until $0
+endsnippet
+
+snippet while "while loop" b
+while $1 do
+ $0
+end
+endsnippet
+
+snippet if "if statement" b
+if $1 then
+ $0
+end
+endsnippet
+
+snippet ife "if/else statement" b
+if $1 then
+ $2
+else
+ $0
+end
+endsnippet
+
+snippet eif "if/elseif statement" b
+if $1 then
+ $2
+elseif $3 then
+ $0
+end
+endsnippet
+
+snippet eife "if/elseif/else statement" b
+if $1 then
+ $2
+elseif $3 then
+ $4
+else
+ $0
+end
+endsnippet
+
+snippet pcall "pcall statement" b
+local ok, err = pcall(${1:your_function})
+if not ok then
+ handler(${2:ok, err})
+${3:else
+ success(${4:ok, err})
+}end
+endsnippet
+
+snippet local "local x = 1"
+local ${1:x} = ${0:1}
+endsnippet
+
+# vim:ft=snippets:
+]]
+
+--------------------------------------------------------------------------------
+-- Test
+
+local function print_table(tableau, tabwidth)
+ if tabwidth == nil then
+ tabwidth = 0
+ end
+
+ -- Iterate
+ for k, v in pairs(tableau) do
+ local tabs = ("\t"):rep(tabwidth)
+
+ print(tabs .. k .. ': "' .. tostring(v) .. '"')
+ if type(v) == "table" then
+ print_table(v, tabwidth + 1)
+ end
+ end
+end
+
+do
+ print("------------ snippet test ------------------------------------")
+ local p = lpeg.Ct(tsnippet)
+ local t = p:match(testsnippet)
+ print_table(t)
+ print("--------------------------------------------------------------")
+end
+
+do
+ print("------------ snippetfile test ------------------------------------")
+ local p = lpeg.Ct(tsnippetsfile)
+ local t = p:match(luasnippetfile)
+ print_table(t)
+ print("--------------------------------------------------------------")
+end
+
+do
+ print("------------ tags test -------------------------------------")
+ local p = lpeg.Ct((lpeg.Ct(ttag) + tanyprintable + tcontrol) ^ 1)
+ local t = p:match(testcontent)
+ print_table(t)
+ print("--------------------------------------------------------------")
+end
diff --git a/config/essentials/vis/vis-ultisnips/ultisnips-parser.lua b/config/essentials/vis/vis-ultisnips/ultisnips-parser.lua
new file mode 100644
index 0000000..a4240b8
--- /dev/null
+++ b/config/essentials/vis/vis-ultisnips/ultisnips-parser.lua
@@ -0,0 +1,211 @@
+--------------------------------------------------------------------------------
+-- Module table
+
+local M = {}
+
+local lpeg = require('lpeg')
+
+
+
+--------------------------------------------------------------------------------
+-- lpeg rules
+
+local tsep = lpeg.S' \t'
+local tws = tsep ^ 1
+local tnewline = lpeg.S'\n'
+local tlowcasedword = lpeg.R'az' ^ 1
+local tdigit = lpeg.locale()['digit']
+-- local talphanum = lpeg.locale()['alnum']
+local tanyprintable = lpeg.locale()['print']
+local tcontrol = lpeg.locale()['cntrl']
+local function surrounded(ch, p) return lpeg.S(ch) * p * lpeg.S(ch) end
+local function anythingbut(ch) return (tanyprintable + tcontrol) - lpeg.S(ch) end
+
+local ttabtriggercomplex = surrounded ('"',
+ tlowcasedword * lpeg.S'()[]?0123456789-'^1
+ )
+-- TODO This is just retarded
+-- Check the actual grammar and see what special starting chars are
+-- then relax the grammar a bit
+local ttabtriggerweird = surrounded('!',
+ (lpeg.R'az' + lpeg.S'?()') ^ 1
+ )
+local ttabtriggerweird2 = lpeg.P'#!'
+local ttabtriggerweird3 = surrounded('/',
+ (anythingbut'/') ^1
+ )
+local ttabtrigger = ttabtriggercomplex
+ + ttabtriggerweird
+ + ttabtriggerweird2
+ + ttabtriggerweird3
+ + (tlowcasedword + lpeg.S'.')
+local tdescription = surrounded ('"',
+ lpeg.Cg( (tanyprintable - lpeg.S'"')^1, 'description')
+ )
+local toption = lpeg.R'az'
+
+local tstartsnippet = lpeg.P'snippet'
+ * tws
+ * lpeg.Cg(ttabtrigger, 'tabtrigger')
+ * tws
+ * tdescription
+ * tws ^ 0
+ * lpeg.Cg(toption^0, 'options')
+local tendsnippet = lpeg.P'endsnippet'
+
+-- The content parsing needs cleanup, its really convoluted due to me learning
+-- lpeg while using it
+--tcontent = ((tanyprintable + tcontrol)^1 - tendsnippet) * tnewline
+local tcontent = ((lpeg.S' \t' + tanyprintable)^1 - tendsnippet)
+ * tnewline
+local tsnippet = tstartsnippet
+ * tnewline
+ * ((tendsnippet * tnewline) + lpeg.Cg(tcontent ^ 1, 'content'))
+
+-- local tcomment = lpeg.S'#'
+-- * tanyprintable^0
+-- * tnewline
+-- local tpriority = lpeg.P'priority'
+-- * tws
+-- * lpeg.Cg(lpeg.S('-')^0 * tdigit^1, 'priority')
+
+-- TODO doesn't work
+-- local tsnippetsfile = (lpeg.Ct(tsnippet) + tpriority + tcomment + tnewline) ^ 1
+
+
+-- TODO does parse values correctly, but parsing out nested tags will
+-- require recursion at the callsite since I have no clue how to do it
+local ttag = { 'T'
+ ; Expr = lpeg.C((lpeg.V'T' + ((tanyprintable + tcontrol) - lpeg.S'}'))^1)
+ , Tnum = lpeg.Cg(tdigit ^ 1, 'tagnum')
+ , Ps = lpeg.Cg(lpeg.Cp(), 'selstart')
+ , Pe = lpeg.Cg(lpeg.Cp(), 'selend')
+ , Tc = lpeg.V'Ps'
+ * lpeg.P'${'
+ * lpeg.V'Tnum'
+ * lpeg.S(':')
+ * lpeg.Cg(lpeg.V'Expr', 'expr')
+ * lpeg.V'Pe'
+ * lpeg.S'}'
+ , Ts = lpeg.V'Ps' * lpeg.S'$' * lpeg.V'Pe' * lpeg.V'Tnum'
+ , T = lpeg.V'Tc' + lpeg.V'Ts'
+ }
+
+
+
+--------------------------------------------------------------------------------
+-- Functions
+
+-- Parses the snippet's content to create a table we later use
+-- to corrently insert the text, the selections, and the default values
+local function create_content(str)
+ local content = {}
+ content.str = str
+ content.tags = {}
+
+ local p = vis.lpeg.Ct((lpeg.Ct(ttag) + tanyprintable + tcontrol) ^ 1)
+ local m = p:match(str)
+
+ local s = 1 -- We start from 1 to adjust position from $^0 to ^$0
+ for k,v in ipairs(m) do
+ content.tags[k] = v
+ -- TODO recurse over tag.expr to extract nested tags
+ -- Of course this will actually have to be used later on, depending
+ -- on whether the tag is added or not
+
+ -- We need to keep track of how much we remove, and readjust all
+ -- subsequent selection points
+ -- Note to self, I hate all this bookkeeping
+ local tagtext = string.sub(str, v.selstart, v.selend)
+ if v.expr ~= nil then
+ content.str = string.gsub(content.str, tagtext, v.expr)
+ content.tags[k].selstart = content.tags[k].selstart - s
+ content.tags[k].selend = content.tags[k].selstart + #v.expr
+ s = s + #'${' + #tostring(k) + #':' + 1
+ else
+ content.str = string.gsub(content.str, tagtext, '')
+ content.tags[k].selstart = content.tags[k].selstart - s
+ content.tags[k].selend = content.tags[k].selstart
+ s = s + #'$' + 1
+ end
+ end
+
+ return content
+end
+
+
+
+-- Takes a line starting with 'snippet' and a lines iterator, and creates
+-- a 'snippet' table to be used
+-- If it fails it returns nil, otherwise returns two values, a tabtrigger
+-- and a snippet
+local function create_snippet(start_line, linesit)
+ local snippetstr = start_line .. '\n'
+ -- Read content into list of lines until we hit `endsnippet`
+ for line in linesit do
+ local s, _ = string.find(line, 'endsnippet')
+ if s == 1 then
+ snippetstr = snippetstr .. 'endsnippet' .. '\n'
+ break
+ else
+ snippetstr = snippetstr .. line .. '\n'
+ end
+ end
+
+ local p = vis.lpeg.Ct(tsnippet)
+ local m = p:match(snippetstr)
+
+ if not m then
+ -- Enable this when debugging, otherwise it nukes whole app
+ vis:info('Failed to parse some snippets!')
+ -- vis:message('Failed to parse snippet: ' .. snippetstr)
+ return nil
+ else
+ local tabtrigger = m.tabtrigger
+ local snippet = {}
+ snippet.description = m.description
+ snippet.options = m.options
+ snippet.content = create_content(m.content)
+ return tabtrigger, snippet
+ end
+end
+
+
+
+-- Loads all snippets from passed '.snippets' file. Should probably be
+-- triggered when new file is loaded or when syntax is set/changed
+M.load_snippets = function(snippetfile)
+ local snippets = {}
+
+ local f = io.open(snippetfile, 'r')
+ if f then
+ io.input(f)
+ local linesit = io.lines()
+
+ for line in linesit do
+ -- TODO read whole file, then apply lpeg grammar that parses all
+ -- snippets out rather than being pedestrian about it like this
+ local s, _ = string.find(line, 'snippet')
+ -- Find lines that start with 'snippet' and enter
+ -- snippet reading loop
+ if s == 1 then
+ local tabtrigger, snippet = create_snippet(line, linesit)
+ if tabtrigger then
+ snippets[tabtrigger] = snippet
+ end
+ end
+ end
+
+ io.close(f)
+ return snippets, true
+ else
+ return snippets, false
+ end
+end
+
+
+
+--------------------------------------------------------------------------------
+-- End module
+
+return M \ No newline at end of file
diff --git a/config/essentials/vis/visrc.lua b/config/essentials/vis/visrc.lua
new file mode 100644
index 0000000..e35b436
--- /dev/null
+++ b/config/essentials/vis/visrc.lua
@@ -0,0 +1,152 @@
+------------------------------------
+--- REQUIRES
+------------------------------------
+require("vis")
+
+-- plugins
+require("build")
+-- use Trash directory instead, remove set_dir function
+require("backup")
+require("cursors")
+require("title")
+require("commentary")
+require("complete-line")
+-- removed formatting because already fulfilled by format.lua
+require("vis-go")
+-- set height to 40%
+require("fzf-open")
+require("vis-ultisnips")
+-- TODO: doesn't work when using with 'e|b'
+-- require("yank-highlight")
+
+-- save position before formatting, use vis:redraw
+local format = require("format")
+
+-- set height to 40%
+local fzfmru = require("fzf-mru")
+fzfmru.fzfmru_path = 'grep "^' .. os.getenv("PWD") .. '" | fzf'
+
+
+-- todo:
+-- c-scope
+-- c-tags
+-- ...
+-- vis-goto, favor open-file-under-cursor
+-- ...
+-- ultisnips
+-- ...
+-- vis-yank-highlight
+
+------------------------------------
+--- VARIABLES
+------------------------------------
+local m = vis.modes
+
+------------------------------------
+--- FUNCTIONS
+------------------------------------
+
+local function map_cmd(mode, map, command, help)
+ vis:map(mode, map, function()
+ vis:command(command)
+ end, help)
+end
+
+-- TOOD: use window selection to restore position
+local function wrap_restore(f, ...)
+ local pos = vis.win.selection.pos
+ f(...)
+ vis.win.selection.pos = pos
+end
+
+local function map_keys(mode, map, keys, help)
+ vis:map(mode, map, function()
+ vis:feedkeys(keys)
+ end, help)
+end
+
+------------------------------------
+--- COMMANDS
+-----------------------------------
+
+vis:command_register("make", function()
+ vis:command("!make && head -n 1")
+end, "make")
+vis:command_register("Q", function()
+ vis:command("qa!")
+end, "Quit all")
+vis:command_register("delws", function()
+ vis:command(",x/[ \t]+$|^[ \t]+$/d")
+end, "Remove trailing whitespace")
+
+-------------------------------------
+--- MAPPINGS
+-------------------------------------
+
+vis:map(m.NORMAL, "<C-p>", function() vis:command("fzf") end, "Open file with fzf")
+
+
+vis:map(m.NORMAL, " r", function()
+ wrap_restore(vis.command, vis, "e $vis_filepath")
+end, "Reload active file")
+
+vis:map(m.NORMAL, "=", format.apply, "Format active file")
+
+map_cmd(m.NORMAL, " c", "e ~/.config/vis/visrc.lua", "Edit config file")
+map_cmd(m.NORMAL, " q", "q!", "Quit (force)")
+map_cmd(m.NORMAL, " s", "!doas vis $vis_filepath", "Edit as superuser")
+map_cmd(m.NORMAL, " w", "w", "Write")
+map_cmd(m.NORMAL, " x", "!chmod u+x $vis_filepath", "Make active file executable")
+
+vis:map(m.NORMAL, " eh", function()
+ vis:command("!lowdown $vis_filepath > ${vis_filepath%.md}.html")
+ vis:info("exported.")
+end, "Export markdown to html")
+
+map_keys(m.NORMAL, " nl", ":<seq -f '%0.0f. ' 1 ", "Insert numbered list")
+
+-- select markdown list element: ,x/^(\d+\.|[-*])\s+.+\n(^ .+\n)*/
+
+------------------------------------
+--- EVENTS
+------------------------------------
+
+vis.events.subscribe(vis.events.INIT, function()
+ vis.options.ignorecase = true
+ vis.options.autoindent = true
+ vis.options.shell = "/bin/sh"
+ local theme = "nord"
+ vis:command("set theme " .. theme)
+end)
+
+vis.events.subscribe(vis.events.WIN_OPEN, function(win) -- luacheck: no unused args
+ win.options.relativenumbers = true
+
+ if win.syntax == "bash" then
+ map_keys(
+ m.NORMAL,
+ ";p",
+ "V:x/^(\\s*)(.+)$/ c/\\1>\\&2 printf '\\2: %s\\\\n' \"$\\2\"/<Enter><Escape>",
+ "Print variable"
+ )
+ map_keys(
+ m.NORMAL,
+ ";v",
+ "V:x/^(\\s*)(.+)$/ c/\\1\"$(\\2)\"/<Enter><Escape>",
+ "Surround in variable"
+ )
+ map_keys(
+ m.NORMAL,
+ ";|",
+ "V:x/\\| / c/|\n\t/<Enter><Escape>",
+ "Wrap one-line multi pipe command"
+ )
+ map_keys(
+ m.NORMAL,
+ ";e",
+ "V:x/^(\\s*)(.+)$/ c/\\1[ \"\\2\" ] || exit 1/<Enter><Escape>",
+ "Condition exit if empty"
+ )
+
+ end
+end)
diff --git a/config/essentials/vis/yank-highlight.lua b/config/essentials/vis/yank-highlight.lua
new file mode 100644
index 0000000..37a9578
--- /dev/null
+++ b/config/essentials/vis/yank-highlight.lua
@@ -0,0 +1,37 @@
+require("vis")
+
+local M = {
+ style = "reverse", -- Style used for highlighting
+ duration = 0.2, -- [s] Time to remain highlighted (10 ms precision)
+}
+
+vis.events.subscribe(vis.events.INIT, function()
+ local yank = vis:action_register("highlighted-yank", function()
+ vis.win:style_define(vis.win.STYLE_SELECTION, M.style)
+ vis:redraw()
+ local tstamp = os.clock()
+ while os.clock() - tstamp < M.duration do end
+ vis.win:style_define(vis.win.STYLE_SELECTION, vis.lexers.STYLE_SELECTION)
+ vis:redraw()
+ vis:feedkeys("<vis-operator-yank>")
+ end, "Yank operator with highlighting")
+ vis:map(vis.modes.OPERATOR_PENDING, "y", yank)
+ vis:map(vis.modes.VISUAL, "y", yank)
+ vis:map(vis.modes.VISUAL_LINE, "y", yank)
+
+ vis:map(vis.modes.NORMAL, "y", function(keys)
+ local sel_end_chrs = "$%^{}()wp"
+ if #keys < 1 or sel_end_chrs:find(keys:sub(-1), 1, true) == nil then
+ if keys:find("<Escape>") then
+ return #keys
+ end
+ return -1
+ end
+ vis:feedkeys("<vis-mode-visual-charwise>")
+ vis:feedkeys(keys)
+ vis:feedkeys("y<Escape>")
+ return #keys
+ end)
+end)
+
+return M
diff --git a/config/essentials/zsh/.zshrc b/config/essentials/zsh/.zshrc
index 545f9cc..5981fd9 100644
--- a/config/essentials/zsh/.zshrc
+++ b/config/essentials/zsh/.zshrc
@@ -7,8 +7,6 @@ then
[ "${TTY%%tty*}" = '/dev/' ] && clear
case "${TTY#/dev/tty}" in
1) exec startx > /dev/null 2>&1 ;;
- 2) exec startdwl > /dev/null 2>&1 ;;
- 3) exec startw > /dev/null 2>&1 ;;
*) false ;;
esac && exit
fi
@@ -18,10 +16,12 @@ autoload -z edit-command-line
zle -N edit-command-line
### Source files
-. $XDG_CONFIG_HOME/zsh/comp.zsh
-. $XDG_CONFIG_HOME/shell/functions.sh
-. $XDG_CONFIG_HOME/shell/aliases.sh
-. $XDG_CONFIG_HOME/zsh/widgets.zsh
+source_it() { [ -f "$1" ] && . "$1" }
+source_it /etc/profile.d/plan9.sh
+source_it $XDG_CONFIG_HOME/zsh/comp.zsh
+source_it $XDG_CONFIG_HOME/shell/functions.sh
+source_it $XDG_CONFIG_HOME/shell/aliases.sh
+source_it $XDG_CONFIG_HOME/zsh/widgets.zsh
# . $XDG_CONFIG_HOME/zsh/prompt.zsh
# . $XDG_CONFIG_HOME/zsh/plugins.zsh
@@ -31,6 +31,7 @@ eval "$(zoxide init zsh)"
### Plugins
[ -f "$HOME/.local/share/zap/zap.zsh" ] && source "$HOME/.local/share/zap/zap.zsh"
+# plug "MichaelAquilina/zsh-you-should-use"
plug "chivalryq/git-alias"
# plug "marlonrichert/zsh-autocomplete"
plug "zap-zsh/fzf"
@@ -41,7 +42,7 @@ plug "zsh-users/zsh-completions"
plug "MichaelAquilina/zsh-auto-notify"
export AUTO_NOTIFY_TITLE="zsh"
export AUTO_NOTIFY_BODY="%command [%exit_code]"
-AUTO_NOTIFY_IGNORE+=("gurk" "ttyper" "pulsemixer" "tmux" "btop" "vis")
+AUTO_NOTIFY_IGNORE+=("gurk" "ttyper" "pulsemixer" "tmux" "btop" "vis" "clock")
# Substring search settings
export HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND="bg=blue,fg=black,bold"
@@ -58,7 +59,7 @@ fi
# Add nnn shell level to prompt
-[ -n "$NNNLVL" ] && PS1="N$NNNLVL $PS1"
+[ -n "$NNNLVL" ] && PS1="N$NNNLVL$PS1"
# cd on nnn quiting
nnn_cd ()
diff --git a/config/extra/mutt/.gitignore b/config/extra/mutt/.gitignore
new file mode 100644
index 0000000..ad7bbfd
--- /dev/null
+++ b/config/extra/mutt/.gitignore
@@ -0,0 +1,2 @@
+cache
+mailboxes
diff --git a/config/extra/mutt/muttrc b/config/extra/mutt/muttrc
new file mode 100644
index 0000000..a5cfa90
--- /dev/null
+++ b/config/extra/mutt/muttrc
@@ -0,0 +1 @@
+source /home/aluc/.config/mutt/configs/raymaekers.luca@gmail.com
diff --git a/config/home/.zshenv b/config/home/.zshenv
index 1d732ab..34a7c2f 100644
--- a/config/home/.zshenv
+++ b/config/home/.zshenv
@@ -81,8 +81,8 @@ export FZF_DEFAULT_OPTS=$FZF_DEFAULT_OPTS'
export LESS="-i -r"
# Colored manpages
-export MANPAGER="less -R --use-color -Dd+r -Du+b"
-export MANROFFOPT="-P -c"
+# export MANPAGER="less -R --use-color -Dd+r -Du+b"
+# export MANROFFOPT="-P -c"
export CM_LAUNCHER="commander -c"
@@ -96,3 +96,6 @@ export PATH="$PATH:$GOPATH/bin"
export PLAN9=/usr/lib/plan9
export PATH="$PATH:$PLAN9/bin"
+
+export SSH_ASKPASS=askpass
+export SSH_ASKPASS_REQUIRE=prefer
diff --git a/config/wayland/gammastep/config.ini b/config/wayland/gammastep/config.ini
index 3a80417..e0699ac 100644
--- a/config/wayland/gammastep/config.ini
+++ b/config/wayland/gammastep/config.ini
@@ -1,7 +1,7 @@
[general]
fade=0
location-provider=manual
-adjustment-method=wayland
+# adjustment-method=wayland
gamma=0.8
temp-day=5700
temp-night=3600
diff --git a/config/wayland/hypr/hyprland.conf b/config/wayland/hypr/hyprland.conf
index 0a00b31..d084eb9 100644
--- a/config/wayland/hypr/hyprland.conf
+++ b/config/wayland/hypr/hyprland.conf
@@ -31,7 +31,7 @@ general {
layout = dwindle
- cursor_inactive_timeout = 0
+ # cursor_inactive_timeout = 0
}
misc {