:DOC-CONFIG:
#+property: header-args: mkdirp yes :comments no
#+startup: fold
:END:

#+title: PWL Arch Linux Config
#+OPTIONS: toc:3

* Table of Contents :toc:
- [[#prerequisites][Prerequisites]]
- [[#literate-file-headers][Literate File Headers]]
  - [[#updatesh][update.sh]]
  - [[#packagestxt][packages.txt]]
  - [[#aliassh][alias.sh]]
  - [[#pathsh][path.sh]]
  - [[#doom-emacs][Doom Emacs]]
  - [[#zshrc][.zshrc]]
  - [[#bashrc][.bashrc]]
  - [[#autostartsh][autostart.sh]]
  - [[#alacrittytoml][alacritty.toml]]
- [[#package-management][Package Management]]
  - [[#arch-and-aur-packages][Arch and AUR Packages]]
- [[#base-system][Base System]]
  - [[#arch-linux][Arch Linux]]
  - [[#network-manager][Network Manager]]
  - [[#man-pages-and-texinfo][Man Pages and Texinfo]]
  - [[#build-tools][Build Tools]]
  - [[#system-locale][System Locale]]
  - [[#keyboard-layout][Keyboard Layout]]
- [[#desktop-environments-and-window-manager][Desktop Environments and Window Manager]]
  - [[#lightdm][LightDM]]
  - [[#gnome][GNOME]]
  - [[#qtile][Qtile]]
- [[#text-editors][Text Editors]]
  - [[#doom-emacs-1][Doom Emacs]]
  - [[#vscode][VSCode]]
  - [[#neovim][NeoVim]]
- [[#browser][Browser]]
  - [[#firefox][Firefox]]
- [[#shells][Shells]]
  - [[#aliases][Aliases]]
  - [[#zsh][ZSH]]
  - [[#bash][Bash]]
- [[#alacritty][Alacritty]]
  - [[#font][Font]]
- [[#theming][Theming]]
  - [[#doom-emacs-2][Doom Emacs]]
  - [[#vscode-1][VSCode]]
  - [[#qtile-1][Qtile]]
  - [[#alacritty-1][Alacritty]]
  - [[#xorg][Xorg]]
  - [[#gtk][GTK]]
- [[#git][Git]]
  - [[#installation][Installation]]
  - [[#configuration][Configuration]]
- [[#miniconda][Miniconda]]
  - [[#installation-1][Installation]]
  - [[#zsh-special-settings][ZSH special settings]]
  - [[#do-not-activate-base-environment-on-startup][Do not activate base environment on startup]]
- [[#misc-programs][Misc Programs]]
  - [[#zathura][Zathura]]
  - [[#nextcloud][Nextcloud]]
  - [[#bitwarden][Bitwarden]]
  - [[#inkscape][Inkscape]]
- [[#manual-tasks-after-tangling][Manual Tasks after tangling]]
- [[#other-todos][Other TODOs]]
  - [[#configure-bitwarden-via-config-file][configure Bitwarden via config file]]
  - [[#add-firefox-user-via-updatesh][add Firefox user via update.sh]]

* Prerequisites
- Completed Arch Linux Installation
  - partitioning
  - encryption
  - main user
* Literate File Headers
This is used to initialize all files that are accessed from multiple places in the config
** update.sh
#+begin_src shell :tangle update.sh
#!/bin/sh
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

#+end_src

** packages.txt
contains all Arch and AUR packages
#+begin_src conf :tangle pkg-list.txt
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

#+end_src

** alias.sh
#+begin_src shell :tangle ~/alias.sh
#!/bin/sh
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

#+end_src

** path.sh
contains all modifications to the path variables
#+begin_src shell :tangle ~/path.sh
#!/bin/sh
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

#+end_src

** Doom Emacs
We start by simply defining the standard headers used by the three files. These headers come from the initial files generated by =doom install=, and contain either some Emacs-LISP relevant indicators like =lexical-binding=, or instructions about the contents of the file.
*** init.el
#+html: <details><summary>init.el</summary>
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/init.el
;;; init.el -*- lexical-binding: t; -*-

;; DO NOT EDIT THIS FILE DIRECTLY
;; This is a file generated from a literate programing source file
;; You should make any changes there and regenerate it from Emacs org-mode
;; using org-babel-tangle (C-c C-v t)

;; This file controls what Doom modules are enabled and what order they load
;; in. Remember to run 'doom sync' after modifying it!

;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's
;;      documentation. There you'll find a "Module Index" link where you'll find
;;      a comprehensive list of Doom's modules and what flags they support.

;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or
;;      'C-c c k' for non-vim users) to view its documentation. This works on
;;      flags as well (those symbols that start with a plus).
;;
;;      Alternatively, press 'gd' (or 'C-c c d') on a module to browse its
;;      directory (for easy access to its source code).
#+end_src
#+html: </details>

*** packages.el
#+html: <details><summary>packages.el</summary>
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/packages.el
;; -*- no-byte-compile: t; -*-
;;; $DOOMDIR/packages.el

;; DO NOT EDIT THIS FILE DIRECTLY
;; This is a file generated from a literate programing source file
;; You should make any changes there and regenerate it from Emacs org-mode
;; using org-babel-tangle (C-c C-v t)

;; To install a package with Doom you must declare them here and run 'doom sync'
;; on the command line, then restart Emacs for the changes to take effect -- or
;; use 'M-x doom/reload'.

;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror:
;;(package! some-package)

;; To install a package directly from a remote git repo, you must specify a
;; `:recipe'. You'll find documentation on what `:recipe' accepts here:
;; https://github.com/raxod502/straight.el#the-recipe-format
;;(package! another-package
;;  :recipe (:host github :repo "username/repo"))

;; If the package you are trying to install does not contain a PACKAGENAME.el
;; file, or is located in a subdirectory of the repo, you'll need to specify
;; `:files' in the `:recipe':
;;(package! this-package
;;  :recipe (:host github :repo "username/repo"
;;           :files ("some-file.el" "src/lisp/*.el")))

;; If you'd like to disable a package included with Doom, you can do so here
;; with the `:disable' property:
;;(package! builtin-package :disable t)

;; You can override the recipe of a built in package without having to specify
;; all the properties for `:recipe'. These will inherit the rest of its recipe
;; from Doom or MELPA/ELPA/Emacsmirror:
;;(package! builtin-package :recipe (:nonrecursive t))
;;(package! builtin-package-2 :recipe (:repo "myfork/package"))

;; Specify a `:branch' to install a package from a particular branch or tag.
;; This is required for some packages whose default branch isn't 'master' (which
;; our package manager can't deal with; see raxod502/straight.el#279)
;;(package! builtin-package :recipe (:branch "develop"))

;; Use `:pin' to specify a particular commit to install.
;;(package! builtin-package :pin "1a2b3c4d5e")

;; Doom's packages are pinned to a specific commit and updated from release to
;; release. The `unpin!' macro allows you to unpin single packages...
;;(unpin! pinned-package)
;; ...or multiple packages
;;(unpin! pinned-package another-pinned-package)
;; ...Or *all* packages (NOT RECOMMENDED; will likely break things)
;;(unpin! t)
#+end_src
#+html: </details>

*** config.el
#+html: <details><summary>config.el</summary>
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-

;; DO NOT EDIT THIS FILE DIRECTLY
;; This is a file generated from a literate programing source file
;; You should make any changes there and regenerate it from Emacs org-mode
;; using org-babel-tangle (C-c C-v t)

;; Place your private configuration here! Remember, you do not need to run 'doom
;; sync' after modifying this file!

;; Some functionality uses this to identify you, e.g. GPG configuration, email
;; clients, file templates and snippets.
;; (setq user-full-name "John Doe"
;;      user-mail-address "john@doe.com")

;; Doom exposes five (optional) variables for controlling fonts in Doom. Here
;; are the three important ones:
;;
;; + `doom-font'
;; + `doom-variable-pitch-font'
;; + `doom-big-font' -- used for `doom-big-font-mode'; use this for
;;   presentations or streaming.
;;
;; They all accept either a font-spec, font string ("Input Mono-12"), or xlfd
;; font string. You generally only need these two:
;; (setq doom-font (font-spec :family "monospace" :size 12 :weight 'semi-light)
;;       doom-variable-pitch-font (font-spec :family "sans" :size 13))

;; There are two ways to load a theme. Both assume the theme is installed and
;; available. You can either set `doom-theme' or manually load a theme with the
;; `load-theme' function. This is the default:
;; (setq doom-theme 'doom-one)

;; If you use `org' and don't want your org files in the default location below,
;; change `org-directory'. It must be set before org loads!
;; (setq org-directory "~/org/")

;; This determines the style of line numbers in effect. If set to `nil', line
;; numbers are disabled. For relative line numbers, set this to `relative'.
;; (setq display-line-numbers-type t)

;; Here are some additional functions/macros that could help you configure Doom:
;;
;; - `load!' for loading external *.el files relative to this one
;; - `use-package!' for configuring packages
;; - `after!' for running code after a package has loaded
;; - `add-load-path!' for adding directories to the `load-path', relative to
;;   this file. Emacs searches the `load-path' when you load packages with
;;   `require' or `use-package'.
;; - `map!' for binding new keys
;;
;; To get information about any of these functions/macros, move the cursor over
;; the highlighted symbol at press 'K' (non-evil users must press 'C-c c k').
;; This will open documentation for it, including demos of how they are used.
;;
;; You can also try 'gd' (or 'C-c c d') to jump to their definition and see how
;; they are implemented.
#+end_src
#+html: </details>

** .zshrc
#+begin_src shell :tangle ~/.zshrc
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

#+end_src
** .bashrc
#+begin_src shell :tangle ~/.bashrc
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

#+end_src
** autostart.sh
#+begin_src shell :mkdirp yes :tangle ~/.config/autostart.sh
#!/bin/sh
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

#+end_src
** alacritty.toml
#+begin_src toml :tangle ~/.config/alacritty/alacritty.toml :mkdirp yes
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

#+end_src
* Package Management
** Arch and AUR Packages
*** Yay
**** Prerequisites
#+begin_src conf :tangle pkg-list.txt
git
base-devel
#+end_src

**** Installation
General Package Management is done via [[https://github.com/Jguer/yay][Yay]].
~update.sh~ will install it if needed.
#+begin_src shell :tangle update.sh
command_name="yay"

if ! command -v "$command_name" &> /dev/null; then
    echo "Installing $command_name ..."
    git clone https://aur.archlinux.org/yay.git /tmp/yay
    cd /tmp/yay
    makepkg -si
fi
#+end_src
after installation add yay to the packages list to ensure it doesn't delete itself
#+begin_src conf :tangle pkg-list.txt
yay
#+end_src
*** Package Installation
remove all packages not in ~pkg-list.txt~
#+begin_src shell :tangle update.sh
# Get list of installed packages
INSTALLED_PACKAGES=$(pacman -Qqe)

# Read the list of packages to keep from the file
KEEP_LIST=$(cat "pkg-list.txt")

# Loop through installed packages
for PACKAGE in $INSTALLED_PACKAGES; do
    # Check if the package is not in the keep list
    if ! echo "$KEEP_LIST" | grep -q "^$PACKAGE$"; then
        echo "Removing package: $PACKAGE"
        # Uncomment the following line to actually remove the package
        yay -Rns --noconfirm "$PACKAGE"
    fi
done
#+end_src
and install the packages specified in ~pkg-list.txt~
#+begin_src shell :tangle update.sh
yay -S --needed `grep -v '^#' pkg-list.txt`
#+end_src

* Base System
** Arch Linux
the following packages are required for basic operation and should never be deleted
#+begin_src conf :tangle pkg-list.txt
amd-ucode
base
efibootmgr
grub
linux-zen
linux-lts
linux-firmware
lvm2
sudo
#+end_src

** Network Manager
*** Installation
This config uses the [[https://wiki.archlinux.org/title/NetworkManager][NetworkManager]]
#+begin_src conf :tangle pkg-list.txt
networkmanager
#+end_src
after being installed it also needs to be enabled
#+begin_src shell :tangle update.sh
systemd_service="NetworkManager"
if ! systemctl is-enabled --quiet "$systemd_service"; then
    echo "Enabling $systemd_service"
    sudo systemctl enable "$systemd_service"
    sudo systemctl start "$systemd_service"
fi
#+end_src
*** TODO Networks

** [[https://wiki.archlinux.org/title/Man_page][Man Pages]] and [[https://wiki.archlinux.org/title/GNU#Texinfo][Texinfo]]
#+begin_src conf :tangle pkg-list.txt
man-db
man-pages
texinfo
#+end_src
** Build Tools
#+begin_src conf :tangle pkg-list.txt
cmake
make
#+end_src
** System Locale
#+begin_src conf :tangle "/sudo::/etc/locale.conf"
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

LANG=en_US.UTF-8
LC_CTYPE=de_DE.UTF-8
LC_NUMERIC=de_DE.UTF-8
LC_TIME=de_DE.UTF-8
LC_COLLATE=en_US.UTF-8
LC_MONETARY=de_DE.UTF-8
LC_MESSAGES=en_US.UTF-8
LC_PAPER=de_DE.UTF-8
LC_NAME=en_US.UTF-8
LC_ADDRESS=de_DE.UTF-8
LC_TELEPHONE=de_DE.UTF-8
LC_MEASUREMENTS=de_DE.UTF-8
LC_IDENTIFICATION=en_US.UTF-8
LC_ALL=
#+end_src
** Keyboard Layout
*** vconsole
#+begin_src conf :tangle "/sudo::/etc/vconsole.conf"
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

KEYMAP=de-latin1
#+end_src
*** Xorg
#+begin_src shell :tangle update.sh
localectl set-x11-keymap --no-convert de
#+end_src
* Desktop Environments and Window Manager
** [[https://wiki.archlinux.org/title/LightDM][LightDM]]
install the required packages
#+begin_src conf :tangle pkg-list.txt
lightdm
lightdm-gtk-greeter
#+end_src
and enable the systemd service
#+begin_src shell :tangle update.sh
systemd_service="lightdm"
if ! systemctl is-enabled --quiet "$systemd_service"; then
    echo "Enabling $systemd_service"
    sudo systemctl enable "$systemd_service"
fi
#+end_src

** GNOME
[[https://wiki.archlinux.org/title/GNOME][GNOME]] is installed as a fallback in case the main Window Manager breaks
#+begin_src conf :tangle pkg-list.txt
gnome
#+end_src
*** TODO GNOME programs
#+begin_src conf :tangle pkg-list.txt
baobab
epiphany
evince
gdm
gnome-backgrounds
gnome-calculator
gnome-calendar
gnome-characters
gnome-clocks
gnome-color-manager
gnome-connections
gnome-console
gnome-contacts
gnome-control-center
gnome-disk-utility
gnome-font-viewer
gnome-keyring
gnome-logs
gnome-maps
gnome-menus
gnome-music
gnome-remote-desktop
gnome-session
gnome-settings-daemon
gnome-shell
gnome-shell-extensions
gnome-software
gnome-system-monitor
gnome-text-editor
gnome-tour
gnome-user-docs
gnome-user-share
gnome-weather
grilo-plugins
gvfs
gvfs-afc
gvfs-goa
gvfs-google
gvfs-gphoto2
gvfs-mtp
gvfs-nfs
gvfs-smb
loupe
malcontent
nautilus
orca
ripgrep
rygel
simple-scan
snapshot
sushi
tecla
totem
tracker3-miners
xdg-desktop-portal-gnome
xdg-user-dirs-gtk
yelp
#+end_src
** [[https://qtile.org/][Qtile]]
(Almost) all configuration is done via the ~config.py~ file
*** config.py Literate File Header
#+begin_src python :mkdirp yes :tangle ~/.config/qtile/config.py
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

#+end_src
*** Installation
#+begin_src conf :tangle pkg-list.txt
qtile
#+end_src
*** Import Qtile Dependencies
#+begin_src python :mkdirp yes :tangle ~/.config/qtile/config.py
from libqtile import layout, bar, widget, hook
from libqtile.config import Key, Drag, Click, Group, Screen, ScratchPad, DropDown
from libqtile.command import lazy
#+end_src
*** Defines
Defines are stored in a separate ~defines.py~ file
**** defines.py Literate File Header
#+begin_src python :mkdirp yes :tangle ~/.config/qtile/defines.py
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

#+end_src
**** Terminal
Install [[https://alacritty.org/][Alacritty]]
#+begin_src conf :tangle pkg-list.txt
alacritty
#+end_src
and set it as default
#+begin_src python :tangle ~/.config/qtile/defines.py :mkdirp yes
term = 'alacritty'
#+end_src
**** Main/Mod Key
This config uses the "Master" or "Windows" Key as Main/Mod Key
#+begin_src python :tangle ~/.config/qtile/defines.py :mkdirp yes
mod = 'mod4'
#+end_src

*** Visual
**** Colors
Colors are set in the [[Theming]] section of this config
**** Border Width
#+begin_src python :tangle ~/.config/qtile/defines.py :mkdirp yes
border_width = 2
#+end_src
**** Window Margin
#+begin_src python :tangle ~/.config/qtile/defines.py :mkdirp yes
window_margin = 5
#+end_src
**** Floats kept above
Keep floating windows above others
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
floats_kept_above = True
#+end_src
**** Automatic Full Screen
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
auto_fullscreen = True
#+end_src
**** Automaitc Minimization
If things like steam games want to auto-minimize themselves when losing focus, should we respect this or not?
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
auto_minimize = True
#+end_src
**** _NET_ACTIVATE_WINDOW Behavior
Behavior of the _NET_ACTIVATE_WINDOW message sent by applications
- urgent: urgent flag is set for the window
- focus: automatically focus the window
- smart: automatically focus if the window is in the current group
- never: never automatically focus any window that requests
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
focus_on_window_activation = 'smart'
#+end_src

**** Widget Defaults
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
from chassis_type import ChassisType, chassis_type
from defines import base_color
widget_defaults = dict(
    background=base_color,
    font='UbuntuMono Nerd Font',
    fontsize=18,
    padding=1 if chassis_type == ChassisType.LAPTOP else 5,
)
extension_defaults = widget_defaults.copy()
#+end_src
**** Bar Sizes and Heights
#+begin_src python :tangle ~/.config/qtile/defines.py :mkdirp yes
from chassis_type import ChassisType, chassis_type
main_bar_fontsize=22
main_bar_height=24 if chassis_type == ChassisType.LAPTOP else 28
secondary_bar_height=24
secondary_bar_fontsize=18
#+end_src
*** Compositor
[[https://github.com/yshui/picom][picom]] is used to enable window composition, transparency, etc.
**** Installation
#+begin_src shell :tangle pkg-list.txt
picom
#+end_src
**** Configuration
#+begin_src conf :tangle ~/.config/picom/picom.conf :mkdirp yes
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

#+end_src
***** Shadows
disable shadow
#+begin_src conf :tangle ~/.config/picom/picom.conf :mkdirp yes
shadow = false;
#+end_src
***** Rounded Corners
exclude Dock and Desktop from corner rounding
#+begin_src conf :tangle ~/.config/picom/picom.conf :mkdirp yes
rounded-corners-exclude = [
  "window_type = 'dock'",
  "window_type = 'desktop'"
]
#+end_src

**** Add to Autostart
#+begin_src shell :tangle ~/.autostart.sh
picom &
#+end_src

*** Chassis Type Detection
Needed to load correct settings for given hardware (laptop/desktop)
**** chassis_type.py Literate File Header
#+begin_src python :mkdirp yes :tangle ~/.config/qtile/chassis_type.py
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

#+end_src
**** Enum
#+begin_src python :tangle ~/.config/qtile/chassis_type.py :mkdirp yes
from enum import Enum
import subprocess

class ChassisType(Enum):
    DESKTOP = 0
    LAPTOP = 1
#+end_src
**** Detection Function
#+begin_src python :mkdirp yes :tangle ~/.config/qtile/chassis_type.py
def detect_chassis_type() -> ChassisType:
    try:
        output = subprocess.check_output(["hostnamectl", "status"], universal_newlines=True)
    except subprocess.CalledProcessError as e:
        print("Error running hostnamectl:", e)
        exit(1)
    return ChassisType.LAPTOP if "Chassis: laptop" in output else ChassisType.DESKTOP

chassis_type = detect_chassis_type()
#+end_src
*** Mouse Settings
**** Follow Mouse Focus
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
follow_mouse_focus = True
#+end_src
**** Bring to Front with Click
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
bring_front_click = True
#+end_src
**** Warp Cursor
Cursor should not jump to the window selected via keyboard
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
cursor_warp = False
#+end_src
*** Autostart
#+begin_src python :mkdirp yes :tangle ~/.config/qtile/config.py
import os

@hook.subscribe.startup_once
def autostart():
    home = os.path.expanduser('~/.config/autostart.sh')
    subprocess.call(['sh', home])
#+end_src
*** Custom Microphone Widgets
Based on the [[https://docs.qtile.org/en/stable/manual/ref/widgets.html#volume][Volume]] widget.
It requires some packages to be installed
#+begin_src conf :tangle pkg-list.txt
python-psutil
alsa-utils
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
import subprocess
import psutil
import re

re_vol = re.compile(r'\[(\d?\d?\d?)%\]')
BUTTON_MUTE = 1
class Microphone(widget.base._TextBox):
    """
    Custom Microphone widget
    """
    orientations = widget.base.ORIENTATION_HORIZONTAL
    defaults = [
        ("cardid", None, "Card Id"),
        ("device", "default", "Device Name"),
        ("channel", "Capture", "Channel"),
        ("padding", 3, "Padding left and right. Calculated if None."),
        ("update_interval", 0.2, "Update time in seconds."),
        ("theme_path", None, "Path of the icons"),
        ("emoji", False, "Use emoji to display volume states, only if ``theme_path`` is not set."
                         "The specified font needs to contain the correct unicode characters."),
        ("mute_command", None, "Mute command"),
        ("volume_app", None, "App to control volume"),
        ("volume_up_command", None, "Volume up command"),
        ("volume_down_command", None, "Volume down command"),
        ("get_volume_command", None, "Command to get the current volume"),
        ("step", 2, "Volume change for up an down commands in percentage."
                    "Only used if ``volume_up_command`` and ``volume_down_command`` are not set.")
    ]

    def __init__(self, **config):
        widget.base._TextBox.__init__(self, '0', width=bar.CALCULATED, **config)
        self.add_defaults(Microphone.defaults)
        if self.theme_path:
            self.length_type = bar.STATIC
            self.length = 0
        self.surfaces = {}
        self.volume = None

    def timer_setup(self):
        self.timeout_add(self.update_interval, self.update)
        if self.theme_path:
            self.setup_images()

    def create_amixer_command(self, *args):
        cmd = ['amixer']
        cmd.extend([x for x in args])
        return cmd

    def button_press(self, x, y, button):
        if button == BUTTON_MUTE:
            if self.mute_command is not None:
                subprocess.call(self.mute_command, shell=True)
            else:
                subprocess.call(self.create_amixer_command('-q',
                                                           'sset',
                                                           self.channel,
                                                           'toggle'))
        self.draw()

    def update(self):
        vol = self.get_volume()
        if vol != self.volume:
            self.volume = vol
            # Update the underlying canvas size before actually attempting
            # to figure out how big it is and draw it.
            self._update_drawer()
            self.bar.draw()
        self.timeout_add(self.update_interval, self.update)

    def _update_drawer(self):
        if self.emoji:
            if self.volume > 0:
                self.text = ''
            elif self.volume <= 0:
                self.text = ''
        else:
            if self.volume == -1:
                self.text = 'M'
            else:
                self.text = '{}%'.format(self.volume)
    def get_volume(self):
        try:
            get_volume_cmd = self.create_amixer_command('sget',
                                                        self.channel)

            if self.get_volume_command:
                get_volume_cmd = self.get_volume_command

            mixer_out = self.call_process(get_volume_cmd)
        except subprocess.CalledProcessError:
            return -1

        if '[off]' in mixer_out:
            return -1

        volgroups = re_vol.search(mixer_out)
        if volgroups:
            return int(volgroups.groups()[0])
        else:
            # this shouldn't happen
            return -1

    def draw(self):
        if self.theme_path:
            self.drawer.draw(offsetx=self.offset, width=self.length)
        else:
            widget.base._TextBox.draw(self)

    def cmd_mute(self):
        # Emulate button press.
        self.button_press(0, 0, BUTTON_MUTE)
#+end_src
*** Widget Groups
To simplify the configuration of the [[Bars]] widgets are grouped
**** Imports
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
from libqtile import widget
from defines import term
from defines import focus_color, light_foreground_color, dark_foreground_color, background_color0, background_color8, base_color
from defines import red_color, light_red_color, green_color, light_green_color, orange_color, yellow_color, light_yellow_color, blue_color, purple_color, light_purple_color, magenta_color, cyan_color
#+end_src
**** Workspace Status
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
def workspace_status_widgets(size, fontsize):
    return [
        widget.CurrentLayoutIcon(
            scale = 0.9,
        ),
        widget.TextBox(
            text=' ',
            foreground=light_foreground_color,
            fontsize=fontsize,
            background=blue_color
        ),
        widget.GroupBox(
            fontsize=fontsize,
            rounded=False,
            disable_drag=True,
            active=light_foreground_color,
            inactive=dark_foreground_color,
            highlight_method='block',
            highlight_color=red_color,
            other_screen_border = light_purple_color,
            other_current_screen_border = purple_color,
            this_current_screen_border = blue_color,
            this_screen_border = blue_color,
            urgent_alert_method='block',
            urgent_border = red_color,
        ),
        widget.WindowName(fontsize=fontsize)
    ]
#+end_src
**** Audio
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
def audio_widgets(size, fontsize):
    return[
        widget.Volume(
            foreground=light_foreground_color,
            background=blue_color,
            emoji=True,
            fontsize=fontsize,
            ),
        widget.Volume(
            foreground=light_foreground_color,
            background=blue_color,
            fontsize=fontsize,
            padding=0
            ),
        Microphone(
            foreground=light_foreground_color,
            background=blue_color,
            emoji=True,
            fontsize=fontsize,
        ),
        Microphone(
            foreground=light_foreground_color,
            background=blue_color,
            fontsize=fontsize,
            padding=0
        )
    ]
#+end_src
**** System Widgets
These change depending on [[Chassis Type Detection][Chassis Type
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
def system_widgets(size,fontsize):
    sys_widgets = []
    # first widget is battery for laptop and cpu temp otherwise
    if chassis_type == ChassisType.LAPTOP:
        sys_widgets.append(
            widget.Battery(
                foreground=light_foreground_color,
                background=orange_color,
                fontsize=fontsize,
                update_interval=1,
                format="{char} {percent:2.0%}",
                low_percentage=0.2,
                notify_below=True,
                low_foreground=red_color,
                )
        )
    else:
        sys_widgets.extend([
            widget.TextBox(
                text='󰈸',
                foreground=light_foreground_color,
                background=orange_color,
                fontsize=fontsize+6
                ),
            widget.ThermalSensor(
                foreground=light_foreground_color,
                background=orange_color,
                fontsize=fontsize,
                tag_sensor='Tctl',
                )
        ])
    sys_widgets.extend([
        widget.TextBox(
            text=' ',
            foreground=light_foreground_color,
            background=green_color,
            fontsize=fontsize
            ),
        widget.CPU(
            foreground=light_foreground_color,
            background=green_color,
            fontsize=fontsize,
            format='{load_percent}%' if chassis_type == ChassisType.LAPTOP else'{load_percent}% @ {freq_current}GHz',
            ),
        widget.TextBox(
            text='',
            foreground=light_foreground_color,
            background=yellow_color,
            fontsize=fontsize
            ),
        widget.Memory(
            foreground=light_foreground_color,
            background=yellow_color,
            fontsize=fontsize,
            format='{MemUsed: 2.1f}GB|{SwapUsed: 2.1f}GB' if chassis_type == ChassisType.LAPTOP else'{MemUsed: 2.1f}GB({MemPercent: 2.0f}%) | {SwapUsed: 2.1f}GB({SwapPercent: 2.0f}%)',
            measure_mem = 'G',
            measure_swap = 'G',
            ),
        widget.TextBox(
            text='󰈀 ',
            foreground=light_foreground_color,
            background=blue_color,
            fontsize=fontsize
            ),
        widget.Net(
            background=blue_color,
            foreground=light_foreground_color,
            fontsize=fontsize,
            prefix='M',
            format='{down:6.2f}{down_suffix}↓{up:6.2f}{up_suffix}↑',
            )
        ]
    )
    return sys_widgets
#+end_src
**** Datetime
These require the [[https://www.keshikan.net/fonts-e.html][DSEG Font]]
#+begin_src conf :tangle pkg-list.txt
ttf-dseg
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
def datetime_widgets(size,fontsize):
    return [
        widget.TextBox(
            text='󰸗 ',
            foreground=light_foreground_color,
            background=purple_color,
            fontsize=fontsize
            ),
        widget.Clock(
            foreground=light_foreground_color,
            background=purple_color,
            fontsize=fontsize,
            format='%Y-%m-%d'
            ),
        widget.Clock(
            font='dseg7 classic bold',
            fontsize=16,
            format='%H:%M'
            ),
    ]
#+end_src
*** Bars
**** Imports
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
from libqtile import widget, bar
from defines import base_color, blue_color
from defines import main_bar_fontsize, main_bar_height, secondary_bar_height, secondary_bar_fontsize
#+end_src
**** Main Bar
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
main_bar = bar.Bar([
    *workspace_status_widgets(main_bar_height,main_bar_fontsize),
    widget.Systray(fontsize=main_bar_fontsize),
    *audio_widgets(main_bar_height,main_bar_fontsize),
    *system_widgets(main_bar_height,main_bar_fontsize),
    *datetime_widgets(main_bar_height,main_bar_fontsize),
],main_bar_height)
#+end_src
**** Left Screen Bars
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
left_bar = bar.Bar([
    *workspace_status_widgets(secondary_bar_height,secondary_bar_fontsize),
    *audio_widgets(secondary_bar_height,secondary_bar_fontsize),
    *datetime_widgets(secondary_bar_height,secondary_bar_fontsize)
],secondary_bar_height)
#+end_src
**** Secondary Bar
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
secondary_bar = bar.Bar([
    *workspace_status_widgets(secondary_bar_height,secondary_bar_fontsize),
    *audio_widgets(secondary_bar_height,secondary_bar_fontsize),
    *datetime_widgets(secondary_bar_height,secondary_bar_fontsize)
],secondary_bar_height)
#+end_src

**** Top Screen Bar
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
top_bar = bar.Bar([
    *workspace_status_widgets(secondary_bar_height,secondary_bar_fontsize),
    *audio_widgets(secondary_bar_height,secondary_bar_fontsize),
    *datetime_widgets(secondary_bar_height,secondary_bar_fontsize)
],secondary_bar_height)
#+end_src

*** Screens
**** Desktop Screen Detection
On my desktop setup I have to special screens that should be detected
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
main_screen_res = [3440,1440]
top_screen_res = [1440,900]
#+end_src
**** Getting Screen Information
***** Dependencies
#+begin_src conf :tangle pkg-list.txt
xorg-xrandr
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
import subprocess
import re
import numpy as np
from libqtile.config import Screen
#+end_src
***** Reading the Information
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
cmd = ['xrandr']
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
resolution_string, junk = p.communicate()
p.stdout.close()
screen_resolutions = [np.array(screen_res.split('x')).astype(int) for screen_res in re.findall('[0-9]+x[0-9]+(?=[^\\\\n]*\*)',str(resolution_string))]
number_of_screens = len(screen_resolutions)
max_width = max(screen_resolutions, key=lambda res: res[0])[0]
#+end_src
**** Setting the Screens
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
screens = []
defined_main_window = False
for width, height in screen_resolutions:
    if width == main_screen_res[0] and height == main_screen_res[1]:
        screens.append(Screen(top=main_bar, wallpaper= "~/Pictures/Wallpapers/gruvbox-like.jpg", wallpaper_mode="fill"))
        defined_main_window = True
    elif width == top_screen_res[0] and height == top_screen_res[1]:
        screens.append(Screen(bottom=top_bar, wallpaper="~/Pictures/Wallpapers/wallpaperflare.com_wallpaper.jpg", wallpaper_mode="fill"))
    elif width < height:
        screens.append(Screen(top=left_bar, wallpaper="~/Pictures/Wallpapers/gruvbox-like-left.jpg", wallpaper_mode="fill"))
    elif width == max_width and not defined_main_window:
        screens.append(Screen(top=main_bar, wallpaper= "~/Pictures/Wallpapers/gruvbox-like.jpg", wallpaper_mode="fill"))
        defined_main_window = True
    else:
        screens.append(Screen(top=secondary_bar, wallpaper= "~/Pictures/Wallpapers/gruvbox-like.jpg", wallpaper_mode="fill"))
#+end_src
**** Automatically Reconfigure Screens
Controls whether or not to automatically reconfigure screens when there are changes in randr output configuration.
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
reconfigure_screens = True
#+end_src
*** Layouts
**** Basic Layouts
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
from libqtile import layout
from defines import focus_color, border_width, window_margin

layouts = [
    layout.MonadTall(
        align=1,
        border_focus = focus_color,
        border_width =  border_width,
        margin=window_margin,
        new_client_position = 'after_current',
          ),
    layout.Floating(
        border_focus = focus_color,
        border_width =  border_width,
        margin=window_margin,
    ),
    layout.Max(),
    layout.MonadWide(
        border_focus = focus_color,
        border_width =  border_width,
        new_client_position = 'after_current',
        margin=window_margin,
    ),
    layout.Columns(
        border_focus = focus_color,
        border_width = border_width,
        num_columns = 3,
        margin = window_margin,
        )
]
#+end_src
**** Floating Layout
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
from libqtile import layout
from libqtile.config import Match
from defines import focus_color, border_width

floating_layout = layout.Floating(
    border_focus = focus_color,
    border_width =  border_width,
    float_rules=[
    # Run the utility of `xprop` to see the wm class and name of an X client.
    ,*layout.Floating.default_float_rules,
    Match(wm_class='confirmreset'),  # gitk
    Match(wm_class='makebranch'),  # gitk
    Match(wm_class='maketag'),  # gitk
    Match(title='branchdialog'),  # gitk
    Match(title='pinentry'),  # GPG key password entry
    Match(wm_class='ssh-askpass'),  # ssh-askpass
    Match(wm_class='sun-awt-X11-XWindowPeer'), #matlab
    Match(wm_class='sun-awt-X11-XDialogPeer'), #matlab
])
#+end_src
***** Enable Dragging
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
from libqtile.config import Drag, Click
from libqtile.command import lazy
from defines import mod
mouse = [
    Drag([mod], "Button1", lazy.window.set_position_floating(),
         start=lazy.window.get_position()),
    Drag([mod], "Button3", lazy.window.set_size_floating(),
         start=lazy.window.get_size()),
    Click([mod], "Button2", lazy.window.bring_to_front())
]
#+end_src
*** Groups
**** Dependencies
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
from libqtile.config import Group, ScratchPad, DropDown, Key, Match
from libqtile.command import lazy

import re

from defines import mod,term
#+end_src
**** Main Groups
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
main_groups_info = [(" ","Org",'o',{'layout': 'monadtall'}),
               (" ","Home", 'h',{'layout': 'monadtall'}),
               (" ","Browser", 'f',{'layout': 'monadtall'}),
               ("  ","Mail", 'm',{'layout': 'monadtall', 'matches':[Match(wm_class="Mail")]}),
               (" ","Coding", 'c',{'layout': 'monadtall', 'matches' : [Match(wm_class="code")]}),
               (" ","Documents", 'l',{'layout': 'monadtall'}),
               ("󰝚 ","Music", 'u',{'layout': 'monadtall', 'matches' : [Match(wm_class="spotify")]}),
               (" ","Video", 'v',{'layout': 'monadtall', 'matches' : [Match(wm_class="vlc")]}),
               ("󰙯 ","VideoChat", 'z',{'layout': 'monadtall', 'matches':[Match(wm_class="discord")]}),
               ("一","etc1", '1', {'layout': 'monadtall'}),
               ("二","etc2", '2', {'layout': 'monadtall'}),
               ("三","etc3", '3', {'layout': 'monadtall'}),
               ("四","etc4", '4', {'layout': 'monadtall'})]

groups = [Group(icon, **kwargs) for icon, name, key, kwargs in main_groups_info]
#+end_src
**** DropDown Groups
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
dropdown_groups_info = []
#+end_src
***** [[https://christian.amsuess.com/tools/arandr/][ARandR]]
#+begin_src conf :tangle pkg-list.txt
arandr
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
name = 'ARandR'
dropdown_groups_info.append((name,
                           DropDown(name,
                                    'arandr',
                                    height = 0.5,
                                    width = 0.8,
                                    x = 0.1, # (1-0.8)/2
                                    on_focus_lost_hide=True,
                                    opacity=1,
                                    match = Match(wm_class='arandr')
                                    ),
                           [mod],'p'))
#+end_src
***** DropDown Terminal
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
name = 'Terminal'
dropdown_groups_info.append((name,
                           DropDown(name,
                                    term,
                                    height = 0.5,
                                    width = 0.8,
                                    x = .1
                                    ),
                           ['mod1','control'],'space'))
#+end_src
***** [[https://htop.dev/][htop]]
#+begin_src conf :tangle pkg-list.txt
htop
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
name = 'htop'
dropdown_groups_info.append((name,
                           DropDown(name,
                                    term + ' -e htop'
                                    ),
                           ['control','shift'],'Escape'))
#+end_src
***** Audio Settings
#+begin_src conf :tangle pkg-list.txt
pavucontrol
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
name = 'Audio Settings'
dropdown_groups_info.append((name,
                           DropDown(name,
                                    'pavucontrol'
                                    ),
                           ['mod1','control'],'a'))
#+end_src
***** DropDown [[https://wiki.archlinux.org/title/PCManFM][PCManFM]]
#+begin_src conf :tangle pkg-list.txt
pcmanfm-gtk3
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
name = 'filemanager'
dropdown_groups_info.append((name,
                           DropDown(name,
                                    'pcmanfm',
                                    on_focus_lost_hide=False
                                    ),
                           ['mod1','control'],'e'))
#+end_src
***** [[https://bitwarden.com/][Bitwarden]]
#+begin_src conf :tangle pkg-list.txt
bitwarden
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
name = 'Bitwarden'
dropdown_groups_info.append((name,
                           DropDown(name,
                                    'bitwarden-desktop',
                                    on_focus_lost_hide=False,
                                    match = Match(wm_class='bitwarden')
                                    ),
                           ['mod1','control'],'b'))
#+end_src
***** WhatsApp
#+begin_src conf :tangle pkg-list.txt
whatsapp-for-linux
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
name = 'WhatsApp'
dropdown_groups_info.append((name,
                           DropDown(name,
                                    'whatsapp-for-linux',
                                    height = 0.5,
                                    width = 0.8,
                                    x = .1,
                                    on_focus_lost_hide=False,
                                    opacity=1
                                    ),
                           ['mod1','control'],'w'))
#+end_src

***** [[https://www.signal.org/][Signal]]
#+begin_src conf :tangle pkg-list.txt
signal-desktop
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
name = 'Signal'
dropdown_groups_info.append((name,
                           DropDown(name,
                                    'signal-desktop',
                                    height = 0.5,
                                    width = 0.8,
                                    x = .1,
                                    on_focus_lost_hide=False,
                                    opacity = 1,
                                    match = Match(wm_class='signal')
                                    ),
                           ['mod1','control'],'i'))
#+end_src
***** [[https://qalculate.github.io/][Qalculate!]]
#+begin_src conf :tangle pkg-list.txt
qalculate-gtk
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
name = 'Qalculate!'
dropdown_groups_info.append((name,
                           DropDown(name,
                                    'qalculate-gtk',
                                    height = 0.5,
                                    width = 0.5,
                                    x = .25,
                                    on_focus_lost_hide=True,
                                    opacity = 1
                                    ),
                           ['mod1','control'],'q'))
#+end_src
***** [[https://slack.com][Slack]]
#+begin_src conf :tangle pkg-list.txt
slack-desktop
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
name = 'Slack'
dropdown_groups_info.append((name,
                           DropDown(name,
                                    'slack',
                                    height = 0.5,
                                    width = 0.8,
                                    x = 0.1,
                                    on_focus_lost_hide=False,
                                    opacity=1
                                    ),
                           ['mod1','control'],'s'))
#+end_src
***** [[https://www.deepl.com/translator][DeepL]]
DeepL is being used inside a [[https://surf.suckless.org/][surf]] DropDown
#+begin_src conf :tangle pkg-list.txt
surf
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
name = 'DeepL'
dropdown_groups_info.append((name,
                           DropDown(name,
                                    'surf deepl.com',
                                    height = 0.5,
                                    width = 0.8,
                                    x = 0.1,
                                    on_focus_lost_hide=True,
                                    opacity=1
                                    ),
                           ['mod1','control'],'d'))
#+end_src
***** [[https://telegram.org/][Telegram]]
#+begin_src conf :tangle pkg-list.txt
telegram-desktop
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
name = 'Telegram'
dropdown_groups_info.append((name,
                           DropDown(name,
                                    'telegram-desktop',
                                    height = 0.5,
                                    width = 0.8,
                                    x = 0.1,
                                    on_focus_lost_hide=False,
                                    opacity=1,
                                    match = Match(wm_class='telegram-desktop')
                                    ),
                           ['mod1','control'],'t'))
#+end_src
***** Org Agenda
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
name = 'Org Agenda'
dropdown_groups_info.append((name,
                           DropDown(name,
                                    'emacsclient -c -e \'(org-agenda-list)\'',
                                    height = 0.5,
                                    width = 0.8,
                                    x = 0.1,
                                    on_focus_lost_hide=True,
                                    opacity=1,
                                    match = Match(wm_class='emacs')
                                    ),
                           ['mod1','control'],'k'))
#+end_src
***** Add ScratchPad to Groups
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
groups.append(ScratchPad("scratchpad",
   [dropdown for (name,dropdown,base_keys,key) in dropdown_groups_info]
        ))
#+end_src
**** Hotkeys
***** Main Group Hotkeys
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
try:
    _ = keys
except NameError:
    keys = []
for (icon,name,key, kwargs) in main_groups_info:
    keys.extend([
        Key(["mod1","control"], str(key), lazy.group[icon].toscreen(toggle=True),
            desc="Switch to group {}".format(name)),

        Key(['mod1','control', "shift"], str(key), lazy.window.togroup(icon),
            desc="move focused window to group {}".format(name)),
    ])
#+end_src
***** DropDown Group Hotkeys
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
try:
    _ = keys
except NameError:
    keys = []
for (name,dropdown,base_keys,key) in dropdown_groups_info:
    keys.extend([
Key(base_keys,key,lazy.group['scratchpad'].dropdown_toggle(name), desc=f'open the dropdown for {name}')
        ])
#+end_src
*** Keys
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
from libqtile.config import Key
from libqtile.command import lazy

from defines import mod, term
from chassis_type import ChassisType, chassis_type

try:
    _ = keys
except NameError:
    keys = []
#+end_src
**** Screen Lock
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod], "End" , lazy.spawn('dm-tool lock'),desc="locks session"),
    Key([], "Pause" , lazy.spawn('dm-tool lock'),desc="locks session")
])
#+end_src
**** Moving Focus
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod], "h", lazy.layout.left(),desc="move focus left"),
    Key([mod], "l", lazy.layout.right(),desc="move focus right"),
    Key([mod], "j", lazy.layout.down(),desc="move focus down"),
    Key([mod], "k", lazy.layout.up(),desc="move focus up"),
    Key([mod,"mod1"], "n", lazy.next_screen(),desc="move focus to next screen")
])
#+end_src
**** Moving Windows
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod, "shift"], "h", lazy.layout.swap_left(),desc="move focused window left"),
    Key([mod, "shift"], "l", lazy.layout.swap_right(),desc="move focused window right"),
    Key([mod, "shift"], "j", lazy.layout.shuffle_down(),desc="move focused window down"),
    Key([mod, "shift"], "k", lazy.layout.shuffle_up(),desc="move focused window up"),
])
#+end_src
**** Resize Windows
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod], "plus", lazy.layout.grow(),desc="increase window size"),
    Key([mod], "minus", lazy.layout.shrink(),desc="decrease window size"),
    Key([mod], "m", lazy.layout.maximize(),desc="maximize current window"),
    Key([mod], "space", lazy.window.toggle_fullscreen(),desc="toggle current window fullscreen"),
])
#+end_src
**** Toggle Layouts
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod], "Tab", lazy.next_layout(), desc="Toggle between layouts"),
])
#+end_src
**** Close Current Window
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod], "BackSpace", lazy.window.kill(), desc="Kill focused window"),
])
#+end_src
**** Qtile Meta Commands
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod, "control"], "r", lazy.restart(), desc="Restart qtile"),
    Key([mod, "control"], "q", lazy.shutdown(), desc="Shutdown qtile"),
])
#+end_src
**** Audio
#+begin_src conf :tangle pkg-list.txt
pulseaudio-ctl
alsa-utils
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([], 'XF86AudioRaiseVolume', lazy.spawn(f'pulseaudio-ctl up {5 if chassis_type == ChassisType.LAPTOP else 1}'), desc="increase speaker volume"),
    Key([], 'XF86AudioLowerVolume', lazy.spawn(f'pulseaudio-ctl down {5 if chassis_type == ChassisType.LAPTOP else 1}'), desc="decrease speaker volume"),
    Key([], 'XF86AudioMute', lazy.spawn('pulseaudio-ctl mute'), desc="toggle speaker mute"),
    Key(['control'], 'XF86AudioRaiseVolume', lazy.spawn(f'amixer set Capture {5 if chassis_type == ChassisType.LAPTOP else 1}%+'), desc="increase mic volume"),
    Key(['control'], 'XF86AudioLowerVolume', lazy.spawn(f'amixer set Capture {5 if chassis_type == ChassisType.LAPTOP else 1}%-'), desc="decrease mic volume"),
    Key(['control'], 'XF86AudioMute', lazy.spawn('amixer set Capture toggle'), desc="toggle mic mute"),
    Key([], 'XF86AudioMicMute', lazy.spawn('amixer set Capture toggle'), desc="toggle mic mute"),
])
#+end_src
***** Add User to Audio Group
#+begin_src shell :tangle update.sh
groupname="audio"

# Add the current user to the group if not already a member
if ! groups "$USER" | grep -q "\b$groupname\b"; then
    echo "Adding user $USER to group $groupname"
    sudo usermod -aG "$groupname" "$USER"
    if [ $? -eq 0 ]; then
        echo "User $USER added to group $groupname successfully."
    else
        echo "Failed to add user $USER to group $groupname."
    fi
fi
#+end_src
**** Media Playback
#+begin_src conf :tangle pkg-list.txt
playerctl
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([], 'XF86AudioNext', lazy.spawn('playerctl next')),
    Key([], 'XF86AudioPrev', lazy.spawn('playerctl previous')),
    Key([], 'XF86AudioPlay', lazy.spawn('playerctl play-pause')),
    Key([mod], 'Right', lazy.spawn('playerctl next')),
    Key([mod], 'Left', lazy.spawn('playerctl previous')),
    Key([mod], 'Down', lazy.spawn('playerctl play-pause')),
])
#+end_src
**** Monitor Backlight
#+begin_src conf :tangle pkg-list.txt
acpilight
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([], 'XF86MonBrightnessUp', lazy.spawn('xbacklight -inc 5')),
    Key([], 'XF86MonBrightnessDown', lazy.spawn('xbacklight -dec 5')),
])
#+end_src
***** Add User to Video Group
#+begin_src shell :tangle update.sh
groupname="video"

# Add the current user to the group if not already a member
if ! groups "$USER" | grep -q "\b$groupname\b"; then
    echo "Adding user $USER to group $groupname"
    sudo usermod -aG "$groupname" "$USER"
    if [ $? -eq 0 ]; then
        echo "User $USER added to group $groupname successfully."
    else
        echo "Failed to add user $USER to group $groupname."
    fi
fi
#+end_src
**** App Launch Hotkeys
***** Terminal
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod],"t", lazy.spawn(term), desc="Launch terminal"),
])
#+end_src
***** [[Firefox]]
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod],"f", lazy.spawn("firefox"),desc="Launch firefox"),
])
#+end_src
***** PCManFM
#+begin_src conf :tangle pkg-list.txt
pcmanfm-gtk3
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod],"e", lazy.spawn("pcmanfm"),desc="Launch pcmanfm"),
])
#+end_src
***** [[VSCode]]
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod],"c", lazy.spawn("code"),desc="Launch visual studio code"),
])
#+end_src
***** [[NeoVim]]
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod],"v", lazy.spawn(term + " -e nvim"),desc="Launch NeoVim"),
])
#+end_src
***** Screenshot Tool
#+begin_src conf :tangle pkg-list.txt
gscreenshot
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod, "shift"],"s", lazy.spawn('gscreenshot -s -o -f /tmp/screenshots'),desc="take a screenshot"),
])
#+end_src
***** [[Doom Emacs]]
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod], "o", lazy.spawn("emacsclient -c -a 'emacs'"), desc="Launch Emacs (Client)"),
])
#+end_src
***** App Launcher
#+begin_src conf :tangle pkg-list.txt
rofi
#+end_src
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
keys.extend([
    Key([mod],'Return',lazy.spawn("rofi -show drun -show-icons -modi drun"),desc="launch rofi (drun)"),
])
#+end_src
*** Misc
Miscelaneous settings from the [[https://docs.qtile.org/en/stable/manual/config/default.html][default config]]
**** Deactivate dgroups
dynamic group keys are not needed, because they are assigned manually
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
dgroups_key_binder = None
dgroups_app_rules = []  # type: List
#+end_src
**** Setting WM Name
Nobody really uses or cares about this string besides java UI toolkits;
you can see several discussions on the mailing lists, GitHub issues, and other WM documentation that suggest setting this string if your java app doesn't work correctly.
We may as well just lie and say that we're a working one by default.
We choose LG3D to maximize irony:
it is a 3D non-reparenting WM written in java that happens to be on java's whitelist.
#+begin_src python :tangle ~/.config/qtile/config.py :mkdirp yes
wmname = 'LG3D'
#+end_src
* Text Editors
** Doom Emacs
*** Installation
**** [[https://github.com/doomemacs/doomemacs#prerequisites][Prerequisites]]
#+begin_src conf :tangle pkg-list.txt
git
emacs
ripgrep
findutils
fd
#+end_src
**** Doom Installation
~update.sh~ will install Doom Emacs if needed
#+begin_src shell :tangle update.sh
if [ ! -d "/home/paul/.config/doom" ]; then
    echo "Installing Doom Emacs ..."
    git clone --depth 1 https://github.com/doomemacs/doomemacs /home/paul/.config/emacs
    /home/paul/.config/emacs/bin/doom install-devel
fi
#+end_src
**** add to PATH
#+begin_src shell :tangle ~/path.sh
export PATH=$PATH:~/.config/emacs/bin
#+end_src
*** Doom Modules
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/init.el
(doom! :input
       ;;bidi              ; (tfel ot) thgir etirw uoy gnipleh
       ;;chinese
       ;;japanese
       ;;layout            ; auie,ctsrnm is the superior home row

       :completion
       company           ; the ultimate code completion backend
       ;;helm              ; the *other* search engine for love and life
       ;;ido               ; the other *other* search engine...
       ;;ivy               ; a search engine for love and life
       vertico           ; the search engine of the future

       :ui
       ;;deft              ; notational velocity for Emacs
       doom              ; what makes DOOM look the way it does
       doom-dashboard    ; a nifty splash screen for Emacs
       doom-quit         ; DOOM quit-message prompts when you quit Emacs
       (emoji +unicode)  ; 🙂
       hl-todo           ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
       ;;hydra
       ;;indent-guides     ; highlighted indent columns
       ;;ligatures         ; ligatures and symbols to make your code pretty again
       ;;minimap           ; show a map of the code on the side
       modeline          ; snazzy, Atom-inspired modeline, plus API
       nav-flash         ; blink cursor line after big motions
       ;;neotree           ; a project drawer, like NERDTree for vim
       ophints           ; highlight the region an operation acts on
       (popup +defaults)   ; tame sudden yet inevitable temporary windows
       tabs              ; a tab bar for Emacs
       treemacs          ; a project drawer, like neotree but cooler
       unicode           ; extended unicode support for various languages
       (vc-gutter +pretty) ; vcs diff in the fringe
       vi-tilde-fringe   ; fringe tildes to mark beyond EOB
       ;;window-select     ; visually switch windows
       workspaces        ; tab emulation, persistence & separate workspaces
       ;;zen               ; distraction-free coding or writing

       :editor
       (evil +everywhere); come to the dark side, we have cookies
       file-templates    ; auto-snippets for empty files
       fold              ; (nigh) universal code folding
       ;;(format +onsave)  ; automated prettiness
       ;;god               ; run Emacs commands without modifier keys
       ;;lispy             ; vim for lisp, for people who don't like vim
       ;;multiple-cursors  ; editing in many places at once
       ;;objed             ; text object editing for the innocent
       ;;parinfer          ; turn lisp into python, sort of
       ;;rotate-text       ; cycle region at point between text candidates
       snippets          ; my elves. They type so I don't have to
       ;;word-wrap         ; soft wrapping with language-aware indent

       :emacs
       dired             ; making dired pretty [functional]
       electric          ; smarter, keyword-based electric-indent
       ;;ibuffer         ; interactive buffer management
       undo              ; persistent, smarter undo for your inevitable mistakes
       vc                ; version-control and Emacs, sitting in a tree

       :term
       ;;eshell            ; the elisp shell that works everywhere
       ;;shell             ; simple shell REPL for Emacs
       ;;term              ; basic terminal emulator for Emacs
       vterm             ; the best terminal emulation in Emacs

       :checkers
       syntax              ; tasing you for every semicolon you forget
       (spell +flyspell +everywhere) ; tasing you for misspelling mispelling
       grammar           ; tasing grammar mistake every you make

       :tools
       ;;ansible
       biblio           ; Writes a PhD for you (citation needed)
       ;;collab            ; buffers with friends
       (debugger +lsp)          ; FIXME stepping through code, to help you add bugs
       ;;direnv
       docker
       ;;editorconfig      ; let someone else argue about tabs vs spaces
       ;;ein               ; tame Jupyter notebooks with emacs
       (eval +overlay)     ; run code, run (also, repls)
       ;;gist              ; interacting with github gists
       lookup              ; navigate your code and its documentation
       lsp               ; M-x vscode
       magit             ; a git porcelain for Emacs
       ;;make              ; run make tasks from Emacs
       ;;pass              ; password manager for nerds
       pdf               ; pdf enhancements
       ;;prodigy           ; FIXME managing external services & code builders
       ;;rgb               ; creating color strings
       ;;taskrunner        ; taskrunner for all your projects
       ;;terraform         ; infrastructure as code
       ;;tmux              ; an API for interacting with tmux
       tree-sitter       ; syntax and parsing, sitting in a tree...
       ;;upload            ; map local to remote projects via ssh/ftp

       :os
       (:if IS-MAC macos)  ; improve compatibility with macOS
       ;;tty               ; improve the terminal Emacs experience

       :lang
       ;;agda              ; types of types of types of types...
       ;;beancount         ; mind the GAAP
       (cc +lsp +tree-sitter)         ; C > C++ == 1
       ;;clojure           ; java with a lisp
       ;;common-lisp       ; if you've seen one lisp, you've seen them all
       ;;coq               ; proofs-as-programs
       ;;crystal           ; ruby at the speed of c
       ;;csharp            ; unity, .NET, and mono shenanigans
       ;;data              ; config/data formats
       ;;(dart +flutter)   ; paint ui and not much else
       ;;dhall
       ;;elixir            ; erlang done right
       ;;elm               ; care for a cup of TEA?
       emacs-lisp        ; drown in parentheses
       ;;erlang            ; an elegant language for a more civilized age
       ;;ess               ; emacs speaks statistics
       ;;factor
       ;;faust             ; dsp, but you get to keep your soul
       ;;fortran           ; in FORTRAN, GOD is REAL (unless declared INTEGER)
       ;;fsharp            ; ML stands for Microsoft's Language
       ;;fstar             ; (dependent) types and (monadic) effects and Z3
       ;;gdscript          ; the language you waited for
       ;;(go +lsp)         ; the hipster dialect
       ;;(graphql +lsp)    ; Give queries a REST
       ;;(haskell +lsp)    ; a language that's lazier than I am
       ;;hy                ; readability of scheme w/ speed of python
       ;;idris             ; a language you can depend on
       json              ; At least it ain't XML
       ;;(java +lsp)       ; the poster child for carpal tunnel syndrome
       ;;javascript        ; all(hope(abandon(ye(who(enter(here))))))
       ;;julia             ; a better, faster MATLAB
       ;;kotlin            ; a better, slicker Java(Script)
       (latex +fold +latexmk +lsp)             ; writing papers in Emacs has never been so fun
       ;;lean              ; for folks with too much to prove
       ;;ledger            ; be audit you can be
       lua               ; one-based indices? one-based indices
       ;; markdown          ; writing docs for people to ignore
       ;;nim               ; python + lisp at the speed of c
       ;;nix               ; I hereby declare "nix geht mehr!"
       ;;ocaml             ; an objective camel
       (org +roam2 +dragndrop +pretty +present)               ; organize your plain life in plain text
       ;;php               ; perl's insecure younger brother
       ;;plantuml          ; diagrams for confusing people more
       ;;purescript        ; javascript, but functional
       (python +conda +lsp +pyright +pyenv +tree-sitter)            ; beautiful is better than ugly
       ;;qt                ; the 'cutest' gui framework ever
       ;;racket            ; a DSL for DSLs
       ;;raku              ; the artist formerly known as perl6
       ;;rest              ; Emacs as a REST client
       ;;rst               ; ReST in peace
       ;;(ruby +rails)     ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
       ;;(rust +lsp)       ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
       ;;scala             ; java, but good
       ;;(scheme +guile)   ; a fully conniving family of lisps
       sh                ; she sells {ba,z,fi}sh shells on the C xor
       ;;sml
       ;;solidity          ; do you need a blockchain? No.
       ;;swift             ; who asked for emoji variables?
       ;;terra             ; Earth and Moon in alignment for performance.
       ;;web               ; the tubes
       yaml              ; JSON, but readable
       ;;zig               ; C, but simpler

       :email
       ;;(mu4e +org +gmail)
       ;;notmuch
       ;;(wanderlust +gmail)

       :app
       calendar
       ;;emms
       ;;everywhere        ; *leave* Emacs!? You must be joking
       ;;irc               ; how neckbeards socialize
       ;;(rss +org)        ; emacs as an RSS reader
       ;;twitter           ; twitter client https://twitter.com/vnought

       :config
       ;; literate
       (default +bindings +smartparens))
#+end_src

*** General Configuration
**** User Information
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(setq user-full-name "Paul Lödige"
      user-mail-address "paul@gve-loedige.de")
#+end_src

**** Visual Settings
***** Font
install Ubuntu Mono
#+begin_src conf :tangle pkg-list.txt
ttf-ubuntu-font-family
ttf-ubuntu-mono-nerd
ttf-ubuntu-nerd
adobe-source-han-sans-jp-fonts
adobe-source-han-serif-jp-fonts
#+end_src
and activate it
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(setq doom-font (font-spec :family "Ubuntu Mono" :size 16)
      doom-variable-pitch-font (font-spec :family "Ubuntu" :size 14))
#+end_src

***** Line Numbering
having used Neovim for quiet some time I got used to relative line numbering for navigation.
Until I get used to the [[https://github.com/Greduan/emacs-theme-gruvbox][evil-snipe]] navigation I would like to keep them.
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(setq display-line-numbers-type 'relative)
#+end_src

**** TODO Authentication
Authentication information will be stored in a encrypted file that is part of my dotfiles
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(setq auth-sources
    '((:source "~/.authinfo.gpg")))
#+end_src
**** Start Daemon on Startup
#+begin_src shell :tangle ~/.config/autostart.sh
emacs --daemon &
#+end_src
**** Misc
***** Set Start of Week to Monday
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/init.el
(setq calendar-week-start-day 1)
#+end_src
*** Multilanguage Spellcheck
Enables use of multiple dictionaries. In my case German and English
install dependencies
#+begin_src conf :tangle pkg-list.txt
hunspell
hunspell-de
hunspell-en_us
#+end_src
and configure it
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(with-eval-after-load "ispell"
  (setq ispell-program-name "hunspell")
  (setq ispell-dictionary "en_US,de_DE")
  (ispell-set-spellchecker-params)
  (ispell-hunspell-add-multi-dic "en_US,de_DE"))
#+end_src

*** TODO LaTeX
install texlive
#+begin_src conf :tangle pkg-list.txt
biber
texlive-basic
texlive-bibtexextra
texlive-binextra
texlive-context
texlive-fontsextra
texlive-fontsrecommended
texlive-fontutils
texlive-formatsextra
texlive-games
texlive-humanities
texlive-langarabic
texlive-langchinese
texlive-langcjk
texlive-langcyrillic
texlive-langczechslovak
texlive-langenglish
texlive-langeuropean
texlive-langfrench
texlive-langgerman
texlive-langgreek
texlive-langitalian
texlive-langjapanese
texlive-langkorean
texlive-langother
texlive-langpolish
texlive-langportuguese
texlive-langspanish
texlive-latex
texlive-latexextra
texlive-latexrecommended
texlive-luatex
texlive-mathscience
texlive-metapost
texlive-music
texlive-pictures
texlive-plaingeneric
texlive-pstricks
texlive-publishers
texlive-xetex
#+end_src
**** Set PDF Viewer
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(setq +latex-viewers '(zathura))
#+end_src
**** Add auto-compile hook for TeX mode
Because TeX-command-run-all is an interactive command we need a helper function for the hook.
This function could also become useful if we ever want to extend the compile command
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(defun custom-tex-compile ()
  (interactive)
  (TeX-command-run-all nil))

(add-hook 'TeX-mode-hook
          (lambda ()
            (add-hook 'after-save-hook #'custom-tex-compile nil t)))
#+end_src

*** Org Mode
install dependencies
#+begin_src conf :tangle pkg-list.txt
xclip
gnome-screenshot
graphviz
#+end_src
**** Default Location
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(setq org-directory "~/org/")
#+end_src
**** Visual
***** Enable Header Numbering
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! org
  (setq org-startup-numerated t))
#+end_src
***** Image Display as Default
[[https://emacs.stackexchange.com/questions/57603/how-to-always-display-inline-images-by-default-existing-solutions-dont-seem-to#comment89772_57607][this stackexchange comment]] states that this has to be done before the [[Add "~/org" to Agenda][adding the ~/org directory to Org Agenda]]
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! org
  (setq org-startup-with-inline-images t))
#+end_src
***** Enable \LaTeX preview on default
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/init.el
(after! org
  (setq org-startup-latex-with-latex-preview t))
#+end_src

**** CalDAV Sync
[[https://github.com/dengste/org-caldav][org-caldav]] provides a tool for syncing with a CalDAV server (in my case Nextcloud).
A lot of the config is also taken from [[https://www.reddit.com/r/orgmode/comments/8rl8ep/comment/e0sb5j0/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button][this]] reddit post.
***** org-caldav installation
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/packages.el
(package! org-caldav)
#+end_src
***** Enable TODOs
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! org-caldav
  (setq org-icalendar-include-todo 'all
    org-caldav-sync-todo t))
#+end_src
***** Configure Sync
add the calendars to the org-caldav config
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! org-caldav
  (setq org-caldav-url "https://cloud.ploedige.com/remote.php/dav/calendars/paul-loedige")
  (setq org-caldav-sync-direction 'org->cal)
  (setq org-caldav-calendars
        '((:calendar-id "todo" :files ("~/org/todo.org")))))
#+end_src
**** Org Agenda Setup
***** Progress States
To get a more nuanced overview of my current TODOs I add more progress states.
|            | INACTIVE | TODO | BLOCKED | IN_PROGRESS | REVIEW | TESTING |   | DONE | DELEGATED | CANCELED |   |
|------------+----------+------+---------+-------------+--------+---------+---+------+-----------+----------+---|
| Access Key | i        | t    | b       | i           | r      | t       |   | d    |           | c        |   |
| Log Type   | time     | time | note    | time        | note   | note    |   | time | note      | note     |   |
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! org
  (setq org-todo-keywords
        '((sequence "INACTIVE(i!)" "TODO(t!)" "IN_PROGRESS(p!)" "BLOCKED(b@)" "REVIEW(r@)" "TESTING(e@)" "|" "DONE(d!)" "DELEGATED(x@)" "CANCELED(c@)"))))
#+end_src
Also set the percent states for [[*CalDAV Sync][CalDAV Sync]]
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! org-caldav
  (setq org-caldav-todo-percent-states '((0 "INACTIVE") (1 "TODO") (2 "IN_PROGRESS") (3 "BLOCKED") (90 "REVIEW") (90 "TESTING") (100 "DONE") (100 "DELEGATED") (100 "CANCELED"))))
#+end_src
***** Add "~/org" to Agenda
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! org
  (setq org-agenda-files (f-files "~/org"
                                  (lambda (f)
                                    (string= (f-ext f) "org"))
                                  'recursive)))
#+end_src
**** Org Roam
***** set base directory
Both the org files themselves and the database should be located in the same directory to enable syncing via Nextcloud
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! org
  (setq org-roam-directory (file-truename "~/org/org-roam"))
  (org-roam-db-autosync-mode))
#+end_src
***** Note Templates
This contains all the capture templates I am using.
Adding the "#+category: " tag improves the Org Agenda View for tasks captured in Org Roam
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! org-roam
  (setq org-roam-capture-templates
  '(("d" "default" plain
      "%?"
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+category: ${title}\n")
      :unnarrowed t)
    ("m" "Meeting Templates")
    ("mm" "Meeting Master Thesis" plain
      "* Current Progress\n\n* Open Questions\n\n* TODOs\n"
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: Master Thesis Meeting ${title}\n#+category: Master Thesis\n")
      :unnarrowed t))))
#+end_src
***** Misc
****** Follow Links on RET
Because the normal shortcut for `org-open-at-point` is quite cumbersome I want it to just follow links when clicking the RET button
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! org
  (setq return-follows-link t))
#+end_src
**** Org Transclusion
***** Installation
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/packages.el
(package! org-transclusion)
#+end_src
**** Bibliography
***** Enabling Zotero Links
#+begin_src conf :tangle pkg-list.txt
zotero
#+end_src
Following [[https://www.riccardopinosio.com/blog/posts/zotero_notes_article.html#opening-zotero-pdf-from-org-roam][this guide]] we enable using zotero links with the following code
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! org
  :custom
  (org-link-set-parameters "zotero" :follow
                           (lambda (zpath)
                             (browse-url
                              (format "zotero:%s" zpath)))))
#+end_src
***** Citar Config
****** Setting the Citar Bibliography
Following the [[https://github.com/doomemacs/doomemacs/tree/master/modules/tools/biblio][Doom Emacs documentation ]]we set the citar bibliography and notes paths
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! oc
  (setq citar-bibliography '("~/org/biblio.bib"))
  (setq citar-notes-paths '("~/org/org-roam/")))
#+end_src
****** Citar Templates
Following the [[https://github.com/emacs-citar/citar#configuration][citar package documentation]] we modify the note template to contain the pdf link to Zotero
*NOTE:* This requires the a [[https://www.riccardopinosio.com/blog/posts/zotero_notes_article.html#opening-zotero-pdf-from-org-roam][specific Zotero Export Configuration]]
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! oc
  (setq citar-templates
      '((main . "${author editor:30%sn}     ${date year issued:4}     ${title:48}")
        (suffix . "          ${=key= id:15}    ${=type=:12}    ${tags keywords:*}")
        (preview . "${author editor:%etal} (${year issued date}) ${title}, ${journal journaltitle publisher container-title collection-title}.\n")
        (note . "Notes on ${author editor:%etal}, ${title}\npdf: ${file}"))))
#+end_src
****** Enable Zotero Link Support
In [[https://www.riccardopinosio.com/blog/posts/zotero_notes_article.html#citar][this tutorial]] I found the config for enabling Zotero Link Support through Citar
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! citar
  (defadvice! riccardo/citar-file-trust-zotero (oldfun &rest r)
    "Leave Zotero-generated file paths alone, especially zotero://..."
    :around '(citar-file-open citar-file--find-files-in-dirs)
    (cl-letf (((symbol-function 'file-exists-p) #'always)
              ((symbol-function 'expand-file-name) (lambda (first &rest _) first)))
      (apply oldfun r)))

  (add-to-list 'citar-file-open-functions '("pdf" . citar-file-open-external)))
#+end_src
**** Poly-Org
[[Polymode]] for Org
#+begin_src emacs-lisp :tangle ~/.config/doom/packages.el
(package! poly-org)
#+end_src
#+begin_src emacs-lisp :tangle ~/.config/doom/config.el
;; (after! org
;;   (require 'poly-org))
#+end_src

*** Polymode
[[https://polymode.github.io/][Polymode]] enables using multiple major modes inside a single buffer.
This is especially useful for Org Mode as it allows for better code editing inside code blocks
#+begin_src emacs-lisp :tangle ~/.config/doom/packages.el
(package! polymode)
#+end_src
*** TODO Python
install dependencies
#+begin_src conf :tangle pkg-list.txt
python-isort
python-pipenv
python-pytest
pyright
#+end_src
**** Set Debugger to debugpy
as per the [[https://github.com/doomemacs/doomemacs/tree/master/modules/tools/debugger#dap-python][Doom Emacs Documentation]] it is recommended to set the debugger used for python debugging to debugpy
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(after! dap-mode
  (setq dap-python-debugger 'debugpy))
#+end_src

** VSCode
*** Installation
#+begin_src conf :tangle pkg-list.txt
visual-studio-code-bin
#+end_src
*** Add-On Configuration
**** Config File Header
#+begin_src conf :tangle vscode-extensions.txt
# DO NOT EDIT THIS FILE DIRECTLY
# This is a file generated from a literate programing source file
# You should make any changes there and regenerate it from Emacs org-mode
# using org-babel-tangle (C-c C-v t)

#+end_src
**** Basic Look & Feel Extensions
***** [[https://github.com/VSCodeVim/Vim][Vim Key Bindings]]
#+begin_src conf :tangle vscode-extensions.txt
vscodevim.vim
#+end_src
**** Useful Tools
***** [[https://github.com/ChristianKohler/PathIntellisense][Path Intellisense]]
#+begin_src conf :tangle vscode-extensions.txt
christian-kohler.path-intellisense
#+end_src
***** [[https://github.com/streetsidesoftware/vscode-spell-checker][Spellcheck]]
#+begin_src conf :tangle vscode-extensions.txt
streetsidesoftware.code-spell-checker
#+end_src
**** Languages
***** [[https://github.com/Microsoft/vscode-python][Python]]
#+begin_src conf :tangle vscode-extensions.txt
ms-python.python
donjayamanne.python-environment-manager
#+end_src

*** Add-On Sync
remove all packages not in ~vscode-extensions.txt~ and install otherwise
#+begin_src shell :tangle update.sh
INSTALLED_EXTENSIONS=$(code --list-extensions)
KEEP_LIST=$(grep -v '^#' "vscode-extensions.txt")

for EXTENSION in $INSTALLED_EXTENSIONS; do
    if ! echo "$KEEP_LIST" | grep -q "^$EXTENSION$"; then
        echo "Removing VS Code Extension: $EXTENSION"
        code --uninstall-extension "$EXTENSION"
    fi
done
for EXTENSION in $KEEP_LIST; do
    echo "Installing VS Code Extension: $EXTENSION"
    code --install-extension "$EXTENSION"
done
#+end_src
** NeoVim
[[https://neovim.io/][NeoVim Documentation]]
*** Installation
#+begin_src conf :tangle pkg-list.txt
neovim
#+end_src
*** TODO Configuration
* Browser
** Firefox
*** Installation
#+begin_src conf :tangle pkg-list.txt
firefox
#+end_src
*** TODO Configuration

* Shells
ZSH is used as the default shell
** Aliases
*** Shutdown and Reboot
#+begin_src shell :tangle ~/alias.sh
alias sn='shutdown now'
alias rb='reboot'
#+end_src
*** Confirm before overwriting
#+begin_src shell :tangle ~/alias.sh
alias cp="cp -i"
alias mv='mv -i'
alias rm='rm -i'
#+end_src

*** Git Aliases
#+begin_src conf :tangle pkg-list.txt
git
#+end_src
#+begin_src shell :tangle ~/alias.sh
alias add='git add'
alias addup='git add -u'
alias addall='git add .'
alias branch='git branch'
alias checkout='git checkout'
alias co='git checkout'
alias clone='git clone'
alias commit='git commit -m'
alias fetch='git fetch'
alias pull='git pull origin'
alias push='git push origin'
alias status='git status'
alias diff='git diff'
alias remote='git remote'
alias ftemplate='git fetch template'
alias mtemplate='git merge template/master --allow-unrelated-histories'
alias log='git log'
#+end_src
*** ls -> [[https://github.com/eza-community/eza][eza]]
#+begin_src shell :tangle pkg-list.txt
eza
#+end_src
#+begin_src shell :tangle ~/alias.sh
alias ls='eza --icons -lF --color=always --group-directories-first --git' # my preferred listing
alias la='eza --icons -aF --color=always --group-directories-first --git'  # all files and dirs
alias ll='eza --icons -alF --color=always --group-directories-first --git'  # long format
alias lt='eza --icons -aTF --color=always --group-directories-first --git' # tree listing
alias lx='eza --icons -lF --color=always --group-directories-first --git --extended' # extended info
alias l.='eza -a | egrep "^\."' # list dotfiles
#+end_src
** [[https://www.zsh.org/][ZSH]]
*** Installation
#+begin_src conf :tangle pkg-list.txt
zsh
which
#+end_src
*** Set as default shell
#+begin_src shell :tangle update.sh
if [ "$(basename $SHELL)" != "zsh" ]; then
    chsh -s $(which zsh)
fi
#+end_src
*** [[https://ohmyz.sh/][Oh-My-Zsh]]
**** Installation
#+begin_src conf :tangle pkg-list.txt
curl
#+end_src
Install if needed
Notes:
Because the tangled ~.zshrc~ already would usually be overwritten it needs to be backed up and restored.
Also, the ~$ZSH~ variable needs to be unset to avoid errors during installation
#+begin_src shell :tangle update.sh
if [ ! -d "$HOME/.oh-my-zsh" ]; then
    echo "Backing up .zshrc..."
    mv ~/.zshrc ~/.zshrc-tmp
    echo "Installing Oh-My-Zsh..."
    unset ZSH
    sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
    if [ -e "$HOME/.zshrc.pre-oh-my-zsh" ]; then
        rm ~/.zshrc.pre-oh-my-zsh
    fi
    echo "Restoring .zshrc..."
    mv ~/.zshrc-tmp ~/.zshrc
fi
#+end_src
**** Basic Configuration
#+begin_src shell :tangle ~/.zshrc
export ZSH="$HOME/.oh-my-zsh"

# Uncomment the following line to use case-sensitive completion.
CASE_SENSITIVE="false"

# Uncomment the following line to use hyphen-insensitive completion.
# Case-sensitive completion must be off. _ and - will be interchangeable.
HYPHEN_INSENSITIVE="true"

# Uncomment the following line to change how often to auto-update (in days).
export UPDATE_ZSH_DAYS=3

# Uncomment the following line to enable command auto-correction.
ENABLE_CORRECTION="true"

# Uncomment the following line to display red dots whilst waiting for completion.
# Caution: this setting can cause issues with multiline prompts (zsh 5.7.1 and newer seem to work)
# See https://github.com/ohmyzsh/ohmyzsh/issues/5765
COMPLETION_WAITING_DOTS="true"
#+end_src
**** [[https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins][Plugins]]
***** Dependencies
some of the following plugins require dependencies
#+begin_src shell :tangle pkg-list.txt
#for bgnotify
libnotify
fd
fzf
github-cli
#+end_src
***** Symlink External Plugins
****** [[https://github.com/conda-incubator/conda-zsh-completion][conda-zsh-completion]]
#+begin_src shell :tangle update.sh
if [ ! -L "$HOME/.oh-my-zsh/custom/plugins/conda-zsh-completion" ]; then
    echo "Installing conda-zsh-completion..."
    if [ ! -d "$HOME/.oh-my-zsh/custom/plugins" ]; then
        mkdir -p ~/.oh-my-zsh/custom/plugins
    fi
    ln -s ~/.dotfiles/zsh/.oh-my-zsh/custom/plugins/conda-zsh-completion ~/.oh-my-zsh/custom/plugins/conda-zsh-completion
fi
#+end_src
****** [[https://github.com/zsh-users/zsh-autosuggestions][zsh-autosuggestions]]
#+begin_src shell :tangle update.sh
if [ ! -L "$HOME/.oh-my-zsh/custom/plugins/zsh-autosuggestions" ]; then
    echo "Installing conda-zsh-completion..."
    if [ ! -d "$HOME/.oh-my-zsh/custom/plugins" ]; then
        mkdir -p ~/.oh-my-zsh/custom/plugins
    fi
    ln -s ~/.dotfiles/zsh/.oh-my-zsh/custom/plugins/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions
fi
#+end_src
****** [[https://github.com/zsh-users/zsh-syntax-highlighting][zsh-syntax-highlighting]]
#+begin_src shell :tangle update.sh
if [ ! -L "$HOME/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting" ]; then
    echo "Installing conda-zsh-completion..."
    if [ ! -d "$HOME/.oh-my-zsh/custom/plugins" ]; then
        mkdir -p ~/.oh-my-zsh/custom/plugins
    fi
    ln -s ~/.dotfiles/zsh/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting ~/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting
fi
#+end_src
***** Install Plugins
#+begin_src shell :tangle ~/.zshrc
# Which plugins would you like to load?
# Standard plugins can be found in $ZSH/plugins/
# Custom plugins may be added to $ZSH_CUSTOM/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(
    adb
    aliases
    archlinux
    bgnotify
    colored-man-pages
    command-not-found
    docker
    docker-compose
    emacs
    extract
    fd
    gh
    git
    git-auto-fetch
    git-lfs
    isodate
    nmap
    pip
    pipenv
    python
    ripgrep
    rsync
    svn
    systemd
    themes
    vi-mode
    vscode
    # # non oh-my-zsh plugins
    zsh-autosuggestions
    zsh-syntax-highlighting
    conda-zsh-completion
)
#+end_src
**** [[https://github.com/romkatv/powerlevel10k][Powerlevel10k]]
create symlink if needed
#+begin_src shell :tangle update.sh
if [ ! -L "$HOME/.oh-my-zsh/custom/themes/powerlevel10k" ]; then
    echo "Installing Powerlevel10k..."
    if [ ! -d "$HOME/.oh-my-zsh/custom/themes" ]; then
        mkdir -p ~/.oh-my-zsh/custom/themes
    fi
    ln -s ~/.dotfiles/zsh/.oh-my-zsh/custom/themes/powerlevel10k ~/.oh-my-zsh/custom/themes/powerlevel10k
fi
#+end_src
init
#+begin_src shell :tangle ~/.zshrc
ZSH_THEME="powerlevel10k/powerlevel10k"
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
#+end_src
***** Config
create symlink if needed.
The config file was created via the ~p10k configure~ command
#+begin_src shell :tangle update.sh
if [ ! -L "$HOME/.p10k.zsh" ]; then
    echo "Configuring Powerlevel10k..."
    ln -s ~/.dotfiles/zsh/.p10k.zsh ~/.p10k.zsh
fi
#+end_src

**** Source oh-my-zsh
#+begin_src shell :tangle ~/.zshrc
source $ZSH/oh-my-zsh.sh
#+end_src
*** Configuration
**** Source Aliases
#+begin_src shell :tangle ~/.zshrc
source ~/alias.sh
#+end_src
**** Modify PATH
#+begin_src shell :tangle ~/.zshrc
source path.sh
#+end_src
**** [[https://github.com/dylanaraps/neofetch][neofetch]]
install
#+begin_src conf :tangle pkg-list.txt
neofetch
#+end_src
and start
#+begin_src shell :tangle ~/.zshrc
neofetch
#+end_src
** [[https://www.gnu.org/software/bash/][Bash]]
*** Installation
#+begin_src conf :tangle pkg-list.txt
bash
#+end_src
*** Configuration
**** Source Aliases
#+begin_src shell :tangle ~/.bashrc
source ~/alias.sh
#+end_src
**** Modify PATH
#+begin_src shell :tangle ~/.bashrc
source path.sh
#+end_src
**** [[https://github.com/dylanaraps/neofetch][neofetch]]
install
#+begin_src conf :tangle pkg-list.txt
neofetch
#+end_src
and start
#+begin_src shell :tangle ~/.bashrc
neofetch
#+end_src

* Alacritty
** Font
#+begin_src toml :tangle ~/.config/alacritty/alacritty.toml :mkdirp yes
[font]
size = xx

[font.bold]
family = "UbuntuMonoNerdFont"
style = "Bold"

[font.bold_italic]
family = "UbuntuMonoNerdFont"
style = "Bold Italic"

[font.italic]
family = "UbuntuMonoNerdFont"
style = "Italic"

[font.normal]
family = "UbuntuMonoNerdFont"
style = "Regular"
#+end_src
The size is set via the autostart script depending on the system type (Laptop/Desktop)
#+begin_src shell :mkdirp yes :tangle ~/.config/autostart.sh
# Use hostnamectl to get system information
chassis_type=$(hostnamectl status | grep "Chassis:" | awk '{print $2}')
# Check if the chassis type is "laptop"
if [ "$chassis_type" == "laptop" ]; then
    # set font size for alacritty
    sed -i 's/size = xx/size = 11/' ~/.config/alacritty/alacritty.toml
else
    # set font size for alacritty
    sed -i 's/size = xx/size = 14/' ~/.config/alacritty/alacritty.toml
fi
#+end_src
since ~update.sh~ will reset the font size value. This also needs to be set in there
#+begin_src shell :tangle update.sh
# Use hostnamectl to get system information
chassis_type=$(hostnamectl status | grep "Chassis:" | awk '{print $2}')
# Check if the chassis type is "laptop"
if [ "$chassis_type" == "laptop" ]; then
    # set font size for alacritty
    sed -i 's/size = xx/size = 11/' ~/.config/alacritty/alacritty.toml
else
    # set font size for alacritty
    sed -i 's/size = xx/size = 14/' ~/.config/alacritty/alacritty.toml
fi
#+end_src

#+RESULTS:

* Theming
This Config applies the [[https://github.com/gruvbox-community/gruvbox][Gruvbox Theme]] to as many programs as possible
** Doom Emacs
Install specific package
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/packages.el
(package! gruvbox-theme)
#+end_src
and then set it
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.config/doom/config.el
(setq doom-theme 'gruvbox-dark-hard)
#+end_src
** VSCode
#+begin_src conf :tangle vscode-extensions.txt
jdinhlife.gruvbox
#+end_src

** Qtile
#+begin_src python :tangle ~/.config/qtile/defines.py :mkdirp yes
focus_color = '#076678'

light_foreground_color = ['#fbf1c7','#fbf1c7']
dark_foreground_color = ['#282828','#282828']
background_color0  = ['#1d2021','#1d2021']
background_color8  = ['#7c6f64','#7c6f64']
base_color = background_color0
# red
red_color = ['#cc241d','#cc241d']
light_red_color  = ['#fb4934','#fb4934']
# green
green_color = ['#98971a','#98971a']
light_green_color  = ['#b8bb26','#b8bb26']
#orange
orange_color = ['#d65d0e','#d65d0e']
# yellow
yellow_color  = ['#d79921','#d79921']
light_yellow_color = ['#fabd2f','#fabd2f']
#blue
blue_color = ['#076678','#076678']
# purple
purple_color  = ['#b16286','#b16286']
light_purple_color  = ['#d3869b','#d3869b']
# magenta
magenta_color  = ['#ff79c6','#ff79c6']
# cyan
cyan_color  = ['#8be9fd','#8be9fd']
#+end_src
** Alacritty
#+begin_src toml :tangle ~/.config/alacritty/alacritty.toml :mkdirp yes
[colors.bright]
black = "#928374"
blue = "#83a598"
cyan = "#8ec07c"
green = "#b8bb26"
magenta = "#d3869b"
red = "#fb4934"
white = "#ebdbb2"
yellow = "#fabd2f"

[colors.cursor]
cursor = "CellForeground"
text = "CellBackground"

[colors.dim]
black = "#32302f"
blue = "#076678"
cyan = "#427b58"
green = "#79740e"
magenta = "#8f3f71"
red = "#9d0006"
white = "#928374"
yellow = "#b57614"

[colors.normal]
black = "#282828"
blue = "#458588"
cyan = "#689d6a"
green = "#98971a"
magenta = "#b16286"
red = "#cc241d"
white = "#a89984"
yellow = "#d79921"

[colors.primary]
background = "#282828"
bright_foreground = "#f9f5d7"
dim_foreground = "#f2e5bc"
foreground = "#fbf1c7"

[colors.selection]
background = "CellForeground"
text = "CellBackground"

[colors.vi_mode_cursor]
cursor = "CellForeground"
text = "CellBackground"
#+end_src
** Xorg
#+begin_src config :tangle ~/.Xresources
! DO NOT EDIT THIS FILE DIRECTLY
! This is a file generated from a literate programing source file
! You should make any changes there and regenerate it from Emacs org-mode
! using org-babel-tangle (C-c C-v t)

! -----------------------------------------------------------------------------
! File: gruvbox-dark.xresources
! Description: Retro groove colorscheme generalized
! Author: morhetz <morhetz@gmail.com>
! Source: https://github.com/morhetz/gruvbox-generalized
! Last Modified: 6 Sep 2014
! -----------------------------------------------------------------------------

! hard contrast: *background: #1d2021
*background: #282828
! soft contrast: *background: #32302f
*foreground: #ebdbb2
! Black + DarkGrey
*color0:  #282828
*color8:  #928374
! DarkRed + Red
*color1:  #cc241d
*color9:  #fb4934
! DarkGreen + Green
*color2:  #98971a
*color10: #b8bb26
! DarkYellow + Yellow
*color3:  #d79921
*color11: #fabd2f
! DarkBlue + Blue
*color4:  #458588
*color12: #83a598
! DarkMagenta + Magenta
*color5:  #b16286
*color13: #d3869b
! DarkCyan + Cyan
*color6:  #689d6a
*color14: #8ec07c
! LightGrey + White
*color7:  #a89984
*color15: #ebdbb2
#+end_src

** GTK
#+begin_src shell :tangle pkg-list.txt
gruvbox-dark-gtk
papirus-icon-theme
#+end_src
*** GTK 3
#+begin_src conf :tangle ~/.config/gtk-3.0/settings.ini
[Settings]
gtk-icon-theme-name = Papirus-Dark
gtk-theme-name = gruvbox-dark-gtk
gtk-font-name = UbuntuMono Nerd Font 11
#+end_src
*** GTK 4
#+begin_src conf :tangle ~/.config/gtk-4.0/settings.ini
[Settings]
gtk-icon-theme-name = Papirus-Dark
gtk-theme-name = gruvbox-dark-gtk
gtk-font-name = UbuntuMono Nerd Font 11
#+end_src
* Git
** Installation
#+begin_src conf :tangle pkg-list.txt
git
#+end_src
** Configuration
set user
#+begin_src conf :tangle ~/.gitconfig
[user]
    name = paul-loedige
    email = paul@gve-loedige.de
#+end_src
set default branch to =main=
#+begin_src conf :tangle ~/.gitconfig
[init]
    defaultBranch = main
#+end_src
* Miniconda
** Installation
#+begin_src conf :tangle pkg-list.txt
miniconda3
#+end_src
universal link
#+begin_src shell :tangle update.sh
if [ ! -e "/etc/profile.d/conda.sh" ]; then
    sudo ln -s /opt/miniconda3/etc/profile.d/conda.sh /etc/profile.d/conda.sh
fi
#+end_src
add to path
#+begin_src shell :tangle ~/.path.sh
source /etc/profile.d/conda.sh
export PATH="/opt/miniconda3/bin:$PATH"
#+end_src
** ZSH special settings
#+begin_src shell :tangle ~/.zshrc
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/opt/miniconda3/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/opt/miniconda3/etc/profile.d/conda.sh" ]; then
        . "/opt/miniconda3/etc/profile.d/conda.sh"
    else
        export PATH="/opt/miniconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<
#+end_src
** Do not activate base environment on startup
#+begin_src shell :tangle ~/.condarc
auto_activate_base: false
#+end_src
* TODO Misc Programs
** Zathura
*** Installation
#+begin_src conf :tangle pkg-list.txt
zathura
#+end_src
*** enable synctex
#+begin_src conf :mkdirp yes :tangle ~/.config/zathura/zathurarc
set synctex true
#+end_src
** Nextcloud
#+begin_src conf :tangle pkg-list.txt
nextcloud-client
#+end_src
** Bitwarden
*** Installation
#+begin_src conf :tangle pkg-list.txt
bitwarden
#+end_src
*** TODO Configuration

** Inkscape
*** Installation
#+begin_src conf :tangle pkg-list.txt
inkscape
#+end_src
* Manual Tasks after tangling
1. run ~update.sh~
2. log out and back in to update group permissions
3. setup Nextcloud sync directories
4. sign into Bitwarden
5. add Firefox Account
6. configure networks
   - [[https://www.scc.kit.edu/dienste/7181.php][eduroam]]

* Other TODOs
** TODO configure Bitwarden via config file
- remove manual task afterwards
** TODO add Firefox user via update.sh
- remove manual task afterwards
