diff --git a/.gitignore b/.gitignore
index e69de29..9f11b75 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+.idea/
diff --git a/README.md b/README.md
index cb91c5d..e5923c5 100644
--- a/README.md
+++ b/README.md
@@ -2,13 +2,13 @@
## Installation
-Run the `install.sh` script to install neovim, zsh (via oh-my-zsh) and all of the omz plugins.
+```bash
+pacman -S ansible-tools
+ansible-galaxy install -r requirements.yml
+ansible-playbook playbook.yml --ask-become-pass
+```
-## nvim
-
--- TODO --
-
-- Install nerdfont
+- Install nerdfont -- TODO
## zsh
diff --git a/ansible.cfg b/ansible.cfg
new file mode 100644
index 0000000..bf7b4a3
--- /dev/null
+++ b/ansible.cfg
@@ -0,0 +1,4 @@
+[default]
+inventory = inventory
+stdout_callback = yaml
+host_key_checking = False
diff --git a/group_vars/all.yml b/group_vars/all.yml
new file mode 100644
index 0000000..951714d
--- /dev/null
+++ b/group_vars/all.yml
@@ -0,0 +1,70 @@
+default_roles:
+ # === Core System Tools (Recommended) ===
+ - system # Essential system configurations and tools
+ # - fonts # Developer-friendly fonts (Nerd Fonts)
+
+ # === Development Core ===
+ # - git # Version control system
+ - nvim # Modern text editor (or use 'vim')
+ # - tmux # Terminal multiplexer for session management
+ - zsh # Modern shell with oh-my-zsh
+ # - ssh
+ - hyprland
+ - ghostty
+
+temp:
+ - docker # Container platform
+
+system_packages:
+ # Network
+ - curl
+ - wget
+ - rsync
+ - nmap
+
+ # archive/compression
+ - unzip
+ - tar
+
+ # text processing
+ - jq
+ - ripgrep
+ - fd
+
+ # utilities
+ - btop
+ - which
+ # - fzf
+ - bat
+ - eza
+ - tealdeer
+ - neofetch
+
+ # dev
+ - nvm
+ - go
+ - discord # Team communication
+
+ # Window manager
+ - hyprland
+ - waybar
+ - wofi
+ - hyprshot
+ - dunst
+ - hyprpaper
+
+ # desktop
+ - thunar
+ - imv
+
+
+# TODO
+aur_packages:
+ - autojump
+ - spotify
+ - qownnotes
+ - stripe-cli
+ - pgformatter-git
+ # - jetbrains-toolbox
+
+config_dir: "{{ ansible_facts.env.HOME }}/.config"
diff --git a/install.sh b/install.sh
index 643332d..f48f7e2 100755
--- a/install.sh
+++ b/install.sh
@@ -1,48 +1,38 @@
#!/bin/bash
-command_exists() {
- command -v "$1" >/dev/null 2>&1
+set -e
+
+DOTFILES_DIR="$HOME/dotfiles"
+
+
+function arch_setup() {
+ if ! [ -x "$(which ansible)" ]; then
+ echo "Installing ansible"
+ sudo pacman -S ansible
+ fi
}
-create_symlink() {
- local source=$1
- local target=$2
-
- if [ ! -e "$target" ]; then
- ln -s "$source" "$target"
- echo "Added symlink $source -> $target"
- fi
+
+function detect_os() {
+ source /etc/os-release
+ echo "$ID"
}
-install_package() {
- local package=$1
- if ! command_exists "$package"; then
- # sudo dnf update && sudo dnf install "$package"
- sudo pacman -S "$package"
- fi
-}
+local_os=$(detect_os)
-install_package "neovim"
-create_symlink "$HOME/dotfiles/nvim" "$HOME/.config/nvim"
+case $local_os in
+ cachyos|arch)
+ arch_setup
+ ;;
+ debian)
+ debian_setup
+ ;;
+ fedora)
+ fedora_setup
+ ;;
+ *)
+ echo "OS $local_os not supported"
+ exit 1
+esac
-install_package "zsh"
-create_symlink "$HOME/dotfiles/zsh/.zshrc" "$HOME/.zshrc"
-
-if [ ! -d "$HOME/.oh-my-zsh" ]; then
- sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
-fi
-
-ZSH_CUSTOM=${ZSH_CUSTOM:-~/.oh-my-zsh/custom}
-
-# Install zsh-syntax-highlighting
-if [ ! -d "${ZSH_CUSTOM}/plugins/zsh-syntax-highlighting" ]; then
- git clone --depth 1 https://github.com/zsh-users/zsh-syntax-highlighting.git \
- ${ZSH_CUSTOM}/plugins/zsh-syntax-highlighting
-fi
-
-
-# Install zsh-syntax-highlighting
-if [ ! -d "${ZSH_CUSTOM}/plugins/fzf-zsh-plugin" ]; then
- git clone --depth 1 https://github.com/unixorn/fzf-zsh-plugin.git \
- ${ZSH_CUSTOM}/plugins/fzf-zsh-plugin
-fi
+ansible-playbook "$DOTFILES_DIR/playbook.yml" "$@"
\ No newline at end of file
diff --git a/inventory b/inventory
new file mode 100644
index 0000000..fe31dc2
--- /dev/null
+++ b/inventory
@@ -0,0 +1,2 @@
+[local]
+localhost ansible_connection=local ansible_user=johannes
diff --git a/playbook.yml b/playbook.yml
new file mode 100644
index 0000000..da49a69
--- /dev/null
+++ b/playbook.yml
@@ -0,0 +1,28 @@
+---
+- name: Setup dotfiles configuration
+ hosts: localhost
+ connection: local
+ become: false
+ vars:
+ dotfiles_dir: "{{ ansible_env.HOME }}/dotfiles"
+ # roles:
+ # - zsh
+
+ pre_tasks:
+ - name: Create btrfs snapshot before changes
+ shell: |
+ sudo btrfs subvolume snapsho / /.snapshots/before-dotfiles-$(date +%Y%m%d-%H%M%S)
+ tags: [snapshot]
+ become: true
+ become_method: sudo
+
+ tasks:
+ - name: Install enabled roles
+ ansible.builtin.include_role:
+ name: "{{ item }}"
+ apply:
+ tags:
+ - install
+ loop:
+ "{{ default_roles }}"
+ # when: default_roles is defined
diff --git a/requirements.yml b/requirements.yml
new file mode 100644
index 0000000..a937e53
--- /dev/null
+++ b/requirements.yml
@@ -0,0 +1,4 @@
+---
+collections:
+ - community.general
+ - kewlfft.aur
diff --git a/roles/ghostty/files/config b/roles/ghostty/files/config
new file mode 100644
index 0000000..c26140e
--- /dev/null
+++ b/roles/ghostty/files/config
@@ -0,0 +1,29 @@
+shell-integration = zsh
+shell-integration-features = cursor,sudo,title
+
+font-family = "RobotoMono Nerd Font Mono"
+
+# Monokai Pro
+# Based on Monokai Pro color scheme, made by Monokai. https://monokai.pro/
+window-colorspace = srgb
+palette = 0=2d2a2e
+palette = 1=ff6188
+palette = 2=a9dc76
+palette = 3=ffd866
+palette = 4=fc9867
+palette = 5=ab9df2
+palette = 6=78dce8
+palette = 7=fcfcfa
+palette = 8=727072
+palette = 9=ff6188
+palette = 10=a9dc76
+palette = 11=ffd866
+palette = 12=fc9867
+palette = 13=ab9df2
+palette = 14=78dce8
+palette = 15=fcfcfa
+background = 2d2a2e
+foreground = fcfcfa
+cursor-color = c1c0c0
+selection-background = 5b595c
+selection-foreground = fcfcfa
diff --git a/roles/ghostty/tasks/main.yml b/roles/ghostty/tasks/main.yml
new file mode 100644
index 0000000..1654e7e
--- /dev/null
+++ b/roles/ghostty/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- name: Symlink ghostty config
+ file:
+ src: "{{ role_path }}/files"
+ dest: "{{ config_dir }}/ghostty"
+ state: link
+ force: true
diff --git a/roles/hyprland/files/dunst/dunstrc b/roles/hyprland/files/dunst/dunstrc
new file mode 100644
index 0000000..fcfb2f4
--- /dev/null
+++ b/roles/hyprland/files/dunst/dunstrc
@@ -0,0 +1,76 @@
+[global]
+ monitor = 0
+ follow = mouse
+ width = 300
+ height = 300
+ origin = top-right
+ offset = 10x50
+ scale = 0
+ notification_limit = 0
+
+ progress_bar = true
+ progress_bar_height = 10
+ progress_bar_frame_width = 1
+ progress_bar_min_width = 150
+ progress_bar_max_width = 300
+
+ indicate_hidden = yes
+ transparency = 0
+ separator_height = 2
+ padding = 8
+ horizontal_padding = 8
+ text_icon_padding = 0
+ frame_width = 2
+ frame_color = "#89b4fa"
+ separator_color = frame
+ sort = yes
+
+ font = JetBrains Mono 10
+ line_height = 0
+ markup = full
+ format = "%s\n%b"
+ alignment = left
+ vertical_alignment = center
+ show_age_threshold = 60
+ ellipsize = middle
+ ignore_newline = no
+ stack_duplicates = true
+ hide_duplicate_count = false
+ show_indicators = yes
+
+ icon_position = left
+ min_icon_size = 0
+ max_icon_size = 32
+
+ dmenu = /usr/bin/dmenu -p dunst:
+ browser = /usr/bin/xdg-open
+ always_run_script = true
+ title = Dunst
+ class = Dunst
+ corner_radius = 8
+ ignore_dbusclose = false
+ force_xwayland = false
+ force_xinerama = false
+ mouse_left_click = close_current
+ mouse_middle_click = do_action, close_current
+ mouse_right_click = close_all
+
+[experimental]
+ per_monitor_dpi = false
+
+[urgency_low]
+ background = "#1e1e2e"
+ foreground = "#cdd6f4"
+ timeout = 10
+
+[urgency_normal]
+ background = "#1e1e2e"
+ foreground = "#cdd6f4"
+ timeout = 10
+
+[urgency_critical]
+ background = "#1e1e2e"
+ foreground = "#f38ba8"
+ frame_color = "#f38ba8"
+ timeout = 0
+
diff --git a/roles/hyprland/files/hypr/hyprland.conf b/roles/hyprland/files/hypr/hyprland.conf
new file mode 100644
index 0000000..92ab65e
--- /dev/null
+++ b/roles/hyprland/files/hypr/hyprland.conf
@@ -0,0 +1,307 @@
+################
+### MONITORS ###
+################
+
+# See https://wiki.hypr.land/Configuring/Monitors/
+monitor=,preferred,auto,auto
+source = ./monitors.conf
+source = ./workspaces.conf
+
+###################
+### MY PROGRAMS ###
+###################
+
+# See https://wiki.hypr.land/Configuring/Keywords/
+
+$terminal = ghostty
+$fileManager = thunar
+$menu = wofi --show drun
+
+#################
+### AUTOSTART ###
+#################
+
+# Autostart necessary processes (like notifications daemons, status bars, etc.)
+# Or execute your favorite apps at launch like this:
+exec-once = waybar
+exec-once = dunst
+exec-once = firefox
+exec-once = hyprpaper
+exec-once = spotify
+
+#############################
+### ENVIRONMENT VARIABLES ###
+#############################
+
+# See https://wiki.hypr.land/Configuring/Environment-variables/
+env = XCURSOR_SIZE,24
+env = HYPRCURSOR_SIZE,24
+env = QT_QPA_PLATFORM,waylandl;xcb
+env = QT_QPA_PLATFORMTHEME,qt5ct
+
+env = XDG_CURRENT_DESKTOP,Hyprland
+env = XDG_SESSION_TYPE,wayland
+env = WLR_NO_HARDWARE_CURSORS,1
+env = CLUTTER_BACKEND,wayland
+env = SDL_VIDEODRIVER,wayland,x11
+env = GDK_BACKEND,wayland,x11
+
+# jetbrains
+env = _JAVA_AWT_WM_NONREPARENTING, 1
+# env = AWT_TOOLKIT, MToolkit
+
+###################
+### PERMISSIONS ###
+###################
+
+# See https://wiki.hypr.land/Configuring/Permissions/
+# Please note permission changes here require a Hyprland restart and are not applied on-the-fly
+# for security reasons
+
+# ecosystem {
+# enforce_permissions = 1
+# }
+
+# permission = /usr/(bin|local/bin)/grim, screencopy, allow
+# permission = /usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland, screencopy, allow
+# permission = /usr/(bin|local/bin)/hyprpm, plugin, allow
+
+
+#####################
+### LOOK AND FEEL ###
+#####################
+
+# https://wiki.hypr.land/Configuring/Variables/#general
+general {
+ gaps_in = 5
+ gaps_out = 20
+
+ border_size = 2
+
+ # https://wiki.hypr.land/Configuring/Variables/#variable-types for info about colors
+ col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
+ col.inactive_border = rgba(595959aa)
+ # Active: cosmic purple -> neon cyan gradient
+ # col.active_border = rgba(7f5af0ee) rgba(00d1ffee) 45deg
+ #
+ # # Inactive: deep space slate
+ # col.inactive_border = rgba(0c0e14aa)
+
+ # Set to true enable resizing windows by clicking and dragging on borders and gaps
+ resize_on_border = false
+
+ # Please see https://wiki.hypr.land/Configuring/Tearing/ before you turn this on
+ allow_tearing = false
+
+ layout = dwindle
+}
+
+
+# --- Decorations / cosmic glass ---
+decoration {
+ rounding = 12
+ active_opacity = 1.0
+ inactive_opacity = 0.96
+ fullscreen_opacity = 1.0
+
+ # Shadows (new nested syntax)
+ shadow {
+ enabled = true
+ range = 20 # size of the shadow
+ render_power = 3 # 1–4, higher = faster falloff
+ color = rgba(0, 0, 0, 0.35)
+ offset = 0 6 # optional: drop slightly downward
+ scale = 1.0
+ }
+
+ # Blur (nested)
+ blur {
+ enabled = true
+ size = 8
+ passes = 3
+ new_optimizations = true
+ noise = 0.02
+ contrast = 1.00
+ brightness = 1.00
+ vibrancy = 0.18
+ xray = true
+ }
+}
+
+# wofi
+layerrule = blur, wofi # apply compositor blur
+layerrule = ignorezero, wofi # keep blur even on near-opaque colors
+layerrule = dimaround, wofi # optional: dim background behind wofi
+layerrule = ignorealpha 0.90, wofi # target overall opacity for the layer
+
+# waybar
+layerrule = blur, waybar
+layerrule = ignorealpha 0.15, waybar
+
+# https://wiki.hypr.land/Configuring/Variables/#animations
+animations {
+ enabled = yes, please :)
+
+ # Default animations, see https://wiki.hypr.land/Configuring/Animations/ for more
+
+ bezier = easeOutQuint,0.23,1,0.32,1
+ bezier = easeInOutCubic,0.65,0.05,0.36,1
+ bezier = linear,0,0,1,1
+ bezier = almostLinear,0.5,0.5,0.75,1.0
+ bezier = quick,0.15,0,0.1,1
+
+ animation = global, 1, 10, default
+ animation = border, 1, 5.39, easeOutQuint
+ animation = windows, 1, 4.79, easeOutQuint
+ animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
+ animation = windowsOut, 1, 1.49, linear, popin 87%
+ animation = fadeIn, 1, 1.73, almostLinear
+ animation = fadeOut, 1, 1.46, almostLinear
+ animation = fade, 1, 3.03, quick
+ animation = layers, 1, 3.81, easeOutQuint
+ animation = layersIn, 1, 4, easeOutQuint, fade
+ animation = layersOut, 1, 1.5, linear, fade
+ animation = fadeLayersIn, 1, 1.79, almostLinear
+ animation = fadeLayersOut, 1, 1.39, almostLinear
+ animation = workspaces, 1, 1.94, almostLinear, fade
+ animation = workspacesIn, 1, 1.21, almostLinear, fade
+ animation = workspacesOut, 1, 1.94, almostLinear, fade
+}
+
+# Ref https://wiki.hypr.land/Configuring/Workspace-Rules/
+# "Smart gaps" / "No gaps when only"
+# uncomment all if you wish to use that.
+# workspace = w[tv1], gapsout:0, gapsin:0
+# workspace = f[1], gapsout:0, gapsin:0
+# windowrule = bordersize 0, floating:0, onworkspace:w[tv1]
+# windowrule = rounding 0, floating:0, onworkspace:w[tv1]
+# windowrule = bordersize 0, floating:0, onworkspace:f[1]
+# windowrule = rounding 0, floating:0, onworkspace:f[1]
+
+# See https://wiki.hypr.land/Configuring/Dwindle-Layout/ for more
+dwindle {
+ pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
+ preserve_split = true # You probably want this
+}
+
+# See https://wiki.hypr.land/Configuring/Master-Layout/ for more
+master {
+ new_status = master
+}
+
+# https://wiki.hypr.land/Configuring/Variables/#misc
+misc {
+ force_default_wallpaper = 0 # Set to 0 or 1 to disable the anime mascot wallpapers
+ disable_hyprland_logo = true # If true disables the random hyprland logo / anime girl background. :(
+ middle_click_paste = false
+}
+
+
+#############
+### INPUT ###
+#############
+
+# https://wiki.hypr.land/Configuring/Variables/#input
+input {
+ kb_layout = us
+ kb_variant = altgr-intl
+ kb_model =
+ kb_options =
+ kb_rules =
+
+ follow_mouse = 2
+
+ sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
+
+ scroll_method = on_button_down
+ scroll_button = 274
+}
+
+# Example per-device config
+# See https://wiki.hypr.land/Configuring/Keywords/#per-device-input-configs for more
+device {
+ name = benq-zowie-benq-zowie-gaming-mouse
+ sensitivity = 0
+}
+
+
+###################
+### KEYBINDINGS ###
+###################
+
+# See https://wiki.hypr.land/Configuring/Keywords/
+$mainMod = SUPER # Sets "Super" key as main modifier
+bind = $mainMod, T, exec, $terminal
+bind = $mainMod, Q, killactive,
+bind = $mainMod, N, exec, $fileManager
+bind = $mainMod, V, togglefloating,
+bind = $mainMod, Space, exec, $menu
+bind = $mainMod, G, togglesplit, # dwindle
+bind = $mainMod, F, fullscreen
+bind = $mainMod, B, exec, firefox
+bind = $mainMod, M, exec, thunderbird
+bind = $mainMod, L, exec, hyprlock
+
+# Move focus with mainMod + arrow keys
+bind = $mainMod, left, movefocus, l
+bind = $mainMod, right, movefocus, r
+bind = $mainMod, up, movefocus, u
+bind = $mainMod, down, movefocus, d
+
+bind = $mainMod SHIFT, left, movewindow, l
+bind = $mainMod SHIFT, right, movewindow, r
+bind = $mainMod SHIFT, up, movewindow, u
+bind = $mainMod SHIFT, down, movewindow, d
+
+# Example special workspace (scratchpad)
+bind = $mainMod, S, togglespecialworkspace, magic
+bind = $mainMod SHIFT, S, movetoworkspace, special:magic
+
+# Scroll through existing workspaces with mainMod + scroll
+bind = $mainMod, mouse_down, workspace, e+1
+bind = $mainMod, mouse_up, workspace, e-1
+
+# Move/resize windows with mainMod + LMB/RMB and dragging
+bindm = $mainMod, mouse:272, movewindow
+bindm = $mainMod, mouse:273, resizewindow
+
+# Laptop multimedia keys for volume and LCD brightness
+bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
+bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
+bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
+bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
+bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+
+bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%-
+
+# Requires playerctl
+# Spotify controls
+bind = CTRL ALT, K, exec, playerctl --player=spotify play-pause
+bind = CTRL ALT, Left, exec, playerctl --player=spotify previous
+bind = CTRL ALT, Right, exec, playerctl --player=spotify next
+bind = CTRL ALT, Up, exec, playerctl --player=spotify volume 0.05+
+bind = CTRL ALT, Down, exec, playerctl --player=spotify volume 0.05-
+
+bind = ,F7,pass,class:^(discord)$
+bind = ,F8,pass,class:^(discord)$
+
+# Printscreen
+# Screenshot a selected region (interactive)
+# bind = , Print, exec, hyprshot -m region
+bind = , Print, exec, hyprshot -zm region
+
+##############################
+### WINDOWRULES ###
+##############################
+
+# See https://wiki.hypr.land/Configuring/Window-Rules/ for more
+# See https://wiki.hypr.land/Configuring/Workspace-Rules/ for workspace rules
+
+# Ignore maximize requests from apps. You'll probably like this.
+windowrule = suppressevent maximize, class:.*
+
+# Fix some dragging issues with XWayland
+windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
+
+windowrulev2 = tag +jb, class:^jetbrains-.+$,floating:1
+windowrulev2 = stayfocused, tag:jb
+windowrulev2 = noinitialfocus, tag:jb
diff --git a/roles/hyprland/files/hypr/hyprlock.conf b/roles/hyprland/files/hypr/hyprlock.conf
new file mode 100644
index 0000000..bd6a0a9
--- /dev/null
+++ b/roles/hyprland/files/hypr/hyprlock.conf
@@ -0,0 +1,37 @@
+general {
+ disable_loading_bar = true
+ grace = 2
+ hide_cursor = true
+ no_fade_in = false
+}
+
+background {
+ monitor =
+ path = screenshot
+ blur_passes = 3
+ blur_size = 8
+}
+
+input-field {
+ monitor =
+ size = 300, 50
+ position = 0, -80
+ dots_center = true
+ fade_on_empty = false
+ font_color = rgb(202, 211, 245)
+ inner_color = rgb(91, 96, 120)
+ outer_color = rgb(24, 25, 38)
+ outline_thickness = 5
+ placeholder_text = Password...
+ shadow_passes = 2
+}
+
+label {
+ monitor =
+ text = Hi there, $USER
+ font_size = 20
+ font_family = RobotoMono Nerd Font Mono
+ position = 0, 160
+ halign = center
+ valign = center
+}
diff --git a/roles/hyprland/files/hypr/hyprpaper.conf b/roles/hyprland/files/hypr/hyprpaper.conf
new file mode 100644
index 0000000..0e236c6
--- /dev/null
+++ b/roles/hyprland/files/hypr/hyprpaper.conf
@@ -0,0 +1,7 @@
+preload = /home/johannes/Pictures/Wallpapers/wallhaven-5g22q5.png
+
+wallpaper = DP-1,/home/johannes/Pictures/Wallpapers/wallhaven-5g22q5.png
+wallpaper = DP-2,/home/johannes/Pictures/Wallpapers/wallhaven-5g22q5.png
+wallpaper = HDMI-A-2,/home/johannes/Pictures/Wallpapers/wallhaven-5g22q5.png
+
+splash = false
diff --git a/roles/hyprland/files/hypr/monitors.conf b/roles/hyprland/files/hypr/monitors.conf
new file mode 100644
index 0000000..d0957cb
--- /dev/null
+++ b/roles/hyprland/files/hypr/monitors.conf
@@ -0,0 +1,8 @@
+# Generated by nwg-displays on 2025-09-09 at 19:00:43. Do not edit manually.
+
+monitor=DP-1,2560x1440@165.0,6626x876,1.0
+monitor=DP-2,2560x1440@165.0,4066x876,1.0
+monitor=HDMI-A-1,0x0@60.0,-1x-1,1.0
+monitor=HDMI-A-1,disable
+monitor=HDMI-A-2,1920x1080@60.0,9186x396,1.0
+monitor=HDMI-A-2,transform,3
diff --git a/roles/hyprland/files/hypr/workspaces.conf b/roles/hyprland/files/hypr/workspaces.conf
new file mode 100644
index 0000000..ba4b7c3
--- /dev/null
+++ b/roles/hyprland/files/hypr/workspaces.conf
@@ -0,0 +1,34 @@
+$mainMod = SUPER # Sets "Super" key as main modifier
+
+workspace = 1, monitor:DP-1, persistent:true, default:true
+workspace = 2, monitor:DP-1, persistent:true
+workspace = 3, monitor:DP-1, persistent:true
+workspace = 4, monitor:DP-2, persistent:true, default:true
+workspace = 5, monitor:DP-2, persistent:true
+workspace = 6, monitor:DP-2, persistent:true
+workspace = 7, monitor:HDMI-A-2, persistent:true, default:true
+workspace = 8, monitor:HDMI-A-2, persistent:true
+workspace = 9, monitor:HDMI-A-2, persistent:true
+workspace = 10, monitor:HDMI-A-1, persistent:true, default:true
+
+bind = $mainMod, 1, exec, hyprctl --batch "dispatch focusmonitor DP-1; dispatch workspace 1;"
+bind = $mainMod, 2, exec, hyprctl --batch "dispatch focusmonitor DP-1; dispatch workspace 2;"
+bind = $mainMod, 3, exec, hyprctl --batch "dispatch focusmonitor DP-1; dispatch workspace 3;"
+bind = $mainMod, 4, exec, hyprctl --batch "dispatch focusmonitor DP-2; dispatch workspace 4;"
+bind = $mainMod, 5, exec, hyprctl --batch "dispatch focusmonitor DP-2; dispatch workspace 5;"
+bind = $mainMod, 6, exec, hyprctl --batch "dispatch focusmonitor DP-2; dispatch workspace 6;"
+bind = $mainMod, 7, exec, hyprctl --batch "dispatch focusmonitor HDMI-A-2; dispatch workspace 7;"
+bind = $mainMod, 8, exec, hyprctl --batch "dispatch focusmonitor HDMI-A-2; dispatch workspace 8;"
+bind = $mainMod, 9, exec, hyprctl --batch "dispatch focusmonitor HDMI-A-2; dispatch workspace 9;"
+bind = $mainMod, 0, exec, hyprctl --batch "dispatch focusmonitor HDMI-A-1; dispatch workspace 10;"
+
+bind = $mainMod SHIFT, 1, movetoworkspacesilent, 1
+bind = $mainMod SHIFT, 2, movetoworkspacesilent, 2
+bind = $mainMod SHIFT, 3, movetoworkspacesilent, 3
+bind = $mainMod SHIFT, 4, movetoworkspacesilent, 4
+bind = $mainMod SHIFT, 5, movetoworkspacesilent, 5
+bind = $mainMod SHIFT, 6, movetoworkspacesilent, 6
+bind = $mainMod SHIFT, 7, movetoworkspacesilent, 7
+bind = $mainMod SHIFT, 8, movetoworkspacesilent, 8
+bind = $mainMod SHIFT, 9, movetoworkspacesilent, 9
+bind = $mainMod SHIFT, 0, movetoworkspacesilent, 10
diff --git a/roles/hyprland/files/waybar/config.jsonc b/roles/hyprland/files/waybar/config.jsonc
new file mode 100644
index 0000000..34693fd
--- /dev/null
+++ b/roles/hyprland/files/waybar/config.jsonc
@@ -0,0 +1,128 @@
+{
+ "layer": "top",
+ "position": "top",
+
+ "exclusive": true, // keep the gap reserved
+ "margin-top": 8, // gap from the top edge
+ "margin-left": 10, // gap from the left edge
+ "margin-right": 10, // gap from the right edge
+ "margin-bottom": 0,
+
+ /* order: 1-2-3 | window-title | tray + clock */
+ // "modules-left": [ "custom/group1", "custom/group2", "custom/group3", "custom/group4","custom/group5","custom/group6","custom/group7","custom/group8","custom/group9","custom/group10"],
+ "modules-left": ["hyprland/workspaces"],
+ "modules-center": [ "hyprland/window" ],
+ "modules-right": [ "tray", "custom/separator", "network", "bluetooth", "custom/separator", "disk", "cpu", "memory", "pulseaudio", "custom/separator", "clock"],
+
+
+ "hyprland/workspaces": {
+ "disable-scroll": true,
+ "all-outputs": true,
+ "warp-on-scroll": false,
+ "format": "{icon}",
+ "format-icons": {
+ "1": "1",
+ "2": "2",
+ "3": "3",
+ "4": "4",
+ "5": "5",
+ "6": "6",
+ "7": "7",
+ "8": "8",
+ "9": "9",
+ "10": "0"
+ },
+ "persistent-workspaces": {
+ "1": [],
+ "2": [],
+ "3": [],
+ "4": [],
+ "5": [],
+ "6": [],
+ "7": [],
+ "8": [],
+ "9": [],
+ "10": []
+ }
+ },
+
+
+ "hyprland/window": { "format": "{title}", "max-length": 60 },
+ "tray": { "icon-size": 16, "spacing": 10 },
+
+ "pulseaudio": {
+ // ——— behaviour ———
+ "scroll-step": 5, // ± 5 % per wheel-step
+ "max-volume": 150, // allow 0 – 150 %
+ "on-click": "pactl set-sink-mute @DEFAULT_SINK@ toggle",
+ "on-click-right": "pavucontrol",
+
+ // ——— appearance ———
+ "markup": "pango", // enable coloured markup
+ "format": "{icon} {volume}%",
+ "format-muted": " muted",
+
+ // choose the glyphs you like (Nerd Font / Font Awesome)
+ "format-icons": {
+ "default": "", // speaker
+ "muted": "", // muted speaker
+ "headphones": ""
+ }
+ },
+
+ "custom/separator": {
+ // emit a JSON object with field "text"
+ "exec": "echo '{\"text\":\"|\"}'",
+ // treat stdout as JSON
+ "return-type": "json",
+ // wrap the text in a colored Pango span
+ "format": "{text}",
+ "markup": "pango",
+ // refresh only hourly
+ "interval": 3600
+ },
+
+ "cpu": {
+ "interval": 1, // update every second
+ "markup": "pango",
+ "format": " {usage}%"
+ },
+
+ "memory": {
+ "interval": 2, // fast enough, still light
+ "markup": "pango",
+ "format": " {percentage}%"
+ },
+
+ "disk": {
+ "interval": 30, // disks change slowly
+ "path": "/",
+ "markup": "pango",
+ "format": " {percentage_used}%"
+ },
+
+ /* ─── CLOCK (add date) ──────────────────────────────────── */
+
+ "clock": {
+ "interval": 1,
+ "format": "{:%Y-%m-%d %H:%M:%S}",
+ "format-alt": "{:%Y-%m-%d %H:%M}"
+ },
+
+/* ─── NETWORK ─────────────────────────────────────────────── */
+"network": {
+ "interface": ["enp.*", "eth.*"], // wired NICs (regex—adjust if needed)
+ "interval": 3,
+ "markup": "pango",
+
+ "format-ethernet": " up",
+ "format-wifi": " {essid}",
+ // "format-linked": " link",
+ "format-unknown": " up",
+ "format-disconnected":" down",
+
+ "on-click": "nm-connection-editor"
+},
+
+}
+
diff --git a/roles/hyprland/files/waybar/scripts/groups.sh b/roles/hyprland/files/waybar/scripts/groups.sh
new file mode 100755
index 0000000..50c8aa2
--- /dev/null
+++ b/roles/hyprland/files/waybar/scripts/groups.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+current=$(hyprctl activeworkspace -j | jq -r '.id')
+
+if [ "$1" = "click" ]; then
+ group=$2
+ start=$(( (group - 1) * 3 + 1 ))
+
+ hyprctl --batch " \
+ dispatch focusmonitor DP-1; dispatch workspace $start; \
+ dispatch focusmonitor DP-2; dispatch workspace $((start+1)); \
+ dispatch focusmonitor HDMI-A-2; dispatch workspace $((start+2)); \
+ dispatch focusmonitor DP-1"
+
+else
+ # Display button state
+ group=$1
+ start=$(( (group - 1) * 3 + 1 ))
+ end=$(( start + 2 ))
+ case $group in
+ 1) range="1-3"; icon="" ;;
+ 2) range="4-6"; icon="" ;;
+ 3) range="7-9"; icon="" ;;
+ 4) range="10-12"; icon="" ;;
+ 5) range="13-15"; icon="" ;;
+ 6) range="16-18"; icon="" ;;
+ 7) range="19-21"; icon="" ;;
+ 8) range="22-24"; icon="" ;;
+ 9) range="25-27"; icon="" ;;
+ 10) range="28-30"; icon="" ;;
+ esac
+
+ if [ $current -ge $start ] && [ $current -le $end ]; then
+ # Active group - return with active class
+ echo "{\"text\": \"$icon\", \"class\": \"active\"}"
+ else
+ # Inactive group
+ echo "{\"text\": \"$icon\", \"class\": \"inactive\"}"
+ fi
+fi
diff --git a/roles/hyprland/files/waybar/style.css b/roles/hyprland/files/waybar/style.css
new file mode 100644
index 0000000..eb9c920
--- /dev/null
+++ b/roles/hyprland/files/waybar/style.css
@@ -0,0 +1,100 @@
+/* Palette */
+@define-color glass rgba(12, 14, 20, 0.34);
+@define-color glass_strong rgba(12, 14, 20, 0.46);
+@define-color fg #DDE1EA;
+@define-color fg_dim #B8BECC;
+@define-color accent1 #7F5AF0;
+@define-color accent2 #00D1FF;
+@define-color occupied #a8557f;
+
+/* Whole bar: more vertical padding, no border, stronger shadow */
+window#waybar {
+ background: @glass;
+ color: @fg;
+ border-radius: 12px;
+ /* margin: 6px 8px; */
+ border: none; /* ← removed border */
+ box-shadow: 0 10px 34px rgba(0,0,0,0.34);
+ -gtk-outline-radius: 12px;
+}
+
+* {
+ border: none;
+ padding: 2px 6px;
+ margin-top: 0;
+ font-family: "RobotoMono Nerd Font", "Roboto Mono Nerd Font", "RobotoMono NF", monospace;
+ font-size: 14px;
+ font-weight: 500;
+}
+
+/* Keep groups transparent */
+#modules-left, #modules-center, #modules-right { background: transparent; }
+
+/* Common modules stay transparent; compact rounded hit area */
+#tray, #window, #clock, #cpu, #memory, #disk, #network, #bluetooth, #pulseaudio {
+ background: transparent;
+ border-radius: 8px;
+ color: @fg;
+}
+
+/* Subtle separators */
+#custom-separator {
+ color: rgba(200,200,200,0.20);
+ padding: 0 4px;
+}
+
+/* Tray tweaks */
+#tray { margin-right: 0px; }
+#tray * { padding-left: 0px; padding-right: 0px; }
+
+/* Tray menu glass look (also lighter, no border) */
+#tray menu {
+ padding: 6px 0;
+ margin: 0;
+ background: @glass_strong;
+ border-radius: 10px;
+ border: none;
+ box-shadow: 0 10px 34px rgba(0,0,0,0.38);
+}
+#tray menu menuitem { padding: 6px 12px; }
+#tray menu menuitem:hover { background: alpha(@accent1, 0.16); }
+
+#workspaces button {
+ padding: 0 8px;
+ background-color: transparent;
+ color: #6c7086;
+ border-radius: 3px;
+ margin: 2px;
+ transition: all 0.2s ease-in-out;
+}
+
+/* Hover effect */
+#workspaces button:hover {
+ background-color: #74c7ec;
+ color: #1e1e2e;
+}
+
+#workspaces button:not(.active):not(.empty) {
+ color: #cdd6f4;
+ background-color: #585b70;
+}
+
+/* Active/focused workspace */
+#workspaces button.active {
+ color: #1e1e2e;
+ background-color: @occupied;
+ font-weight: bold;
+}
+
+#workspaces button.visible {
+ color: #f9e2af;
+ /* background-color: #45475a; */
+ border: 1px solid #f9e2af;
+}
+
+/* Default state for persistent workspaces */
+#workspaces button {
+ color: #6c7086;
+ background-color: @glass;
+}
+
diff --git a/roles/hyprland/files/wofi/config b/roles/hyprland/files/wofi/config
new file mode 100644
index 0000000..334a4a8
--- /dev/null
+++ b/roles/hyprland/files/wofi/config
@@ -0,0 +1,13 @@
+[config]
+allow_images=true
+width=500
+show=drun
+prompt=Search
+height=400
+term=ghostty
+hide_scroll=true
+print_command=true
+insensitive=true
+columns=1
+pre_display_exec=true
+no_actions=true
diff --git a/roles/hyprland/files/wofi/style.css b/roles/hyprland/files/wofi/style.css
new file mode 100644
index 0000000..b2d70fb
--- /dev/null
+++ b/roles/hyprland/files/wofi/style.css
@@ -0,0 +1,91 @@
+* {
+ /* smoother corners everywhere */
+ border-radius: 12px;
+ font-weight: 450;
+}
+
+/* Window container */
+window {
+ margin: 0px;
+ padding: 6px;
+ border: 1px solid rgba(127, 90, 240, 0.35); /* accent tint */
+ background-color: rgba(12, 14, 20, 0.55); /* translucent */
+ color: #E6E7EB;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
+ backg
+}
+
+/* Input field */
+#input {
+ margin: 8px;
+ padding: 10px 12px;
+ border: 1px solid rgba(127, 90, 240, 0.25);
+ background-color: rgba(34, 38, 48, 0.70);
+ color: #E6E7EB;
+ outline: none;
+}
+
+/* Lists/boxes */
+#outer-box, #inner-box {
+ margin: 6px;
+ border: none;
+ background-color: rgba(24, 28, 36, 0.60);
+}
+
+#scroll {
+ margin: 0px;
+ border: none;
+}
+
+/* Entry text */
+#text, #entry > * {
+ margin: 6px 10px;
+ color: #E6E7EB;
+}
+
+/* Rows (entries) */
+#entry {
+ margin: 4px 6px;
+ padding: 8px 6px;
+ border: 1px solid transparent;
+ background-color: transparent;
+ transition: background-color 120ms ease, border-color 120ms ease;
+}
+
+/* Hover — soft highlight */
+#entry:hover {
+ background-color: rgba(127, 90, 240, 0.10);
+ border-color: rgba(127, 90, 240, 0.25);
+}
+
+/* Selected row — stronger surface and bold text */
+#entry:selected {
+ background-color: rgba(127, 90, 240, 0.18);
+ border-color: rgba(127, 90, 240, 0.40);
+}
+
+#entry:selected #text {
+ font-weight: 600;
+}
+
+/* Activatable (e.g., currently typed match) — invert text for contrast */
+#entry.activatable #text {
+ color: rgba(12, 14, 20, 0.92);
+}
+
+/* Muted secondary text, if present */
+#entry .secondary, #entry .desc {
+ color: #AAB0BC;
+}
+
+/* Optional: focus ring for keyboard nav */
+#entry:focus {
+ border-color: rgba(127, 90, 240, 0.55);
+ background-color: rgba(127, 90, 240, 0.12);
+}
+
+/* Optional: thin separators using subtle overlay lines */
+separator, .separator {
+ background-color: rgba(255, 255, 255, 0.06);
+ min-height: 1px;
+}
diff --git a/roles/hyprland/tasks/main.yml b/roles/hyprland/tasks/main.yml
new file mode 100644
index 0000000..6d5d578
--- /dev/null
+++ b/roles/hyprland/tasks/main.yml
@@ -0,0 +1,29 @@
+---
+- name: Symlink hyprland
+ file:
+ src: "{{ role_path }}/files/hypr"
+ dest: "{{ config_dir }}/hypr"
+ state: link
+ force: true
+
+- name: Symlink dunst
+ file:
+ src: "{{ role_path }}/files/dunst"
+ dest: "{{ config_dir }}/dunst"
+ state: link
+ force: true
+
+- name: Symlink wofi
+ file:
+ src: "{{ role_path }}/files/wofi"
+ dest: "{{ config_dir }}/wofi"
+ state: link
+ force: true
+
+- name: Symlink waybar
+ file:
+ src: "{{ role_path }}/files/waybar"
+ dest: "{{ config_dir }}/waybar"
+ state: link
+ force: true
+
diff --git a/nvim/after/ftplugin/markdown.lua b/roles/nvim/files/after/ftplugin/markdown.lua
similarity index 100%
rename from nvim/after/ftplugin/markdown.lua
rename to roles/nvim/files/after/ftplugin/markdown.lua
diff --git a/nvim/after/ftplugin/scss.lua b/roles/nvim/files/after/ftplugin/scss.lua
similarity index 100%
rename from nvim/after/ftplugin/scss.lua
rename to roles/nvim/files/after/ftplugin/scss.lua
diff --git a/nvim/after/ftplugin/typescript.lua b/roles/nvim/files/after/ftplugin/typescript.lua
similarity index 100%
rename from nvim/after/ftplugin/typescript.lua
rename to roles/nvim/files/after/ftplugin/typescript.lua
diff --git a/nvim/after/ftplugin/vim.lua b/roles/nvim/files/after/ftplugin/vim.lua
similarity index 100%
rename from nvim/after/ftplugin/vim.lua
rename to roles/nvim/files/after/ftplugin/vim.lua
diff --git a/nvim/init.lua b/roles/nvim/files/init.lua
similarity index 100%
rename from nvim/init.lua
rename to roles/nvim/files/init.lua
diff --git a/nvim/lazy-lock.json b/roles/nvim/files/lazy-lock.json
similarity index 100%
rename from nvim/lazy-lock.json
rename to roles/nvim/files/lazy-lock.json
diff --git a/nvim/lua/config/core/init.lua b/roles/nvim/files/lua/config/core/init.lua
similarity index 100%
rename from nvim/lua/config/core/init.lua
rename to roles/nvim/files/lua/config/core/init.lua
diff --git a/nvim/lua/config/core/keymaps.lua b/roles/nvim/files/lua/config/core/keymaps.lua
similarity index 93%
rename from nvim/lua/config/core/keymaps.lua
rename to roles/nvim/files/lua/config/core/keymaps.lua
index f739e66..c2c5ba3 100644
--- a/nvim/lua/config/core/keymaps.lua
+++ b/roles/nvim/files/lua/config/core/keymaps.lua
@@ -6,7 +6,7 @@ local opts = { noremap = true, silent = true }
-- INSERT MODE
-- map `ctrl + backspace` to delete previous word in insert mode
-keymap.set('i', '', '', opts)
+keymap.set('i', '', '', opts)
-- map `ctrl + delete` to delete next word in insert mode
keymap.set('i', '', 'dw', opts)
diff --git a/nvim/lua/config/core/options.lua b/roles/nvim/files/lua/config/core/options.lua
similarity index 100%
rename from nvim/lua/config/core/options.lua
rename to roles/nvim/files/lua/config/core/options.lua
diff --git a/nvim/lua/config/lazy.lua b/roles/nvim/files/lua/config/lazy.lua
similarity index 100%
rename from nvim/lua/config/lazy.lua
rename to roles/nvim/files/lua/config/lazy.lua
diff --git a/nvim/lua/config/plugins/airline.lua# b/roles/nvim/files/lua/config/plugins/airline.lua#
similarity index 100%
rename from nvim/lua/config/plugins/airline.lua#
rename to roles/nvim/files/lua/config/plugins/airline.lua#
diff --git a/nvim/lua/config/plugins/alpha.lua b/roles/nvim/files/lua/config/plugins/alpha.lua
similarity index 100%
rename from nvim/lua/config/plugins/alpha.lua
rename to roles/nvim/files/lua/config/plugins/alpha.lua
diff --git a/nvim/lua/config/plugins/auto-session.lua b/roles/nvim/files/lua/config/plugins/auto-session.lua
similarity index 100%
rename from nvim/lua/config/plugins/auto-session.lua
rename to roles/nvim/files/lua/config/plugins/auto-session.lua
diff --git a/nvim/lua/config/plugins/autopairs.lua b/roles/nvim/files/lua/config/plugins/autopairs.lua
similarity index 100%
rename from nvim/lua/config/plugins/autopairs.lua
rename to roles/nvim/files/lua/config/plugins/autopairs.lua
diff --git a/nvim/lua/config/plugins/bufdelete.lua b/roles/nvim/files/lua/config/plugins/bufdelete.lua
similarity index 100%
rename from nvim/lua/config/plugins/bufdelete.lua
rename to roles/nvim/files/lua/config/plugins/bufdelete.lua
diff --git a/nvim/lua/config/plugins/bufferline.lua b/roles/nvim/files/lua/config/plugins/bufferline.lua
similarity index 100%
rename from nvim/lua/config/plugins/bufferline.lua
rename to roles/nvim/files/lua/config/plugins/bufferline.lua
diff --git a/nvim/lua/config/plugins/cmp.lua b/roles/nvim/files/lua/config/plugins/cmp.lua
similarity index 100%
rename from nvim/lua/config/plugins/cmp.lua
rename to roles/nvim/files/lua/config/plugins/cmp.lua
diff --git a/nvim/lua/config/plugins/colorscheme.lua b/roles/nvim/files/lua/config/plugins/colorscheme.lua
similarity index 100%
rename from nvim/lua/config/plugins/colorscheme.lua
rename to roles/nvim/files/lua/config/plugins/colorscheme.lua
diff --git a/nvim/lua/config/plugins/diffview.lua b/roles/nvim/files/lua/config/plugins/diffview.lua
similarity index 100%
rename from nvim/lua/config/plugins/diffview.lua
rename to roles/nvim/files/lua/config/plugins/diffview.lua
diff --git a/nvim/lua/config/plugins/dressing.lua b/roles/nvim/files/lua/config/plugins/dressing.lua
similarity index 100%
rename from nvim/lua/config/plugins/dressing.lua
rename to roles/nvim/files/lua/config/plugins/dressing.lua
diff --git a/nvim/lua/config/plugins/floaterm.lua b/roles/nvim/files/lua/config/plugins/floaterm.lua
similarity index 100%
rename from nvim/lua/config/plugins/floaterm.lua
rename to roles/nvim/files/lua/config/plugins/floaterm.lua
diff --git a/nvim/lua/config/plugins/flutter.lua b/roles/nvim/files/lua/config/plugins/flutter.lua
similarity index 100%
rename from nvim/lua/config/plugins/flutter.lua
rename to roles/nvim/files/lua/config/plugins/flutter.lua
diff --git a/nvim/lua/config/plugins/init.lua b/roles/nvim/files/lua/config/plugins/init.lua
similarity index 100%
rename from nvim/lua/config/plugins/init.lua
rename to roles/nvim/files/lua/config/plugins/init.lua
diff --git a/nvim/lua/config/plugins/lazygit.lua b/roles/nvim/files/lua/config/plugins/lazygit.lua
similarity index 100%
rename from nvim/lua/config/plugins/lazygit.lua
rename to roles/nvim/files/lua/config/plugins/lazygit.lua
diff --git a/nvim/lua/config/plugins/lsp/lspconfig.lua b/roles/nvim/files/lua/config/plugins/lsp/lspconfig.lua
similarity index 100%
rename from nvim/lua/config/plugins/lsp/lspconfig.lua
rename to roles/nvim/files/lua/config/plugins/lsp/lspconfig.lua
diff --git a/nvim/lua/config/plugins/lsp/mason.lua b/roles/nvim/files/lua/config/plugins/lsp/mason.lua
similarity index 100%
rename from nvim/lua/config/plugins/lsp/mason.lua
rename to roles/nvim/files/lua/config/plugins/lsp/mason.lua
diff --git a/nvim/lua/config/plugins/lsp/null-ls.lua b/roles/nvim/files/lua/config/plugins/lsp/null-ls.lua
similarity index 100%
rename from nvim/lua/config/plugins/lsp/null-ls.lua
rename to roles/nvim/files/lua/config/plugins/lsp/null-ls.lua
diff --git a/nvim/lua/config/plugins/lsp/pyrightconfig.json b/roles/nvim/files/lua/config/plugins/lsp/pyrightconfig.json
similarity index 100%
rename from nvim/lua/config/plugins/lsp/pyrightconfig.json
rename to roles/nvim/files/lua/config/plugins/lsp/pyrightconfig.json
diff --git a/nvim/lua/config/plugins/lualine.lua b/roles/nvim/files/lua/config/plugins/lualine.lua
similarity index 100%
rename from nvim/lua/config/plugins/lualine.lua
rename to roles/nvim/files/lua/config/plugins/lualine.lua
diff --git a/nvim/lua/config/plugins/nvim-tree.lua b/roles/nvim/files/lua/config/plugins/nvim-tree.lua
similarity index 100%
rename from nvim/lua/config/plugins/nvim-tree.lua
rename to roles/nvim/files/lua/config/plugins/nvim-tree.lua
diff --git a/nvim/lua/config/plugins/surround.lua b/roles/nvim/files/lua/config/plugins/surround.lua
similarity index 100%
rename from nvim/lua/config/plugins/surround.lua
rename to roles/nvim/files/lua/config/plugins/surround.lua
diff --git a/nvim/lua/config/plugins/telescope.lua b/roles/nvim/files/lua/config/plugins/telescope.lua
similarity index 100%
rename from nvim/lua/config/plugins/telescope.lua
rename to roles/nvim/files/lua/config/plugins/telescope.lua
diff --git a/nvim/lua/config/plugins/todo-comments.lua b/roles/nvim/files/lua/config/plugins/todo-comments.lua
similarity index 100%
rename from nvim/lua/config/plugins/todo-comments.lua
rename to roles/nvim/files/lua/config/plugins/todo-comments.lua
diff --git a/nvim/lua/config/plugins/treesitter.lua b/roles/nvim/files/lua/config/plugins/treesitter.lua
similarity index 100%
rename from nvim/lua/config/plugins/treesitter.lua
rename to roles/nvim/files/lua/config/plugins/treesitter.lua
diff --git a/nvim/lua/config/plugins/venv-selector.lua b/roles/nvim/files/lua/config/plugins/venv-selector.lua
similarity index 100%
rename from nvim/lua/config/plugins/venv-selector.lua
rename to roles/nvim/files/lua/config/plugins/venv-selector.lua
diff --git a/nvim/lua/config/plugins/which-key.lua b/roles/nvim/files/lua/config/plugins/which-key.lua
similarity index 100%
rename from nvim/lua/config/plugins/which-key.lua
rename to roles/nvim/files/lua/config/plugins/which-key.lua
diff --git a/roles/nvim/tasks/main.yml b/roles/nvim/tasks/main.yml
new file mode 100644
index 0000000..bad1f3b
--- /dev/null
+++ b/roles/nvim/tasks/main.yml
@@ -0,0 +1,12 @@
+---
+- name: Install neovim
+ package:
+ name: neovim
+ state: present
+
+- name: Symlink neovim
+ file:
+ src: "{{ role_path }}/files"
+ dest: "{{ config_dir }}/nvim"
+ state: link
+ force: true
diff --git a/roles/system/tasks/main.yml b/roles/system/tasks/main.yml
new file mode 100644
index 0000000..67fc787
--- /dev/null
+++ b/roles/system/tasks/main.yml
@@ -0,0 +1,20 @@
+---
+- name: Update package cache (Arch-based systems)
+ pacman:
+ update_cache: yes
+ when: ansible_os_family == "Archlinux"
+ become: yes
+
+- name: Install system packages
+ package:
+ name: "{{ system_packages }}"
+ state: present
+ become: yes
+
+- name: Ensure .config directory exists
+ file:
+ path: "{{ config_dir }}"
+ state: directory
+ mode: '0755'
+ owner: "{{ ansible_user }}"
+ group: "{{ ansible_user }}"
diff --git a/roles/zsh/files/.zshrc b/roles/zsh/files/.zshrc
new file mode 100644
index 0000000..2a70a1e
--- /dev/null
+++ b/roles/zsh/files/.zshrc
@@ -0,0 +1,51 @@
+# If you come from bash you might have to change your $PATH.
+# export PATH=$HOME/bin:$HOME/.local/bin:/usr/local/bin:$PATH
+
+# Path to your Oh My Zsh installation.
+export ZSH="$HOME/.oh-my-zsh"
+
+ZSH_THEME="bira"
+zstyle ':omz:update' mode reminder # just remind me to update when it's time
+COMPLETION_WAITING_DOTS="true"
+
+plugins=(
+ git
+ zsh-syntax-highlighting
+ zsh-autosuggestions
+ fzf-zsh-plugin
+)
+
+source $ZSH/oh-my-zsh.sh
+
+
+# Preferred editor for local and remote sessions
+if [[ -n $SSH_CONNECTION ]]; then
+ export EDITOR='vim'
+else
+ export EDITOR='nvim'
+fi
+
+export DOTFILES_ZSH_DIR="$HOME/dotfiles/roles/zsh/files"
+
+for zsh_file in "$DOTFILES_ZSH_DIR"/*.zsh; do
+ [[ -r "$zsh_file" ]] && source "$zsh_file"
+done
+
+
+# TODO source all files with .zsh suffix
+# source ./aliases.zsh
+# source ./dev_env.zsh
+# source ./tools.zsh
+
+# TODO
+export NVM_DIR="$HOME/.nvm"
+[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
+[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
+
+if [[ -n "$MACHINE_TYPE" && -f "$HOME/dotfiles/zsh/hosts/$MACHINE_TYPE.zsh" ]]; then
+ source "$HOME/dotfiles/zsh/hosts/$MACHINE_TYPE.zsh"
+fi
+
+
+alias drun='docker run -it --network=host --device=/dev/kfd --device=/dev/dri --group-add=video --ipc=host --cap-add=SYS_PTRACE --security-opt seccomp=unconfined'
+
diff --git a/zsh/aliases.zsh b/roles/zsh/files/aliases.zsh
similarity index 67%
rename from zsh/aliases.zsh
rename to roles/zsh/files/aliases.zsh
index a4f838c..8d3de04 100644
--- a/zsh/aliases.zsh
+++ b/roles/zsh/files/aliases.zsh
@@ -4,8 +4,14 @@ alias tp='trash-put'
alias tl='trash-list'
alias szrc='source ~/.zshrc'
+alias zrc="vim ~/.zshrc"
alias dotf='vim ~/dotfiles/'
+# TODO relative path
+alias hyprconf='vim ~/dotfiles/roles/hyprland/files/hypr/hyprland.conf'
+
+alias ls='eza'
+
rm() {
print "ℹ️ Consider using trash-put instead of rm"
print "➡️ Running: trash-put $*"
diff --git a/zsh/dev_env.zsh b/roles/zsh/files/dev_env.zsh
similarity index 100%
rename from zsh/dev_env.zsh
rename to roles/zsh/files/dev_env.zsh
diff --git a/zsh/hosts/personal.zsh b/roles/zsh/files/hosts/personal.zsh
similarity index 100%
rename from zsh/hosts/personal.zsh
rename to roles/zsh/files/hosts/personal.zsh
diff --git a/zsh/hosts/work.zsh b/roles/zsh/files/hosts/work.zsh
similarity index 100%
rename from zsh/hosts/work.zsh
rename to roles/zsh/files/hosts/work.zsh
diff --git a/zsh/tools.zsh b/roles/zsh/files/tools.zsh
similarity index 100%
rename from zsh/tools.zsh
rename to roles/zsh/files/tools.zsh
diff --git a/roles/zsh/tasks/main.yaml b/roles/zsh/tasks/main.yaml
new file mode 100644
index 0000000..8cd5ac0
--- /dev/null
+++ b/roles/zsh/tasks/main.yaml
@@ -0,0 +1,24 @@
+---
+- name: Install zsh
+ package:
+ name: zsh
+ state: present
+
+- name: Install oh-my-zsh
+ shell: |
+ sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" --unattended
+ args:
+ creates: "{{ ansible_env.HOME }}/.oh-my-zsh"
+
+- name: Check for custom zshrc
+ stat:
+ path: "{{ role_path }}/files/.zshrc"
+ register: custom_zshrc
+
+- name: Symlink custom zshrc
+ file:
+ src: "{{ role_path }}/files/.zshrc"
+ dest: "{{ ansible_env.HOME }}/.zshrc"
+ state: link
+ force: yes
+ when: custom_zshrc.stat.exists
diff --git a/todo_ansible.md b/todo_ansible.md
new file mode 100644
index 0000000..ec1e301
--- /dev/null
+++ b/todo_ansible.md
@@ -0,0 +1,238 @@
+Here's how such a role-based Ansible dotfiles configuration would work:
+
+## Directory Structure
+```
+dotfiles/
+├── playbook.yml # Main playbook
+├── group_vars/
+│ └── all.yml # Your config with default_roles
+├── roles/
+│ ├── system/
+│ │ ├── tasks/main.yml
+│ │ ├── vars/main.yml
+│ │ └── files/
+│ ├── git/
+│ │ ├── tasks/main.yml
+│ │ ├── templates/
+│ │ │ └── .gitconfig.j2
+│ │ └── vars/main.yml
+│ ├── neovim/
+│ │ ├── tasks/main.yml
+│ │ └── files/
+│ └── zsh/
+│ ├── tasks/main.yml
+│ ├── files/
+│ │ └── .zshrc
+│ └── vars/main.yml
+└── inventory
+```
+
+## Main Configuration (`group_vars/all.yml`)
+```yaml
+# Your system configuration
+default_roles:
+ - system
+ - git
+ - neovim
+ - zsh
+ - docker
+
+# Global variables
+dotfiles_dir: "{{ ansible_env.HOME }}/dotfiles"
+config_dir: "{{ ansible_env.HOME }}/.config"
+
+# Git configuration
+git_user_name: "Johannes"
+git_user_email: "johannes@example.com"
+git_editor: "nvim"
+
+# System packages to install
+system_packages:
+ - curl
+ - wget
+ - unzip
+ - tree
+```
+
+## Main Playbook (`playbook.yml`)
+```yaml
+---
+- name: Setup development environment
+ hosts: localhost
+ connection: local
+ become: yes
+ become_method: sudo
+
+ pre_tasks:
+ - name: Create btrfs snapshot before changes
+ shell: |
+ sudo btrfs subvolume snapshot / /.snapshots/before-dotfiles-$(date +%Y%m%d-%H%M%S)
+ ignore_errors: yes
+ tags: [snapshot]
+
+ roles: "{{ default_roles }}"
+
+ post_tasks:
+ - name: Summary of installed roles
+ debug:
+ msg: "Completed setup for: {{ default_roles | join(', ') }}"
+```
+
+## Example Roles
+
+### System Role (`roles/system/tasks/main.yml`)
+```yaml
+---
+- name: Install system packages
+ package:
+ name: "{{ system_packages }}"
+ state: present
+
+- name: Ensure .config directory exists
+ file:
+ path: "{{ config_dir }}"
+ state: directory
+ mode: '0755'
+
+- name: Set up shell as default
+ user:
+ name: "{{ ansible_env.USER }}"
+ shell: /usr/bin/zsh
+ when: "'zsh' in default_roles"
+```
+
+### Git Role (`roles/git/tasks/main.yml`)
+```yaml
+---
+- name: Install git
+ package:
+ name: git
+ state: present
+
+- name: Check if custom gitconfig exists
+ stat:
+ path: "{{ dotfiles_dir }}/git/.gitconfig"
+ register: custom_gitconfig
+
+- name: Use custom gitconfig if available
+ file:
+ src: "{{ dotfiles_dir }}/git/.gitconfig"
+ dest: "{{ ansible_env.HOME }}/.gitconfig"
+ state: link
+ force: yes
+ when: custom_gitconfig.stat.exists
+
+- name: Generate gitconfig from template if no custom config
+ template:
+ src: .gitconfig.j2
+ dest: "{{ ansible_env.HOME }}/.gitconfig"
+ mode: '0644'
+ when: not custom_gitconfig.stat.exists
+```
+
+### Git Template (`roles/git/templates/.gitconfig.j2`)
+```ini
+[user]
+ name = {{ git_user_name }}
+ email = {{ git_user_email }}
+
+[core]
+ editor = {{ git_editor }}
+ autocrlf = input
+
+[init]
+ defaultBranch = main
+
+[push]
+ default = simple
+```
+
+### Neovim Role (`roles/neovim/tasks/main.yml`)
+```yaml
+---
+- name: Install neovim
+ package:
+ name: neovim
+ state: present
+
+- name: Check for custom neovim config
+ stat:
+ path: "{{ dotfiles_dir }}/nvim"
+ register: nvim_config
+
+- name: Symlink neovim config
+ file:
+ src: "{{ dotfiles_dir }}/nvim"
+ dest: "{{ config_dir }}/nvim"
+ state: link
+ force: yes
+ when: nvim_config.stat.exists
+
+- name: Create basic neovim config if none exists
+ copy:
+ content: |
+ -- Basic Neovim configuration
+ vim.opt.number = true
+ vim.opt.expandtab = true
+ vim.opt.tabstop = 2
+ vim.opt.shiftwidth = 2
+ dest: "{{ config_dir }}/nvim/init.lua"
+ mode: '0644'
+ when: not nvim_config.stat.exists
+```
+
+### ZSH Role (`roles/zsh/tasks/main.yml`)
+```yaml
+---
+- name: Install zsh
+ package:
+ name: zsh
+ state: present
+
+- name: Install oh-my-zsh
+ shell: |
+ sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" --unattended
+ args:
+ creates: "{{ ansible_env.HOME }}/.oh-my-zsh"
+
+- name: Check for custom zshrc
+ stat:
+ path: "{{ dotfiles_dir }}/zsh/.zshrc"
+ register: custom_zshrc
+
+- name: Symlink custom zshrc
+ file:
+ src: "{{ dotfiles_dir }}/zsh/.zshrc"
+ dest: "{{ ansible_env.HOME }}/.zshrc"
+ state: link
+ force: yes
+ when: custom_zshrc.stat.exists
+```
+
+## Usage
+
+**To install everything:**
+```bash
+ansible-playbook -i inventory playbook.yml --ask-become-pass
+```
+
+**To install only specific roles:**
+```bash
+ansible-playbook -i inventory playbook.yml --ask-become-pass --tags "git,neovim"
+```
+
+**To override roles temporarily:**
+```bash
+ansible-playbook -i inventory playbook.yml --ask-become-pass -e "default_roles=['system','git']"
+```
+
+## Benefits of This Approach
+
+1. **Modular**: Each tool is a separate role
+2. **Configurable**: Easy to enable/disable tools in `all.yml`
+3. **Reusable**: Roles can be shared across different machines
+4. **Flexible**: Can override variables per host/group
+5. **Fallback configs**: Generates basic configs when custom ones don't exist
+6. **Scalable**: Easy to add new tools without touching existing code
+
+This approach lets you manage your entire development environment as code while keeping it organized and maintainable!
diff --git a/zsh/.zshrc b/zsh/.zshrc
deleted file mode 100644
index a620ac0..0000000
--- a/zsh/.zshrc
+++ /dev/null
@@ -1,126 +0,0 @@
-# If you come from bash you might have to change your $PATH.
-# export PATH=$HOME/bin:$HOME/.local/bin:/usr/local/bin:$PATH
-
-# Path to your Oh My Zsh installation.
-export ZSH="$HOME/.oh-my-zsh"
-
-# Set name of the theme to load --- if set to "random", it will
-# load a random theme each time Oh My Zsh is loaded, in which case,
-# to know which specific one was loaded, run: echo $RANDOM_THEME
-# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
-ZSH_THEME="bira"
-
-# Set list of themes to pick from when loading at random
-# Setting this variable when ZSH_THEME=random will cause zsh to load
-# a theme from this variable instead of looking in $ZSH/themes/
-# If set to an empty array, this variable will have no effect.
-# ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" )
-
-# Uncomment the following line to use case-sensitive completion.
-# CASE_SENSITIVE="true"
-
-# Uncomment the following line to use hyphen-insensitive completion.
-# Case-sensitive completion must be off. _ and - will be interchangeable.
-# HYPHEN_INSENSITIVE="true"
-
-# Uncomment one of the following lines to change the auto-update behavior
-# zstyle ':omz:update' mode disabled # disable automatic updates
-# zstyle ':omz:update' mode auto # update automatically without asking
-zstyle ':omz:update' mode reminder # just remind me to update when it's time
-
-# Uncomment the following line to change how often to auto-update (in days).
-# zstyle ':omz:update' frequency 13
-
-# Uncomment the following line if pasting URLs and other text is messed up.
-# DISABLE_MAGIC_FUNCTIONS="true"
-
-# Uncomment the following line to disable colors in ls.
-# DISABLE_LS_COLORS="true"
-
-# Uncomment the following line to disable auto-setting terminal title.
-# DISABLE_AUTO_TITLE="true"
-
-# Uncomment the following line to enable command auto-correction.
-# ENABLE_CORRECTION="true"
-
-# Uncomment the following line to display red dots whilst waiting for completion.
-# You can also set it to another string to have that shown instead of the default red dots.
-# e.g. COMPLETION_WAITING_DOTS="%F{yellow}waiting...%f"
-# Caution: this setting can cause issues with multiline prompts in zsh < 5.7.1 (see #5765)
-COMPLETION_WAITING_DOTS="true"
-
-# Uncomment the following line if you want to disable marking untracked files
-# under VCS as dirty. This makes repository status check for large repositories
-# much, much faster.
-# DISABLE_UNTRACKED_FILES_DIRTY="true"
-
-# Uncomment the following line if you want to change the command execution time
-# stamp shown in the history command output.
-# You can set one of the optional three formats:
-# "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd"
-# or set a custom format using the strftime function format specifications,
-# see 'man strftime' for details.
-# HIST_STAMPS="mm/dd/yyyy"
-
-# Would you like to use another custom folder than $ZSH/custom?
-# ZSH_CUSTOM=/path/to/new-custom-folder
-
-# 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=(
- git
- zsh-syntax-highlighting
- zsh-autosuggestions
- fzf-zsh-plugin
-)
-
-source $ZSH/oh-my-zsh.sh
-
-# User configuration
-
-# export MANPATH="/usr/local/man:$MANPATH"
-
-# You may need to manually set your language environment
-# export LANG=en_US.UTF-8
-
-# Preferred editor for local and remote sessions
-if [[ -n $SSH_CONNECTION ]]; then
- export EDITOR='vim'
-else
- export EDITOR='nvim'
-fi
-
-# Compilation flags
-# export ARCHFLAGS="-arch $(uname -m)"
-
-# Set personal aliases, overriding those provided by Oh My Zsh libs,
-# plugins, and themes. Aliases can be placed here, though Oh My Zsh
-# users are encouraged to define aliases within a top-level file in
-# the $ZSH_CUSTOM folder, with .zsh extension. Examples:
-# - $ZSH_CUSTOM/aliases.zsh
-# - $ZSH_CUSTOM/macos.zsh
-# For a full list of active aliases, run `alias`.
-#
-# Example aliases
-# alias zshconfig="mate ~/.zshrc"
-# alias ohmyzsh="mate ~/.oh-my-zsh"
-# bindkey '^R' history-incremental-search-backward
-
-# TODO source all files with .zsh suffix
-source ~/dotfiles/zsh/aliases.zsh
-source ~/dotfiles/zsh/dev_env.zsh
-source ~/dotfiles/zsh/tools.zsh
-
-
-
-
-export NVM_DIR="$HOME/.nvm"
-[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
-[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
-
-if [[ -n "$MACHINE_TYPE" && -f "$HOME/dotfiles/zsh/hosts/$MACHINE_TYPE.zsh" ]]; then
- source "$HOME/dotfiles/zsh/hosts/$MACHINE_TYPE.zsh"
-fi