Compare commits

...

2 Commits

Author SHA1 Message Date
Fabio Scotto di Santolo
bac7d92cf6 Add optional KDE desktop profile 2026-06-21 20:45:11 +02:00
Fabio Scotto di Santolo
2fdda39395 Provision Emacs development tools 2026-06-21 18:41:48 +02:00
15 changed files with 772 additions and 125 deletions

View File

@@ -52,7 +52,7 @@ Ansible-driven personal infrastructure repo for Void desktops, Linux workstation
- Use `no_log: true` for secret-bearing task inputs or outputs.
## Desktop Notes
- `profile_desktop_common` owns the shared desktop bootstrap; `profile_desktop_sway` (Wayland/SwayFX) and `profile_desktop_hyprland` (Wayland) install their respective sessions in parallel and are wired into the `void` play in `ansible/site.yml`. `desktop_sessions_enabled` and `desktop_default_session` in host vars decide which sessions are exposed in `emptty` and which is preselected.
- `desktop_environment` selects the mutually exclusive `minimal` (default) or `kde` desktop mode. `profile_desktop_common` owns shared bootstrap; the minimal mode uses `profile_desktop_sway` and `profile_desktop_hyprland`, while `profile_desktop_kde` owns KDE-specific defaults and cleanup. `desktop_sessions_enabled` and `desktop_default_session` apply only to the minimal mode.
- `.emacs.d` is deployed by a dedicated `profile_desktop_common` task tagged `emacs`.
- NTFS filesystem support is provided by `ntfs-3g` in `ansible/inventory/group_vars/void.yml`.
- Void user services are managed by `turnstile` and live under `dotfiles/desktop/.config/service/`.
@@ -60,16 +60,17 @@ Ansible-driven personal infrastructure repo for Void desktops, Linux workstation
- Critical session entrypoints:
- `dotfiles/desktop/.config/sway/config` plus `host.conf` and `session-env` deployed via `host_sway_dotfiles` (sway / Wayland)
- `dotfiles/desktop/.config/hypr/hyprland.conf` plus `host.conf` and `session-env` deployed via `host_hyprland_dotfiles` (Hyprland / Wayland)
- Do not auto-restart `emptty` during playbook runs on active Void desktop hosts; restart it manually from another TTY/SSH session if needed.
- Do not switch or restart a display manager during a playbook run from an active graphical session. Changing between `emptty` and SDDM requires an explicit run from another TTY/SSH session with `desktop_allow_display_manager_switch=true`.
- `nymph` is a Void laptop with NVIDIA Optimus, running sway (Wayland) and Hyprland (Wayland); host-specific tasks in `profile_desktop_host/tasks/nymph.yml` handle GRUB NVIDIA cmdline params, `prime-run` wrapper, and the WirePlumber camera priority config. Multi-monitor on sway is driven by `kanshi` (config deployed via `host_sway_dotfiles`), and on Hyprland by host-specific Hyprland monitor/workspace rules.
## Void Package And Dotfile Bucket Rules
The four Void desktop package lists in `ansible/inventory/group_vars/void.yml` are kept disjoint by role:
The Void desktop package lists in `ansible/inventory/group_vars/void.yml` are kept disjoint by role:
- `void_packages_base` — system runtime only (init/services, kernel, audio core, networking, filesystem, firewall, hardware daemons, runit logging).
- `desktop_common_packages`WM-agnostic GUI infra (GTK theme, polkit, keyring, NM-applet, blueman, audio GUI, file manager backend + GVFS, portal, flatpak, printing/scanning).
- `desktop_sway_packages` / `desktop_hyprland_packages`binaries specific to each session. Cross-WM packages used by both (`dunst`, `rofi`, `alacritty`) are intentionally duplicated in the two lists.
- `desktop_common_packages`GUI infrastructure shared by minimal and KDE modes.
- `desktop_minimal_packages` / `desktop_kde_packages`mutually exclusive applications, integration components, and display managers.
- `desktop_sway_packages` / `desktop_hyprland_packages` — binaries specific to each session. Cross-WM packages used by both (such as `dunst`, `rofi`, and `foot`) are intentionally duplicated in the two lists.
`profile_packages` in the same file is cross-distro and is overridden by `group_vars/server.yml` and the workstation group vars; do not move desktop-specific Void entries through it.
The dotfile vars follow the same split: `desktop_common_dotfiles` (in `group_vars/desktop.yml`) carries WM-agnostic GUI config and user scripts (Thunar, mimeapps, GTK theme setup, Udiskie, fontconfig, WirePlumber, mpv, …); `desktop_void_dotfiles` (in `group_vars/void.yml`) is reserved for files that need Void runtime (turnstile services, bash runit/dbus/ssh-agent fragments, `update-turnstile-env`).
The dotfile vars follow the same split: `desktop_common_dotfiles` carries mode-independent content, while `desktop_minimal_dotfiles` carries Thunar, Udiskie, and minimal MIME defaults. KDE uses its own MIME defaults. `desktop_void_dotfiles` remains reserved for files that need the Void runtime.
## Workstation Notes
- Native Linux workstation hosts can combine `workstation_host_linux` with an OS-specific dev group.

View File

@@ -70,34 +70,36 @@ Sistema operativo:
- Void Linux
Sessioni desktop:
Modalita desktop:
- `ikaros`: sway (Wayland) + Hyprland (Wayland), default sway
- `nymph`: sway (Wayland) + Hyprland (Wayland), default sway
- `minimal`: sway (Wayland) + Hyprland (Wayland), gestite da `emptty`
- `kde`: KDE Plasma, gestito da SDDM
Macchine:
- `ikaros`
- `nymph`
Queste macchine condividono la stessa configurazione base desktop e vengono mantenute allineate tramite Ansible. Sway/SwayFX e Hyprland sono installate in parallelo e selezionabili da `emptty`; `desktop_default_session` decide quale sessione viene preselezionata al login.
Queste macchine condividono la stessa configurazione base desktop e vengono mantenute allineate tramite Ansible. `desktop_environment` seleziona in modo esclusivo `minimal` (default) oppure `kde`. Nella modalita minimale Sway/SwayFX e Hyprland sono installate in parallelo e selezionabili da `emptty`; `desktop_default_session` decide quale sessione viene preselezionata al login.
Lo stato attuale del profilo desktop include, tra le altre cose:
- dotfiles comuni e desktop
- sessioni sway e Hyprland su entrambi gli host (default sway, Hyprland disponibile via `emptty`)
- `emptty` con default host-specific per il desktop attivo, con `XORG_SESSIONS_PATH` puntato a `/etc/emptty/xsessions` e session file Wayland esposti su `WAYLAND_SESSIONS_PATH` per `sway` e `hyprland`
- sessioni sway e Hyprland su entrambi gli host in modalita `minimal`
- KDE Plasma con applicazioni KDE curate e SDDM disponibile come alternativa esclusiva
- `emptty` con default host-specific in modalita `minimal`, con session file Wayland esposti per `sway` e `hyprland`
- pacchetti Void Linux e servizi runit; le liste pacchetti Void desktop sono separate per criterio:
- `void_packages_base` per il runtime sistema (init, kernel, audio core, networking, firewall, hw daemons)
- `desktop_common_packages` per l'infrastruttura GUI WM-agnostic (tema, polkit, keyring, NM-applet, blueman, audio GUI, file manager backend, portal, flatpak, printing/scanning)
- `desktop_common_packages` per l'infrastruttura condivisa dalle due modalita
- `desktop_minimal_packages` per applicazioni GTK/XFCE e `emptty`
- `desktop_kde_packages` per Plasma, SDDM e le applicazioni KDE equivalenti
- `desktop_sway_packages` e `desktop_hyprland_packages` per i binari specifici di ciascuna sessione
- `turnstile` per i servizi utente, inclusi `emacs` e `ssh-agent`
- `ssh-agent` con socket stabile condiviso tra shell, SSH ed Emacs in `~/.local/state/ssh-agent/socket`
- `.emacs.d` distribuito da un task dedicato Ansible con tag `emacs`
- `tmux` con plugin gestiti da TPM al bootstrap del profilo desktop
- Flatpak con remoto Flathub
- GNOME Keyring e bootstrap della posta via script dedicato
- `udiskie` come backend per automount/LUKS
- GNOME Keyring e `udiskie` nella modalita minimale; KWallet e integrazione UDisks di Plasma nella modalita KDE
- multi-monitor: sotto sway è gestito da `kanshi` (config host-specifica in `host_sway_dotfiles` su `nymph`); sotto Hyprland gli override monitor vivono in `host_hyprland_dotfiles`
- override NVIDIA Optimus su `nymph`: parametri kernel GRUB iniettati in modo idempotente in `GRUB_CMDLINE_LINUX`, wrapper `prime-run` e config WirePlumber per priorità telecamera
@@ -395,6 +397,14 @@ Per vedere l'elenco reale aggiornato dei tag disponibili:
ansible-playbook ansible/site.yml --list-tags
```
Per attivare KDE su un host, impostare `desktop_environment: kde` nei relativi `host_vars` ed eseguire prima un dry run. Il primo play configura KDE ma, se `emptty` e ancora attivo, rinvia il cambio del display manager. Da una TTY o sessione SSH separata, applicare quindi il passaggio esplicito:
```bash
ansible-playbook ansible/site.yml --limit <host> -e desktop_allow_display_manager_switch=true
```
La stessa procedura vale in senso inverso per tornare a `minimal`.
Allo stato attuale `ansible/site.yml` espone questi tag:
| Tag | Scopo | Ambito principale |
@@ -407,6 +417,8 @@ Allo stato attuale `ansible/site.yml` espone questi tag:
| `dotfiles:server` | dotfiles dedicati al profilo server | server |
| `dotfiles:workstation` | dotfiles dedicati alle workstation | workstation Linux, WSL |
| `emptty` | gestione display manager `emptty` | desktop Void |
| `display-manager` | selezione protetta tra `emptty` e SDDM | desktop Void |
| `kde` | profilo KDE Plasma e relativa pulizia | desktop Void |
| `gnome` | configurazione host GNOME | workstation host Linux, parte desktop |
| `sway` | sessione/configurazione sway / SwayFX (Wayland) | desktop Void |
| `hyprland` | sessione/configurazione Hyprland (Wayland) | desktop Void |

View File

@@ -1,6 +1,9 @@
---
desktop_protonmail_bridge_cert_path: ~/.var/app/ch.protonmail.protonmail-bridge/config/protonmail/bridge-v3/cert.pem
desktop_environment: minimal
desktop_allow_display_manager_switch: false
desktop_sessions_enabled:
- sway
- hyprland
@@ -30,7 +33,18 @@ desktop_source_tools:
desktop_binary_tools: []
desktop_npm_packages: "{{ ai_agents_npm_packages + [] }}"
desktop_npm_packages: >-
{{
ai_agents_npm_packages
+ [
{'name': '@mermaid-js/mermaid-cli', 'state': 'latest'},
{'name': 'vscode-langservers-extracted', 'state': 'latest'}
]
}}
desktop_uv_tools:
- debugpy
- python-lsp-server
desktop_common_dotfiles:
- name: XDG autostart entries
@@ -49,22 +63,6 @@ desktop_common_dotfiles:
src: .local/bin/setup-gtk-theme
dest: .local/bin/setup-gtk-theme
mode: "0755"
- name: MIME application defaults
src: .config/mimeapps.list
dest: .config/mimeapps.list
mode: "0644"
- name: Thunar config
src: .config/Thunar/
dest: .config/Thunar/
mode: preserve
- name: Udiskie config
src: .config/udiskie/
dest: .config/udiskie/
mode: preserve
- name: Udiskie password helper
src: .local/bin/udiskie-password
dest: .local/bin/udiskie-password
mode: "0755"
- name: WirePlumber config
src: .config/wireplumber/
dest: .config/wireplumber/
@@ -134,6 +132,40 @@ desktop_common_dotfiles:
dest: .ssh/config
mode: "0600"
desktop_minimal_dotfiles:
- name: Minimal desktop MIME defaults
src: .config/mimeapps.list
dest: .config/mimeapps.list
mode: "0644"
- name: Thunar config
src: .config/Thunar/
dest: .config/Thunar/
mode: preserve
- name: Udiskie config
src: .config/udiskie/
dest: .config/udiskie/
mode: preserve
- name: Udiskie password helper
src: .local/bin/udiskie-password
dest: .local/bin/udiskie-password
mode: "0755"
desktop_minimal_managed_paths:
- .config/Thunar
- .config/alacritty
- .config/dunst
- .config/flameshot
- .config/foot
- .config/gtklock
- .config/hypr
- .config/kanshi
- .config/rofi
- .config/sway
- .config/udiskie
- .config/waybar
- .config/wlogout
- .local/bin/udiskie-password
desktop_emacs_dotfiles:
- name: Emacs config
src: .emacs.d/

View File

@@ -64,7 +64,6 @@ enabled_services:
- cupsd
- dbus
- elogind
- emptty
- libvirtd
- nanoklogd
- socklog-unix
@@ -99,32 +98,64 @@ desktop_void_dotfiles:
mode: "0755"
desktop_common_packages:
- blueman
- brightnessctl
- cups
- cups-filters
- cups-pk-helper
- dex
- emptty
- flatpak
- gnome-keyring
- gvfs
- libsecret
- network-manager-applet
- pavucontrol
- pinentry-emacs
- pinentry-gtk
- sane
- sane-airscan
- turnstile
- xdg-desktop-portal
- xdg-user-dirs
desktop_minimal_packages:
- alacritty
- blueman
- brightnessctl
- dex
- emptty
- exo
- ffmpegthumbnailer
- gnome-keyring
- gvfs
- gvfs-cdda
- gvfs-mtp
- gvfs-smb
- network-manager-applet
- pavucontrol
- pinentry-gtk
- ristretto
- seahorse
- shotwell
- simple-scan
- system-config-printer
- turnstile
- Thunar
- thunar-archive-plugin
- thunar-volman
- tumbler
- udiskie
- xdg-desktop-portal
- xarchiver
- xdg-desktop-portal-gtk
- xdg-user-dirs
- xfce-polkit
- xournalpp
desktop_kde_packages:
- ark
- dolphin
- ffmpegthumbs
- gwenview
- kate
- kde-plasma
- kleopatra
- konsole
- okular
- polkit-kde-agent
- print-manager
- sddm
- skanpage
- spectacle
desktop_sway_packages:
- cliphist
@@ -169,23 +200,23 @@ desktop_hyprland_packages:
- xorg-server-xwayland
profile_packages:
- alacritty
- bash-language-server
- bluez
- bridge-utils
- ctags
- firefox
- deluge-gtk
- delve
- dnsmasq
- emacs-pgtk
- poppler-glib
- poppler-utils
- exo
- fontconfig-devel
- freetype-devel
- gvfs-cdda
- gvfs-mtp
- gvfs-smb
- gufw
- golangci-lint
- gopls
- hunspell
- libvirt
- libspa-bluetooth
- libreoffice
@@ -206,24 +237,16 @@ profile_packages:
- remmina
- ripgrep
- rustup
- ristretto
- rsync
- shotwell
- shfmt
- ruff
- terminus-font
- texlive
- ty
- tumbler
- uv
- Thunar
- thunar-archive-plugin
- thunar-volman
- ffmpegthumbnailer
- virt-manager
- virt-manager-tools
- wireplumber
- xarchiver
- xournalpp
- yaru
- yaru-plus
- zstd

View File

@@ -19,7 +19,7 @@
loop: "{{ void_xbps_repositories | default([]) + host_xbps_repositories | default([]) }}"
loop_control:
label: "{{ item.name }}"
register: void_xbps_repository_configs
register: packages_void_xbps_repository_configs
when: (void_xbps_repositories | default([]) + host_xbps_repositories | default([])) | length > 0
- name: Install Void nonfree repository if needed
@@ -28,7 +28,7 @@
name: void-repo-nonfree
state: present
update_cache: false
register: void_nonfree_repository
register: packages_void_nonfree_repository
when: "'void-repo-nonfree' in (host_packages | default([]) + void_packages_base | default([]))"
- name: Refresh XBPS cache after configuring repositories
@@ -38,7 +38,7 @@
accept_pubkey: true
when: >-
(void_xbps_repositories | default([]) + host_xbps_repositories | default([])) | length > 0
or (void_nonfree_repository is defined and void_nonfree_repository is changed)
or (packages_void_nonfree_repository is defined and packages_void_nonfree_repository is changed)
- name: Synchronize and upgrade Void Linux packages
tags: [packages]
@@ -56,14 +56,25 @@
+ (void_packages_base | default([]))
+ (profile_packages | default([]))
+ (desktop_common_packages | default([]))
+ (
(desktop_minimal_packages | default([]))
if (desktop_environment | default('minimal')) == 'minimal'
else (desktop_kde_packages | default([]))
)
+ (
(desktop_sway_packages | default([]))
if 'sway' in (desktop_sessions_enabled | default([]))
if (
(desktop_environment | default('minimal')) == 'minimal'
and 'sway' in (desktop_sessions_enabled | default([]))
)
else []
)
+ (
(desktop_hyprland_packages | default([]))
if 'hyprland' in (desktop_sessions_enabled | default([]))
if (
(desktop_environment | default('minimal')) == 'minimal'
and 'hyprland' in (desktop_sessions_enabled | default([]))
)
else []
)
+ (host_packages | default([]))
@@ -73,6 +84,40 @@
state: present
update_cache: false
- name: Check whether the selected display manager is active
tags: [packages, display-manager]
ansible.builtin.stat:
path: >-
/var/service/{{ 'sddm' if (desktop_environment | default('minimal')) == 'kde' else 'emptty' }}
register: packages_void_selected_display_manager
- name: Remove packages managed by the inactive desktop environment
tags: [packages]
community.general.xbps:
name: >-
{{
(
(
(desktop_minimal_packages | default([]))
| reject('equalto', 'emptty')
| list
)
+ (desktop_sway_packages | default([]))
+ (desktop_hyprland_packages | default([]))
)
if (desktop_environment | default('minimal')) == 'kde'
else (
(desktop_kde_packages | default([]))
| reject('equalto', 'sddm')
| list
)
}}
state: absent
update_cache: false
when: >-
packages_void_selected_display_manager.stat.exists
or (desktop_allow_display_manager_switch | default(false))
- name: Remove host-absent packages on Void Linux
tags: [packages]
community.general.xbps:

View File

@@ -1,4 +1,22 @@
---
- name: Validate desktop environment selection
tags: [always]
ansible.builtin.assert:
that:
- (desktop_environment | default('minimal')) in ['minimal', 'kde']
- >-
(desktop_environment | default('minimal')) == 'kde'
or (desktop_sessions_enabled | default([]) | length > 0)
- >-
(desktop_environment | default('minimal')) == 'kde'
or (desktop_sessions_enabled | default([]) | difference(['sway', 'hyprland']) | length == 0)
- >-
(desktop_environment | default('minimal')) == 'kde'
or desktop_default_session in (desktop_sessions_enabled | default([]))
fail_msg: >-
desktop_environment must be minimal or kde. Minimal desktops also require
desktop_default_session to be included in desktop_sessions_enabled.
- name: Configure elogind to suspend on lid close
tags: [packages]
ansible.builtin.lineinfile:
@@ -34,32 +52,33 @@
group: "{{ user_group }}"
mode: "0755"
- name: Enable gnome-keyring PAM auth hook
- name: Manage gnome-keyring PAM auth hook
tags: [packages, gnome]
ansible.builtin.lineinfile:
path: /etc/pam.d/login
insertafter: '^auth\s+include\s+system-local-login$'
line: "auth optional pam_gnome_keyring.so"
state: present
state: "{{ 'present' if (desktop_environment | default('minimal')) == 'minimal' else 'absent' }}"
when: "'void' in group_names"
- name: Enable gnome-keyring PAM session hook
- name: Manage gnome-keyring PAM session hook
tags: [packages, gnome]
ansible.builtin.lineinfile:
path: /etc/pam.d/login
insertafter: '^session\s+include\s+system-local-login$'
line: "session optional pam_gnome_keyring.so auto_start"
state: present
state: "{{ 'present' if (desktop_environment | default('minimal')) == 'minimal' else 'absent' }}"
when: "'void' in group_names"
- name: Enable gnome-keyring PAM password hook
- name: Manage gnome-keyring PAM password hook
tags: [packages, gnome]
ansible.builtin.lineinfile:
path: /etc/pam.d/login
insertafter: '^password\s+include\s+system-local-login$'
line: "password optional pam_gnome_keyring.so use_authtok"
state: present
when: "'void' in group_names"
state: "{{ 'present' if (desktop_environment | default('minimal')) == 'minimal' else 'absent' }}"
when:
- "'void' in group_names"
- name: Check whether SSH host ed25519 key exists
tags: [services]
@@ -234,7 +253,9 @@
owner: root
group: root
mode: "0755"
when: "'void' in group_names"
when:
- "'void' in group_names"
- (desktop_environment | default('minimal')) == 'minimal'
- name: Ensure emptty session directories exist
tags: [packages, services, emptty]
@@ -247,7 +268,9 @@
loop:
- /etc/emptty/xsessions
- /etc/emptty/wayland-sessions
when: "'void' in group_names"
when:
- "'void' in group_names"
- (desktop_environment | default('minimal')) == 'minimal'
- name: Configure emptty
tags: [packages, services, emptty]
@@ -258,7 +281,9 @@
group: root
mode: "0644"
notify: Restart emptty
when: "'void' in group_names"
when:
- "'void' in group_names"
- (desktop_environment | default('minimal')) == 'minimal'
- name: Copy common desktop dotfiles
tags: [dotfiles, dotfiles:desktop]
@@ -271,6 +296,11 @@
loop: >-
{{
(desktop_common_dotfiles | default([]))
+ (
(desktop_minimal_dotfiles | default([]))
if (desktop_environment | default('minimal')) == 'minimal'
else []
)
+ ((desktop_void_dotfiles | default([])) if 'void' in group_names else [])
}}
loop_control:
@@ -445,6 +475,14 @@
owner: root
group: root
mode: "0644"
when: (desktop_environment | default('minimal')) == 'minimal'
- name: Remove minimal Qt theme override for KDE
tags: [theme]
ansible.builtin.file:
path: /etc/profile.d/10-qt-theme.sh
state: absent
when: (desktop_environment | default('minimal')) == 'kde'
- name: Ensure flathub remote is configured
tags: [packages]
@@ -552,3 +590,21 @@
when: desktop_npm_packages | length > 0
loop_control:
label: "{{ item.name }}"
- name: Install desktop Python tools with uv
tags: [packages, emacs]
ansible.builtin.command:
cmd: "uv tool install --upgrade {{ item }}"
become: true
become_user: "{{ username }}"
environment:
HOME: "{{ user_home }}"
register: profile_desktop_common_uv_tool_install
changed_when: >-
(profile_desktop_common_uv_tool_install.stdout | default('')
+ profile_desktop_common_uv_tool_install.stderr | default(''))
is regex('(?i)installed|updated')
loop: "{{ desktop_uv_tools | default([]) }}"
when: desktop_uv_tools | default([]) | length > 0
loop_control:
label: "{{ item }}"

View File

@@ -16,6 +16,7 @@
loop_control:
label: "{{ item.dest }}"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'sway' in (desktop_sessions_enabled | default([]))"
- (host_sway_dotfiles | default([])) | length > 0
@@ -32,5 +33,6 @@
loop_control:
label: "{{ item.dest }}"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'hyprland' in (desktop_sessions_enabled | default([]))"
- (host_hyprland_dotfiles | default([])) | length > 0

View File

@@ -15,7 +15,9 @@
- "{{ user_home }}/.config/hypr"
- "{{ user_home }}/.config/rofi"
- "{{ user_home }}/.config/waybar"
when: "'hyprland' in (desktop_sessions_enabled | default([]))"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'hyprland' in (desktop_sessions_enabled | default([]))"
- name: Install allowed emptty Hyprland Wayland session
tags: [packages, services, emptty, hyprland]
@@ -25,14 +27,18 @@
owner: root
group: root
mode: "0644"
when: "'hyprland' in (desktop_sessions_enabled | default([]))"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'hyprland' in (desktop_sessions_enabled | default([]))"
- name: Remove legacy Hyprland session launcher shadowing package binary
tags: [packages, services, hyprland]
ansible.builtin.file:
path: /usr/local/bin/start-hyprland
state: absent
when: "'hyprland' in (desktop_sessions_enabled | default([]))"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'hyprland' in (desktop_sessions_enabled | default([]))"
- name: Install Hyprland session launcher in /usr/local/bin
tags: [packages, services, hyprland]
@@ -42,7 +48,9 @@
owner: root
group: root
mode: "0755"
when: "'hyprland' in (desktop_sessions_enabled | default([]))"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'hyprland' in (desktop_sessions_enabled | default([]))"
- name: Ensure /etc/xdg/xdg-desktop-portal exists for Hyprland
tags: [packages, services, hyprland, portal]
@@ -52,7 +60,9 @@
owner: root
group: root
mode: "0755"
when: "'hyprland' in (desktop_sessions_enabled | default([]))"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'hyprland' in (desktop_sessions_enabled | default([]))"
- name: Configure xdg-desktop-portal backend preferences for Hyprland
tags: [packages, services, hyprland, portal]
@@ -62,7 +72,9 @@
owner: root
group: root
mode: "0644"
when: "'hyprland' in (desktop_sessions_enabled | default([]))"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'hyprland' in (desktop_sessions_enabled | default([]))"
- name: Copy Hyprland desktop dotfiles
tags: [dotfiles, dotfiles:desktop, hyprland]
@@ -75,4 +87,6 @@
loop: "{{ desktop_hyprland_dotfiles | default([]) }}"
loop_control:
label: "{{ item.dest }}"
when: "'hyprland' in (desktop_sessions_enabled | default([]))"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'hyprland' in (desktop_sessions_enabled | default([]))"

View File

@@ -0,0 +1,54 @@
---
- name: Check whether SDDM is the active runit display manager
tags: [packages, services, kde, display-manager]
ansible.builtin.stat:
path: /var/service/sddm
register: profile_desktop_kde_sddm_service
when: (desktop_environment | default('minimal')) == 'kde'
- name: Copy KDE MIME application defaults
tags: [dotfiles, dotfiles:desktop, kde]
ansible.builtin.copy:
src: "{{ playbook_dir }}/../dotfiles/desktop/.config/mimeapps.kde.list"
dest: "{{ user_home }}/.config/mimeapps.list"
owner: "{{ username }}"
group: "{{ user_group }}"
mode: "0644"
when: (desktop_environment | default('minimal')) == 'kde'
- name: Remove minimal desktop user configuration managed by Ansible
tags: [dotfiles, dotfiles:desktop, kde]
ansible.builtin.file:
path: "{{ user_home }}/{{ item }}"
state: absent
loop: "{{ desktop_minimal_managed_paths | default([]) }}"
loop_control:
label: "{{ item }}"
when:
- (desktop_environment | default('minimal')) == 'kde'
- profile_desktop_kde_sddm_service.stat.exists
- name: Remove minimal desktop portal preferences
tags: [packages, services, kde, portal]
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- /etc/xdg/xdg-desktop-portal/hyprland-portals.conf
- /etc/xdg/xdg-desktop-portal/sway-portals.conf
when:
- (desktop_environment | default('minimal')) == 'kde'
- profile_desktop_kde_sddm_service.stat.exists
- name: Remove inactive emptty and minimal session launchers
tags: [packages, services, kde, display-manager]
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- /etc/emptty
- /usr/local/bin/start-hyprland-session
- /usr/local/bin/start-sway
when:
- (desktop_environment | default('minimal')) == 'kde'
- profile_desktop_kde_sddm_service.stat.exists

View File

@@ -15,7 +15,9 @@
- "{{ user_home }}/.config/sway"
- "{{ user_home }}/.config/waybar"
- "{{ user_home }}/.config/wlogout"
when: "'sway' in (desktop_sessions_enabled | default([]))"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'sway' in (desktop_sessions_enabled | default([]))"
- name: Install allowed emptty Wayland sessions
tags: [packages, services, emptty, sway]
@@ -25,7 +27,9 @@
owner: root
group: root
mode: "0644"
when: "'sway' in (desktop_sessions_enabled | default([]))"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'sway' in (desktop_sessions_enabled | default([]))"
- name: Install Sway session launcher in /usr/local/bin
tags: [packages, services, sway]
@@ -35,7 +39,9 @@
owner: root
group: root
mode: "0755"
when: "'sway' in (desktop_sessions_enabled | default([]))"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'sway' in (desktop_sessions_enabled | default([]))"
- name: Ensure /etc/xdg/xdg-desktop-portal exists
tags: [packages, services, sway, portal]
@@ -45,7 +51,9 @@
owner: root
group: root
mode: "0755"
when: "'sway' in (desktop_sessions_enabled | default([]))"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'sway' in (desktop_sessions_enabled | default([]))"
- name: Configure xdg-desktop-portal backend preferences for sway
tags: [packages, services, sway, portal]
@@ -55,7 +63,9 @@
owner: root
group: root
mode: "0644"
when: "'sway' in (desktop_sessions_enabled | default([]))"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'sway' in (desktop_sessions_enabled | default([]))"
- name: Copy sway desktop dotfiles
tags: [dotfiles, dotfiles:desktop, sway]
@@ -68,4 +78,6 @@
loop: "{{ desktop_sway_dotfiles | default([]) }}"
loop_control:
label: "{{ item.dest }}"
when: "'sway' in (desktop_sessions_enabled | default([]))"
when:
- (desktop_environment | default('minimal')) == 'minimal'
- "'sway' in (desktop_sessions_enabled | default([]))"

View File

@@ -14,3 +14,79 @@
dest: "/var/service/{{ item }}"
state: link
loop: "{{ host_enabled_services | default([]) }}"
- name: Define desktop display manager services
tags: [services, packages, display-manager]
ansible.builtin.set_fact:
services_runit_desktop_display_manager_service: >-
{{ 'sddm' if (desktop_environment | default('minimal')) == 'kde' else 'emptty' }}
services_runit_inactive_display_manager_service: >-
{{ 'emptty' if (desktop_environment | default('minimal')) == 'kde' else 'sddm' }}
when: "'desktop' in group_names"
- name: Inspect desktop display manager services
tags: [services, packages, display-manager]
ansible.builtin.stat:
path: "/var/service/{{ item }}"
loop:
- "{{ services_runit_desktop_display_manager_service }}"
- "{{ services_runit_inactive_display_manager_service }}"
loop_control:
label: "{{ item }}"
register: services_runit_display_manager_links
when: "'desktop' in group_names"
- name: Report deferred desktop display manager switch
tags: [services, packages, display-manager]
ansible.builtin.debug:
msg: >-
{{ desktop_environment }} is configured, but {{ services_runit_inactive_display_manager_service }}
is still active. Re-run from a TTY or SSH session with
-e desktop_allow_display_manager_switch=true to switch safely to
{{ services_runit_desktop_display_manager_service }}.
when:
- "'desktop' in group_names"
- services_runit_display_manager_links.results[1].stat.exists
- not (services_runit_display_manager_links.results[0].stat.exists)
- not (desktop_allow_display_manager_switch | default(false))
- name: Disable inactive desktop display manager
tags: [services, packages, display-manager]
ansible.builtin.file:
path: "/var/service/{{ services_runit_inactive_display_manager_service }}"
state: absent
register: services_runit_display_manager_disabled
when:
- "'desktop' in group_names"
- services_runit_display_manager_links.results[1].stat.exists
- not (services_runit_display_manager_links.results[0].stat.exists)
- desktop_allow_display_manager_switch | default(false)
- name: Enable selected desktop display manager
tags: [services, packages, display-manager]
ansible.builtin.file:
src: "/etc/sv/{{ services_runit_desktop_display_manager_service }}"
dest: "/var/service/{{ services_runit_desktop_display_manager_service }}"
state: link
register: services_runit_display_manager_enabled
when:
- "'desktop' in group_names"
- not (services_runit_display_manager_links.results[0].stat.exists)
- >-
not (services_runit_display_manager_links.results[1].stat.exists)
or (desktop_allow_display_manager_switch | default(false))
- name: Remove inactive desktop display manager package after switching
tags: [services, packages, display-manager]
community.general.xbps:
name: "{{ services_runit_inactive_display_manager_service }}"
state: absent
update_cache: false
when:
- "'desktop' in group_names"
- >-
services_runit_display_manager_links.results[0].stat.exists
or (services_runit_display_manager_enabled is defined and services_runit_display_manager_enabled is changed)
- >-
not (services_runit_display_manager_links.results[1].stat.exists)
or (services_runit_display_manager_disabled is defined and services_runit_display_manager_disabled is changed)

View File

@@ -26,6 +26,7 @@
- profile_desktop_common
- profile_desktop_sway
- profile_desktop_hyprland
- profile_desktop_kde
- profile_desktop_host
- hosts: workstation_dev_fedora

View File

@@ -0,0 +1,338 @@
[Default Applications]
text/html=userapp-Firefox-91DVN3.desktop
x-scheme-handler/http=userapp-Firefox-91DVN3.desktop
x-scheme-handler/https=userapp-Firefox-91DVN3.desktop
x-scheme-handler/about=firefox.desktop
x-scheme-handler/unknown=firefox.desktop
application/pdf=org.kde.okular.desktop
application/json=emacs.desktop
application/json5=emacs.desktop
application/xml=emacs.desktop
application/xml-external-parsed-entity=emacs.desktop
application/x-shellscript=emacs.desktop
application/yaml=emacs.desktop
inode/directory=org.kde.dolphin.desktop
image/bmp=org.kde.gwenview.desktop
image/gif=org.kde.gwenview.desktop
image/jpeg=org.kde.gwenview.desktop
image/png=org.kde.gwenview.desktop
image/svg+xml=org.kde.gwenview.desktop
image/tiff=org.kde.gwenview.desktop
image/webp=org.kde.gwenview.desktop
image/x-pixmap=org.kde.gwenview.desktop
image/x-xpixmap=org.kde.gwenview.desktop
audio/aac=mpv.desktop
audio/flac=mpv.desktop
audio/m4a=mpv.desktop
audio/mp3=mpv.desktop
audio/mpeg=mpv.desktop
audio/mp4=mpv.desktop
audio/ogg=mpv.desktop
audio/opus=mpv.desktop
audio/vnd.wave=mpv.desktop
audio/wav=mpv.desktop
audio/webm=mpv.desktop
audio/x-aac=mpv.desktop
audio/x-m4a=mpv.desktop
audio/x-matroska=mpv.desktop
audio/x-mp3=mpv.desktop
audio/x-mpegurl=mpv.desktop
audio/x-ms-wma=mpv.desktop
audio/x-ogg=mpv.desktop
audio/x-pn-wav=mpv.desktop
audio/x-scpls=mpv.desktop
audio/x-wav=mpv.desktop
video/3gp=mpv.desktop
video/3gpp=mpv.desktop
video/3gpp2=mpv.desktop
video/avi=mpv.desktop
video/mp2t=mpv.desktop
video/mp4=mpv.desktop
video/mp4v-es=mpv.desktop
video/mpeg=mpv.desktop
video/ogg=mpv.desktop
video/quicktime=mpv.desktop
video/vnd.avi=mpv.desktop
video/webm=mpv.desktop
video/x-avi=mpv.desktop
video/x-flc=mpv.desktop
video/x-flic=mpv.desktop
video/x-flv=mpv.desktop
video/x-m4v=mpv.desktop
video/x-matroska=mpv.desktop
video/x-mpeg2=mpv.desktop
video/x-ms-asf=mpv.desktop
video/x-ms-wmv=mpv.desktop
video/x-msvideo=mpv.desktop
video/x-ogm+ogg=mpv.desktop
video/x-theora=mpv.desktop
video/x-theora+ogg=mpv.desktop
application/msword=libreoffice-writer.desktop
application/rtf=libreoffice-writer.desktop
application/vnd.ms-word=libreoffice-writer.desktop
application/vnd.ms-word.document.macroEnabled.12=libreoffice-writer.desktop
application/vnd.ms-word.template.macroEnabled.12=libreoffice-writer.desktop
application/vnd.oasis.opendocument.text=libreoffice-writer.desktop
application/vnd.oasis.opendocument.text-template=libreoffice-writer.desktop
application/vnd.openxmlformats-officedocument.wordprocessingml.document=libreoffice-writer.desktop
application/vnd.openxmlformats-officedocument.wordprocessingml.template=libreoffice-writer.desktop
application/x-doc=libreoffice-writer.desktop
text/rtf=libreoffice-writer.desktop
application/csv=libreoffice-calc.desktop
application/excel=libreoffice-calc.desktop
application/msexcel=libreoffice-calc.desktop
application/tab-separated-values=libreoffice-calc.desktop
application/vnd.ms-excel=libreoffice-calc.desktop
application/vnd.ms-excel.sheet.binary.macroEnabled.12=libreoffice-calc.desktop
application/vnd.ms-excel.sheet.macroEnabled.12=libreoffice-calc.desktop
application/vnd.ms-excel.template.macroEnabled.12=libreoffice-calc.desktop
application/vnd.oasis.opendocument.spreadsheet=libreoffice-calc.desktop
application/vnd.oasis.opendocument.spreadsheet-template=libreoffice-calc.desktop
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet=libreoffice-calc.desktop
application/vnd.openxmlformats-officedocument.spreadsheetml.template=libreoffice-calc.desktop
application/x-dos_ms_excel=libreoffice-calc.desktop
application/x-excel=libreoffice-calc.desktop
application/x-ms-excel=libreoffice-calc.desktop
application/x-msexcel=libreoffice-calc.desktop
text/comma-separated-values=libreoffice-calc.desktop
text/csv=libreoffice-calc.desktop
text/tab-separated-values=libreoffice-calc.desktop
text/x-comma-separated-values=libreoffice-calc.desktop
text/x-csv=libreoffice-calc.desktop
application/mspowerpoint=libreoffice-impress.desktop
application/vnd.ms-powerpoint=libreoffice-impress.desktop
application/vnd.ms-powerpoint.presentation.macroEnabled.12=libreoffice-impress.desktop
application/vnd.ms-powerpoint.slideshow.macroEnabled.12=libreoffice-impress.desktop
application/vnd.ms-powerpoint.template.macroEnabled.12=libreoffice-impress.desktop
application/vnd.oasis.opendocument.presentation=libreoffice-impress.desktop
application/vnd.oasis.opendocument.presentation-template=libreoffice-impress.desktop
application/vnd.openxmlformats-officedocument.presentationml.presentation=libreoffice-impress.desktop
application/vnd.openxmlformats-officedocument.presentationml.slide=libreoffice-impress.desktop
application/vnd.openxmlformats-officedocument.presentationml.slideshow=libreoffice-impress.desktop
application/vnd.openxmlformats-officedocument.presentationml.template=libreoffice-impress.desktop
application/gzip=org.kde.ark.desktop
application/vnd.debian.binary-package=org.kde.ark.desktop
application/vnd.ms-cab-compressed=org.kde.ark.desktop
application/vnd.rar=org.kde.ark.desktop
application/x-7z-compressed=org.kde.ark.desktop
application/x-archive=org.kde.ark.desktop
application/x-arj=org.kde.ark.desktop
application/x-bzip=org.kde.ark.desktop
application/x-bzip-compressed-tar=org.kde.ark.desktop
application/x-bzip2=org.kde.ark.desktop
application/x-bzip2-compressed-tar=org.kde.ark.desktop
application/x-cd-image=org.kde.ark.desktop
application/x-compressed-tar=org.kde.ark.desktop
application/x-cpio=org.kde.ark.desktop
application/x-cpio-compressed=org.kde.ark.desktop
application/x-lha=org.kde.ark.desktop
application/x-lrzip=org.kde.ark.desktop
application/x-lrzip-compressed-tar=org.kde.ark.desktop
application/x-lzip=org.kde.ark.desktop
application/x-lzip-compressed-tar=org.kde.ark.desktop
application/x-lzma=org.kde.ark.desktop
application/x-lzma-compressed-tar=org.kde.ark.desktop
application/x-rar=org.kde.ark.desktop
application/x-rpm=org.kde.ark.desktop
application/x-rzip=org.kde.ark.desktop
application/x-rzip-compressed-tar=org.kde.ark.desktop
application/x-source-rpm=org.kde.ark.desktop
application/x-tar=org.kde.ark.desktop
application/x-tarz=org.kde.ark.desktop
application/x-xz=org.kde.ark.desktop
application/x-xz-compressed-tar=org.kde.ark.desktop
application/x-zpaq=org.kde.ark.desktop
application/x-zstd-compressed-tar=org.kde.ark.desktop
application/zip=org.kde.ark.desktop
application/zstd=org.kde.ark.desktop
text/markdown=emacs.desktop
text/org=emacs.desktop
text/plain=emacs.desktop
text/rust=emacs.desktop
text/x-c++hdr=emacs.desktop
text/x-c++src=emacs.desktop
text/x-chdr=emacs.desktop
text/x-csrc=emacs.desktop
text/x-emacs-lisp=emacs.desktop
text/x-go=emacs.desktop
text/x-java=emacs.desktop
text/x-makefile=emacs.desktop
text/x-patch=emacs.desktop
text/x-python=emacs.desktop
text/x-python3=emacs.desktop
text/x-readme=emacs.desktop
text/x-rst=emacs.desktop
text/x-tex=emacs.desktop
text/x-texinfo=emacs.desktop
x-scheme-handler/chrome=userapp-Firefox-91DVN3.desktop
application/x-extension-htm=userapp-Firefox-91DVN3.desktop
application/x-extension-html=userapp-Firefox-91DVN3.desktop
application/x-extension-shtml=userapp-Firefox-91DVN3.desktop
application/xhtml+xml=userapp-Firefox-91DVN3.desktop
application/x-extension-xhtml=userapp-Firefox-91DVN3.desktop
application/x-extension-xht=userapp-Firefox-91DVN3.desktop
[Added Associations]
application/json=emacs.desktop;
application/json5=emacs.desktop;
application/pdf=org.kde.okular.desktop;
application/xml=emacs.desktop;
application/xml-external-parsed-entity=emacs.desktop;
application/x-shellscript=emacs.desktop;
application/yaml=emacs.desktop;
text/plain=emacs.desktop;
inode/directory=org.kde.dolphin.desktop;
image/bmp=org.kde.gwenview.desktop;
image/gif=org.kde.gwenview.desktop;
image/jpeg=org.kde.gwenview.desktop;
image/png=org.kde.gwenview.desktop;
image/svg+xml=org.kde.gwenview.desktop;
image/tiff=org.kde.gwenview.desktop;
image/webp=org.kde.gwenview.desktop;
image/x-pixmap=org.kde.gwenview.desktop;
image/x-xpixmap=org.kde.gwenview.desktop;
audio/aac=mpv.desktop;
audio/flac=mpv.desktop;
audio/m4a=mpv.desktop;
audio/mp3=mpv.desktop;
audio/mpeg=mpv.desktop;
audio/mp4=mpv.desktop;
audio/ogg=mpv.desktop;
audio/opus=mpv.desktop;
audio/vnd.wave=mpv.desktop;
audio/wav=mpv.desktop;
audio/webm=mpv.desktop;
audio/x-aac=mpv.desktop;
audio/x-m4a=mpv.desktop;
audio/x-matroska=mpv.desktop;
audio/x-mp3=mpv.desktop;
audio/x-mpegurl=mpv.desktop;
audio/x-ms-wma=mpv.desktop;
audio/x-ogg=mpv.desktop;
audio/x-pn-wav=mpv.desktop;
audio/x-scpls=mpv.desktop;
audio/x-wav=mpv.desktop;
video/3gp=mpv.desktop;
video/3gpp=mpv.desktop;
video/3gpp2=mpv.desktop;
video/avi=mpv.desktop;
video/mp2t=mpv.desktop;
video/mp4=mpv.desktop;
video/mp4v-es=mpv.desktop;
video/mpeg=mpv.desktop;
video/ogg=mpv.desktop;
video/quicktime=mpv.desktop;
video/vnd.avi=mpv.desktop;
video/webm=mpv.desktop;
video/x-avi=mpv.desktop;
video/x-flc=mpv.desktop;
video/x-flic=mpv.desktop;
video/x-flv=mpv.desktop;
video/x-m4v=mpv.desktop;
video/x-matroska=mpv.desktop;
video/x-mpeg2=mpv.desktop;
video/x-ms-asf=mpv.desktop;
video/x-ms-wmv=mpv.desktop;
video/x-msvideo=mpv.desktop;
video/x-ogm+ogg=mpv.desktop;
video/x-theora=mpv.desktop;
video/x-theora+ogg=mpv.desktop;
application/msword=libreoffice-writer.desktop;
application/rtf=libreoffice-writer.desktop;
application/vnd.ms-word=libreoffice-writer.desktop;
application/vnd.ms-word.document.macroEnabled.12=libreoffice-writer.desktop;
application/vnd.ms-word.template.macroEnabled.12=libreoffice-writer.desktop;
application/vnd.oasis.opendocument.text=libreoffice-writer.desktop;
application/vnd.oasis.opendocument.text-template=libreoffice-writer.desktop;
application/vnd.openxmlformats-officedocument.wordprocessingml.document=libreoffice-writer.desktop;
application/vnd.openxmlformats-officedocument.wordprocessingml.template=libreoffice-writer.desktop;
application/x-doc=libreoffice-writer.desktop;
text/rtf=libreoffice-writer.desktop;
application/csv=libreoffice-calc.desktop;
application/excel=libreoffice-calc.desktop;
application/msexcel=libreoffice-calc.desktop;
application/tab-separated-values=libreoffice-calc.desktop;
application/vnd.ms-excel=libreoffice-calc.desktop;
application/vnd.ms-excel.sheet.binary.macroEnabled.12=libreoffice-calc.desktop;
application/vnd.ms-excel.sheet.macroEnabled.12=libreoffice-calc.desktop;
application/vnd.ms-excel.template.macroEnabled.12=libreoffice-calc.desktop;
application/vnd.oasis.opendocument.spreadsheet=libreoffice-calc.desktop;
application/vnd.oasis.opendocument.spreadsheet-template=libreoffice-calc.desktop;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet=libreoffice-calc.desktop;
application/vnd.openxmlformats-officedocument.spreadsheetml.template=libreoffice-calc.desktop;
application/x-dos_ms_excel=libreoffice-calc.desktop;
application/x-excel=libreoffice-calc.desktop;
application/x-ms-excel=libreoffice-calc.desktop;
application/x-msexcel=libreoffice-calc.desktop;
text/comma-separated-values=libreoffice-calc.desktop;
text/csv=libreoffice-calc.desktop;
text/tab-separated-values=libreoffice-calc.desktop;
text/x-comma-separated-values=libreoffice-calc.desktop;
text/x-csv=libreoffice-calc.desktop;
application/mspowerpoint=libreoffice-impress.desktop;
application/vnd.ms-powerpoint=libreoffice-impress.desktop;
application/vnd.ms-powerpoint.presentation.macroEnabled.12=libreoffice-impress.desktop;
application/vnd.ms-powerpoint.slideshow.macroEnabled.12=libreoffice-impress.desktop;
application/vnd.ms-powerpoint.template.macroEnabled.12=libreoffice-impress.desktop;
application/vnd.oasis.opendocument.presentation=libreoffice-impress.desktop;
application/vnd.oasis.opendocument.presentation-template=libreoffice-impress.desktop;
application/vnd.openxmlformats-officedocument.presentationml.presentation=libreoffice-impress.desktop;
application/vnd.openxmlformats-officedocument.presentationml.slide=libreoffice-impress.desktop;
application/vnd.openxmlformats-officedocument.presentationml.slideshow=libreoffice-impress.desktop;
application/vnd.openxmlformats-officedocument.presentationml.template=libreoffice-impress.desktop;
application/gzip=org.kde.ark.desktop;
application/vnd.debian.binary-package=org.kde.ark.desktop;
application/vnd.ms-cab-compressed=org.kde.ark.desktop;
application/vnd.rar=org.kde.ark.desktop;
application/x-7z-compressed=org.kde.ark.desktop;
application/x-archive=org.kde.ark.desktop;
application/x-arj=org.kde.ark.desktop;
application/x-bzip=org.kde.ark.desktop;
application/x-bzip-compressed-tar=org.kde.ark.desktop;
application/x-bzip2=org.kde.ark.desktop;
application/x-bzip2-compressed-tar=org.kde.ark.desktop;
application/x-cd-image=org.kde.ark.desktop;
application/x-compressed-tar=org.kde.ark.desktop;
application/x-cpio=org.kde.ark.desktop;
application/x-cpio-compressed=org.kde.ark.desktop;
application/x-lha=org.kde.ark.desktop;
application/x-lrzip=org.kde.ark.desktop;
application/x-lrzip-compressed-tar=org.kde.ark.desktop;
application/x-lzip=org.kde.ark.desktop;
application/x-lzip-compressed-tar=org.kde.ark.desktop;
application/x-lzma=org.kde.ark.desktop;
application/x-lzma-compressed-tar=org.kde.ark.desktop;
application/x-rar=org.kde.ark.desktop;
application/x-rpm=org.kde.ark.desktop;
application/x-rzip=org.kde.ark.desktop;
application/x-rzip-compressed-tar=org.kde.ark.desktop;
application/x-source-rpm=org.kde.ark.desktop;
application/x-tar=org.kde.ark.desktop;
application/x-tarz=org.kde.ark.desktop;
application/x-xz=org.kde.ark.desktop;
application/x-xz-compressed-tar=org.kde.ark.desktop;
application/x-zpaq=org.kde.ark.desktop;
application/x-zstd-compressed-tar=org.kde.ark.desktop;
application/zip=org.kde.ark.desktop;
application/zstd=org.kde.ark.desktop;
text/markdown=emacs.desktop;
text/org=emacs.desktop;
text/rust=emacs.desktop;
text/x-c++hdr=emacs.desktop;
text/x-c++src=emacs.desktop;
text/x-chdr=emacs.desktop;
text/x-csrc=emacs.desktop;
text/x-emacs-lisp=emacs.desktop;
text/x-go=emacs.desktop;
text/x-java=emacs.desktop;
text/x-makefile=emacs.desktop;
text/x-patch=emacs.desktop;
text/x-python=emacs.desktop;
text/x-python3=emacs.desktop;
text/x-readme=emacs.desktop;
text/x-rst=emacs.desktop;
text/x-tex=emacs.desktop;
text/x-texinfo=emacs.desktop;
x-scheme-handler/http=userapp-Firefox-91DVN3.desktop;
x-scheme-handler/https=userapp-Firefox-91DVN3.desktop;
x-scheme-handler/chrome=userapp-Firefox-91DVN3.desktop;

View File

@@ -40,9 +40,6 @@
(setq-local process-environment (copy-sequence process-environment))
(setenv "PATH" (concat venv-bin path-separator (getenv "PATH")))))
(defvar fscotto/python-lsp-install-asked nil
"Non-nil if user was already asked about installing pylsp this session.")
(defun fscotto/resolve-pylsp ()
"Return the pylsp binary path if found, else nil.
Checks: project .venv, uv tool install path, and PATH."
@@ -60,41 +57,18 @@ Checks: project .venv, uv tool install path, and PATH."
(fscotto/resolve-pylsp))
(defun fscotto/python-ensure-lsp-server ()
"Ensure a Python LSP server is installed, prompting the user if needed.
If pylsp is already available, start LSP immediately. Otherwise, ask once
whether to install it via uv. On confirmation, install python-lsp-server
as a uv tool and then start LSP."
(unless (fboundp 'lsp-deferred)
(message "python: lsp-mode not available")
(return-from fscotto/python-ensure-lsp-server))
(if (fscotto/python-lsp-server-available-p)
(progn
(setq lsp-pylsp-server-command (fscotto/resolve-pylsp))
(lsp-deferred))
(when (or fscotto/python-lsp-install-asked
(y-or-n-p "python-lsp-server not found. Install it via uv? "))
(setq fscotto/python-lsp-install-asked t)
(let ((buf (current-buffer)))
(message "Installing python-lsp-server via uv in background...")
(make-process
:name "uv-pylsp-install"
:buffer (get-buffer-create " *uv-pylsp-install*")
:command '("uv" "tool" "install" "--upgrade" "python-lsp-server")
:sentinel
(lambda (proc event)
(cond
((string-match-p "finished" event)
(message "python-lsp-server installed.")
(setq lsp-pylsp-server-command (fscotto/resolve-pylsp))
(with-current-buffer buf
(lsp-deferred)))
((string-match-p "exited\\|failed" event)
(with-current-buffer buf
(message "python-lsp-server installation failed. Check *uv-pylsp-install* buffer."))))))))))
"Start Python LSP when its Ansible-managed pylsp executable is available."
(cond
((not (fboundp 'lsp-deferred))
(message "python: lsp-mode not available"))
((fscotto/python-lsp-server-available-p)
(setq lsp-pylsp-server-command (fscotto/resolve-pylsp))
(lsp-deferred))
(t
(message "python: pylsp not found; run the desktop Ansible profile"))))
(defun fscotto/python-maybe-start-lsp ()
"Start Python LSP, installing pylsp via uv if needed."
"Start Python LSP when pylsp is available."
(fscotto/python-ensure-lsp-server))
(defun fscotto/python-setup-check-command ()

View File

@@ -21,4 +21,11 @@
;; Loading DAP adapters
;; For Python
(require 'dap-python)
(setq dap-python-debugger 'debugpy))
(setq dap-python-debugger 'debugpy
dap-python-executable
(let ((uv-debugpy-python
(expand-file-name
"~/.local/share/uv/tools/debugpy/bin/python")))
(if (file-executable-p uv-debugpy-python)
uv-debugpy-python
"python3"))))