diff --git a/.zshrc b/.zshrc
deleted file mode 100644
index f247c1c..0000000
--- a/.zshrc
+++ /dev/null
@@ -1,52 +0,0 @@
-# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
-# Initialization code that may require console input (password prompts, [y/n]
-# confirmations, etc.) must go above this block; everything else may go below.
-if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
- source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
-fi
-
-# Lines configured by zsh-newuser-install
-HISTFILE=~/.histfile
-HISTSIZE=2000
-SAVEHIST=2000
-bindkey -v
-# End of lines configured by zsh-newuser-install
-# The following lines were added by compinstall
-bindkey "\e[3~" delete-char
-autoload -Uz compinit
-compinit
-# End of lines added by compinstall
-
-# zsh extensionst
-source /data/kits/zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
-source /data/kits/zsh/powerlevel10k/powerlevel10k.zsh-theme
-source /data/kits/zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
-eval `dircolors /data/kits/zsh/dircolor/bliss.dircolors`
-
-# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
-
-[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
-
-export PATH="$HOME/.local/bin:$PATH"
-export PATH="/data/runtimes/julia/bin/:$PATH"
-export PATH="/data/runtimes/gurobi/linux64/bin/:$PATH"
-export PATH="/data/runtimes/conda/bin:$PATH"
-export PATH="/data/runtimes/nodejs/bin:$PATH"
-export EDITOR=nvim
-export TERM='xterm-256color'
-
-
-alias ls='ls --color=auto'
-
-# >>> juliaup initialize >>>
-
-# !! Contents within this block are managed by juliaup !!
-
-path=('/data/runtimes/julia/bin' $path)
-export PATH
-
-# <<< juliaup initialize <<<
-zshaddhistory() {
- whence ${${(z)1}[1]} >/dev/null || return 2
-}
-
diff --git a/i3/config b/i3/config
old mode 100644
new mode 100755
index 26a17d2..ffc6d3d
--- a/i3/config
+++ b/i3/config
@@ -10,7 +10,8 @@
# Please see https://i3wm.org/docs/userguide.html for a complete reference!
set $mod Mod1
-set $wallpaper '/data/sync/images/wallpapers/suse.png'
+set $wallpaper_dir /sync/images/wallpapers
+set $terminal 'wezterm'
# Font for window titles. Will also be used by the bar unless a different font
# is used in the bar {} block below.
font pango:NotoSans 12
@@ -27,26 +28,33 @@ exec --no-startup-id dex --autostart --environment i3
# they are included here as an example. Modify as you see fit.
#exec --no-startup-id /usr/bin/gnome-keyring-daemon --start --components=gpg,pkcs11,secrets,ssh
# xss-lock grabs a logind suspend inhibit lock and will use i3lock to lock the
-# screen before suspend. Use loginctl lock-session to lock your screen.
-exec --no-startup-id xrand --output HDMI-0 --mode 1920x1080 --rate 120
-bindsym $mod+l exec i3lock --ignore-empty-password -i $wallpaper
+# screen before suspend. Use systemctl lock-session to lock your screen.
+exec --no-startup-id xrandr --output HDMI-0 --mode 1920x1080 --rate 120
-bindsym $mod+Shift+p exec loginctl poweroff
-bindsym Print exec flameshot gui -c
+# burn-in prevention: blank after 5min, DPMS off after 10min, skip lock if fullscreen
+exec --no-startup-id xset b off
+exec --no-startup-id xset s 300 300
+exec --no-startup-id xset dpms 300 600 900
+exec --no-startup-id xss-lock -- ~/.config/i3/scripts/lock $wallpaper_dir
+
+bindsym $mod+l exec ~/.config/i3/scripts/lock-now $wallpaper_dir
+bindsym $mod+Shift+o exec systemctl suspend
+bindsym $mod+Shift+p exec systemctl poweroff
+
+bindsym Print exec --no-startup-id bash -c 'f="$(xdg-user-dir PICTURES)/$(date +%s_scrot.png)" && scrot -s "$f" && xclip -selection clipboard -t image/png -i "$f" && notify-send "Screenshot saved" "$f"'
+bindsym $mod+Print exec --no-startup-id bash -c 'f="$(xdg-user-dir PICTURES)/$(date +%s_scrot.png)" && scrot "$f" && xclip -selection clipboard -t image/png -i "$f" && notify-send "Screenshot saved" "$f"'
# NetworkManager is the most popular way to manage wireless networks on Linux,
# and nm-applet is a desktop environment-independent system tray GUI for it.
# applets
+exec --no-startup-id picom --config ~/.config/picom/picom.conf
exec --no-startup-id fcitx5 -d
exec --no-startup-id nm-applet
exec --no-startup-id blueman-applet
-exec --no-startup-id feh --bg-fill $wallpaper
-exec --no-startup-id owncloud
-exec --no-startup-id pasystray
+exec --no-startup-id /usr/bin/gnome-keyring-daemon --start --components=ssh,pkcs11
+exec --no-startup-id ~/.config/i3/scripts/wallpaper-rotate $wallpaper_dir
+#exec --no-startup-id pasystray
exec --no-startup-id polybar
-exec --no-startup-id xset m 1/1 0
-exec xinput --set-prop "Razer Razer DeathAdder V2 X HyperSpeed Mouse" "Device Accel Constant Deceleration" 3
-exec --no-startup-id gentoo-pipewire-launcher restart &
set $refresh_i3status killall -SIGUSR1 i3status
@@ -87,9 +95,9 @@ floating_modifier $mod
#tiling_drag modifier titlebar
#xrandr --output HDMI-2 --auto --right-of eDP1
-# start a 3terminal
+# start a terminal
#bindsym $mod+Return exec i3-sensible-terminal
-bindsym $mod+Return exec alacritty
+bindsym $mod+Return exec $terminal
# kill focused window
bindsym $mod+Shift+q kill
@@ -237,23 +245,20 @@ bindsym $mod+r mode "resize"
bindsym $mod+Tab workspace back_and_forth
# class border bground text indicator child_border
- client.focused #05707E #05707E #FFFFFF #000000 #05707E
- client.placeholder #000000 #F1E3D3 #FFFFFF #000000 #0d100f
- client.unfocused #000000 #1B4D3E #FFFFFF #000000 #0d100f
- client.focused_inactive #333333 #C8C9C9 #7A858D #484E50 #5F676A
+ client.focused #3A7CA5 #3A7CA5 #E2EBF0 #0D1B27 #3A7CA5
+ client.placeholder #0D1B27 #0D1B27 #BDD5E4 #0D1B27 #0D1B27
+ client.unfocused #0D1B27 #152535 #6A8DA0 #0D1B27 #152535
+ client.focused_inactive #1A3347 #1A3347 #6A8DA0 #1A3347 #1A3347
#focused_workspace #4c7899 #285577 #ffff
# (No) Title Bars
for_window [class="^.*"] border pixel 1
#floating
-for_window [class="Signal"] floating enable
-for_window [class="Fluffychat"] floating enable
-for_window [class="Proton VPN"] floating enable
+for_window [class="signal"] floating enable
for_window [class="Dino"] floating enable
-for_window [class="ownCloud"] floating enable
for_window [class="firefox"] move container to workspace 1
for_window [class="thunderbird"] move container to workspace 4
-for_window [class="Dolphin"] move container to workspace 3
for_window [class="Thunar"] move container to workspace 3
+for_window [class="steam_app_1364781"] border none, fullscreen enable
diff --git a/i3/i3blocks.conf b/i3/i3blocks.conf
new file mode 100644
index 0000000..c9d1d3c
--- /dev/null
+++ b/i3/i3blocks.conf
@@ -0,0 +1,182 @@
+# i3blocks config file changed for EndeavourOS-i3 setup
+
+# source is available here:
+# https://raw.githubusercontent.com/endeavouros-team/endeavouros-i3wm-setup/main/etc/skel/.config/i3/i3blocks.conf
+# Maintainer: joekamprad [joekamprad //a_t// endeavouros.com]
+# Former Visual Designer: Florent Valetti [@FLVAL EndeavourOS]
+# created for i3wm setup on EndeavourOS
+# https://endeavouros.com
+
+# cheatsheet for icon fonts used on the block-bar:
+# https://fontawesome.com/v4.7/cheatsheet/
+
+# --> to update this run the following command:
+# wget --backups=1 https://raw.githubusercontent.com/endeavouros-team/endeavouros-i3wm-setup/main/etc/skel/.config/i3/i3blocks.conf -P ~/.config/i3/
+
+# Please see man i3blocks for a complete reference!
+# The man page is also hosted at http://vivien.github.io/i3blocks
+
+
+# List of valid properties:
+#
+# align
+# color
+# command
+# full_text
+# instance
+# interval
+# label
+# min_width
+# name
+# separator
+# separator_block_width
+# short_text
+# signal
+# urgent
+
+# Global properties
+#
+# The top properties below are applied to every block, but can be overridden.
+separator=false
+markup=pango
+
+#[Weather]
+#command=~/.config/i3/scripts/openweather
+#interval=1800
+#color=#7275b3
+
+[terminal]
+full_text=
+color=#807dfe
+command=i3-msg -q exec xfce4-terminal
+
+[browser]
+full_text=
+color=#ff7f81
+command=i3-msg -q exec firefox
+
+[files]
+full_text=
+color=#7f3fbf
+command=i3-msg -q exec thunar ~/
+
+#[mail]
+#full_text=
+#color=#dbcb75
+#command=i3-msg -q exec thunderbird
+
+[simple-2]
+full_text=: :
+color=#717171
+
+# Disk usage
+#
+# The directory defaults to $HOME if the instance is not specified.
+# The script may be called with a optional argument to set the alert
+# (defaults to 10 for 10%).
+[disk]
+label=
+instance=/
+command=~/.config/i3/scripts/disk
+interval=30
+
+# Memory usage
+#
+# The type defaults to "mem" if the instance is not specified.
+[memory]
+label=
+command=~/.config/i3/scripts/memory
+interval=2
+
+[cpu_usage]
+label=
+command=~/.config/i3/scripts/cpu_usage
+#min_width=CPU: 100.00%
+interval=2
+
+[CPU-temperature]
+label=
+command=~/.config/i3/scripts/temperature
+interval=30
+#T_WARN=70
+#T_CRIT=90
+#SENSOR_CHIP=""
+# where SENSOR_CHIP can be find with sensors output
+# can be used also for GPU temperature or other temperature sensors lm-sensors detects.
+
+# showing name of connected network (enable for wifi use)
+#[net]
+#label=
+#command=echo "$(LANG=C nmcli d | grep connected | awk '{print $4}')"
+#interval=30
+
+[bandwidth]
+command=~/.config/i3/scripts/bandwidth2
+interval=persist
+
+#[vpn]
+#command=~/.config/i3/scripts/vpn
+#init_color=#FFFF00
+#on_color=#00FF00
+#label=VPN:
+#interval=5
+
+# Battery indicator
+[battery]
+command=~/.config/i3/scripts/battery
+# change this to battery-pinebook-pro if you are running on pinebook-pro
+label=
+interval=30
+
+[simple-2]
+full_text=: :
+color=#717171
+
+[pavucontrol]
+full_text=♪
+command=pavucontrol
+
+[volume]
+command=~/.config/i3/scripts/volume
+interval=2
+
+# display keyboard layout name
+# for keyboard layouts switcher
+# see i3 config file
+# this needs xkblayout-state installed from the AUR:
+# https://aur.archlinux.org/packages/xkblayout-state-git
+#[keyboard-layout]
+#command=~/.config/i3/scripts/keyboard-layout
+#interval=2
+
+[keybindings]
+full_text=
+command=~/.config/i3/scripts/keyhint
+
+# power-profiles-daemon implementation:
+# needs package power-profiles-daemon installed and the service running see here:
+# https://wiki.archlinux.org/title/CPU_frequency_scaling#power-profiles-daemon
+
+#set power-profile
+[ppd_menu]
+full_text=
+command=~/.config/i3/scripts/power-profiles
+color=#407437
+
+#Show the current power-profile
+[ppd-status]
+command=~/.config/i3/scripts/ppd-status
+interval=5
+
+[time]
+#label=
+command=date '+%a %d %b %H:%M:%S'
+interval=1
+
+[shutdown_menu]
+full_text=
+command=~/.config/i3/scripts/powermenu
+
+[simple-2]
+full_text=: :
+color=#717171
diff --git a/i3/i3status.conf b/i3/i3status.conf
old mode 100644
new mode 100755
diff --git a/i3/keybindings b/i3/keybindings
new file mode 100644
index 0000000..f5edbc6
--- /dev/null
+++ b/i3/keybindings
@@ -0,0 +1,106 @@
+EndeavourOS i3wm Keybindings cheat sheet:
+
+--> to update this run the following command:
+wget --backups=1 https://raw.githubusercontent.com/endeavouros-team/endeavouros-i3wm-setup/main/.config/i3/keybindings -P ~/.config/i3/
+
+All sources and updates are available at GitHub:
+https://github.com/endeavouros-team/endeavouros-i3wm-setup
+
+For reference consult our WIKI:
+https://discovery.endeavouros.com/window-tiling-managers/i3-wm/
+
+ = windows key
+
+# start xfce4-terminal
++Return
+
+# kill focused window
++q
+
+# Application menu search by typing (fancy Rofi menu):
++d
+
+# Window switcher menu (fancy Rofi menu):
++t
+
+# fancy exit-menu on bottom right:
++Shift+e
+
+# Lock the system
+# lock with a picture or blurring the screen (options in config)
++l
+
+# reload the configuration file
++Shift+c
+
+# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
++Shift+r
+
+# keybinding in fancy rofi (automated)
+F1
+
+# full keybinding list in editor:
++F1
+
+# change window focus
++j focus left
++k focus down
++b focus up
++o focus right
+
+# alternatively, you can use the cursor keys:
++Left focus left
++Down focus down
++Up focus up
++Right focus right
+
+# move a focused window
++Shift+j move left
++Shift+k move down
++Shift+b move up
++Shift+o move right
+
+# alternatively, you can use the cursor keys:
++Shift+Left move left
++Shift+Down move down
++Shift+Up move up
++Shift+Right move right
+
+# split in horizontal orientation
++h split h
+
+# split in vertical orientation
++v split v
+
+# enter fullscreen mode for the focused container
++f fullscreen toggle
+
+# change container layout (stacked, tabbed, toggle split)
++s layout stacking
++g layout tabbed
++e layout toggle split
+
+# toggle tiling / floating
++Shift+space floating toggle
+
+# change focus between tiling / floating windows
++space focus mode_toggle
+
+# focus the parent container
++a focus parent
+
+# focus the child container
+#+d focus child
+
+# resize floating window
++right mouse button
+
+## Multimedia Keys
+
+# Redirect sound to headphones
++p
+
+## App shortcuts
++w starts Firefox
++n starts Thunar
+ Button screenshot
diff --git a/i3/scripts/audio-device-switch b/i3/scripts/audio-device-switch
new file mode 100755
index 0000000..6077d38
--- /dev/null
+++ b/i3/scripts/audio-device-switch
@@ -0,0 +1,100 @@
+#!/usr/bin/env bash
+
+# audio-device-switch - audio device switch with a keybind
+# Adapted from this:
+# https://gist.githubusercontent.com/kbravh/1117a974f89cc53664e55823a55ac320/raw/9d04a10ae925074536047ae8100c6b0dbfc303d6/audio-device-switch.sh
+# Readme: https://gist.github.com/kbravh/1117a974f89cc53664e55823a55ac320
+# Creator: https://github.com/kbravh
+
+# Audio Output Switcher
+# This script will cycle to the next available audio output device.
+# It can be tied to a hotkey to easily be triggered.
+# This is handy, for example, for swapping between speakers and headphones.
+# This script will work on systems running PulseAudio or Pipewire services.
+
+
+
+# Check which sound server is running
+if pgrep pulseaudio >/dev/null; then
+ sound_server="pulseaudio"
+elif pgrep pipewire >/dev/null; then
+ sound_server="pipewire"
+else
+ echo "Neither PulseAudio nor PipeWire is running."
+ exit 1
+fi
+
+# Grab a count of how many audio sinks we have
+if [[ "$sound_server" == "pulseaudio" ]]; then
+ sink_count=$(pacmd list-sinks | grep -c "index:[[:space:]][[:digit:]]")
+ # Create an array of the actual sink IDs
+ sinks=()
+ mapfile -t sinks < <(pacmd list-sinks | grep 'index:[[:space:]][[:digit:]]' | sed -n -e 's/.*index:[[:space:]]\([[:digit:]]\)/\1/p')
+ # Get the ID of the active sink
+ active_sink=$(pacmd list-sinks | sed -n -e 's/[[:space:]]*\*[[:space:]]index:[[:space:]]\([[:digit:]]\)/\1/p')
+
+elif [[ "$sound_server" == "pipewire" ]]; then
+ sink_count=$(pactl list sinks | grep -c "Sink #[[:digit:]]")
+ # Create an array of the actual sink IDs
+ sinks=()
+ mapfile -t sinks < <(pactl list sinks | grep 'Sink #[[:digit:]]' | sed -n -e 's/.*Sink #\([[:digit:]]\)/\1/p')
+ # Get the ID of the active sink
+ active_sink_name=$(pactl info | grep 'Default Sink:' | sed -n -e 's/.*Default Sink:[[:space:]]\+\(.*\)/\1/p')
+ active_sink=$(pactl list sinks | grep -B 2 "$active_sink_name" | sed -n -e 's/Sink #\([[:digit:]]\)/\1/p' | head -n 1)
+fi
+
+# Get the ID of the last sink in the array
+final_sink=${sinks[$((sink_count - 1))]}
+
+# Find the index of the active sink
+for index in "${!sinks[@]}"; do
+ if [[ "${sinks[$index]}" == "$active_sink" ]]; then
+ active_sink_index=$index
+ fi
+done
+
+# Default to the first sink in the list
+next_sink=${sinks[0]}
+next_sink_index=0
+
+# If we're not at the end of the list, move up the list
+if [[ $active_sink -ne $final_sink ]]; then
+ next_sink_index=$((active_sink_index + 1))
+ next_sink=${sinks[$next_sink_index]}
+fi
+
+#change the default sink
+if [[ "$sound_server" == "pulseaudio" ]]; then
+ pacmd "set-default-sink ${next_sink}"
+elif [[ "$sound_server" == "pipewire" ]]; then
+ # Get the name of the next sink
+ next_sink_name=$(pactl list sinks | grep -C 2 "Sink #$next_sink" | sed -n -e 's/.*Name:[[:space:]]\+\(.*\)/\1/p' | head -n 1)
+ pactl set-default-sink "$next_sink_name"
+fi
+
+#move all inputs to the new sink
+if [[ "$sound_server" == "pulseaudio" ]]; then
+ for app in $(pacmd list-sink-inputs | sed -n -e 's/index:[[:space:]]\([[:digit:]]\)/\1/p'); do
+ pacmd "move-sink-input $app $next_sink"
+ done
+elif [[ "$sound_server" == "pipewire" ]]; then
+ for app in $(pactl list sink-inputs | sed -n -e 's/.*Sink Input #\([[:digit:]]\)/\1/p'); do
+ pactl "move-sink-input $app $next_sink"
+ done
+fi
+
+# Create a list of the sink descriptions
+sink_descriptions=()
+if [[ "$sound_server" == "pulseaudio" ]]; then
+ mapfile -t sink_descriptions < <(pacmd list-sinks | sed -n -e 's/.*alsa.name[[:space:]]=[[:space:]]"\(.*\)"/\1/p')
+elif [[ "$sound_server" == "pipewire" ]]; then
+ mapfile -t sink_descriptions < <(pactl list sinks | sed -n -e 's/.*Description:[[:space:]]\+\(.*\)/\1/p')
+fi
+
+# Find the index that matches our new active sink
+for sink_index in "${!sink_descriptions[@]}"; do
+ if [[ "$sink_index" == "$next_sink_index" ]]; then
+ notify-send -i audio-volume-high "Sound output switched to:" "${sink_descriptions[$sink_index]}"
+ exit
+ fi
+done
diff --git a/i3/scripts/bandwidth2 b/i3/scripts/bandwidth2
new file mode 100755
index 0000000..bd79e1a
--- /dev/null
+++ b/i3/scripts/bandwidth2
@@ -0,0 +1,109 @@
+#!/usr/bin/env bash
+#
+# Copyright (C) 2015 James Murphy
+# Licensed under the terms of the GNU GPL v2 only.
+#
+# i3blocks blocklet script to monitor bandwidth usage
+# detecting active device device
+# option to set used unit
+
+iface="${BLOCK_INSTANCE}"
+iface="${IFACE:-$iface}"
+dt="${DT:-3}"
+unit="${UNIT:-MB}"
+LABEL="${LABEL:-⇄ }" # down arrow up arrow
+printf_command="${PRINTF_COMMAND:-"printf \"${LABEL}%1.0f/%1.0f %s/s\\n\", rx, wx, unit;"}"
+
+function default_interface {
+ ip route | awk '/^default via/ {print $5; exit}'
+}
+
+function check_proc_net_dev {
+ if [ ! -f "/proc/net/dev" ]; then
+ echo "/proc/net/dev not found"
+ exit 1
+ fi
+}
+
+function list_interfaces {
+ check_proc_net_dev
+ echo "Interfaces in /proc/net/dev:"
+ grep -o "^[^:]\\+:" /proc/net/dev | tr -d " :"
+}
+
+while getopts i:t:u:p:lh opt; do
+ case "$opt" in
+ i) iface="$OPTARG" ;;
+ t) dt="$OPTARG" ;;
+ u) unit="$OPTARG" ;;
+ p) printf_command="$OPTARG" ;;
+ l) list_interfaces && exit 0 ;;
+ h) printf \
+"Usage: bandwidth3 [-i interface] [-t time] [-u unit] [-p printf_command] [-l] [-h]
+Options:
+-i\tNetwork interface to measure. Default determined using \`ip route\`.
+-t\tTime interval in seconds between measurements. Default: 3
+-u\tUnits to measure bytes in. Default: Mb
+\tAllowed units: Kb, KB, Mb, MB, Gb, GB, Tb, TB
+\tUnits may have optional it/its/yte/ytes on the end, e.g. Mbits, KByte
+-p\tAwk command to be called after a measurement is made.
+\tDefault: printf \" %%-5.1f/%%5.1f %%s/s\\\\n\", rx, wx, unit;
+\tExposed variables: rx, wx, tx, unit, iface
+-l\tList available interfaces in /proc/net/dev
+-h\tShow this help text
+" && exit 0;;
+ esac
+done
+
+check_proc_net_dev
+
+iface="${iface:-$(default_interface)}"
+while [ -z "$iface" ]; do
+ echo No default interface
+ sleep "$dt"
+ iface=$(default_interface)
+done
+
+case "$unit" in
+ Kb|Kbit|Kbits) bytes_per_unit=$((1024 / 8));;
+ KB|KByte|KBytes) bytes_per_unit=$((1024));;
+ Mb|Mbit|Mbits) bytes_per_unit=$((1024 * 1024 / 8));;
+ MB|MByte|MBytes) bytes_per_unit=$((1024 * 1024));;
+ Gb|Gbit|Gbits) bytes_per_unit=$((1024 * 1024 * 1024 / 8));;
+ GB|GByte|GBytes) bytes_per_unit=$((1024 * 1024 * 1024));;
+ Tb|Tbit|Tbits) bytes_per_unit=$((1024 * 1024 * 1024 * 1024 / 8));;
+ TB|TByte|TBytes) bytes_per_unit=$((1024 * 1024 * 1024 * 1024));;
+ *) echo Bad unit "$unit" && exit 1;;
+esac
+
+scalar=$((bytes_per_unit * dt))
+init_line=$(cat /proc/net/dev | grep "^[ ]*$iface:")
+if [ -z "$init_line" ]; then
+ echo Interface not found in /proc/net/dev: "$iface"
+ exit 1
+fi
+
+init_received=$(awk '{print $2}' <<< $init_line)
+init_sent=$(awk '{print $10}' <<< $init_line)
+
+(while true; do cat /proc/net/dev; sleep "$dt"; done) |\
+ stdbuf -oL grep "^[ ]*$iface:" |\
+ awk -v scalar="$scalar" -v unit="$unit" -v iface="$iface" '
+BEGIN {
+ old_received='"$init_received"'
+ old_sent='"$init_sent"'
+}
+{
+ received=$2
+ sent=$10
+ rx=(received-old_received)/scalar
+ wx=(sent-old_sent)/scalar
+ tx=rx+wx
+ old_received=received
+ old_sent=sent
+ if (rx >= 0 && wx >= 0) {
+ '"$printf_command"'
+ fflush(stdout)
+ }
+}
+'
diff --git a/i3/scripts/battery b/i3/scripts/battery
new file mode 100755
index 0000000..2d55dab
--- /dev/null
+++ b/i3/scripts/battery
@@ -0,0 +1,106 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2016 James Murphy
+# Licensed under the GPL version 2 only
+#
+# A battery indicator blocklet script for i3blocks
+
+from subprocess import check_output
+import os
+import re
+
+config = dict(os.environ)
+status = check_output(['acpi'], universal_newlines=True)
+
+if not status:
+ # stands for no battery found
+ color = config.get("color_10", "red")
+ fulltext = "\uf00d \uf240".format(color)
+ percentleft = 100
+else:
+ # if there is more than one battery in one laptop, the percentage left is
+ # available for each battery separately, although state and remaining
+ # time for overall block is shown in the status of the first battery
+ batteries = status.split("\n")
+ state_batteries=[]
+ commasplitstatus_batteries=[]
+ percentleft_batteries=[]
+ time = ""
+ for battery in batteries:
+ if battery!='':
+ state_batteries.append(battery.split(": ")[1].split(", ")[0])
+ commasplitstatus = battery.split(", ")
+ if not time:
+ time = commasplitstatus[-1].strip()
+ # check if it matches a time
+ time = re.match(r"(\d+):(\d+)", time)
+ if time:
+ time = ":".join(time.groups())
+ timeleft = " ({})".format(time)
+ else:
+ timeleft = ""
+
+ p = int(commasplitstatus[1].rstrip("%\n"))
+ if p>0:
+ percentleft_batteries.append(p)
+ commasplitstatus_batteries.append(commasplitstatus)
+ state = state_batteries[0]
+ commasplitstatus = commasplitstatus_batteries[0]
+ if percentleft_batteries:
+ percentleft = int(sum(percentleft_batteries)/len(percentleft_batteries))
+ else:
+ percentleft = 0
+
+ # stands for charging
+ color = config.get("color_charging", "yellow")
+ FA_LIGHTNING = "\uf0e7".format(color)
+
+ # stands for plugged in
+ FA_PLUG = "\uf1e6"
+
+ # stands for using battery
+ FA_BATTERY = "\uf240"
+
+ # stands for unknown status of battery
+ FA_QUESTION = "\uf128"
+
+
+ if state == "Discharging":
+ fulltext = FA_BATTERY + " "
+ elif state == "Full":
+ fulltext = FA_PLUG + " "
+ timeleft = ""
+ elif state == "Unknown":
+ fulltext = FA_QUESTION + " " + FA_BATTERY + " "
+ timeleft = ""
+ else:
+ fulltext = FA_LIGHTNING + " " + FA_PLUG + " "
+
+ def color(percent):
+ if percent < 10:
+ # exit code 33 will turn background red
+ return config.get("color_10", "#FFFFFF")
+ if percent < 20:
+ return config.get("color_20", "#FF3300")
+ if percent < 30:
+ return config.get("color_30", "#FF6600")
+ if percent < 40:
+ return config.get("color_40", "#FF9900")
+ if percent < 50:
+ return config.get("color_50", "#FFCC00")
+ if percent < 60:
+ return config.get("color_60", "#FFFF00")
+ if percent < 70:
+ return config.get("color_70", "#FFFF33")
+ if percent < 80:
+ return config.get("color_80", "#FFFF66")
+ return config.get("color_full", "#FFFFFF")
+
+ form = '{}%'
+ fulltext += form.format(color(percentleft), percentleft)
+ #fulltext += timeleft
+
+print(fulltext)
+print(fulltext)
+if percentleft < 10:
+ exit(33)
diff --git a/i3/scripts/battery-pinebook-pro b/i3/scripts/battery-pinebook-pro
new file mode 100755
index 0000000..45317d5
--- /dev/null
+++ b/i3/scripts/battery-pinebook-pro
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+# simple Shellscript for i3blocks on Pinebook pro
+# 05012020 geri123 //at// gmx.net Gerhard S.
+# battery-symbols: you need the awesome-terminal-font package installed
+
+PERCENT=$(cat /sys/class/power_supply/cw2015-battery/capacity)
+STATUS=$(cat /sys/class/power_supply/cw2015-battery/status)
+case $((
+ $PERCENT >= 0 && $PERCENT <= 20 ? 1 :
+ $PERCENT > 20 && $PERCENT <= 40 ? 2 :
+ $PERCENT > 40 && $PERCENT <= 60 ? 3 :
+ $PERCENT > 60 && $PERCENT <= 80 ? 4 : 5)) in
+#
+ (1) echo $STATUS:"" :$PERCENT%;;
+ (2) echo $STATUS:"" :$PERCENT%;;
+ (3) echo $STATUS:"" :$PERCENT%;;
+ (4) echo $STATUS:"" :$PERCENT%;;
+ (5) echo $STATUS:"" :$PERCENT%;;
+esac
diff --git a/i3/scripts/blur-lock b/i3/scripts/blur-lock
new file mode 100755
index 0000000..2f6cc31
--- /dev/null
+++ b/i3/scripts/blur-lock
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+# simple screenlocker using i3lock that creates ablurred screenshot to overlay
+
+PICTURE=/tmp/i3lock.png
+SCREENSHOT="scrot -z $PICTURE"
+
+BLUR="5x4"
+
+$SCREENSHOT
+magick $PICTURE -blur $BLUR $PICTURE
+i3lock -i $PICTURE
+shred $PICTURE
+rm $PICTURE
diff --git a/i3/scripts/cpu_usage b/i3/scripts/cpu_usage
new file mode 100755
index 0000000..8d8a267
--- /dev/null
+++ b/i3/scripts/cpu_usage
@@ -0,0 +1,62 @@
+#!/usr/bin/perl
+#
+# Copyright 2014 Pierre Mavro
+# Copyright 2014 Vivien Didelot
+# Copyright 2014 Andreas Guldstrand
+#
+# Licensed under the terms of the GNU GPL v3, or any later version.
+
+use strict;
+use warnings;
+use utf8;
+use Getopt::Long;
+
+# default values
+my $t_warn = $ENV{T_WARN} // 50;
+my $t_crit = $ENV{T_CRIT} // 80;
+my $cpu_usage = -1;
+my $decimals = $ENV{DECIMALS} // 0;
+my $label = $ENV{LABEL} // "";
+
+sub help {
+ print "Usage: cpu_usage [-w ] [-c ] [-d ]\n";
+ print "-w : warning threshold to become yellow\n";
+ print "-c : critical threshold to become red\n";
+ print "-d : Use decimals for percentage (default is $decimals) \n";
+ exit 0;
+}
+
+GetOptions("help|h" => \&help,
+ "w=i" => \$t_warn,
+ "c=i" => \$t_crit,
+ "d=i" => \$decimals,
+);
+
+# Get CPU usage
+$ENV{LC_ALL}="en_US"; # if mpstat is not run under en_US locale, things may break, so make sure it is
+open (MPSTAT, 'mpstat 1 1 |') or die;
+while () {
+ if (/^.*\s+(\d+\.\d+)[\s\x00]?$/) {
+ $cpu_usage = 100 - $1; # 100% - %idle
+ last;
+ }
+}
+close(MPSTAT);
+
+$cpu_usage eq -1 and die 'Can\'t find CPU information';
+
+# Print short_text, full_text
+print "${label}";
+printf "%02.${decimals}f%%\n", $cpu_usage;
+print "${label}";
+printf "%02.${decimals}f%%\n", $cpu_usage;
+
+# Print color, if needed
+if ($cpu_usage >= $t_crit) {
+ print "#FF0000\n";
+ exit 33;
+} elsif ($cpu_usage >= $t_warn) {
+ print "#FFFC00\n";
+}
+
+exit 0;
diff --git a/i3/scripts/cputemp b/i3/scripts/cputemp
new file mode 100755
index 0000000..8a7d821
--- /dev/null
+++ b/i3/scripts/cputemp
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+# script to monitor temperatures in waybar/i3blocks e.t.c.
+# example only use `sensors` to find your names to replace `Tdie|Tctl|Package`
+# example output part from sensors:
+# zenpower-pci-00c3
+# Adapter: PCI adapter
+# SVI2_Core: 1.03 V
+# SVI2_SoC: 994.00 mV
+# Tdie: +53.1°C
+# Tctl: +53.1°C
+# Tccd1: +42.5°C
+# Tccd2: +43.2°C
+
+temp=$(sensors 2>/dev/null | grep -E 'Tdie|Tctl|Package id 0' | grep -oP '\+?[0-9]+\.\d+(?=°C)' | tr -d '+' | head -n1)
+
+echo "${temp}°C"
diff --git a/i3/scripts/disk b/i3/scripts/disk
new file mode 100755
index 0000000..e18c7aa
--- /dev/null
+++ b/i3/scripts/disk
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+# Copyright (C) 2014 Julien Bonjean
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+DIR="${DIR:-$BLOCK_INSTANCE}"
+DIR="${DIR:-$HOME}"
+ALERT_LOW="${ALERT_LOW:-$1}"
+ALERT_LOW="${ALERT_LOW:-10}" # color will turn red under this value (default: 10%)
+
+LOCAL_FLAG="-l"
+if [ "$1" = "-n" ] || [ "$2" = "-n" ]; then
+ LOCAL_FLAG=""
+fi
+
+df -h -P $LOCAL_FLAG "$DIR" | awk -v label="$LABEL" -v alert_low=$ALERT_LOW '
+/\/.*/ {
+ # full text
+ print label $4
+
+ # short text
+ print label $4
+
+ use=$5
+
+ # no need to continue parsing
+ exit 0
+}
+
+END {
+ gsub(/%$/,"",use)
+ if (100 - use < alert_low) {
+ # color
+ print "#FF0000"
+ }
+}
+'
diff --git a/i3/scripts/empty_workspace b/i3/scripts/empty_workspace
new file mode 100755
index 0000000..fd21131
--- /dev/null
+++ b/i3/scripts/empty_workspace
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2025 Johannes Kamprad
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# empty_workspace - open a new workspace automatically named with next number on i3
+
+
+MAX_DESKTOPS=20
+
+WORKSPACES=$(seq -s '\n' 1 1 ${MAX_DESKTOPS})
+
+EMPTY_WORKSPACE=$( (i3-msg -t get_workspaces | tr ',' '\n' | grep num | awk -F: '{print int($2)}' ; \
+ echo -e ${WORKSPACES} ) | sort -n | uniq -u | head -n 1)
+
+i3-msg workspace ${EMPTY_WORKSPACE}
diff --git a/i3/scripts/gputemp b/i3/scripts/gputemp
new file mode 100755
index 0000000..a63166c
--- /dev/null
+++ b/i3/scripts/gputemp
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+# script to monitor temperatures in waybar/i3blocks e.t.c.
+# example only use `sensors` to find your sensor to replace `i915-pci-0600`
+# example output part from sensors:
+# i915-pci-0600
+# Adapter: PCI adapter
+# in0: 630.00 mV
+# fan1: 0 RPM
+# temp1: +55.0°C
+# energy1: 1.26 MJ
+
+# examples using Nvidia tools:
+#echo "$(nvidia-smi --format=csv,noheader --query-gpu=temperature.gpu) °C"
+#echo "$(nvidia-settings -q gpucoretemp -t) °C"
+# example using sensor name:
+sensors 2>/dev/null | awk '/i915-pci-0600/{flag=1} flag && /temp1/ {gsub("\\+", "", $2); print $2, $3; exit}'
diff --git a/i3/scripts/import-gsettings b/i3/scripts/import-gsettings
new file mode 100755
index 0000000..b848168
--- /dev/null
+++ b/i3/scripts/import-gsettings
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# needed for nwg-looks
+# usage: import-gsettings
+config="${XDG_CONFIG_HOME:-$HOME/.config}/gtk-3.0/settings.ini"
+if [ ! -f "$config" ]; then exit 1; fi
+
+gnome_schema="org.gnome.desktop.interface"
+gtk_theme="$(grep 'gtk-theme-name' "$config" | cut -d'=' -f2)"
+icon_theme="$(grep 'gtk-icon-theme-name' "$config" | cut -d'=' -f2)"
+cursor_theme="$(grep 'gtk-cursor-theme-name' "$config" | cut -d'=' -f2)"
+font_name="$(grep 'gtk-font-name' "$config" | cut -d'=' -f2)"
+gsettings set "$gnome_schema" gtk-theme "$gtk_theme"
+gsettings set "$gnome_schema" icon-theme "$icon_theme"
+gsettings set "$gnome_schema" cursor-theme "$cursor_theme"
+gsettings set "$gnome_schema" font-name "$font_name"
\ No newline at end of file
diff --git a/i3/scripts/keyhint b/i3/scripts/keyhint
new file mode 100755
index 0000000..34a123a
--- /dev/null
+++ b/i3/scripts/keyhint
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+# simple yad gui to show default keybindings
+
+Main() {
+ source /usr/share/endeavouros/scripts/eos-script-lib-yad || return 1
+
+ local command=(
+ eos_yad --title="EndeavourOS i3-wm keybindings:" --no-buttons --geometry=400x345-15-400 --list
+ --column=key: --column=description: --column=command:
+ "ESC" "close this app" ""
+ "=" "modkey" "(set mod Mod4)"
+ "+enter" "open a terminal" ""
+ "+Shift+n" "new empty workspace" ""
+ "+w" "open Browser" ""
+ "+n" "open Filebrowser" ""
+ "+d" "app menu" ""
+ "+q" "close focused app" ""
+ "Print-key" "screenshot" ""
+ "+Shift+e" "logout menu" ""
+ "F1" "open keybinding helper" ""
+ )
+
+ "${command[@]}"
+}
+
+Main "$@"
diff --git a/i3/scripts/keyhint-2 b/i3/scripts/keyhint-2
new file mode 100755
index 0000000..a5fd92f
--- /dev/null
+++ b/i3/scripts/keyhint-2
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# keyhint rofi tool to search used keybindings in i3wm
+
+I3_CONFIG=$HOME/.config/i3/config
+mod_key=$(sed -nre 's/^set \$mod (.*)/\1/p' ${I3_CONFIG})
+grep "^bindsym" ${I3_CONFIG} \
+ | sed "s/-\(-\w\+\)\+//g;s/\$mod/${mod_key}/g;s/Mod1/Alt/g;s/exec //;s/bindsym //;s/^\s\+//;s/^\([^ ]\+\) \(.\+\)$/\2: \1/;s/^\s\+//" \
+ | tr -s ' ' \
+ | rofi -dmenu -theme ~/.config/rofi/rofikeyhint.rasi
diff --git a/i3/scripts/lock b/i3/scripts/lock
new file mode 100755
index 0000000..3b43364
--- /dev/null
+++ b/i3/scripts/lock
@@ -0,0 +1,10 @@
+#!/bin/bash
+# Skip lock if a fullscreen window is active (game, video, etc.)
+active=$(xprop -root _NET_ACTIVE_WINDOW 2>/dev/null | awk '{print $NF}')
+if [ -n "$active" ] && [ "$active" != "0x0" ]; then
+ state=$(xprop -id "$active" _NET_WM_STATE 2>/dev/null)
+ if echo "$state" | grep -q "_NET_WM_STATE_FULLSCREEN"; then
+ exit 0
+ fi
+fi
+exec ~/.config/i3/scripts/lock-now "$1"
diff --git a/i3/scripts/lock-now b/i3/scripts/lock-now
new file mode 100755
index 0000000..d7b8f91
--- /dev/null
+++ b/i3/scripts/lock-now
@@ -0,0 +1,11 @@
+#!/bin/bash
+wall_dir="${1:?wallpaper directory required}"
+img=$(find "$wall_dir" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | shuf -n1)
+tmp=/tmp/lockscreen.png
+res=$(xrandr --current | awk '/ connected/ {getline; print $1; exit}')
+: "${res:=1920x1080}"
+if [ -n "$img" ] && convert "$img" -resize "${res}^" -gravity Center -extent "$res" "$tmp" 2>/dev/null; then
+ exec i3lock -i "$tmp" --nofork
+else
+ exec i3lock -c 000000 --nofork
+fi
diff --git a/i3/scripts/memory b/i3/scripts/memory
new file mode 100755
index 0000000..e60be50
--- /dev/null
+++ b/i3/scripts/memory
@@ -0,0 +1,69 @@
+#!/usr/bin/env bash
+# Copyright (C) 2014 Julien Bonjean
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+TYPE="${BLOCK_INSTANCE:-mem}"
+
+awk -v type=$TYPE '
+/^MemTotal:/ {
+ mem_total=$2
+}
+/^MemFree:/ {
+ mem_free=$2
+}
+/^Buffers:/ {
+ mem_free+=$2
+}
+/^Cached:/ {
+ mem_free+=$2
+}
+/^SwapTotal:/ {
+ swap_total=$2
+}
+/^SwapFree:/ {
+ swap_free=$2
+}
+END {
+ if (type == "swap") {
+ free=swap_free/1024/1024
+ used=(swap_total-swap_free)/1024/1024
+ total=swap_total/1024/1024
+ } else {
+ free=mem_free/1024/1024
+ used=(mem_total-mem_free)/1024/1024
+ total=mem_total/1024/1024
+ }
+
+ pct=0
+ if (total > 0) {
+ pct=used/total*100
+ }
+
+ # full text
+ # printf("%.1fG/%.1fG (%.f%%)\n", used, total, pct)
+
+ # short text
+ printf("%02.f%%\n", pct)
+
+ # color
+ if (pct > 90) {
+ print("#FF0000")
+ } else if (pct > 80) {
+ print("#FFAE00")
+ } else if (pct > 70) {
+ print("#FFF600")
+ }
+}
+' /proc/meminfo
diff --git a/i3/scripts/openweather b/i3/scripts/openweather
new file mode 100755
index 0000000..e41b833
--- /dev/null
+++ b/i3/scripts/openweather
@@ -0,0 +1,471 @@
+#!/usr/bin/env bash
+
+# openweater - OpenWeatherMap Weather Fetcher for Waybar/Status Bars
+#
+# Copyright (C) 2025 Johannes Kamprad
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+
+# openweater - OpenWeatherMap Weather Fetcher for Waybar/Status Bars
+# Secure API key handling with configurable locations
+# including setup script and help
+# Options:
+# -h, --help Show this help message
+# -c, --city-id ID Override city ID (required if not in config)
+# -k, --api-key KEY Override API key (not recommended, use config file)
+# -u, --units UNITS Units: metric, imperial, kelvin (default: $DEFAULT_UNITS)
+# -f, --force-refresh Force refresh (ignore cache)
+# --setup Interactive setup wizard
+# --show-config Show current configuration
+
+set -euo pipefail
+
+# Set C locale to avoid German decimal formatting issues
+export LC_NUMERIC=C
+export LC_ALL=C
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+# Default configuration (no default location)
+DEFAULT_UNITS="metric"
+CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}"
+CONFIG_FILE="$CONFIG_DIR/openweather/config"
+CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/openweather"
+CACHE_FILE="$CACHE_DIR/weather_data"
+CACHE_DURATION=600 # 10 minutes
+
+# Logging functions
+log_error() {
+ echo -e "${RED}[ERROR]${NC} $*" >&2
+}
+
+log_warn() {
+ echo -e "${YELLOW}[WARN]${NC} $*" >&2
+}
+
+# Show help
+show_help() {
+ cat << EOF
+Usage: $(basename "$0") [OPTIONS]
+
+Secure OpenWeatherMap weather fetcher with configurable locations.
+
+Options:
+ -h, --help Show this help message
+ -c, --city-id ID Override city ID (required if not in config)
+ -k, --api-key KEY Override API key (not recommended, use config file)
+ -u, --units UNITS Units: metric, imperial, kelvin (default: $DEFAULT_UNITS)
+ -f, --force-refresh Force refresh (ignore cache)
+ --setup Interactive setup wizard
+ --show-config Show current configuration
+
+Configuration:
+ Config file: $CONFIG_FILE
+
+ Create config file with:
+ OPENWEATHER_API_KEY="your_api_key_here"
+ OPENWEATHER_CITY_ID="your_city_id" # Required
+ OPENWEATHER_UNITS="metric" # Optional
+
+Examples:
+ $(basename "$0") # Use config file settings
+ $(basename "$0") --city-id 5128581 # New York
+ $(basename "$0") --units imperial # Fahrenheit
+ $(basename "$0") --setup # Run setup wizard
+
+Get your free API key at: https://openweathermap.org/api
+Find city IDs at: https://openweathermap.org/find
+
+EOF
+}
+
+# Check dependencies
+check_dependencies() {
+ local missing_deps=()
+
+ for cmd in jq curl; do
+ if ! command -v "$cmd" >/dev/null 2>&1; then
+ missing_deps+=("$cmd")
+ fi
+ done
+
+ if [[ ${#missing_deps[@]} -gt 0 ]]; then
+ log_error "Missing required dependencies: ${missing_deps[*]}"
+ echo "Install with: sudo pacman -S ${missing_deps[*]}"
+ exit 1
+ fi
+}
+
+# Load configuration
+load_config() {
+ # Set defaults (no default city ID)
+ OPENWEATHER_CITY_ID=""
+ OPENWEATHER_UNITS="$DEFAULT_UNITS"
+
+ # Load from config file if it exists
+ if [[ -f "$CONFIG_FILE" ]]; then
+ source "$CONFIG_FILE"
+ fi
+
+ # Override with environment variables if set
+ OPENWEATHER_API_KEY="${OPENWEATHER_API_KEY:-}"
+ OPENWEATHER_CITY_ID="${OPENWEATHER_CITY_ID:-}"
+ OPENWEATHER_UNITS="${OPENWEATHER_UNITS:-$DEFAULT_UNITS}"
+}
+
+# Validate API key
+validate_api_key() {
+ if [[ -z "$OPENWEATHER_API_KEY" ]]; then
+ log_error "No API key found!"
+ echo
+ echo "To fix this:"
+ echo "1. Get free API key: https://openweathermap.org/api"
+ echo "2. Run setup wizard: $0 --setup"
+ echo "3. Or set environment variable: export OPENWEATHER_API_KEY=your_key"
+ echo "4. Or create config file: $CONFIG_FILE"
+ exit 1
+ fi
+
+ # Basic validation (OpenWeatherMap keys are typically 32 chars)
+ if [[ ${#OPENWEATHER_API_KEY} -ne 32 ]]; then
+ log_warn "API key length seems incorrect (expected 32 characters, got ${#OPENWEATHER_API_KEY})"
+ fi
+}
+
+# Validate city ID
+validate_city_id() {
+ if [[ -z "$OPENWEATHER_CITY_ID" ]]; then
+ log_error "No city ID found!"
+ echo
+ echo "To fix this:"
+ echo "1. Run setup wizard: $0 --setup"
+ echo "2. Or set environment variable: export OPENWEATHER_CITY_ID=your_city_id"
+ echo "3. Or add OPENWEATHER_CITY_ID=\"your_city_id\" to: $CONFIG_FILE"
+ echo "4. Or provide city ID via command line: $0 --city-id your_city_id"
+ echo
+ echo "Find city IDs at: https://openweathermap.org/find"
+ exit 1
+ fi
+
+ # Basic validation (city IDs are typically numeric)
+ if [[ ! "$OPENWEATHER_CITY_ID" =~ ^[0-9]+$ ]]; then
+ log_warn "City ID format seems incorrect (expected numeric, got: $OPENWEATHER_CITY_ID)"
+ fi
+}
+
+# Setup wizard
+run_setup() {
+ echo -e "${GREEN}=== OpenWeatherMap Setup Wizard ===${NC}"
+ echo
+
+ # Create config directory
+ mkdir -p "$(dirname "$CONFIG_FILE")"
+
+ # Get API key
+ echo "Get your free API key at: https://openweathermap.org/api"
+ echo
+ echo -n "Enter your OpenWeatherMap API key: "
+ read -r api_key
+
+ if [[ -z "$api_key" ]]; then
+ log_error "API key cannot be empty"
+ exit 1
+ fi
+
+ # Get city ID (required)
+ echo
+ echo "Find your city ID at: https://openweathermap.org/find"
+ echo -n "Enter city ID: "
+ read -r city_id
+
+ if [[ -z "$city_id" ]]; then
+ log_error "City ID cannot be empty"
+ exit 1
+ fi
+
+ # Get units (optional)
+ echo
+ echo "Available units: metric (°C), imperial (°F), kelvin (K)"
+ echo -n "Enter units [metric]: "
+ read -r units
+ units="${units:-metric}"
+
+ # Write config file
+ cat > "$CONFIG_FILE" << EOF
+# OpenWeatherMap Configuration
+# Generated by $(basename "$0") setup wizard on $(date)
+
+# Your API key from https://openweathermap.org/api
+OPENWEATHER_API_KEY="$api_key"
+
+# City ID from https://openweathermap.org/find
+OPENWEATHER_CITY_ID="$city_id"
+
+# Units: metric, imperial, kelvin
+OPENWEATHER_UNITS="$units"
+EOF
+
+ # Set secure permissions
+ chmod 600 "$CONFIG_FILE"
+
+ echo
+ echo -e "${GREEN}✅ Configuration saved to: $CONFIG_FILE${NC}"
+ echo -e "${GREEN}✅ File permissions set to 600 (user read/write only)${NC}"
+ echo
+ echo "Testing configuration..."
+
+ # Test the configuration
+ OPENWEATHER_API_KEY="$api_key"
+ OPENWEATHER_CITY_ID="$city_id"
+ OPENWEATHER_UNITS="$units"
+
+ if fetch_weather_data; then
+ echo -e "${GREEN}✅ Configuration test successful!${NC}"
+ else
+ log_error "Configuration test failed. Please check your API key and city ID."
+ exit 1
+ fi
+}
+
+# Show current configuration
+show_config() {
+ echo "=== Current Configuration ==="
+ echo "Config file: $CONFIG_FILE"
+ echo "Cache file: $CACHE_FILE"
+ echo "Cache duration: ${CACHE_DURATION}s"
+ echo
+
+ if [[ -f "$CONFIG_FILE" ]]; then
+ echo "Configuration:"
+ echo " API Key: ${OPENWEATHER_API_KEY:0:8}... (${#OPENWEATHER_API_KEY} chars)"
+ echo " City ID: $OPENWEATHER_CITY_ID"
+ echo " Units: $OPENWEATHER_UNITS"
+ else
+ echo "❌ No configuration file found at: $CONFIG_FILE"
+ echo "Run: $0 --setup"
+ fi
+}
+
+# Check cache validity
+is_cache_valid() {
+ [[ -f "$CACHE_FILE" ]] && \
+ [[ $(($(date +%s) - $(stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0))) -lt $CACHE_DURATION ]]
+}
+
+# Fetch weather data from API
+fetch_weather_data() {
+ local url="https://api.openweathermap.org/data/2.5/weather?id=${OPENWEATHER_CITY_ID}&units=${OPENWEATHER_UNITS}&appid=${OPENWEATHER_API_KEY}"
+
+ local response
+ if ! response=$(curl -sf "$url" 2>/dev/null); then
+ log_error "Failed to fetch weather data from API"
+ return 1
+ fi
+
+ # Validate JSON response
+ if ! echo "$response" | jq . >/dev/null 2>&1; then
+ log_error "Invalid JSON response from API"
+ return 1
+ fi
+
+ # Check for API error
+ local api_code
+ api_code=$(echo "$response" | jq -r '.cod // empty')
+ if [[ "$api_code" != "200" ]]; then
+ local api_message
+ api_message=$(echo "$response" | jq -r '.message // "Unknown API error"')
+ log_error "API Error ($api_code): $api_message"
+ return 1
+ fi
+
+ # Cache the response
+ mkdir -p "$CACHE_DIR"
+ echo "$response" > "$CACHE_FILE"
+
+ return 0
+}
+
+# Get weather data (from cache or API)
+get_weather_data() {
+ local force_refresh="${1:-false}"
+
+ if [[ "$force_refresh" != "true" ]] && is_cache_valid; then
+ cat "$CACHE_FILE"
+ else
+ if fetch_weather_data; then
+ cat "$CACHE_FILE"
+ else
+ # Fallback to cache if available
+ if [[ -f "$CACHE_FILE" ]]; then
+ log_warn "Using stale cache data due to API failure"
+ cat "$CACHE_FILE"
+ else
+ return 1
+ fi
+ fi
+ fi
+}
+
+# Calculate wind direction
+get_wind_direction() {
+ local degrees="$1"
+ local directions=(N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW)
+ local index
+ index=$(awk "BEGIN {print int(($degrees % 360) / 22.5)}")
+ echo "${directions[$index]}"
+}
+
+# Get weather icon
+get_weather_icon() {
+ local condition="$1"
+ case "$condition" in
+ 'Clear') echo "☀" ;; # Clear sky
+ 'Clouds') echo "☁" ;; # Cloudy
+ 'Rain'|'Drizzle') echo "🌧" ;; # Rain
+ 'Snow') echo "❄" ;; # Snow
+ 'Thunderstorm') echo "⛈" ;; # Thunder
+ 'Mist'|'Fog') echo "🌫" ;; # Fog
+ *) echo "🌤" ;; # Default
+ esac
+}
+
+# Safe number formatting (handles locale issues)
+safe_printf() {
+ local format="$1"
+ local number="$2"
+
+ # Validate number is actually numeric
+ if [[ ! "$number" =~ ^-?[0-9]+(\.[0-9]+)?$ ]]; then
+ echo "0.0"
+ return 1
+ fi
+
+ # Use awk for reliable formatting regardless of locale
+ awk "BEGIN {printf \"$format\", $number}"
+}
+
+# Format weather output
+format_weather() {
+ local weather_data="$1"
+
+ # Parse weather data with error checking
+ local condition temp wind_speed_ms wind_deg
+ condition=$(echo "$weather_data" | jq -r '.weather[0].main // "Unknown"')
+ temp=$(echo "$weather_data" | jq -r '.main.temp // "0"')
+ wind_speed_ms=$(echo "$weather_data" | jq -r '.wind.speed // "0"')
+ wind_deg=$(echo "$weather_data" | jq -r '.wind.deg // "0"')
+
+ # Validate parsed data
+ [[ "$condition" == "null" ]] && condition="Unknown"
+ [[ "$temp" == "null" ]] && temp="0"
+ [[ "$wind_speed_ms" == "null" ]] && wind_speed_ms="0"
+ [[ "$wind_deg" == "null" ]] && wind_deg="0"
+
+ # Format temperature with safe formatting
+ local temp_formatted
+ temp_formatted=$(safe_printf "%.1f" "$temp")
+
+ # Convert wind speed to km/h with safe formatting
+ local wind_speed_kmh
+ wind_speed_kmh=$(awk "BEGIN {printf \"%.1f\", ($wind_speed_ms + 0) * 3.6}")
+
+ # Get wind direction
+ local wind_dir
+ wind_dir=$(get_wind_direction "$wind_deg")
+
+ # Get weather icon
+ local icon
+ icon=$(get_weather_icon "$condition")
+
+ # Format unit symbol
+ local unit_symbol
+ case "$OPENWEATHER_UNITS" in
+ "imperial") unit_symbol="°F" ;;
+ "kelvin") unit_symbol="K" ;;
+ *) unit_symbol="°C" ;;
+ esac
+
+ # Output formatted weather
+ echo "${icon} ${temp_formatted}${unit_symbol}, ${wind_speed_kmh} km/h ${wind_dir}"
+}
+
+# Main function
+main() {
+ local city_id_override=""
+ local api_key_override=""
+ local units_override=""
+ local force_refresh="false"
+
+ # Parse command line arguments
+ while [[ $# -gt 0 ]]; do
+ case $1 in
+ -h|--help)
+ show_help
+ exit 0
+ ;;
+ -c|--city-id)
+ city_id_override="$2"
+ shift 2
+ ;;
+ -k|--api-key)
+ api_key_override="$2"
+ shift 2
+ ;;
+ -u|--units)
+ units_override="$2"
+ shift 2
+ ;;
+ -f|--force-refresh)
+ force_refresh="true"
+ shift
+ ;;
+ --setup)
+ check_dependencies
+ run_setup
+ exit 0
+ ;;
+ --show-config)
+ load_config
+ show_config
+ exit 0
+ ;;
+ *)
+ log_error "Unknown option: $1"
+ show_help
+ exit 1
+ ;;
+ esac
+ done
+
+ # Check dependencies
+ check_dependencies
+
+ # Load configuration
+ load_config
+
+ # Apply overrides
+ [[ -n "$city_id_override" ]] && OPENWEATHER_CITY_ID="$city_id_override"
+ [[ -n "$api_key_override" ]] && OPENWEATHER_API_KEY="$api_key_override"
+ [[ -n "$units_override" ]] && OPENWEATHER_UNITS="$units_override"
+
+ # Validate configuration
+ validate_api_key
+ validate_city_id
+
+ # Get and format weather data
+ local weather_data
+ if weather_data=$(get_weather_data "$force_refresh"); then
+ format_weather "$weather_data"
+ else
+ echo "⚠️ Weather data unavailable"
+ exit 1
+ fi
+}
+
+# Run main function
+main "$@"
diff --git a/i3/scripts/power-profiles b/i3/scripts/power-profiles
new file mode 100755
index 0000000..6c901b3
--- /dev/null
+++ b/i3/scripts/power-profiles
@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+
+# Simple power-profiles-daemon switcher using rofi and static theme, with notification
+#
+# Copyright (C) 2025 Johannes Kamprad
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# needs rofi config:
+# $HOME/.config/rofi/powermenu.rasi
+
+ROFI_THEME="${HOME}/.config/rofi/power-profiles.rasi"
+
+# Dependency checks
+command -v powerprofilesctl >/dev/null 2>&1 || { echo "powerprofilesctl not found"; exit 1; }
+command -v rofi >/dev/null 2>&1 || { echo "rofi not found"; exit 1; }
+if ! command -v notify-send >/dev/null 2>&1; then
+ notify_send_missing=true
+fi
+
+current_profile="$(powerprofilesctl get 2>/dev/null)"
+ROFI_ARGS=(-dmenu -i -theme "$ROFI_THEME" -p "Change Profile" -mesg "Current used: $current_profile" -markup-rows)
+
+# Menu entries
+cancel=" Cancel"
+perf=" Performance"
+balanced=" Balanced"
+powersave=" Power Saver"
+# sets chancel to be on top
+options="$cancel"
+
+if powerprofilesctl list | grep -q "performance"; then
+ options="$options\n$perf"
+fi
+if powerprofilesctl list | grep -q "balanced"; then
+ options="$options\n$balanced"
+fi
+if powerprofilesctl list | grep -q "power-saver"; then
+ options="$options\n$powersave"
+fi
+
+# Show menu
+chosen="$(echo -e "$options" | rofi "${ROFI_ARGS[@]}")"
+
+# Run selection
+case $chosen in
+ "$perf")
+ powerprofilesctl set performance
+ ;;
+ "$balanced")
+ powerprofilesctl set balanced
+ ;;
+ "$powersave")
+ powerprofilesctl set power-saver
+ ;;
+ "$cancel"|"")
+ exit 0
+ ;;
+esac
+
+# Send notification if available
+if [[ "$chosen" != "$cancel" && -z "${notify_send_missing}" ]]; then
+ notify-send -i dialog-information "Power Profile Changed" "New profile: ${chosen}"
+fi
diff --git a/i3/scripts/powermenu b/i3/scripts/powermenu
new file mode 100755
index 0000000..6111806
--- /dev/null
+++ b/i3/scripts/powermenu
@@ -0,0 +1,81 @@
+#!/usr/bin/env bash
+
+#
+# powermenu - a very simple rofi powermenu
+#
+# Copyright (C) 2025 Johannes Kamprad
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# needs rofi config:
+# $HOME/.config/rofi/powermenu.rasi
+# set to be used in i3wm
+
+ROFI_THEME="${HOME}/.config/rofi/powermenu.rasi"
+# Define possible lock scripts/commands (edit this list as you like)
+LOCK_SCRIPTS=("${HOME}/.config/i3/scripts/blur-lock" "i3lock")
+
+# Find available lock script
+find_lock_script() {
+ for script in "${LOCK_SCRIPTS[@]}"; do
+ # Handle command names vs full paths
+ if [[ "$script" =~ ^[a-zA-Z0-9_-]+$ ]]; then
+ # It's a command name, check if available
+ if command -v "$script" >/dev/null 2>&1; then
+ echo "$script"
+ return 0
+ fi
+ else
+ # It's a path, check if file exists and is executable
+ if [[ -x "$script" ]]; then
+ echo "$script"
+ return 0
+ fi
+ fi
+ done
+ return 1
+}
+
+# Menu entries
+chancel=" Cancel"
+lock=" Lock"
+logout=" Logout"
+reboot=" Reboot"
+shutdown=" Shutdown"
+suspend=" Suspend"
+hibernate=" Hibernate"
+
+
+# Add lock only if script is found
+if lockcmd="$(find_lock_script)"; then
+ options="$chancel\n$lock\n$logout\n$reboot\n$shutdown\n$suspend\n$hibernate"
+else
+ options="$chancel\n$logout\n$reboot\n$shutdown\n$suspend\n$hibernate"
+fi
+
+chosen="$(echo -e "$options" | rofi -dmenu -i -p "Power Menu" \
+ -theme $ROFI_THEME)"
+
+case $chosen in
+ "$lock")
+ $lockcmd
+ ;;
+ "$cancel"|"")
+ exit 0
+ ;;
+ "$logout")
+ i3-msg exit
+ ;;
+ "$reboot")
+ systemctl reboot
+ ;;
+ "$shutdown")
+ systemctl poweroff
+ ;;
+ "$suspend")
+ systemctl suspend
+ ;;
+ "$hibernate")
+ systemctl hibernate
+ ;;
+esac
diff --git a/i3/scripts/ppd-status b/i3/scripts/ppd-status
new file mode 100755
index 0000000..92ab169
--- /dev/null
+++ b/i3/scripts/ppd-status
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+
+
+# power-profiles-daemon implementation:
+# needs package power-profiles-daemon installed and the service running see here:
+# https://wiki.archlinux.org/title/CPU_frequency_scaling#power-profiles-daemon
+# used in i3-blocks: ~/.config/i3/i3blocks.conf together with: ~/.config/i3/scripts/power-profiles
+
+
+# assign tags or translations to each profile
+declare -A tags
+tags=(
+ [performance]="Performance"
+ [balanced]="Balanced"
+ [power-saver]="Power saver"
+)
+
+# Get current profile
+current_profile=$(/usr/bin/powerprofilesctl get)
+
+# Get tag from the array
+profile_tag=${tags[$current_profile]}
+
+# Show tag on i3block
+echo "${profile_tag:-$current_profile}"
diff --git a/i3/scripts/temperature b/i3/scripts/temperature
new file mode 100755
index 0000000..69dcc63
--- /dev/null
+++ b/i3/scripts/temperature
@@ -0,0 +1,75 @@
+#!/usr/bin/env perl
+
+# Copyright 2014 Pierre Mavro
+# Copyright 2014 Vivien Didelot
+# Copyright 2014 Andreas Guldstrand
+# Copyright 2014 Benjamin Chretien
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Edited by Andreas Lindlbauer
+
+use strict;
+use warnings;
+use utf8;
+use Getopt::Long;
+
+binmode(STDOUT, ":utf8");
+
+# default values
+my $t_warn = $ENV{T_WARN} || 70;
+my $t_crit = $ENV{T_CRIT} || 90;
+my $chip = $ENV{SENSOR_CHIP} || "";
+my $temperature = -9999;
+my $label = "😀 ";
+
+sub help {
+ print "Usage: temperature [-w ] [-c ] [--chip ]\n";
+ print "-w : warning threshold to become yellow\n";
+ print "-c : critical threshold to become red\n";
+ print "--chip : sensor chip\n";
+ exit 0;
+}
+
+GetOptions("help|h" => \&help,
+ "w=i" => \$t_warn,
+ "c=i" => \$t_crit,
+ "chip=s" => \$chip);
+
+# Get chip temperature
+open (SENSORS, "sensors -u $chip |") or die;
+while () {
+ if (/^\s+temp1_input:\s+[\+]*([\-]*\d+\.\d)/) {
+ $temperature = $1;
+ last;
+ }
+}
+close(SENSORS);
+
+$temperature eq -9999 and die 'Cannot find temperature';
+
+if ($temperature < 45) {
+ $label = '';
+} elsif ($temperature < 55) {
+ $label = '';
+} elsif ($temperature < 65) {
+ $label = '';
+} elsif ($temperature < 75) {
+ $label = '';
+} else {
+ $label = '';
+}
+# Print short_text, full_text
+print "${label}";
+print " $temperature°C\n";
+print "${label}";
+print " $temperature°C\n";
+
+# Print color, if needed
+if ($temperature >= $t_crit) {
+ print "#FF0000\n";
+ exit 33;
+} elsif ($temperature >= $t_warn) {
+ print "#FFFC00\n";
+}
+
+exit 0;
diff --git a/i3/scripts/volume b/i3/scripts/volume
new file mode 100755
index 0000000..97f2693
--- /dev/null
+++ b/i3/scripts/volume
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+# i3blocks volume block for PipeWire (PulseAudio compatible)
+
+STEP=${1:-5%}
+
+# Default sink
+SINK=$(pactl info | awk '/Default Sink/ {print $3}')
+[[ -z "$SINK" ]] && { echo "No audio"; exit 0; }
+
+# Handle scroll/middle-click
+case "$BLOCK_BUTTON" in
+ 3) pactl set-sink-mute "$SINK" toggle ;; # right click = mute/unmute
+ 4) pactl set-sink-volume "$SINK" +$STEP ;; # scroll up
+ 5) pactl set-sink-volume "$SINK" -$STEP ;; # scroll down
+esac
+
+# Get current volume (front-left channel)
+VOL=$(pactl list sinks | awk -v s="$SINK" '
+ $0 ~ "Name: " s {found=1}
+ found && /Volume:/ {gsub("%","",$5); print $5; exit}
+')
+
+# Get mute state
+MUTED=$(pactl list sinks | awk -v s="$SINK" '
+ $0 ~ "Name: " s {found=1}
+ found && /Mute:/ {print $2; exit}
+')
+
+# Choose symbol
+AUDIO_HIGH=''
+AUDIO_MED=''
+AUDIO_LOW=''
+AUDIO_MUTED=''
+MED_THRESH=50
+LOW_THRESH=0
+
+if [[ "$MUTED" == "no" ]]; then
+ SYMB=$AUDIO_HIGH
+ [[ $VOL -le $MED_THRESH ]] && SYMB=$AUDIO_MED
+ [[ $VOL -le $LOW_THRESH ]] && SYMB=$AUDIO_LOW
+else
+ SYMB=$AUDIO_MUTED
+fi
+
+# Single-line output for i3blocks
+echo "${SYMB} ${VOL}%"
diff --git a/i3/scripts/volume_brightness.sh b/i3/scripts/volume_brightness.sh
new file mode 100755
index 0000000..676c6d3
--- /dev/null
+++ b/i3/scripts/volume_brightness.sh
@@ -0,0 +1,95 @@
+#!/usr/bin/env bash
+
+# original source: https://gitlab.com/Nmoleo/i3-volume-brightness-indicator
+# changed to use brightnessctl [xbacklight is non functional on modern hardware]
+# by joekamprad [Aug 2025]
+
+bar_color="#7f7fff"
+volume_step=1
+brightness_step=5
+max_volume=100
+notification_timeout=1000 # in ms
+
+# Uses regex to get volume from pactl
+function get_volume {
+ pactl get-sink-volume @DEFAULT_SINK@ | grep -Po '[0-9]{1,3}(?=%)' | head -1
+}
+
+# Uses regex to get mute status from pactl
+function get_mute {
+ pactl get-sink-mute @DEFAULT_SINK@ | grep -Po '(?<=Mute: )(yes|no)'
+}
+
+# Uses brightnessctl instead of xbacklight
+function get_brightness {
+ brightnessctl g | awk '{print int($1)}'
+ # You could also use: brightnessctl info | grep -Po '(?<=Current brightness: )[0-9]+'
+}
+
+# Calculates brightness percentage
+function get_brightness_percent {
+ current=$(brightnessctl g)
+ max=$(brightnessctl m)
+ percent=$(( 100 * current / max ))
+ echo $percent
+}
+
+function get_volume_icon {
+ volume=$(get_volume)
+ mute=$(get_mute)
+ if [ "$volume" -eq 0 ] || [ "$mute" == "yes" ] ; then
+ volume_icon=""
+ elif [ "$volume" -lt 50 ]; then
+ volume_icon=""
+ else
+ volume_icon=""
+ fi
+}
+
+function get_brightness_icon {
+ brightness_icon=""
+}
+
+function show_volume_notif {
+ volume=$(get_volume)
+ get_volume_icon
+ notify-send -i volume_icon -t 1000 "Volume" "$volume_icon $volume%" -h int:value:$volume -h string:x-canonical-private-synchronous:volume
+}
+
+
+function show_brightness_notif {
+ get_brightness_icon
+ brightness=$(get_brightness_percent)
+ notify-send -i brightness_icon -t $notification_timeout -h string:x-dunst-stack-tag:brightness_notif -h int:value:$brightness "$brightness_icon $brightness%"
+}
+
+
+
+case $1 in
+ volume_up)
+ pactl set-sink-mute @DEFAULT_SINK@ 0
+ volume=$(get_volume)
+ if [ $(( "$volume" + "$volume_step" )) -gt $max_volume ]; then
+ pactl set-sink-volume @DEFAULT_SINK@ $max_volume%
+ else
+ pactl set-sink-volume @DEFAULT_SINK@ +$volume_step%
+ fi
+ show_volume_notif
+ ;;
+ volume_down)
+ pactl set-sink-volume @DEFAULT_SINK@ -$volume_step%
+ show_volume_notif
+ ;;
+ volume_mute)
+ pactl set-sink-mute @DEFAULT_SINK@ toggle
+ show_volume_notif
+ ;;
+ brightness_up)
+ brightnessctl s +$brightness_step% > /dev/null
+ show_brightness_notif
+ ;;
+ brightness_down)
+ brightnessctl s $brightness_step%- > /dev/null
+ show_brightness_notif
+ ;;
+esac
diff --git a/i3/scripts/volume_brightness2.sh b/i3/scripts/volume_brightness2.sh
new file mode 100755
index 0000000..cd78d77
--- /dev/null
+++ b/i3/scripts/volume_brightness2.sh
@@ -0,0 +1,168 @@
+#!/usr/bin/env bash
+
+# original source: https://gitlab.com/Nmoleo/i3-volume-brightness-indicator
+# alternative to volume_brightness.sh that uses brightnessctl for both keyboard & screen brightness
+
+# See README.md for usage instructions
+volume_step=1
+keyboard_brightness_step=20
+screen_brightness_step=1
+max_volume=100
+notification_timeout=1000
+
+# Specify Icon Theme here:
+volume_theme_icon="audio-volume-high"
+screen_brightness_theme_icon="display-brightness"
+keyboard_brightness_theme_icon="display-brightness"
+
+# Keyboard Backlight device detection here:
+device_cache="/tmp/kbd_backlight_device"
+
+if [ -f "$device_cache" ]; then
+ # If there is cache, load it into device
+ device=$(cat "$device_cache")
+else
+ # If there is no cache, create one
+ device=$(brightnessctl --list | grep -Po '\w+::kbd_backlight')
+ echo "$device" > "$device_cache"
+fi
+
+# Uses regex to get volume from pactl
+function get_volume {
+ pactl get-sink-volume @DEFAULT_SINK@ | grep -Po '[0-9]{1,3}(?=%)' | head -1
+}
+
+# Uses regex to get mute status from pactl
+function get_mute {
+ pactl get-sink-mute @DEFAULT_SINK@ | grep -Po '(?<=Mute: )(yes|no)'
+}
+
+# Get keyboard_brightness from brightnessctl
+function get_keyboard_brightness {
+ if [ -n "$device" ]; then
+ keyboard_curr=$(brightnessctl -d "$device" get)
+ keyboard_max=$(brightnessctl -d "$device" max)
+ echo $(( keyboard_curr * 100 / keyboard_max))
+ fi
+}
+
+
+# Grabs screen brightness and formats it out of 100
+function get_screen_brightness {
+ screen_curr=$(brightnessctl -q get)
+ screen_max=$(brightnessctl -q max)
+ echo $(( screen_curr * 100 / screen_max ))
+}
+
+# Returns a mute icon, a volume-low icon, or a volume-high icon, depending on the volume
+function get_volume_icon {
+ volume=$(get_volume)
+ mute=$(get_mute)
+ if [ "$volume" -eq 0 ] || [ "$mute" == "yes" ] ; then
+ volume_icon=""
+ elif [ "$volume" -lt 50 ] ; then
+ volume_icon=""
+ else
+ volume_icon=""
+ fi
+}
+
+# Always returns the same icon - I couldn't get the brightness-low icon to work with fontawesome
+function get_keyboard_brightness_icon {
+ kb_brightness=$(get_keyboard_brightness)
+ if [ "$kb_brightness" -eq 0 ] ; then
+ keyboard_brightness_icon="" # unfilled circle
+ elif [ "$kb_brightness" -lt 50 ] ; then
+ keyboard_brightness_icon="" # fa-adjust (low brightness)
+ else
+ keyboard_brightness_icon="" # full circle (high brightness)
+ fi
+}
+
+function get_screen_brightness_icon {
+ sc_brightness=$(get_screen_brightness)
+ if [ "$sc_brightness" -eq 0 ] ; then
+ screen_brightness_icon="" # unfilled circle
+ elif [ "$sc_brightness" -lt 50 ] ; then
+ screen_brightness_icon="" # fa-adjust (low brightness)
+ else
+ screen_brightness_icon="" # full circle (high brightness)
+ fi
+}
+
+# Displays a volume notification using notify-send
+function show_volume_notif {
+ mute=$(get_mute)
+ volume=$(get_volume)
+ get_volume_icon
+ notify-send -i $volume_theme_icon -t $notification_timeout "Volume" "$volume_icon $volume%" -h int:value:$volume -h string:x-canonical-private-synchronous:volume
+}
+
+# Displays a keyboard_brightness notification
+function show_keyboard_brightness_notif {
+ keyboard_brightness=$(get_keyboard_brightness)
+ # Debug Purposes:
+ # echo $keyboard_brightness
+ get_keyboard_brightness_icon
+ notify-send -i $keyboard_brightness_theme_icon -t $notification_timeout "Keyboard Brightness" -h string:x-dunst-stack-tag:keyboard_brightness_notif -h int:value:$keyboard_brightness "$keyboard_brightness_icon $keyboard_brightness%"
+}
+
+# Displays a screen_brightness notification
+function show_screen_brightness_notif {
+ screen_brightness=$(get_screen_brightness)
+ # Debug Purposes:
+ # echo $screen_brightness
+ get_screen_brightness_icon
+ notify-send -i $screen_brightness_theme_icon -t $notification_timeout "Screen Brightness" -h string:x-dunst-stack-tag:screen_brightness_notif -h int:value:$screen_brightness "$screen_brightness_icon $screen_brightness%"
+}
+
+# Main function - Takes user input, "volume_up", "volume_down", "keyboard_brightness_up", "keyboard_brightness_down", "brightness_up", or "brightness_down"
+case $1 in
+ volume_up)
+ # Unmutes and increases volume, then displays the notification
+ pactl set-sink-mute @DEFAULT_SINK@ 0
+ volume=$(get_volume)
+ if [ $(( "$volume" + "$volume_step" )) -gt $max_volume ]; then
+ pactl set-sink-volume @DEFAULT_SINK@ $max_volume%
+ else
+ pactl set-sink-volume @DEFAULT_SINK@ +$volume_step%
+ fi
+ show_volume_notif
+ ;;
+
+ volume_down)
+ # Raises volume and displays the notification
+ pactl set-sink-volume @DEFAULT_SINK@ -$volume_step%
+ show_volume_notif
+ ;;
+
+ volume_mute)
+ # Toggles mute and displays the notification
+ pactl set-sink-mute @DEFAULT_SINK@ toggle
+ show_volume_notif
+ ;;
+
+ keyboard_brightness_up)
+ # Increases keyboard brightness and displays the notification
+ brightnessctl -d "$device" set ${keyboard_brightness_step}+
+ show_keyboard_brightness_notif
+ ;;
+
+ keyboard_brightness_down)
+ # Decreases keyboard brightness and displays the notification
+ brightnessctl -d "$device" set ${keyboard_brightness_step}-
+ show_keyboard_brightness_notif
+ ;;
+
+ screen_brightness_up)
+ # Increases screen brightness and displays the notification
+ brightnessctl -q set ${screen_brightness_step}%+
+ show_screen_brightness_notif
+ ;;
+
+ screen_brightness_down)
+ # Decreases screen brightness and displays the notification
+ brightnessctl -q set ${screen_brightness_step}%-
+ show_screen_brightness_notif
+ ;;
+esac
diff --git a/i3/scripts/vpn b/i3/scripts/vpn
new file mode 100755
index 0000000..bcf54ee
--- /dev/null
+++ b/i3/scripts/vpn
@@ -0,0 +1,25 @@
+#!/usr/bin/env sh
+
+# Parses output from nmcli to show the current connected VPN name/status for i3block
+# Source: https://github.com/vivien/i3blocks-contrib/tree/master/nm-vpn
+# uncomment in $HOME/.config/i3/i3blocks.conf if you want to use it
+
+init_color=${init_color:-#FFFF00}
+on_color=${on_color:-#00FF00}
+export init_color on_color
+nmcli -t connection show --active | awk -F ':' '
+BEGIN {
+ init_color=ENVIRON["init_color"]
+ on_color=ENVIRON["on_color"]
+}
+$3=="vpn" {
+ name=$1
+ status="INIT"
+ color=init_color
+}
+$3=="tun" || ($4~/^tap/ || $3~/^tap/) {
+ if(!name) name=$1
+ status="ON"
+ color=on_color
+}
+END {if(status) printf("%s\n%s\n%s\n", name, status, color)}'
diff --git a/i3/scripts/wallpaper-rotate b/i3/scripts/wallpaper-rotate
new file mode 100755
index 0000000..78a84a1
--- /dev/null
+++ b/i3/scripts/wallpaper-rotate
@@ -0,0 +1,44 @@
+#!/bin/bash
+wall_dir="${1:?wallpaper directory required}"
+interval="${2:-1800}"
+
+pick_wall() {
+ find "$wall_dir" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | shuf -n1
+}
+
+set_wall() { [ -n "$1" ] && xwallpaper --zoom "$1"; }
+
+has_fullscreen() {
+ python3 - <<'EOF'
+import json, subprocess, sys
+
+def is_fullscreen(node):
+ if node.get('fullscreen_mode', 0) > 0: return True
+ return any(is_fullscreen(c) for c in node.get('nodes', []) + node.get('floating_nodes', []))
+
+def find_ws(node, name):
+ if node.get('type') == 'workspace' and node.get('name') == name: return node
+ for c in node.get('nodes', []) + node.get('floating_nodes', []):
+ r = find_ws(c, name)
+ if r: return r
+
+try:
+ wss = json.loads(subprocess.check_output(['i3-msg', '-t', 'get_workspaces'], stderr=subprocess.DEVNULL))
+ tree = json.loads(subprocess.check_output(['i3-msg', '-t', 'get_tree'], stderr=subprocess.DEVNULL))
+ for ws in wss:
+ if ws.get('visible'):
+ node = find_ws(tree, ws['name'])
+ if node and is_fullscreen(node):
+ sys.exit(0)
+except Exception:
+ pass
+sys.exit(1)
+EOF
+}
+
+# Initial wallpaper
+set_wall "$(pick_wall)"
+
+while sleep "$interval"; do
+ has_fullscreen || set_wall "$(pick_wall)"
+done
diff --git a/nvim-server/init.lua b/nvim-server/init.lua
new file mode 100644
index 0000000..33a56e5
--- /dev/null
+++ b/nvim-server/init.lua
@@ -0,0 +1,107 @@
+-- Minimal server editor config
+-- Launch with: NVIM_APPNAME=nvim-server nvim
+
+-------------------- Options --------------------
+vim.g.mapleader = ","
+vim.opt.number = true
+vim.opt.cursorline = true
+vim.opt.expandtab = true
+vim.opt.tabstop = 4
+vim.opt.shiftwidth = 4
+vim.opt.softtabstop = 4
+vim.opt.autoindent = true
+vim.opt.smartindent = true
+vim.opt.hlsearch = true
+vim.opt.incsearch = true
+vim.opt.ignorecase = true
+vim.opt.smartcase = true
+vim.opt.splitright = true
+vim.opt.splitbelow = true
+vim.opt.termguicolors = true
+vim.opt.scrolloff = 8
+vim.opt.signcolumn = "no"
+vim.opt.updatetime = 250
+vim.opt.undofile = true
+
+-------------------- Clipboard --------------------
+vim.opt.clipboard = 'unnamedplus'
+
+vim.g.clipboard = {
+ name = 'OSC 52',
+ copy = {
+ ['+'] = require('vim.ui.clipboard.osc52').copy('+'),
+ ['*'] = require('vim.ui.clipboard.osc52').copy('*'),
+ },
+ paste = {
+ ['+'] = require('vim.ui.clipboard.osc52').paste('+'),
+ ['*'] = require('vim.ui.clipboard.osc52').paste('*'),
+ },
+}
+vim.keymap.set("v", "y", '"+y')
+vim.keymap.set("n", "Y", '"+yg_')
+vim.keymap.set("n", "y", '"+y')
+vim.keymap.set("n", "yy", '"+yy')
+vim.keymap.set("n", "p", '"+p')
+vim.keymap.set("n", "P", '"+P')
+
+-------------------- Keymaps --------------------
+vim.keymap.set("n", "i", ":nohlsi", { silent = true })
+vim.keymap.set("n", "", ":w", { silent = true })
+
+-- Window navigation
+vim.keymap.set("n", "", "h")
+vim.keymap.set("n", "", "j")
+vim.keymap.set("n", "", "k")
+vim.keymap.set("n", "", "l")
+vim.keymap.set("n", "", "h")
+vim.keymap.set("n", "", "j")
+vim.keymap.set("n", "", "k")
+vim.keymap.set("n", "", "l")
+
+-- Tab management
+vim.keymap.set("n", "to", ":tabonly", { silent = true })
+vim.keymap.set("n", "o", ":only", { silent = true })
+vim.keymap.set("n", "", ":tabn", { silent = true })
+vim.keymap.set("n", "", ":tabp", { silent = true })
+
+
+-------------------- Netrw (built-in file browser) --------------------
+vim.g.netrw_banner = 0
+vim.g.netrw_liststyle = 3
+vim.keymap.set("n", "", ":Explore", { silent = true })
+
+-------------------- Statusline (built-in) --------------------
+vim.opt.statusline = " %f %m%r%= %y %l:%c %p%% "
+
+-------------------- Bootstrap lazy.nvim --------------------
+local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
+if vim.fn.isdirectory(lazypath) == 0 then
+ vim.fn.system({
+ "git", "clone", "--filter=blob:none",
+ "https://github.com/folke/lazy.nvim.git",
+ "--branch=stable",
+ lazypath,
+ })
+end
+vim.opt.rtp:prepend(lazypath)
+
+require("lazy").setup({
+ { "4ree/viml-surround", event = "VeryLazy" },
+ { "numToStr/Comment.nvim", event = "VeryLazy", opts = {} },
+ {
+ "junegunn/fzf.vim",
+ dependencies = { "junegunn/fzf" },
+ keys = {
+ { "f", "Files", desc = "Find files" },
+ { "b", "Buffers", desc = "Buffers" },
+ { "r", "Rg", desc = "Ripgrep" },
+ { "g", "GFiles", desc = "Git files" },
+ },
+ },
+})
+
+-------------------- Grep (use ripgrep if available) --------------------
+if vim.fn.executable("rg") == 1 then
+ vim.opt.grepprg = "rg --vimgrep --smart-case"
+ vim.opt.grepformat = "%f:%l:%c:%m"
+end
diff --git a/nvim/.vimrc b/nvim/.vimrc
deleted file mode 100644
index 62860f8..0000000
--- a/nvim/.vimrc
+++ /dev/null
@@ -1,143 +0,0 @@
-syntax on
-set number
-set cursorline
-set expandtab tabstop=4 shiftwidth=4 softtabstop=4
-set autoindent
-set spelllang=vi,en
-
-
-" Fold
-set foldmethod=syntax
-set foldlevel=1
-set foldnestmax=1
-set encoding=utf8
-
-" Search
-set hlsearch
-nnoremap i :nohlsi
-
-" Plugin
-call plug#begin()
-Plug 'neoclide/coc.nvim', {'branch': 'release'}
-Plug 'dense-analysis/ale'
-Plug 'preservim/nerdtree'
-Plug 'preservim/nerdcommenter'
-Plug 'lervag/vimtex'
-Plug 'JuliaEditorSupport/julia-vim'
-Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
-Plug 'junegunn/fzf.vim'
-Plug 'honza/vim-snippets'
-Plug 'vim-airline/vim-airline'
-Plug 'vim-airline/vim-airline-themes'
-Plug 'kevinhwang91/nvim-bqf'
-Plug 'morhetz/gruvbox'
-Plug 'tpope/vim-fugitive'
-Plug 'ynkdir/vim-diff'
-Plug '4ree/vim-ime'
-call plug#end()
-
-"Color scheme
-"colorscheme iceberg
-"set background=light
-colorscheme gruvbox
-let g:gruvbox_contrast_light = 'hard'
-hi clear SpellBad
-hi SpellBad cterm=underline ctermfg=red
-
-
-"Open NERDTree
-:nnoremap g:NERDTree.IsOpen() ? "\:NERDTreeClose" : bufexists(expand('%')) ? "\:NERDTreeFind" : "\:NERDTree"
-
-"Coc.nvim
-inoremap
- \ coc#pum#visible() ? coc#_select_confirm() :
- \ coc#expandableOrJumpable() ? "\=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\" :
- \ CheckBackSpace() ? "\" :
- \ coc#refresh()
-inoremap pumvisible() ? coc#_select_confirm()
- \: "\u\\=coc#on_enter()\"
-
-function! CheckBackSpace() abort
- let col = col('.') - 1
- return !col || getline('.')[col - 1] =~# '\s'
-endfunction
-
-let g:coc_snippet_next = ''
-inoremap coc#pum#visible() ? coc#pum#confirm()
- \: "\u\\=coc#on_enter()\"
-
-" Comments
-let mapleader = ","
-
-" remap save
-nnoremap :w
-
-" moving between windows
-nnoremap h
-nnoremap j
-nnoremap k
-nnoremap l
-nnoremap h
-nnoremap j
-nnoremap k
-nnoremap l
-nnoremap to :tabonly
-nnoremap o :only
-nnoremap :tabn
-nnoremap :tabp
-
-"set clipboard+=unnamedplus
-" " Copy to clipboard
-vnoremap y "+y
-nnoremap Y "+yg_
-nnoremap y "+y
-nnoremap yy "+yy
-
-" " Paste from clipboard
-nnoremap p "+p
-nnoremap P "+P
-
-
-" FZF key mapping
-nnoremap b :Buffers
-nnoremap r :Rg
-nnoremap f :Files
-nnoremap g :GFiles
-nnoremap w :Rg
-
-filetype plugin on
-set splitright
-set splitbelow
-
-let g:vimtex_view_method= 'zathura'
-
-"Language tool
-map :ALEToggle
-
-
-"Use 24-bit (true-color) mode in Vim/Neovim when outside tmux.
-"If you're using tmux version 2.2 or later, you can remove the outermost $TMUX check and use tmux's 24-bit color support
-"(see < http://sunaku.github.io/tmux-24bit-color.html#usage > for more information.)
-if (empty($TMUX))
- if (has("nvim"))
- "For Neovim 0.1.3 and 0.1.4 < https://github.com/neovim/neovim/pull/2198 >
- let $NVIM_TUI_ENABLE_TRUE_COLOR=1
- endif
- "For Neovim > 0.1.5 and Vim > patch 7.4.1799 < https://github.com/vim/vim/commit/61be73bb0f965a895bfb064ea3e55476ac175162 >
- "Based on Vim patch 7.4.1770 (`guicolors` option) < https://github.com/vim/vim/commit/8a633e3427b47286869aa4b96f2bfc1fe65b25cd >
- " < https://github.com/neovim/neovim/wiki/Following-HEAD#20160511 >
- if (has("termguicolors"))
- set termguicolors
- endif
-endif
-
-if &term =~ 'xterm' || &term == 'win32'
- " Use DECSCUSR escape sequences
- let &t_SI = "\e[5 q" " blink bar
- let &t_SR = "\e[3 q" " blink underline
- let &t_EI = "\e[1 q" " blink block
- let &t_ti ..= "\e[1 q" " blink block
- let &t_te ..= "\e[0 q" " default (depends on terminal, normally blink
- " block)
-endif
-
diff --git a/nvim/coc-settings.json b/nvim/coc-settings.json
deleted file mode 100644
index 3ba2825..0000000
--- a/nvim/coc-settings.json
+++ /dev/null
@@ -1,2 +0,0 @@
-{"coc.preferences.diagnostic.displayByAle":1
-}
diff --git a/nvim/init.lua b/nvim/init.lua
new file mode 100644
index 0000000..3501ac3
--- /dev/null
+++ b/nvim/init.lua
@@ -0,0 +1,227 @@
+-- Leader key (must be set before lazy.nvim loads)
+vim.g.mapleader = ","
+
+-------------------- Options --------------------
+vim.opt.number = true
+vim.opt.cursorline = true
+vim.opt.expandtab = true
+vim.opt.tabstop = 4
+vim.opt.shiftwidth = 4
+vim.opt.softtabstop = 4
+vim.opt.autoindent = true
+vim.opt.spelllang = "vi,en"
+vim.opt.foldmethod = "syntax"
+vim.opt.foldlevel = 1
+vim.opt.foldnestmax = 1
+vim.opt.hlsearch = true
+vim.opt.splitright = true
+vim.opt.splitbelow = true
+vim.opt.termguicolors = true
+vim.opt.autoread = true
+
+-------------------- Keymaps --------------------
+-- Clear hlsearch then enter insert mode
+vim.keymap.set("n", "i", ":nohlsi", { silent = true })
+
+-- Save with space
+vim.keymap.set("n", "", ":w", { silent = true })
+
+-- Window navigation
+vim.keymap.set("n", "", "h")
+vim.keymap.set("n", "", "j")
+vim.keymap.set("n", "", "k")
+vim.keymap.set("n", "", "l")
+vim.keymap.set("n", "", "h")
+vim.keymap.set("n", "", "j")
+vim.keymap.set("n", "", "k")
+vim.keymap.set("n", "", "l")
+
+-- Tab management
+vim.keymap.set("n", "to", ":tabonly", { silent = true })
+vim.keymap.set("n", "o", ":only", { silent = true })
+vim.keymap.set("n", "", ":tabn", { silent = true })
+vim.keymap.set("n", "", ":tabp", { silent = true })
+
+-- Clipboard operations
+vim.keymap.set("v", "y", '"+y')
+vim.keymap.set("n", "Y", '"+yg_')
+vim.keymap.set("n", "y", '"+y')
+vim.keymap.set("n", "yy", '"+yy')
+vim.keymap.set("n", "p", '"+p')
+vim.keymap.set("n", "P", '"+P')
+
+-- Background toogling
+vim.keymap.set("n", "bg", function()
+ vim.o.background = vim.o.background == "dark" and "light" or "dark"
+end, { desc = "Toggle light/dark background" })
+
+-- Join paragraph
+vim.keymap.set("n", "j", "vipJ", { desc = "Join paragraph into one line" })
+
+-------------------- Bootstrap lazy.nvim --------------------
+local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
+if not vim.uv.fs_stat(lazypath) then
+ vim.fn.system({
+ "git", "clone", "--filter=blob:none",
+ "https://github.com/folke/lazy.nvim.git",
+ "--branch=stable",
+ lazypath,
+ })
+end
+vim.opt.rtp:prepend(lazypath)
+
+-------------------- Plugins --------------------
+require("lazy").setup({
+
+ -- Colorscheme
+ {
+ "ellisonleao/gruvbox.nvim",
+ priority = 1000,
+ config = function()
+ require("gruvbox").setup({
+ contrast = "soft",
+ })
+ vim.cmd.colorscheme("gruvbox")
+ vim.o.background = "light"
+ end,
+ },
+
+ -- Icons (dependency for nvim-tree and lualine)
+ { "nvim-tree/nvim-web-devicons", lazy = true },
+
+ -- File tree
+ {
+ "nvim-tree/nvim-tree.lua",
+ dependencies = { "nvim-tree/nvim-web-devicons" },
+ keys = {
+ { "", "NvimTreeToggle", desc = "Toggle file tree" },
+ },
+ config = function()
+ require("nvim-tree").setup()
+ end,
+ },
+
+ -- Comments
+ {
+ "numToStr/Comment.nvim",
+ event = "VeryLazy",
+ config = function()
+ require("Comment").setup()
+ end,
+ },
+
+ -- Fuzzy finder (fzf-lua with ripgrep)
+ {
+ "ibhagwan/fzf-lua",
+ dependencies = { "nvim-tree/nvim-web-devicons" },
+ keys = {
+ { "b", "FzfLua buffers", desc = "Buffers" },
+ { "r", "FzfLua live_grep", desc = "Live grep" },
+ { "f", "FzfLua files", desc = "Find files" },
+ { "g", "FzfLua git_files", desc = "Git files" },
+ { "w", "FzfLua grep_cword", desc = "Grep word under cursor" },
+ },
+ config = function()
+ require("fzf-lua").setup({
+ files = {
+ cmd = "rg --files --hidden --glob '!**/.git/*'",
+ },
+ grep = {
+ rg_opts = "--hidden --glob '!**/.git/*' --column --line-number --no-heading --color=always --smart-case",
+ },
+ })
+ end,
+ },
+
+ -- Statusline
+ {
+ "nvim-lualine/lualine.nvim",
+ dependencies = { "nvim-tree/nvim-web-devicons" },
+ config = function()
+ require("lualine").setup({
+ options = { theme = "gruvbox" },
+ })
+ end,
+ },
+
+ -- Autopairs
+ {
+ "windwp/nvim-autopairs",
+ event = "InsertEnter",
+ opts = {},
+ },
+
+ -- Surround
+ { "4ree/viml-surround", event = "VeryLazy" },
+
+ -- LSP
+ {
+ "neovim/nvim-lspconfig",
+ config = function()
+ vim.lsp.config("clangd", {})
+ vim.lsp.config("pyright", {})
+ vim.lsp.config("rust_analyzer", {})
+ vim.lsp.config("julials", {})
+ vim.lsp.enable({ "clangd", "pyright", "rust_analyzer", "julials" })
+
+ vim.api.nvim_create_autocmd("LspAttach", {
+ callback = function(args)
+ local opts = { buffer = args.buf }
+ vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts)
+ vim.keymap.set("n", "gr", vim.lsp.buf.references, opts)
+ vim.keymap.set("n", "K", vim.lsp.buf.hover, opts)
+ vim.keymap.set("n", "rn", vim.lsp.buf.rename, opts)
+ vim.keymap.set("n", "ca", vim.lsp.buf.code_action, opts)
+ end,
+ })
+ end,
+ },
+
+ -- Completion (coq_nvim)
+ {
+ "ms-jpq/coq_nvim",
+ branch = "coq",
+ dependencies = {
+ { "ms-jpq/coq.artifacts", branch = "artifacts" },
+ { "ms-jpq/coq.thirdparty", branch = "3p" },
+ },
+ init = function()
+ vim.g.coq_settings = { auto_start = "shut-up" }
+ end,
+ },
+
+ -- Quickfix enhancements
+ { "kevinhwang91/nvim-bqf", ft = "qf" },
+
+ -- Git
+ { "tpope/vim-fugitive" },
+
+ -- IME support
+ {
+ "4ree/vim-ime",
+ event = "VeryLazy",
+ opts = {},
+ },
+
+ -- LaTeX
+ {
+ "lervag/vimtex",
+ config = function()
+ vim.g.vimtex_view_method = "zathura"
+ vim.g.vimtex_compiler_latexmk = {
+ options = {
+ "-verbose",
+ "-file-line-error",
+ "-synctex=1",
+ "-interaction=nonstopmode",
+ "-shell-escape",
+ "-output-directory=./output",
+ "-aux-directory=./",
+ },
+ }
+ end,
+ },
+
+ -- Julia
+ { "JuliaEditorSupport/julia-vim" },
+})
diff --git a/nvim/init.vim b/nvim/init.vim
deleted file mode 100644
index d0b0480..0000000
--- a/nvim/init.vim
+++ /dev/null
@@ -1,132 +0,0 @@
-syntax on
-set number
-set cursorline
-set expandtab tabstop=4 shiftwidth=4 softtabstop=4
-set autoindent
-set spelllang=vi,en
-
-
-" Fold
-set foldmethod=syntax
-set foldlevel=1
-set foldnestmax=1
-set encoding=utf8
-
-" Search
-set hlsearch
-nnoremap i :nohlsi
-
-" Plugin
-call plug#begin()
-Plug 'neoclide/coc.nvim', {'branch': 'release'}
-Plug 'dense-analysis/ale'
-Plug 'preservim/nerdtree'
-Plug 'preservim/nerdcommenter'
-Plug 'lervag/vimtex'
-Plug 'JuliaEditorSupport/julia-vim'
-Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
-Plug 'junegunn/fzf.vim'
-Plug 'honza/vim-snippets'
-Plug 'vim-airline/vim-airline'
-Plug 'vim-airline/vim-airline-themes'
-Plug 'kevinhwang91/nvim-bqf'
-Plug 'morhetz/gruvbox'
-Plug 'tpope/vim-fugitive'
-Plug 'ynkdir/vim-diff'
-Plug '4ree/vim-ime'
-call plug#end()
-
-"Color scheme
-"colorscheme iceberg
-"set background=light
-colorscheme gruvbox
-let g:gruvbox_contrast_light = 'hard'
-
-
-
-"Open NERDTree
- map :NERDTreeToggle
-
-
-"Coc.nvim
-inoremap
- \ coc#pum#visible() ? coc#_select_confirm() :
- \ coc#expandableOrJumpable() ? "\=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\" :
- \ CheckBackSpace() ? "\" :
- \ coc#refresh()
-inoremap pumvisible() ? coc#_select_confirm()
- \: "\u\\=coc#on_enter()\"
-
-function! CheckBackSpace() abort
- let col = col('.') - 1
- return !col || getline('.')[col - 1] =~# '\s'
-endfunction
-
-let g:coc_snippet_next = ''
-inoremap coc#pum#visible() ? coc#pum#confirm()
- \: "\u\\=coc#on_enter()\"
-
-" Comments
-let mapleader = ","
-
-" remap save
-nnoremap :w
-
-" moving between windows
-nnoremap h
-nnoremap j
-nnoremap k
-nnoremap l
-nnoremap h
-nnoremap j
-nnoremap k
-nnoremap l
-nnoremap to :tabonly
-nnoremap o :only