From 08297376a85a1719518507e54fca9de954d2376a Mon Sep 17 00:00:00 2001 From: Petri Hienonen Date: Thu, 23 May 2024 13:56:00 +0300 Subject: Agenix configuration --- .githooks/pre-commit | 1 + .gitignore | 1 + .luarc.json | 358 +++++++++++ Makefile | 26 + README.adoc | 17 + flake.lock | 135 +++- flake.nix | 186 +++++- home/alacritty/default.nix | 71 ++- home/cargo/default.nix | 13 + home/chawan/default.nix | 22 + home/conky/default.nix | 76 +++ home/conky/main.lua | 45 ++ home/default.nix | 776 +++++++++++++++++++++-- home/dunst/default.nix | 157 +++-- home/eww/default.nix | 197 ++++++ home/firefox/default.nix | 164 +++++ home/fish/default.nix | 110 +++- home/git/default.nix | 22 +- home/helix/default.nix | 151 ++++- home/hyprland/default.nix | 114 +++- home/hyprland/hyprpaper.conf | 2 - home/hyprlock/default.nix | 72 +++ home/icons | 377 ++++++++++++ home/lf/default.nix | 41 ++ home/lock/default.nix | 62 -- home/mail/default.nix | 244 ++++++++ home/mpv/default.nix | 25 + home/newsboat/default.nix | 59 ++ home/nvim/autocommands.lua | 272 ++++++++ home/nvim/default.nix | 93 +++ home/nvim/keymaps.lua | 86 +++ home/nvim/lsp.lua | 305 +++++++++ home/nvim/options.lua | 93 +++ home/nvim/plugins/dap.lua | 147 +++++ home/nvim/plugins/mini.lua | 14 + home/nvim/plugins/other.lua | 5 + home/nvim/plugins/treesitter.lua | 81 +++ home/nvim/plugins/undotree.lua | 1 + home/nvim/plugins/which.lua | 6 + home/quickshell/PopupContext.qml | 6 + home/quickshell/README.md | 13 + home/quickshell/Theme.qml | 87 +++ home/quickshell/bar/Bar.qml | 115 ++++ home/quickshell/bar/BarBlock.qml | 75 +++ home/quickshell/bar/BarText.qml | 57 ++ home/quickshell/bar/Notification.qml | 11 + home/quickshell/bar/NotificationPanel.qml | 101 +++ home/quickshell/bar/Tooltip.qml | 89 +++ home/quickshell/bar/blocks/ActiveWorkspace.qml | 34 + home/quickshell/bar/blocks/Battery.qml | 50 ++ home/quickshell/bar/blocks/Date.qml | 10 + home/quickshell/bar/blocks/Datetime.qml | 31 + home/quickshell/bar/blocks/Icon.qml | 146 +++++ home/quickshell/bar/blocks/Memory.qml | 31 + home/quickshell/bar/blocks/Notifications.qml | 34 + home/quickshell/bar/blocks/Sound.qml | 176 ++++++ home/quickshell/bar/blocks/SystemTray.qml | 80 +++ home/quickshell/bar/blocks/Time.qml | 10 + home/quickshell/bar/blocks/Workspace.qml | 28 + home/quickshell/bar/blocks/Workspaces.qml | 74 +++ home/quickshell/bar/utils/HyprlandUtils.qml | 54 ++ home/quickshell/default.nix | 20 + home/quickshell/quickshell.nix | 90 +++ home/quickshell/shell.qml | 8 + home/tenere/default.nix | 16 + home/ticker/default.nix | 41 ++ home/vale/default.nix | 31 + home/walker/config.toml | 251 ++++++++ home/walker/default.nix | 9 + home/wallpapers/crow.jpg | Bin 0 -> 985573 bytes home/wallpapers/crow2.avif | Bin 0 -> 91595 bytes home/wallpapers/default.nix | 87 +++ home/wallpapers/owl1.webp | Bin 0 -> 161844 bytes home/wallpapers/owl2.webp | Bin 0 -> 1000782 bytes home/wallpapers/owl3.webp | Bin 0 -> 514680 bytes home/waybar/config | 160 ----- home/waybar/default.nix | 304 ++++++++- home/waybar/style.css | 354 ++++------- hosts/kataja/default.nix | 141 +++++ hosts/kataja/hardware-configuration.nix | 79 +++ hosts/pihlaja/default.nix | 269 ++++++++ hosts/pihlaja/hardware-configuration.nix | 80 +++ hosts/saarni/default.nix | 316 ++++------ hosts/saarni/hardware-configuration.nix | 81 ++- hosts/tammi/20-wired.network | 31 + hosts/tammi/21-wired.network | 48 ++ hosts/tammi/CM3588.md | 284 +++++++++ hosts/tammi/Caddyfile | 319 ++++++++++ hosts/tammi/cgitrc | 47 ++ hosts/tammi/feeds.opml | 118 ++++ hosts/tammi/iptable-nat.service | 11 + hosts/tammi/syntax-highlighting.js | 23 + roles/shared.nix | 818 +++++++++++++++++++++++++ roles/wallpaper.nix | 23 + secrets/duckdns_login_token.age | Bin 0 -> 432 bytes secrets/gmail.age | 9 + secrets/miniflux_api_key.age | 9 + secrets/openai_auth_token.age | Bin 0 -> 600 bytes secrets/relesoft.age | 9 + secrets/relesoft_cargo_token.age | 9 + secrets/s3fs.age | Bin 0 -> 494 bytes secrets/secrets.nix | 21 + secrets/shiori_password.age | 10 + secrets/unsplash_access_key.age | Bin 0 -> 476 bytes 104 files changed, 9200 insertions(+), 865 deletions(-) create mode 100755 .githooks/pre-commit create mode 100644 .gitignore create mode 100644 .luarc.json create mode 100755 Makefile create mode 100644 README.adoc create mode 100644 home/cargo/default.nix create mode 100644 home/chawan/default.nix create mode 100644 home/conky/default.nix create mode 100644 home/conky/main.lua create mode 100644 home/eww/default.nix create mode 100644 home/firefox/default.nix delete mode 100644 home/hyprland/hyprpaper.conf create mode 100644 home/hyprlock/default.nix create mode 100644 home/icons create mode 100644 home/lf/default.nix delete mode 100644 home/lock/default.nix create mode 100644 home/mail/default.nix create mode 100644 home/mpv/default.nix create mode 100644 home/newsboat/default.nix create mode 100644 home/nvim/autocommands.lua create mode 100644 home/nvim/default.nix create mode 100644 home/nvim/keymaps.lua create mode 100644 home/nvim/lsp.lua create mode 100644 home/nvim/options.lua create mode 100644 home/nvim/plugins/dap.lua create mode 100644 home/nvim/plugins/mini.lua create mode 100644 home/nvim/plugins/other.lua create mode 100644 home/nvim/plugins/treesitter.lua create mode 100644 home/nvim/plugins/undotree.lua create mode 100644 home/nvim/plugins/which.lua create mode 100644 home/quickshell/PopupContext.qml create mode 100644 home/quickshell/README.md create mode 100644 home/quickshell/Theme.qml create mode 100644 home/quickshell/bar/Bar.qml create mode 100644 home/quickshell/bar/BarBlock.qml create mode 100644 home/quickshell/bar/BarText.qml create mode 100644 home/quickshell/bar/Notification.qml create mode 100644 home/quickshell/bar/NotificationPanel.qml create mode 100644 home/quickshell/bar/Tooltip.qml create mode 100644 home/quickshell/bar/blocks/ActiveWorkspace.qml create mode 100644 home/quickshell/bar/blocks/Battery.qml create mode 100644 home/quickshell/bar/blocks/Date.qml create mode 100644 home/quickshell/bar/blocks/Datetime.qml create mode 100644 home/quickshell/bar/blocks/Icon.qml create mode 100644 home/quickshell/bar/blocks/Memory.qml create mode 100644 home/quickshell/bar/blocks/Notifications.qml create mode 100644 home/quickshell/bar/blocks/Sound.qml create mode 100644 home/quickshell/bar/blocks/SystemTray.qml create mode 100644 home/quickshell/bar/blocks/Time.qml create mode 100644 home/quickshell/bar/blocks/Workspace.qml create mode 100644 home/quickshell/bar/blocks/Workspaces.qml create mode 100644 home/quickshell/bar/utils/HyprlandUtils.qml create mode 100644 home/quickshell/default.nix create mode 100644 home/quickshell/quickshell.nix create mode 100644 home/quickshell/shell.qml create mode 100644 home/tenere/default.nix create mode 100644 home/ticker/default.nix create mode 100644 home/vale/default.nix create mode 100644 home/walker/config.toml create mode 100644 home/walker/default.nix create mode 100644 home/wallpapers/crow.jpg create mode 100644 home/wallpapers/crow2.avif create mode 100644 home/wallpapers/default.nix create mode 100644 home/wallpapers/owl1.webp create mode 100644 home/wallpapers/owl2.webp create mode 100644 home/wallpapers/owl3.webp delete mode 100644 home/waybar/config create mode 100644 hosts/kataja/default.nix create mode 100644 hosts/kataja/hardware-configuration.nix create mode 100644 hosts/pihlaja/default.nix create mode 100644 hosts/pihlaja/hardware-configuration.nix create mode 100644 hosts/tammi/20-wired.network create mode 100644 hosts/tammi/21-wired.network create mode 100644 hosts/tammi/CM3588.md create mode 100644 hosts/tammi/Caddyfile create mode 100644 hosts/tammi/cgitrc create mode 100644 hosts/tammi/feeds.opml create mode 100644 hosts/tammi/iptable-nat.service create mode 100644 hosts/tammi/syntax-highlighting.js create mode 100644 roles/shared.nix create mode 100644 roles/wallpaper.nix create mode 100644 secrets/duckdns_login_token.age create mode 100644 secrets/gmail.age create mode 100644 secrets/miniflux_api_key.age create mode 100644 secrets/openai_auth_token.age create mode 100644 secrets/relesoft.age create mode 100644 secrets/relesoft_cargo_token.age create mode 100644 secrets/s3fs.age create mode 100644 secrets/secrets.nix create mode 100644 secrets/shiori_password.age create mode 100644 secrets/unsplash_access_key.age diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..a78682d --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1 @@ +fd -e nix --search-path ../ -x nixfmt --strict --verify diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2863a3f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.plain diff --git a/.luarc.json b/.luarc.json new file mode 100644 index 0000000..985229b --- /dev/null +++ b/.luarc.json @@ -0,0 +1,358 @@ +{ + "format": { + "enable": true, + "defaultConfig": { + "indent_style": "tab", + "indent_size": "1", + "quote_style": "double", + "max_line_length": "120" + } + }, + "workspace.library": [ + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/alpha-nvim", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/gitsigns.nvim", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/gruvbox.nvim", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/hardtime.nvim", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/lualine.nvim", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/nvim-dap", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/nvim-dap-view", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/nvim-dap-virtual-text", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/nvim-treesitter", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/nvim-web-devicons", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/telescope-fzf-native.nvim", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/telescope.nvim", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/undotree", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vim-fugitive", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ada", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-agda", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-angular", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-apex", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-arduino", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-asm", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-astro", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-authzed", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-awk", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-bash", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-bass", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-beancount", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-bibtex", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-bicep", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-bitbake", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-blade", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-blueprint", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-bp", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-brightscript", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-c", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-c3", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-c_sharp", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-caddy", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-cairo", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-capnp", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-chatito", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-circom", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-clojure", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-cmake", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-comment", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-commonlisp", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-cooklang", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-corn", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-cpon", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-cpp", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-css", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-csv", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-cuda", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-cue", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-cylc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-d", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-dart", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-desktop", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-devicetree", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-dhall", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-diff", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-disassembly", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-djot", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-dockerfile", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-dot", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-doxygen", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-dtd", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-earthfile", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ebnf", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-editorconfig", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-eds", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-eex", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-elixir", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-elm", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-elsa", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-elvish", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-embedded_template", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-enforce", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-erlang", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-facility", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-faust", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-fennel", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-fidl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-firrtl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-fish", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-foam", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-forth", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-fortran", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-fsh", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-fsharp", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-func", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-fusion", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gap", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gaptst", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gdscript", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gdshader", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-git_config", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-git_rebase", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gitattributes", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gitcommit", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gitignore", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gleam", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-glimmer", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-glimmer_javascript", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-glimmer_typescript", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-glsl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gn", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gnuplot", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-go", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-goctl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-godot_resource", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gomod", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gosum", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gotmpl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gowork", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gpg", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-graphql", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gren", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-groovy", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-groq", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-gstlaunch", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-hack", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-hare", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-haskell", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-haskell_persistent", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-hcl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-heex", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-helm", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-hjson", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-hlsl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-hlsplaylist", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-hocon", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-hoon", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-html", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-htmldjango", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-http", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-hurl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-hyprlang", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-idl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-idris", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ini", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-inko", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ispc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-janet_simple", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-java", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-javadoc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-javascript", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-jinja", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-jinja_inline", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-jq", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-jsdoc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-json", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-json5", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-jsonc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-jsonnet", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-julia", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-just", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-kcl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-kconfig", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-kdl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-kotlin", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-koto", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-kusto", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-lalrpop", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-latex", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ledger", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-leo", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-linkerscript", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-liquid", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-liquidsoap", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-llvm", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-lua", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-luadoc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-luap", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-luau", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-m68k", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-make", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-markdown", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-markdown_inline", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-matlab", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-menhir", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-mermaid", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-meson", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-mlir", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-muttrc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-nasm", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-nginx", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-nickel", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-nim", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-nim_format_string", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ninja", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-nix", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-nqc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-nu", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-objc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-objdump", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ocaml", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ocaml_interface", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ocamllex", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-odin", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-pascal", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-passwd", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-pem", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-perl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-php", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-php_only", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-phpdoc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-pioasm", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-pkl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-po", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-pod", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-poe_filter", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-pony", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-powershell", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-printf", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-prisma", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-problog", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-prolog", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-promql", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-properties", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-proto", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-prql", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-psv", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-pug", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-puppet", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-purescript", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-pymanifest", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-python", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ql", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-qmldir", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-qmljs", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-query", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-r", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-racket", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ralph", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-rasi", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-razor", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-rbs", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-re2c", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-readline", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-regex", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-rego", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-requirements", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-rescript", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-rifleconf", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-rnoweb", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-robot", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-robots", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-roc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ron", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-rst", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ruby", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-runescript", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-rust", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-scala", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-scfg", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-scheme", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-scss", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-sflog", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-slang", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-slim", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-slint", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-smali", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-smithy", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-snakemake", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-snl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-solidity", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-soql", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-sosl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-sourcepawn", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-sparql", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-sproto", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-sql", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-squirrel", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ssh_config", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-starlark", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-strace", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-styled", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-supercollider", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-superhtml", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-surface", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-svelte", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-sway", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-swift", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-sxhkdrc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-systemtap", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-systemverilog", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-t32", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-tablegen", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-tact", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-tcl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-teal", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-templ", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-tera", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-terraform", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-textproto", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-thrift", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-tiger", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-tlaplus", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-tmux", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-todotxt", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-toml", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-tsv", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-tsx", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-turtle", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-twig", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-typescript", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-typespec", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-typoscript", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-typst", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-udev", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ungrammar", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-unison", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-usd", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-uxntal", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-v", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-vala", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-vento", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-vhdl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-vhs", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-vim", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-vimdoc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-vrl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-vue", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-wgsl", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-wgsl_bevy", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-wing", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-wit", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-wxml", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-xcompose", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-xml", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-xresources", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-yaml", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-yang", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-yuck", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-zathurarc", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-zig", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ziggy", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/vimplugin-treesitter-grammar-ziggy_schema", + "/nix/store/4xnnfyvh125ykhgp83ybpjbgxq56gllv-vim-pack-dir/pack/myNeovimPackages/start/which-key.nvim", + "/home/petri/.config/nvim", + "/nix/store/jfyklnaiyw0f0ik0gi81y2j292i2iix8-ghostty-1.1.3/share/nvim/site", + "/nix/store/mvmm0i2jwvjzdbsd3la48f1d48y2k2m3-neovim-unwrapped-0.11.3/share/nvim/runtime", + "/nix/store/mvmm0i2jwvjzdbsd3la48f1d48y2k2m3-neovim-unwrapped-0.11.3/lib/nvim", + "${3rd}/luassert/library" + ] +} diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..301b3ae --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +default: rebuild + +rebuild: + run0 nixos-rebuild switch --flake . + +update: + nix flake update + run0 nixos-rebuild switch --flake . + +format: + fd -e nix -x nixfmt --strict --verify + +clean: + run0 nix-env --delete-generations +2 --profile /nix/var/nix/profiles/system + run0 nix-store --gc + run0 nix-store --optimise + +validate: + run0 nix-store --repair --verify --check-contents + run0 nix-store --optimise + +index: + systemd-run --scope -p MemoryMax=20G --user nix-index + +firefoxaddons: + nix flake show "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons" diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000..530e465 --- /dev/null +++ b/README.adoc @@ -0,0 +1,17 @@ += Nixos + +- Petri's NixOS installation +- Operation commands are listed in `Makefile`. + + +== Agenix + +Agenix can be used directly with SSH public keys. + +Create an encrypted age file: + + cat gmail.pass.plain | agenix -e gmail.age + +Validate that the secret can be extracted: + + agenix -d relesoft.age -i /home/petri/.ssh/id_ed25519 diff --git a/flake.lock b/flake.lock index 088625d..46fe11c 100644 --- a/flake.lock +++ b/flake.lock @@ -1,33 +1,121 @@ { "nodes": { + "agenix": { + "inputs": { + "darwin": "darwin", + "home-manager": "home-manager", + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems" + }, + "locked": { + "lastModified": 1762618334, + "narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=", + "owner": "ryantm", + "repo": "agenix", + "rev": "fcdea223397448d35d9b31f798479227e80183f6", + "type": "github" + }, + "original": { + "owner": "ryantm", + "repo": "agenix", + "type": "github" + } + }, + "darwin": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1744478979, + "narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=", + "owner": "lnl7", + "repo": "nix-darwin", + "rev": "43975d782b418ebf4969e9ccba82466728c2851b", + "type": "github" + }, + "original": { + "owner": "lnl7", + "ref": "master", + "repo": "nix-darwin", + "type": "github" + } + }, + "firefox-addons": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "dir": "pkgs/firefox-addons", + "lastModified": 1764389080, + "narHash": "sha256-BEn1Z9Uv20u2DS6wzLKdzx5kAzynM3wMQ9JnGf3VJvI=", + "owner": "rycee", + "repo": "nur-expressions", + "rev": "897437c09bf22ce59efb3370f0783d0c662dba31", + "type": "gitlab" + }, + "original": { + "dir": "pkgs/firefox-addons", + "owner": "rycee", + "repo": "nur-expressions", + "type": "gitlab" + } + }, "home-manager": { "inputs": { "nixpkgs": [ + "agenix", "nixpkgs" ] }, "locked": { - "lastModified": 1715381426, - "narHash": "sha256-wPuqrAQGdv3ISs74nJfGb+Yprm23U/rFpcHFFNWgM94=", + "lastModified": 1745494811, + "narHash": "sha256-YZCh2o9Ua1n9uCvrvi5pRxtuVNml8X2a03qIFfRKpFs=", "owner": "nix-community", "repo": "home-manager", - "rev": "ab5542e9dbd13d0100f8baae2bc2d68af901f4b4", + "rev": "abfad3d2958c9e6300a883bd443512c55dfeb1be", "type": "github" }, "original": { "owner": "nix-community", - "ref": "release-23.11", + "repo": "home-manager", + "type": "github" + } + }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1763992789, + "narHash": "sha256-WHkdBlw6oyxXIra/vQPYLtqY+3G8dUVZM8bEXk0t8x4=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "44831a7eaba4360fb81f2acc5ea6de5fde90aaa3", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "release-25.05", "repo": "home-manager", "type": "github" } }, "nixos-hardware": { "locked": { - "lastModified": 1716173274, - "narHash": "sha256-FC21Bn4m6ctajMjiUof30awPBH/7WjD0M5yqrWepZbY=", + "lastModified": 1764440730, + "narHash": "sha256-ZlJTNLUKQRANlLDomuRWLBCH5792x+6XUJ4YdFRjtO4=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "d9e0b26202fd500cf3e79f73653cce7f7d541191", + "rev": "9154f4569b6cdfd3c595851a6ba51bfaa472d9f3", "type": "github" }, "original": { @@ -37,27 +125,27 @@ }, "nixpkgs": { "locked": { - "lastModified": 1716218643, - "narHash": "sha256-i/E7gzQybvcGAYDRGDl39WL6yVk30Je/NXypBz6/nmM=", + "lastModified": 1764316264, + "narHash": "sha256-82L+EJU+40+FIdeG4gmUlOF1jeSwlf2AwMarrpdHF6o=", "owner": "nixos", "repo": "nixpkgs", - "rev": "a8695cbd09a7ecf3376bd62c798b9864d20f86ee", + "rev": "9a7b80b6f82a71ea04270d7ba11b48855681c4b0", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixos-23.11", + "ref": "nixos-25.05", "repo": "nixpkgs", "type": "github" } }, "nixpkgs-unstable": { "locked": { - "lastModified": 1716137900, - "narHash": "sha256-sowPU+tLQv8GlqtVtsXioTKeaQvlMz/pefcdwg8MvfM=", + "lastModified": 1764242076, + "narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=", "owner": "nixos", "repo": "nixpkgs", - "rev": "6c0b7a92c30122196a761b440ac0d46d3d9954f1", + "rev": "2fad6eac6077f03fe109c4d4eb171cf96791faa4", "type": "github" }, "original": { @@ -69,11 +157,28 @@ }, "root": { "inputs": { - "home-manager": "home-manager", + "agenix": "agenix", + "firefox-addons": "firefox-addons", + "home-manager": "home-manager_2", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs", "nixpkgs-unstable": "nixpkgs-unstable" } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 44581ae..5ecc52e 100644 --- a/flake.nix +++ b/flake.nix @@ -1,40 +1,188 @@ { description = "Petri's system"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-23.11"; + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-25.05"; nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable"; home-manager = { - url = "github:nix-community/home-manager/release-23.11"; + url = "github:nix-community/home-manager/release-25.05"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + agenix = { + url = "github:ryantm/agenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + firefox-addons = { + url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons"; inputs.nixpkgs.follows = "nixpkgs"; }; }; - outputs = inputs@{ self, nixpkgs, nixpkgs-unstable, home-manager, nixos-hardware, ... }: - let - inherit (self) outputs; - vars = { - user = "petri"; - name = "Petri Hienonen"; - email= "petri.hienonen@gmail.com"; - location = "$HOME/.nix"; - terminal = "alacritty"; - editor = "helix"; - shell = "fish"; - }; - in { + outputs = + inputs@{ + self, + nixpkgs, + agenix, + home-manager, + nixpkgs-unstable, + nixos-hardware, + ... + }: + let + inherit (self) outputs; + vars = { + user = "petri"; + name = "Petri Hienonen"; + email = "petri.hienonen@gmail.com"; + location = "$HOME/.nix"; + terminal = "ghostty"; + editor = "nvim"; + shell = "fish"; + }; + pkgs-unstable = import nixpkgs-unstable { + system = "x86_64-linux"; + config.allowUnfree = true; + }; + in + { nixosConfigurations = { saarni = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; - specialArgs = {inherit inputs outputs vars nixpkgs-unstable; }; + specialArgs = { + inherit + agenix + inputs + outputs + vars + pkgs-unstable + ; + }; modules = [ ./hosts/saarni + ./roles/shared.nix + agenix.nixosModules.default + home-manager.nixosModules.home-manager + { + home-manager = { + useGlobalPkgs = true; + useUserPackages = true; + sharedModules = [ inputs.agenix.homeManagerModules.default ]; + extraSpecialArgs = { + inherit + vars + inputs + outputs + pkgs-unstable + ; + }; + users = { + petri = import ./home; + }; + }; + } + ]; + }; + pihlaja = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = { + inherit + inputs + outputs + vars + pkgs-unstable + ; + }; + modules = [ + ./hosts/pihlaja + ./roles/shared.nix + agenix.nixosModules.default + home-manager.nixosModules.home-manager { - home-manager.useGlobalPkgs = true; - home-manager.useUserPackages = true; + home-manager = { + useGlobalPkgs = true; + useUserPackages = true; + sharedModules = [ inputs.agenix.homeManagerModules.default ]; + extraSpecialArgs = { + inherit + vars + inputs + outputs + pkgs-unstable + ; + }; + users = { + petri = import ./home; + }; + }; + } + #{ + #nixpkgs = { + # config.cudaSupport = true; + #hostPlatform = { + # aesSupport = true; + # avx2Support = true; + # # useLLVM = true; + # gcc = { + # arch = "x86-64-v3"; + # }; + # system = "x86_64-linux"; + # linker = "mold"; + # libc = "glibc"; + #}; + #}; + #} + ]; + }; + kataja = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = { + inherit + inputs + outputs + vars + pkgs-unstable + ; + }; + modules = [ + ./hosts/kataja + ./roles/shared.nix + agenix.nixosModules.default + home-manager.nixosModules.home-manager + { + home-manager = { + useGlobalPkgs = true; + useUserPackages = true; + sharedModules = [ inputs.agenix.homeManagerModules.default ]; + extraSpecialArgs = { + inherit + inputs + outputs + vars + pkgs-unstable + ; + }; + users = { + petri = import ./home; + }; + }; + } + { + nixpkgs = { + config.rocmSupport = true; + #hostPlatform = { + # aesSupport = true; + # avx2Support = true; + # # useLLVM = true; + # gcc = { + # arch = "x86-64-v3"; + # }; + # system = "x86_64-linux"; + # linker = "mold"; + # libc = "glibc"; + #}; + }; } ]; }; }; }; } - diff --git a/home/alacritty/default.nix b/home/alacritty/default.nix index 5bed57a..6fc9031 100644 --- a/home/alacritty/default.nix +++ b/home/alacritty/default.nix @@ -4,8 +4,75 @@ programs.alacritty = { enable = true; settings = { - selection = { - save_to_clipboard = true; + general = { + live_config_reload = true; + }; + font = { + normal = { + family = "Fira Code"; + style = "Regular"; + }; + size = 11; + }; + scrolling.multiplier = 9; + selection.save_to_clipboard = true; + window = { + opacity = 0.9; + }; + colors = { + primary = { + background = "#2e3440"; + foreground = "#d8dee9"; + dim_foreground = "#a5abb6"; + }; + cursor = { + text = "#2e3440"; + cursor = "#d8dee9"; + }; + vi_mode_cursor = { + text = "#2e3440"; + cursor = "#d8dee9"; + }; + selection = { + text = "CellForeground"; + background = "#4c566a"; + }; + search = { + matches = { + foreground = "CellBackground"; + background = "#88c0d0"; + }; + }; + normal = { + black = "#3b4252"; + red = "#bf616a"; + green = "#a3be8c"; + yellow = "#ebcb8b"; + blue = "#81a1c1"; + magenta = "#b48ead"; + cyan = "#88c0d0"; + white = "#e5e9f0"; + }; + bright = { + black = "#4c566a"; + red = "#bf616a"; + green = "#a3be8c"; + yellow = "#ebcb8b"; + blue = "#81a1c1"; + magenta = "#b48ead"; + cyan = "#8fbcbb"; + white = "#eceff4"; + }; + dim = { + black = "#373e4d"; + red = "#94545d"; + green = "#809575"; + yellow = "#b29e75"; + blue = "#68809a"; + magenta = "#8c738c"; + cyan = "#6d96a5"; + white = "#aeb3bb"; + }; }; }; }; diff --git a/home/cargo/default.nix b/home/cargo/default.nix new file mode 100644 index 0000000..1af2f7f --- /dev/null +++ b/home/cargo/default.nix @@ -0,0 +1,13 @@ +{ inputs, pkgs, ... }: +{ + xdg.configFile."/home/petri/.cargo/config.toml".text = '' + [registry] + global-credential-providers = ["cargo:token"] + + [registries.relesoft] + index = "sparse+https://git.relesoft.io/api/packages/relesoft/cargo/" + + [unstable] + gc = true + ''; +} diff --git a/home/chawan/default.nix b/home/chawan/default.nix new file mode 100644 index 0000000..b343c11 --- /dev/null +++ b/home/chawan/default.nix @@ -0,0 +1,22 @@ +{ vars, pkgs, ... }: + +{ + xdg.configFile."/home/petri/.config/chawan/config.toml".text = '' + [buffer] + autofocus = true + images = true + styling = true + scripting = true + history = true + + [input] + vi-numeric-prefix = true + + [page] + # Here, the arrow function will be called with the vi numbered prefix if + # one was input, and with no argument otherwise. + # The numeric prefix can never be zero, so it is safe to test for undefined + # using the ternary operator. + G = 'n => n ? pager.gotoLine(n) : pager.cursorLastLine()' + ''; +} diff --git a/home/conky/default.nix b/home/conky/default.nix new file mode 100644 index 0000000..1fc628e --- /dev/null +++ b/home/conky/default.nix @@ -0,0 +1,76 @@ +{ + config, + pkgs-unstable, + lib, + ... +}: +let + luaMain = builtins.readFile ./main.lua; +in +{ + services.conky = { + enable = true; + package = + (pkgs-unstable.conky.override { + curlSupport = true; + journalSupport = true; + luaCairoSupport = true; + luaSupport = true; + pulseSupport = true; + waylandSupport = true; + x11Support = true; + }).overrideAttrs + (old: { + buildInputs = old.buildInputs ++ [ + pkgs-unstable.cairo + pkgs-unstable.wayland + pkgs-unstable.libGL + pkgs-unstable.expat + pkgs-unstable.xorg.libXfixes + ]; + }); + + # https://conky.cc/config_settings + extraConfig = '' + conky.config = { + -- wayland + out_to_wayland = false, + out_to_x = true, + own_window_class = 'conky', + own_window_type ='override', + own_window = true, + own_window_transparent = true, + own_window_hints = 'undecorated,sticky,below,skip_taskbar,skip_pager', + double_buffer = true, + + alignment = "top_right", + gap_x = 60, + gap_y = 60, + minimum_width = 400, + minimum_height = 200, + maximum_width = 400, + + -- Colors and fonts + draw_shades = false, + draw_outline = false, + draw_borders = false, + default_color = "white", + default_shade_color = "black", + default_outline_color = "black", + color1 = "lightblue", + + -- Text + use_xft = yes, + font = "Liberation Mono:size=10", + uppercase = false, + + -- Lua configuration + lua_load = '${config.home.homeDirectory}/.config/conky/main.lua', + lua_draw_hook_post = "conky_main" + }; + + conky.text = [[ ]] + ''; + }; + xdg.configFile."conky/main.lua".text = luaMain; +} diff --git a/home/conky/main.lua b/home/conky/main.lua new file mode 100644 index 0000000..04eac69 --- /dev/null +++ b/home/conky/main.lua @@ -0,0 +1,45 @@ +require("cairo") +require("cairo_xlib") + +function conky_main() + if conky_window == nil then + print("No window") + return + end + + local cairo_surface = cairo_xlib_surface_create( + conky_window.display, + conky_window.drawable, + conky_window.visual, + conky_window.width, + conky_window.height + ) + local c = cairo_create(cairo_surface) + + cairo_select_font_face(c, "Liberation Mono", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(c, 12) + cairo_set_source_rgba(c, 1, 1, 1, 1) + cairo_move_to(c, 100, 100) + cairo_show_text(c, "hello world") + cairo_stroke(c) + + -- Settings. + local line_width = 5 + local top_left_x = 20 + local top_left_y = 20 + local rec_width = 100 + local rec_height = 50 + local red = 1 + local green = 0 + local blue = 0 + local alpha = 1 + + -- Draw it. + cairo_set_line_width(c, line_width) + cairo_rectangle(c, top_left_x, top_left_y, rec_width, rec_height) + cairo_set_source_rgba(c, red, green, blue, alpha) + + cairo_destroy(c) + cairo_surface_destroy(cairo_surface) + print("Draw") +end diff --git a/home/default.nix b/home/default.nix index 15054ab..0c845ca 100644 --- a/home/default.nix +++ b/home/default.nix @@ -1,71 +1,761 @@ -{ inputs, lib, config, vars, pkgs, ... }: +{ + inputs, + lib, + config, + vars, + pkgs, + pkgs-unstable, + ... +}: { - imports = [ - ./hyprland - ./waybar + imports = [ + # ./alacritty + # ./conky + # ./helix + # ./lf + # ./quickshell + ./cargo + ./chawan ./dunst - ./lock - ./git - ./helix + ./firefox ./fish - ./alacritty + ./git + ./hyprland + ./hyprlock + ./mail + ./mpv + ./newsboat + ./nvim + ./tenere + ./ticker + ./vale + ./walker + ./wallpapers + ./waybar ]; + age = { + identityPaths = [ "${config.home.homeDirectory}/.ssh/id_ed25519" ]; + secrets = { + miniflux_api_key = { + path = "${config.home.homeDirectory}/.secrets/miniflux_api_key"; + file = ../secrets/miniflux_api_key.age; + }; + openai_auth_token.file = ../secrets/openai_auth_token.age; + relesoft_cargo_token.file = ../secrets/relesoft_cargo_token.age; + shiori_password.file = ../secrets/shiori_password.age; + unsplash_access_key.file = ../secrets/unsplash_access_key.age; + gmail = { + file = ../secrets/gmail.age; + path = "${config.home.homeDirectory}/.secrets/gmail"; + mode = "600"; + }; + relesoft = { + file = ../secrets/relesoft.age; + path = "${config.home.homeDirectory}/.secrets/relesoft"; + mode = "600"; + }; + }; + }; + + gtk = { + enable = true; + theme = { + package = pkgs.whitesur-gtk-theme; + name = "WhiteSur-Dark"; + }; + iconTheme = { + package = pkgs.nordzy-icon-theme; + name = "Nordzy"; + }; + font = { + package = pkgs.roboto-flex; + name = "Roboto Flex 11"; + }; + }; + + qt = { + enable = true; + style = { + package = pkgs.darkly; + name = "Darkly"; + }; + }; + + programs = { + element-desktop = { + enable = true; + settings = { + default_theme = "dark"; + }; + }; + zellij = { + # modern tmux + enable = true; + enableFishIntegration = false; + }; + zoxide = { + # smarter cd command + enable = true; + enableFishIntegration = true; + enableNushellIntegration = true; + }; + nushell = { + enable = true; + extraConfig = '' + $env.config.hooks.command_not_found = source ${pkgs.nix-index}/etc/profile.d/command-not-found.nu + let carapace_completer = {|spans| + carapace $spans.0 nushell ...$spans | from json + } + $env.config = { + show_banner: false, + completions: { + case_sensitive: false # case-sensitive completions + quick: true # set to false to prevent auto-selecting completions + partial: true # set to false to prevent partial filling of the prompt + algorithm: "fuzzy" # prefix or fuzzy + external: { + enable: true + max_results: 100 + completer: $carapace_completer # check 'carapace_completer' + } + } + } + $env.PATH = ($env.PATH | + split row (char esep) | + prepend /home/petri/.apps | + append /usr/bin/env + ) + ''; + }; + carapace = { + enable = true; + enableNushellIntegration = true; + enableFishIntegration = true; + }; + gpg = { + enable = true; + settings = { + no-comments = true; + }; + }; + fzf = { + enable = true; + enableFishIntegration = true; # use CTRL+t for files, CTRL + r for history + defaultOptions = [ + "--style full" + "--preview '${pkgs.pistol}/bin/pistol {}'" + ]; + }; + yazi = { + # file browser + enable = true; + enableNushellIntegration = true; + enableFishIntegration = true; + settings = { + manager = { + show_hidden = true; + show_symlink = true; + }; + preview = { + image_filter = "lanczos3"; + image_quality = 90; + }; + }; + }; + atuin = { + enable = true; + enableFishIntegration = true; + enableNushellIntegration = true; + daemon = { + enable = true; + }; + settings = { + auto_sync = true; + sync_address = "https://atuin.tammi.cc"; + sync_frequency = "5m"; + style = "compact"; + workspaces = true; + }; + }; + starship = { + enable = true; + enableFishIntegration = true; + enableTransience = true; + enableNushellIntegration = true; + }; + eza = { + enable = true; + enableFishIntegration = true; + enableNushellIntegration = true; + git = true; + icons = "auto"; + extraOptions = [ + "--color=always" + "--tree" + "--level=1" + "--group-directories-first" + "--dereference" + ]; + }; + nix-index = { + enable = true; + enableFishIntegration = true; + }; + pistol.enable = true; + ghostty = { + enable = true; + installVimSyntax = true; + enableFishIntegration = true; + settings = { + font-family = "Iosevka Nerd Font"; + font-size = 12; + mouse-hide-while-typing = true; + copy-on-select = true; + theme = "nord"; + }; + themes = { + nord = { + background = "#2e3440"; + foreground = "#d8dee9"; + selection-background = "#3f4758"; + selection-foreground = "#d8dee9"; + cursor-color = "#d8dee9"; + cursor-text = "#2e3440"; + palette = [ + "0=#3b4252" + "1=#bf616a" + "2=#a3be8c" + "3=#ebcb8b" + "4=#81a1c1" + "5=#b48ead" + "6=#88c0d0" + "7=#e5e9f0" + "8=#4c566a" + "9=#bf616a" + "10=#a3be8c" + "11=#ebcb8b" + "12=#81a1c1" + "13=#b48ead" + "14=#8fbcbb" + "15=#eceff4" + ]; + }; + }; + }; + ssh = { + enable = true; + compression = true; + serverAliveInterval = 10; + controlMaster = "auto"; + controlPersist = "10m"; + }; + + chromium = { + enable = true; + package = pkgs.chromium; + commandLineArgs = [ + "--load-media-router-component-extension=1" + "--enable-features=VaapiVideoDecodeLinuxGL,VaapiVideoEncoder,Vulkan,VulkanFromANGLE,DefaultANGLEVulkan,VaapiIgnoreDriverChecks,VaapiVideoDecoder,PlatformHEVCDecoderSupport,UseMultiPlaneFormatForHardwareVideo" + "--enable-features=UseOzonePlatform --ozone-platform=wayland" + "--enable-media-router" + "--enable-smooth-scrolling" + "--force-dark-mode" + ]; + dictionaries = [ pkgs.hunspellDictsChromium.en_US ]; + extensions = [ + # vimium + # https://chromewebstore.google.com/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb + "dbepggeogbaibhgnhhndojpepiihcmeb" + + # bitwarden + # https://chromewebstore.google.com/detail/bitwarden-password-manage/nngceckbapebfimnlniiiahkandclblb + "nngceckbapebfimnlniiiahkandclblb" + + # ublock origin lite + # https://chromewebstore.google.com/detail/ublock-origin-lite/ddkjiahejlhfcafbddmgiahcphecmpfh + "ddkjiahejlhfcafbddmgiahcphecmpfh" + + # decentraleyes + # https://chromewebstore.google.com/detail/decentraleyes/ldpochfccmkkmhdbclfhpagapcfdljkj + "ldpochfccmkkmhdbclfhpagapcfdljkj" + + # redeck + # https://chromewebstore.google.com/detail/readeck/jnmcpmfimecibicbojhopfkcbmkafhee?pli=1 + "jnmcpmfimecibicbojhopfkcbmkafhee" + ]; + }; + + home-manager.enable = true; + }; + + services = { + mpd-mpris.enable = true; + mpd = { + enable = true; + musicDirectory = "/media/skydrive/Music/"; + extraArgs = [ "--verbose" ]; + network = { + listenAddress = "any"; + startWhenNeeded = true; + port = 6600; + }; + }; + + psd = { + enable = true; + backupLimit = 5; + }; + gpg-agent = { + defaultCacheTtl = 1800; + enable = true; + enableFishIntegration = true; + enableSshSupport = true; + pinentry.package = pkgs.pinentry-gnome3; + }; + mpris-proxy.enable = true; + clipse = { + enable = true; + }; + }; + + manual = { + html.enable = true; + json.enable = true; + }; + home = { + enableNixpkgsReleaseCheck = true; + stateVersion = "25.05"; + shell = { + enableFishIntegration = true; + enableNushellIntegration = true; + }; username = "${vars.user}"; sessionVariables = { - EDITOR = "${pkgs.helix}/bin/hx"; - PAGER = "${pkgs.moar}/bin/moar"; + CC = "clang"; + BROWSER = "${pkgs.firefox}/bin/firefox"; + CARGO_REGISTRIES_RELESOFT_CREDENTIAL_PROVIDER = "cargo:token"; + CARGO_REGISTRIES_RELESOFT_INDEX = "sparse+https://git.relesoft.io/api/packages/relesoft/cargo/"; + CARGO_REGISTRIES_RELESOFT_IO_PROTOCOL = "sparse"; + CARGO_REGISTRIES_RELESOFT_TOKEN = "$(${pkgs.coreutils}/bin/cat ${config.age.secrets.relesoft_cargo_token.path})"; + CURSOR_SIZE = "16"; DEFAULT_BROWSER = "${pkgs.firefox}/bin/firefox"; - NIXOS_OZONE_WL = "1"; - MOZ_USE_XINPUT2 = "1"; - MOZ_ENABLE_WAYLAND = "1"; + ELECTRON_OZONE_PLATFORM_HINT = "auto"; GDK_SCALE = "1"; - CURSOR_SIZE = "16"; + MOZ_USE_XINPUT2 = "1"; + NIXOS_OZONE_WL = "1"; + PAGER = "${pkgs.nvimpager}/bin/nvimpager"; + PISTOL_CHROMA_FORMATTER = "terminal256"; + PISTOL_CHROMA_STYLE = "monokai"; + VISUAL = "${pkgs.neovim}/bin/nvim"; + OPENAI_API_KEY = "$(${pkgs.coreutils}/bin/cat ${config.age.secrets.openai_auth_token.path})"; + SHIORI_PASSWORD = "$(${pkgs.coreutils}/bin/cat ${config.age.secrets.shiori_password.path})"; }; + pointerCursor = { package = pkgs.bibata-cursors; gtk.enable = true; name = "Bibata-Modern-Ice"; size = 22; }; + homeDirectory = "/home/${vars.user}"; packages = with pkgs; [ - clang - gnumake - biome - go - mpv - brightnessctl - bluez - element-desktop-wayland - yamlfmt - dprint - nodePackages.jsdoc - nodePackages.typescript-language-server - alacritty - pavucontrol - moar - zathura - grim - slurp - fd - wl-clipboard + # tui tools + bluetui # bluetooth management + chawan # browser, currently crashes + clipse # clipboard management + impala # iwd terminal ui + lux # youtube-downloader + pkgs-unstable.nom # rss reader + rmpc # tui for mpd + rtorrent # torrent + starship # shell aid + systemctl-tui + tenere # llm tui + ticker # stock ticker + wthrr # weather forecast from openmeteo + yazi # file manager + + # gui + bitwarden # password maanger + ghostty # terminal emulator + hypridle + hyprlock hyprpaper - waybar - wofi - dunst + libreoffice + lxqt.pavucontrol-qt + obsidian # note taking application + sqlitebrowser # sqlite + swayimg # image viewer + walker # launcher + wireshark + zathura # pdf viewer + + # spell checking + aspell + aspellDicts.en # english aspell dictionary + aspellDicts.en-computers + aspellDicts.en-science + aspellDicts.fi # finnish aspell dictionary + enchant # spell cherker interface + hunspell + hunspellDicts.en-us + libvoikko # finnish spelling + nuspell # spell checker + + # support + ethtool # ethernet driver info + ffmpeg + libcamera # source camera stack + libnotify # send notifications + libwebp + material-icons + material-symbols + mermaid-cli # diagrams + wl-clipboard + wttrbar # weather bar + + # cli-tools + appimage-run + attic-client # nix cache client + brightnessctl + cloc # count llines of code + dmidecode # memory information + espflash # ESP32 flasher + espup # ESP32 development + eza # modern file list + fastfetch # system information + fd # find files by filenames + file # show the type of file + font-awesome # icons + gat # cat but with extra features + grim # screen capture + inxi # system innformation + jq # commandline json parser + kramdown-asciidoc # command to convert markdown to asciidoc + minio-client + moar # less replacement + ntfy-sh # notifications + nvimpager # use neovim as pager + openai-whisper-cpp + pistol # file preview + pkg-config # needed for compilation + pkgs-unstable.goose-cli # llm cli + pkgs-unstable.vale # spellcheck + pkgs-unstable.valeStyles.microsoft # spellcheck linters + pkgs-unstable.valeStyles.write-good # spellcheck linters + playerctl + poppler-utils # pdf utilities + rdrview # extract content from web page + reader # extract web page and pipe + ripgrep # faster grep + slurp # screen are capture + sqlite # simple database + timg # show image in shell + wlogout # logout helper + xdg-utils + xh # curl replacement + xxd # view binary files + zellij # terminal multiplexer + + # Development + antora # documentation tool for asciidoc + asciidoctor-with-extensions # asciidoc is a markdown replacement + clang # c and rust + cmake # c + couchbase-shell # couchbase + d2 # graphs + gnumake # makefile + lean4 # theorem prover - broken + lld # c and rust linker + nodePackages.jsdoc # javascript documentation + pkgs-unstable.go + pkgs-unstable.golint # linter for go + uv # python package installer ]; }; - xdg.mimeApps = { + fonts = { + fontconfig = { + enable = true; + defaultFonts = { + serif = [ "Roboto Serif" ]; + sansSerif = [ "Roboto Flex" ]; + monospace = [ "Iosevka Nerd Font" ]; + emoji = [ "Twitter Color Emoji" ]; + }; + }; + }; + + xdg = { enable = true; - defaultApplications = { - "application/pdf" = "zathura.desktop"; + autostart.enable = true; + portal = { + enable = true; + xdgOpenUsePortal = true; + config.common = { + default = [ "*" ]; + "org.freedesktop.impl.portal.FileChooser" = "termfilechooser"; + }; + extraPortals = with pkgs; [ + xdg-desktop-portal-wlr + xdg-desktop-portal-termfilechooser + ]; + }; + desktopEntries = { + nvim = { + name = "nvim"; + genericName = "Editor"; + exec = ''${pkgs.neovim}/bin/nvim''; + terminal = true; + categories = [ ]; + comment = "A text editor"; + }; + }; + + mimeApps = { + enable = true; + defaultApplications = { + "application/pdf" = [ "org.pwmt.zathura.desktop" ]; + "inode/directory" = "yazi.desktop"; + "image/jpeg" = [ "swayimg.desktop" ]; + "image/png" = [ "swayimg.desktop" ]; + "image/webp" = [ "swayimg.desktop" ]; + "text/html" = [ "firefox.desktop" ]; + "text/json" = [ "nvim.desktop" ]; + "text/markdown" = "nvim.desktop"; + "text/plain" = "nvim.desktop"; + "video/mp4" = "mpv.desktop"; + "video/webm" = "mpv.desktop"; + "x-scheme-handler/about" = "firefox.desktop"; + "x-scheme-handler/http" = "firefox.desktop"; + "x-scheme-handler/https" = "firefox.desktop"; + "x-scheme-handler/unknown" = "firefox.desktop"; + }; + }; + }; + wayland.windowManager.hyprland.systemd.variables = [ "--all" ]; + systemd.user = { + startServices = "sd-switch"; + }; + + xdg.configFile."nom/config.yml".text = '' + autoread: true + ordering: desc + showread: false + openers: + - regex: "youtube" + cmd: "mpv %s" + - regex: ".*" + cmd: "${pkgs.firefox}/bin/firefox %s" + refreshinterval: 5 + filtering: + defaultIncludeFeedName: true + backends: + miniflux: + host: https://flux.tammi.cc + api_key: $(${pkgs.coreutils}/bin/cat ${config.age.secrets.miniflux_api_key.path}) + ''; + + systemd.user.services.ntfy-client = { + Unit = { + Description = "ntfy client subscriber"; + After = [ "graphical.target" ]; + }; + + Install = { + WantedBy = [ "default.target" ]; + }; + + Service = { + ExecStart = "${pkgs.ntfy-sh}/bin/ntfy subscribe --config /home/petri/.config/ntfy/client.yml --from-config"; + Restart = "on-failure"; + RestartSec = "10s"; + ProtectSystem = "strict"; + ProtectHome = "read-only"; + PrivateTmp = true; + NoNewPrivileges = true; + RestrictRealtime = true; + LockPersonality = true; + }; + }; + + xdg.configFile."xdg-desktop-portal-termfilechooser/config".text = + let + launcherDeps = pkgs.buildEnv { + name = "yazi-launcher-dependencies"; + paths = with pkgs; [ + coreutils + yazi + gnused + bashInteractive + ]; + }; + in + '' + [filechooser] + env=PATH='${launcherDeps}/bin' + env=TERMCMD='${pkgs.ghostty}/bin/ghostty' + cmd='${pkgs.xdg-desktop-portal-termfilechooser}/share/xdg-desktop-portal-termfilechooser/yazi-wrapper.sh' + default_dir=$HOME/Downloads + ''; + + systemd.user.services.bt-notify = { + Unit = { + Description = "Bluetooth Connection & Battery Notifications"; + After = [ "graphical-session.target" ]; + ConditionPathExists = "${config.home.homeDirectory}/.local/bin/bt-notify.sh"; + }; + Install = { + WantedBy = [ "graphical-session.target" ]; + }; + Service = { + Type = "simple"; + ExecStart = "${config.home.homeDirectory}/.local/bin/bt-notify.sh"; + Restart = "always"; + RestartSec = 5; }; }; - programs.home-manager.enable = true; - systemd.user.startServices = "sd-switch"; - home.stateVersion = "23.11"; + + home.file."/.local/bin/bt-notify.sh" = { + executable = true; + text = '' + #!/usr/bin/env bash + set -euo pipefail + + # Temporary file to remember which devices were connected last loop + STATE_FILE="/tmp/bt-connected-state" + + # Ensure the file exists + touch "$STATE_FILE" + + # Listen to BlueZ D-Bus signals AND poll for battery (some devices only report on poll) + ( + # D-Bus listener (connection events) + ${pkgs.dbus}/bin/dbus-monitor "interface=org.bluez.Device1,member=PropertiesChanged" --system & + + # Polling loop for battery (runs in background) + while true; do + ${pkgs.bluez}/bin/bluetoothctl devices | cut -f2 -d' ' | while read -r mac; do + info=$(${pkgs.bluez}/bin/bluetoothctl info "$mac") + name=$(echo "$info" | grep -i "Alias" | cut -d' ' -f2-) + connected=$(echo "$info" | grep -i "Connected" | awk '{print $2}') + battery_line=$(echo "$info" | grep -i "Battery Percentage" || true) + battery=$(echo "$battery_line" | awk '{print $3}' | tr -d '()') + + # --- Connection change detection --- + if [[ "$connected" == "yes" ]] && ! grep -q "^$mac$" "$STATE_FILE"; then + ${pkgs.libnotify}/bin/notify-send -a "Bluetooth" "Connected" "$name" + echo "$mac" >> "$STATE_FILE" + elif [[ "$connected" == "no" ]] && grep -q "^$mac$" "$STATE_FILE"; then + ${pkgs.libnotify}/bin/notify-send -a "Bluetooth" "Disconnected" "$name" + sed -i "/^$mac$/d" "$STATE_FILE" + fi + + # --- Low battery warning --- + if [[ -n "$battery" && "$battery" -lt 20 ]]; then + ${pkgs.libnotify}/bin/notify-send -u critical -a "Bluetooth" "Low Battery" "$name: ''${battery}%" + fi + done + sleep 10 + done & + ) | while read -r line; do + # Parse D-Bus PropertiesChanged for Connected + if echo "$line" | grep -q '"Connected"'; then + path=$(echo "$line" | grep -oP 'path="\K[^"]+') + mac=$(basename "$path") + info=$(${pkgs.bluez}/bin/bluetoothctl info "$mac") + name=$(echo "$info" | grep -i "Alias" | cut -d' ' -f2-) + connected=$(echo "$info" | grep -i "Connected" | awk '{print $2}') + + if [[ "$connected" == "yes" ]] && ! grep -q "^$mac$" "$STATE_FILE"; then + ${pkgs.libnotify}/bin/notify-send -a "Bluetooth" "Connected" "$name" + echo "$mac" >> "$STATE_FILE" + elif [[ "$connected" == "no" ]] && grep -q "^$mac$" "$STATE_FILE"; then + ${pkgs.libnotify}/bin/notify-send -a "Bluetooth" "Disconnected" "$name" + sed -i "/^$mac$/d" "$STATE_FILE" + fi + fi + done + ''; + }; + + xdg.configFile."goose/config.yaml".text = '' + OPENAI_BASE_PATH: v1/chat/completions + extensions: + developer: + available_tools: [] + bundled: true + description: null + display_name: Developer + enabled: true + name: developer + timeout: 300 + type: builtin + computercontroller: + bundled: true + display_name: Computer Controller + enabled: true + name: computercontroller + timeout: 300 + type: builtin + memory: + available_tools: [] + bundled: true + description: Tools to save and retrieve durable memories + display_name: Memory + enabled: true + name: memory + timeout: 80 + type: builtin + todo: + available_tools: [] + bundled: true + description: Enable a todo list for Goose so it can keep track of what it is doing + enabled: true + name: todo + type: platform + chatrecall: + available_tools: [] + bundled: true + description: Search past conversations and load session summaries for contextual memory + enabled: true + name: chatrecall + type: platform + extensionmanager: + available_tools: [] + bundled: true + description: Enable extension management tools for discovering, enabling, and disabling extensions + enabled: true + name: Extension Manager + type: platform + autovisualiser: + available_tools: [] + bundled: true + description: Data visualisation and UI generation tools + display_name: Auto Visualiser + enabled: true + name: autovisualiser + timeout: 300 + type: builtin + GOOSE_MODE: auto + GOOSE_PROVIDER: openai + GOOSE_MODEL: gpt-4.1-mini + OPENAI_HOST: https://api.openai.com + ''; + + xdg.configFile."ntfy/client.yml".text = '' + default-host: https://ntfy.tammi.cc + + subscribe: + - topic: 77WxlkfsTzGrbYFw + host: https://ntfy.tammi.cc + since: 1h # (optional) only get messages from the last hour + persist: true + keepalive: 45s # (optional) keepalive interval + format: markdown # (optional) output formatting: text, json, markdown, etc. + ''; } diff --git a/home/dunst/default.nix b/home/dunst/default.nix index 8a5f4ad..4843a90 100644 --- a/home/dunst/default.nix +++ b/home/dunst/default.nix @@ -1,74 +1,121 @@ -{ config, pkgs, ... }: { +{ config, pkgs, ... }: +{ services.dunst = { enable = true; + iconTheme = { + name = "Twitter Color Emoji"; + package = pkgs.twitter-color-emoji; + }; + settings = { global = { - alignment = "center"; - allow_markup = true; - browser = - "${config.programs.firefox.package}/bin/firefox -new-tab"; - bounce_freq = 0; - corner_radius = 5; - dmenu = "${pkgs.rofi}/bin/rofi -dmenu"; - follow = "mouse"; - font = "Fira Code 10"; - format = '' - %s - %b - %p''; - frame_color = "#555555"; - frame_width = 2; - geometry = "400-30+30"; - horizontal_padding = 15; - icon_position = "off"; - idle_threshold = 120; - ignore_newline = false; - indicate_hidden = true; - line_height = 0; - markup = "full"; - max_icon_size = 130; - padding = 15; - separator_color = "frame"; - separator_height = 2; - show_age_threshold = 60; - shrink = true; - sort = true; - startup_notification = false; - sticky_history = true; + ### Display ### + monitor = 0; + follow = "none"; + width = "(100, 500)"; + height = "(0, 300)"; + origin = "top-right"; + offset = "(5, 15)"; + scale = 0; + notification_limit = 10; + + ### Progress bar ### + progress_bar = true; + progress_bar_height = 14; + progress_bar_frame_width = 0; + progress_bar_min_width = 100; + progress_bar_max_width = 500; + progress_bar_corner_radius = 50; + progress_bar_corners = "bottom-left,top-right"; + icon_corner_radius = 0; + icon_corners = "all"; + + indicate_hidden = "yes"; transparency = 0; - word_wrap = true; - }; + separator_height = 6; + padding = 10; + horizontal_padding = 8; + text_icon_padding = 12; + frame_width = 1; + frame_color = "#a0a0a0"; + gap_size = 6; + separator_color = "frame"; + corner_radius = 10; + corners = "bottom,top-left"; - frame = { - width = 2; - color = "#83a598"; + ### Text ### + font = "Iosevka Nerd Font"; + markup = "full"; + format = "%s\n%b"; + alignment = "left"; + vertical_alignment = "center"; + word_wrap = "yes"; + ellipsize = "middle"; + ignore_newline = "no"; + line_height = 0; + show_age_threshold = -1; + stack_duplicates = true; + hide_duplicate_count = false; + show_indicators = "yes"; + + ### Icons ### + icon_position = "right"; + min_icon_size = 32; + max_icon_size = 128; + enable_recursive_icon_lookup = true; + icon_theme = "Twitter Color Emoji"; + + ### History ### + sticky_history = "yes"; + history_length = 30; + + ### Behavior ### + sort = "yes"; + idle_threshold = 120; + always_run_script = true; + + ### Browser & Menu ### + browser = "${pkgs.firefox}/bin/firefox -new-tab"; + dmenu = "${pkgs.walker}/bin/walker --modules applications,translation,webesearch,clipboard,finder"; + + ### Misc ### + title = "Dunst"; + class = "Dunst"; + startup_notification = true; + ignore_dbusclose = false; + force_xwayland = false; + force_xinerama = false; + per_monitor_dpi = false; + + ### Mouse ### + mouse_left_click = "close_current"; + mouse_middle_click = "do_action,close_current"; + mouse_right_click = "close_all"; }; urgency_low = { - frame_color = "#fabd2f"; - background = "#282828"; - foreground = "#ebdbb2"; - timeout = 5; + background = "#222222"; + foreground = "#ffffff"; + highlight = "#722ae6,#e4b5cb"; + timeout = 20; }; urgency_normal = { - background = "#282828"; - foreground = "#ebdbb2"; - timeout = 15; + background = "#222222"; + foreground = "#ffffff"; + frame_color = "#5e5086"; + highlight = "#722ae6,#e4b5cb"; + timeout = 20; + override_pause_level = 30; }; urgency_critical = { - background = "#282828"; - foreground = "#ebdbb2"; - frame_color = "#CC241D"; + background = "#222222"; + foreground = "#ffffff"; + frame_color = "#d54e53"; + highlight = "#d54e53,#f0f0f0"; timeout = 0; - }; - - shortcuts = { - close = "ctrl+space"; - close_all = "ctrl+shift+space"; - history = "ctrl+grave"; - context = "ctrl+shift+period"; + override_pause_level = 60; }; }; }; diff --git a/home/eww/default.nix b/home/eww/default.nix new file mode 100644 index 0000000..b6a745c --- /dev/null +++ b/home/eww/default.nix @@ -0,0 +1,197 @@ +{ + pkgs, + lib, + config, + ... +}: + +let + timerScript = pkgs.writeShellScriptBin "timer.sh" '' + #!${pkgs.bash}/bin/bash + CUR_TIME=$(${pkgs.coreutils}/bin/date +%s) + STATUS=$(${pkgs.coreutils}/bin/cat /var/tmp/timer_status || echo "READY") + + if [ "$STATUS" = "READY" ]; then + echo "" + elif [ "$STATUS" = "FINISHED" ]; then + ${pkgs.pulseaudio}/bin/paplay "${config.home.homeDirectory}/.config/eww/timer.wav" & + echo "READY" > /var/tmp/timer_status + echo "" + elif [ "$STATUS" -gt "$CUR_TIME" ]; then + DIFF=$(( STATUS - CUR_TIME )) + echo $(${pkgs.coreutils}/bin/date -d "@$DIFF" +%M:%S) + else + echo "FINISHED" > /var/tmp/timer_status + echo "" + fi + ''; + + calendarScript = pkgs.writeShellScriptBin "calendar.sh" '' + #!${pkgs.bash}/bin/bash + ${pkgs.coreutils}/bin/date +'%Y %B\n%d %A' + ''; + +in + +{ + programs.eww = { + enable = true; + package = pkgs.eww; + }; + + # Dependencies + home.packages = with pkgs; [ + hyprland + brightnessctl + lxqt.pavucontrol-qt + wttrbar + bluetui + wlogout + walker + lm_sensors + pulseaudio + socat + jq + procps + gawk + gnugrep + gnused + systemd + iproute2 + dbus + ]; + + home.file.".config/eww/eww.yuck".text = '' + ;; Variables and Polls + (defpoll time :interval "1s" "${pkgs.coreutils}/bin/date +'%A, %Y-%m-%d %H:%M:%S'") + (defpoll weather :interval "3600s" "${pkgs.wttrbar}/bin/wttrbar --main-indicator=FeelsLikeC --date-format=%d.%m.%Y --location=Helsinki | ${pkgs.jq}/bin/jq .FeelsLikeC") + (defpoll cpu-usage :interval "2s" "${pkgs.procps}/bin/top -bn1 | ${pkgs.gnugrep}/bin/grep '^%Cpu' | ${pkgs.gawk}/bin/awk '{print 100 - \$8}'") + (defpoll memory :interval "2s" "${pkgs.procps}/bin/free -h | ${pkgs.gnugrep}/bin/grep '^Mem:' | ${pkgs.gawk}/bin/awk '{print \$3 \"/\" \$2}'") + (defpoll load :interval "2s" "${pkgs.coreutils}/bin/cat /proc/loadavg | ${pkgs.gawk}/bin/awk '{print \$1}'") + (defpoll temperature :interval "5s" "${pkgs.lm_sensors}/bin/sensors | ${pkgs.gnugrep}/bin/grep 'Tctl:' | ${pkgs.gawk}/bin/awk '{print \$2}' | ${pkgs.gnused}/bin/sed 's/+//'") + (defpoll volume :interval "2s" "${pkgs.pulseaudio}/bin/pactl get-sink-volume @DEFAULT_SINK@ | ${pkgs.gawk}/bin/awk '{print \$5}' | ${pkgs.gnused}/bin/sed 's/%//'") + (defpoll mute :interval "2s" "${pkgs.pulseaudio}/bin/pactl get-sink-mute @DEFAULT_SINK@ | ${pkgs.gnugrep}/bin/grep -q 'Mute: yes' && echo 'true' || echo 'false'") + (defpoll backlight :interval "2s" "${pkgs.brightnessctl}/bin/brightnessctl g") + (defpoll battery :interval "10s" "${pkgs.coreutils}/bin/cat /sys/class/power_supply/BAT0/capacity 2>/dev/null || echo '0'") + (defpoll battery-status :interval "10s" "${pkgs.coreutils}/bin/cat /sys/class/power_supply/BAT0/status 2>/dev/null || echo 'Unknown'") + (defpoll failed-units :interval "30s" "${pkgs.systemd}/bin/systemctl --failed --no-legend | ${pkgs.coreutils}/bin/wc -l") + (defpoll processes :interval "10s" "${pkgs.procps}/bin/ps -e --no-headers | ${pkgs.coreutils}/bin/wc -l") + (defpoll sockets :interval "10s" "${pkgs.iproute2}/bin/ss -tuln | ${pkgs.coreutils}/bin/tail -n +2 | ${pkgs.coreutils}/bin/wc -l") + (defpoll keyboard-layout :interval "5s" "${pkgs.hyprland}/bin/hyprctl getoption general:kb_layout -j | ${pkgs.jq}/bin/jq -r .str") + + ;; Hyprland workspace tracking + (defpoll workspaces :interval "1s" "${pkgs.hyprland}/bin/hyprctl workspaces -j") + (defpoll active-workspace :interval "1s" "${pkgs.hyprland}/bin/hyprctl activeworkspace -j | ${pkgs.jq}/bin/jq -r .id") + (defpoll current-window :interval "1s" "${pkgs.hyprland}/bin/hyprctl activewindow -j | ${pkgs.jq}/bin/jq -r .title") + + ;; Widgets + (defwidget bar [] + (box :orientation "h" :class "bar" :space-evenly false + (box :class "left" :halign "start" :spacing 8 + ;; Start menu with eventbox for hover + (eventbox :onhover "${pkgs.pulseaudio}/bin/paplay ${config.home.homeDirectory}/.config/eww/beep.ogg &" + (button :class "startmenu" :onclick "${pkgs.walker}/bin/walker" "⚡")) + (box :class "workspaces" :spacing 4 + (for ws in workspaces + (button :onclick "${pkgs.hyprland}/bin/hyprctl dispatch workspace ''${ws.id}" + :class { ws.id == active-workspace ? "active" : "" } + "''${ws.name}"))) + (label :class "clock" :text time) + (label :class "timer" :text (timer-widget))) + + (box :class "center" :halign "center" + (label :text {current-window ? current-window : "No Windows"})) + + (box :class "right" :halign "end" :spacing 8 + (label :class "cpu" :text " {cpu-usage}%") + (label :class "memory" :text " {memory}") + (label :class "temperature" :text " {temperature}") + ;; Pulseaudio with eventbox for hover + (eventbox :onhover "${pkgs.pulseaudio}/bin/paplay ${config.home.homeDirectory}/.config/eww/beep.ogg &" :onclick "${pkgs.lxqt.pavucontrol-qt}/bin/pavucontrol-qt" + (label :class "pulseaudio" :text {mute ? "" : ""} " {volume}%")) + (label :class "battery" :text {battery-status == "Charging" ? "󰂄" : "󰁹"} " {battery}%") + ;; Bluetooth with eventbox for hover + (eventbox :onhover "${pkgs.pulseaudio}/bin/paplay ${config.home.homeDirectory}/.config/eww/beep.ogg &" :onclick "${pkgs.bluetui}/bin/bluetui" + (button :class "bluetooth" "")) + ;; Exit with eventbox for hover + (eventbox :onhover "${pkgs.pulseaudio}/bin/paplay ${config.home.homeDirectory}/.config/eww/beep.ogg &" :onclick "${pkgs.wlogout}/bin/wlogout" + (button :class "exit" "")))) + + ;; Timer logic + (defpoll timer-display :interval "1s" "${timerScript}/bin/timer.sh") + + (defwidget timer-widget [] + (label :text timer-display)) + + ;; Window + (defwindow bar + :monitor 0 + :geometry (geometry :x "0%" :y "0%" :width "100%" :height "40px") + :stacking "fg" + :windowtype "dock" + :reserve (struts :distance "40px" :side "top") + (bar)) + ''; + + home.file.".config/eww/eww.css".text = '' + * { + font-family: "JetBrainsMono Nerd Font", monospace; + font-size: 14px; + color: #ff9999; + background-color: transparent; + } + + .bar { + background-color: #1a0000; + border-bottom: 1px solid #ff4d4d; + padding: 0 16px; + min-height: 40px; + } + + .left, .center, .right { + padding: 8px 0; + } + + button, label { + padding: 4px 12px; + border-radius: 4px; + background-color: transparent; + } + + button:hover, eventbox:hover > * { + background-color: rgba(255, 77, 77, 0.2); + } + + .active { + background-color: rgba(255, 77, 77, 0.3); + box-shadow: 0 0 8px rgba(255, 77, 77, 0.5); + } + + .cpu, .memory, .temperature, .pulseaudio, .battery { + padding: 4px 8px; + } + + .exit { + background-color: rgba(255, 77, 77, 0.3); + margin-left: 8px; + } + + .exit:hover { + background-color: rgba(255, 77, 77, 0.5); + } + + .bluetooth { + background-color: rgba(77, 77, 255, 0.2); + } + + .bluetooth:hover { + background-color: rgba(77, 77, 255, 0.4); + } + ''; + + # Ensure EWW starts with Hyprland + wayland.windowManager.hyprland.settings.exec-once = [ + "${pkgs.eww}/bin/eww daemon" + "sleep 1 && ${pkgs.eww}/bin/eww open bar" + ]; +} diff --git a/home/firefox/default.nix b/home/firefox/default.nix new file mode 100644 index 0000000..228843c --- /dev/null +++ b/home/firefox/default.nix @@ -0,0 +1,164 @@ +{ inputs, pkgs, ... }: + +{ + programs.firefox = { + enable = true; + languagePacks = [ + "en-GB" + "fi" + ]; + policies = { + Cookies.Behavior = "reject-tracker-and-partition-foreign"; + DisableBuiltinPDFViewer = true; + DisableFirefoxStudies = true; + DisablePocket = true; + DisableTelemetry = true; + DontCheckDefaultBrowser = true; + EnableTrackingProtection = { + Cryptomining = true; + Fingerprinting = true; + Value = true; + }; + HardwareAcceleration = true; + Homepage.StartPage = "previous-session"; + SearchBar = "unified"; + TranslateEnabled = false; + Preferences = { + "browser.in-content.dark-mode" = true; + "extensions.autoDisableScopes" = 0; + "extensions.update.enabled" = false; + "ui.systemUsesDarkTheme" = true; + "widget.use-xdg-desktop-portal.file-picker" = 1; + }; + }; + profiles = { + default = { + id = 0; + name = "default"; + isDefault = true; + extensions.packages = with inputs.firefox-addons.packages."x86_64-linux"; [ + bitwarden + clearurls + decentraleyes + istilldontcareaboutcookies + new-tab-override + qwant-search + readeck + shiori + theme-nord-polar-night + ublock-origin + vimium + youtube-high-definition + youtube-nonstop + youtube-shorts-block + ]; + settings = { + "extensions.activeThemeID" = "{758478b6-29f3-4d69-ab17-c49fe568ed80}"; + "browser.startup.page" = 3; + "browser.startup.homepage" = "https://start.tammi.cc"; + "browser.newtabpage.pinned" = [ + { + title = "Startpage"; + url = "https://start.tammi.cc"; + } + ]; + "browser.download.useDownloadDir" = false; + "browser.eme.ui.enabled" = false; + "browser.search.defaultenginename" = "Searx"; + "browser.search.order.1" = "Searx"; + "browser.send_pings" = false; + "browser.tabs.crashReporting.sendReport" = false; + "browser.translations.neverTranslateLanguages" = "fi"; + "dom.webgpu.enabled" = true; + "experiments.activeExperiment" = false; + "experiments.enabled" = false; + "experiments.supported" = false; + "gfx.webrender.all" = true; + "media.eme.enabled" = false; + "media.ffmpeg.vaapi.enabled" = true; + "media.hardwaremediakeys.enabled" = true; + "mousewheel.default.delta_multiplier_y" = 600; + "network.allow-experiments" = false; + "network.dns.disablePrefetch" = false; + "network.trr.bootstrapAddr" = "87.92.94.136"; + "network.trr.mode" = 0; + "privacy.donottrackheader.enabled" = true; + "widget.wayland-dmabuf-vaapi.enabled" = true; + }; + search = { + force = true; + default = "Searx"; + order = [ + "Searx" + "Nix Packages" + "NixOS Options" + "Home Manager" + "ddg" + ]; + engines = { + "Searx" = { + urls = [ { template = "https://haku.tammi.cc/?q={searchTerms}"; } ]; + icon = "https://nixos.wiki/favicon.png"; + definedAliases = [ "@searx" ]; + }; + "Nix Packages" = { + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = [ "@np" ]; + urls = [ + { + template = "https://search.nixos.org/packages"; + params = [ + { + name = "type"; + value = "packages"; + } + { + name = "query"; + value = "{searchTerms}"; + } + ]; + } + ]; + }; + + "NixOS Options" = { + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = [ "@no" ]; + urls = [ + { + template = "https://search.nixos.org/options"; + params = [ + { + name = "channel"; + value = "unstable"; + } + { + name = "query"; + value = "{searchTerms}"; + } + ]; + } + ]; + }; + + "Home Manager" = { + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = [ "@hm" ]; + url = [ + { + template = "https://mipmip.github.io/home-manager-option-search/"; + params = [ + { + name = "query"; + value = "{searchTerms}"; + } + ]; + } + ]; + }; + }; + }; + }; + }; + }; +} diff --git a/home/fish/default.nix b/home/fish/default.nix index af2a377..08bb295 100644 --- a/home/fish/default.nix +++ b/home/fish/default.nix @@ -1,14 +1,112 @@ -{ vars, pkgs, ... }: +{ config, pkgs, ... }: { programs.fish = { enable = true; + shellAliases = { + browser = "${pkgs.chawan}/bin/cha"; + cat = "${pkgs.gat}/bin/gat"; + gmail = "${pkgs.himalaya}/himalaya envelope list --account gmail --folder gmail/Inbox 'not flag Seen'"; + grep = "${pkgs.ripgrep}/bin/rg"; + http = "${pkgs.xh}/bin/xh"; + journalctl = "${pkgs.systemd}/bin/journalctl --output=short-iso"; + l = "${pkgs.eza}/bin/eza -l --icons --git -a"; + llm = "${pkgs.tenere}/bin/tenere"; + ls = "${pkgs.eza}/bin/eza -a --group-directories-first"; + lt = "${pkgs.eza}/bin/eza --tree --level=2 --long --icons --git"; + relesoft = "${pkgs.himalaya}/himalaya envelope list --account relesoft --folder relesoft/Inbox 'not flag Seen'"; + ssh = "TERM=xterm-256color ${pkgs.openssh}/bin/ssh"; + stocks = "${pkgs.ticker}/bin/ticker --config /home/petri/.config/ticker/config.yaml"; + weather = "${pkgs.wthrr}/bin/wthrr --forecast d"; + wifi = "${pkgs.impala}/bin/impala"; + youtube = "${pkgs.pipe-viewer}/bin/pipe-viewer"; + }; + functions = { + doc = '' + ${pkgs.asciidoctor}/bin/asciidoctor --backend xhtml5 --out-file - "$argv[1]"|${pkgs.chawan}/bin/cha -T application/xhtml+xml + ''; + bookmark = '' + set -l Shiori_URL "https://shiori.tammi.cc" + set -l Username "petri" + set -l token (${pkgs.curl}/bin/curl -s -X POST -H "Content-Type: application/json" -d '{"username": "'$Username'", "password": "'$SHIORI_PASSWORD'", "remember": true}' $Shiori_URL/api/v1/auth/login | string match -r '(?<="token":")[^"]*') + ${pkgs.curl}/bin/curl -s -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $token" -d '{ "url": "'$argv[1]'", "createArchive": true, "public": 1 }' $Shiori_URL/api/bookmarks + ''; + share = '' + ${pkgs.curl}/bin/curl -X PUT --data-binary @$argv[1] https://bin.tammi.cc >&2 + ''; + import = '' + ${pkgs.grim}/bin/grim -g "$(${pkgs.slurp}/bin/slurp)" $argv + ''; + readdoc = "${pkgs.reader}/bin/reader $argv --markdown-output | ${pkgs.moar}/bin/moar --wrap --lang markdown"; + extract = '' + function extract + switch $argv[1] + case "*.tar.bz2" + tar xjf $argv[1] + + case "*.tar.gz" + tar xzf $argv[1] + + case "*.tar.xz" + tar xJf $argv[1] + + case "*.bz2" + bunzip2 $argv[1] + + case "*.rar" + unrar e $argv[1] + + case "*.gz" + gunzip $argv[1] + + case "*.tar" + tar xf $argv[1] + + case "*.tbz2" + tar xjf $argv[1] + + case "*.tgz" + tar xzf $argv[1] + + case "*.zip" + unzip $argv[1] + + case "*.Z" + uncompress $argv[1] + + case "*.7z" + 7z x $argv[1] + + case "*" + echo "unknown extension: $argv[1]" + end + end + ''; + }; interactiveShellInit = '' - function fish_greeting - if status is-interactive - fastfetch - end - end + set -g fish_key_bindings fish_vi_key_bindings + + set -g __fish_git_prompt_show_informative_status 1 + + set -g __fish_git_prompt_color_branch magenta --bold + set -g __fish_git_prompt_showupstream "informative" + set -g __fish_git_prompt_char_upstream_ahead "↑ " + set -g __fish_git_prompt_char_upstream_behind "↓ " + set -g __fish_git_prompt_char_upstream_prefix "" + + set -g __fish_git_prompt_char_stagedstate "● " + set -g __fish_git_prompt_char_dirtystate "✚" + set -g __fish_git_prompt_char_untrackedfiles "…" + set -g __fish_git_prompt_char_conflictedstate "✖" + set -g __fish_git_prompt_char_cleanstate "✔" + + set -g __fish_git_prompt_color_dirtystate blue + set -g __fish_git_prompt_color_stagedstate yellow + set -g __fish_git_prompt_color_invalidstate red + set -g __fish_git_prompt_color_untrackedfiles $fish_color_normal + set -g __fish_git_prompt_color_cleanstate green --bold + + ${pkgs.fastfetch}/bin/fastfetch ''; }; } diff --git a/home/git/default.nix b/home/git/default.nix index d3c605e..6d975e3 100644 --- a/home/git/default.nix +++ b/home/git/default.nix @@ -1,11 +1,27 @@ -{pkgs, ...}:{ +{ pkgs, ... }: +{ programs.git = { enable = true; - userName = "Petri Hienonen"; + aliases = { + lg = "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"; + }; + diff-so-fancy.enable = true; + maintenance.enable = true; userEmail = "petri.hienonen@gmail.com"; + userName = "Petri Hienonen"; extraConfig = { - init.defaultBranch = "master"; + core = { + editor = "${pkgs.neovim}/bin/nvim"; + hooksPath = ".githooks/"; + quotepath = false; + }; + commit.gpgSign = true; credential.helper = "store"; + init.defaultBranch = "master"; + merge.conflictStyle = "diff3"; + pull.rebase = true; + tag.gpgSign = true; + user.signingkey = "76028181DD730D0C"; }; }; } diff --git a/home/helix/default.nix b/home/helix/default.nix index 2438703..37c8529 100644 --- a/home/helix/default.nix +++ b/home/helix/default.nix @@ -1,35 +1,156 @@ +{ inputs, pkgs, ... }: { - inputs, - pkgs, - ... -}: { programs.helix = { + extraPackages = [ ]; enable = true; + defaultEditor = false; settings = { theme = "catppuccin_mocha"; editor = { + auto-format = true; + auto-pairs = false; + bufferline = "multiple"; color-modes = true; + completion-replace = true; + completion-trigger-len = 1; cursorline = true; - cursor-shape = { - insert = "bar"; - normal = "block"; - select = "underline"; - }; indent-guides.render = true; - lsp.display-inlay-hints = true; - statusline.center = ["position-percentage"]; + soft-wrap.enable = true; + statusline.center = [ "position-percentage" ]; true-color = true; - whitespace.characters = { - newline = "↴"; - tab = "⇥"; + whitespace = { + render = "all"; + characters = { + newline = "↴"; + tab = "⇥"; + }; }; }; - keys.normal.space.u = { f = ":format"; # format using LSP formatter w = ":set whitespace.render all"; W = ":set whitespace.render none"; }; + editor.cursor-shape = { + insert = "bar"; + normal = "block"; + select = "underline"; + }; + editor.lsp = { + display-messages = true; + display-inlay-hints = true; + display-signature-help-docs = true; + }; + }; + languages = { + language-server = { + vale-ls = { + command = "${pkgs.vale-ls}/bin/vale-ls"; + }; + rust-analyzer = { + config = { + checkOnSave = { + command = "${pkgs.clippy}/bin/clippy"; + }; + cargo = { + allFeatures = true; + }; + }; + }; + biome = { + command = "${pkgs.biome}/bin/biome"; + args = [ "lsp-proxy" ]; + }; + ruff = { + command = "${pkgs.ruff}/bin/ruff"; + args = [ + "server" + "--preview" + "--isolated" + ]; + }; + pyright = { + command = "${pkgs.pyright}/bin/pyright-langserver"; + args = [ "--stdio" ]; + }; + }; + language = [ + { + name = "asciidoc"; + language-servers = [ "vale-ls" ]; + scope = "source.adoc"; + file-types = [ "adoc" ]; + grammar = "asciidoc"; + } + { + name = "rust"; + auto-format = true; + } + { + name = "python"; + language-servers = [ + "ruff" + "pyright" + ]; + auto-format = true; + } + { + name = "latex"; + language-servers = [ + "texlab" + "vale-ls" + ]; + auto-format = true; + formatter = { + command = "${pkgs.tex-fmt}/bin/tex-fmt"; + args = [ + "--stdin" + "--keep" + ]; + }; + } + { + name = "nix"; + auto-format = true; + formatter.command = "${pkgs.nixfmt-rfc-style}/bin/nixfmt"; + } + { + name = "markdown"; + auto-format = true; + formatter = { + command = "${pkgs.dprint}/bin/dprint"; + args = [ + "fmt" + "--stdin" + "md" + ]; + }; + language-servers = [ + "vale-ls" + "marksman" + ]; + } + { + name = "toml"; + auto-format = true; + } + { + name = "javascript"; + language-servers = [ + { + name = "typescript-language-server"; + except-features = [ "format" ]; + } + "biome" + ]; + auto-format = true; + } + { + name = "json"; + language-servers = [ "biome" ]; + auto-format = true; + } + ]; }; }; } diff --git a/home/hyprland/default.nix b/home/hyprland/default.nix index e00e794..992fa09 100644 --- a/home/hyprland/default.nix +++ b/home/hyprland/default.nix @@ -1,24 +1,110 @@ +{ pkgs, ... }: { + services.hyprpaper = { + enable = true; + settings = { + ipc = "on"; + preload = [ + "/etc/nixos/home/wallpapers/owl1.webp" + "/etc/nixos/home/wallpapers/owl2.webp" + "/etc/nixos/home/wallpapers/owl3.webp" + ]; + wallpaper = [ ", /etc/nixos/home/wallpapers/owl1.webp" ]; + }; + }; + + services.hyprpolkitagent.enable = true; + + services.hypridle = { + enable = true; + settings = { + general = { + after_sleep_cmd = "${pkgs.hyprland}/bin/hyprctl dispatch dpms on"; + ignore_dbus_inhibit = false; + lock_cmd = "${pkgs.procps}/bin/pidof hyprlock || ${pkgs.hyprlock}/bin/hyprlock"; + }; + + listener = [ + { + timeout = 300; + on-timeout = "${pkgs.brightnessctl}/bin/brightnessctl -s set 10"; + on-resume = "${pkgs.brightnessctl}/bin/brightnessctl -r"; + } + { + timeout = 600; + on-timeout = "${pkgs.systemd}/bin/loginctl lock-session"; + } + { + timeout = 900; # 15 minutes + on-timeout = "${pkgs.hyprland}/bin/hyprctl dispatch dpms off"; # screen off when timeout has passed + on-resume = "${pkgs.hyprland}/bin/hyprctl dispatch dpms on"; # screen on when activity is detected after timeout has fired. + } + { + timeout = 1800; + on-timeout = "${pkgs.systemd}/bin/systemctl suspend"; + } + ]; + }; + }; wayland.windowManager.hyprland = { enable = true; - systemd.enable = true; + package = pkgs.hyprland; + systemd = { + variables = [ "--all" ]; + enable = true; + enableXdgAutostart = true; + }; + extraConfig = '' + exec-once = ${pkgs.hyprlock}/bin/hyprlock --immediate; + ''; + xwayland.enable = true; settings = { - "exec-once" = "waybar & hyprpaper"; - "monitor" = ",preferred,auto,1"; + monitor = ", preferred, auto, 1"; + general = { + gaps_out = 10; + }; input = { - kb_layout = "fi"; - repeat_delay = 280; - repeat_rate = 100; + kb_layout = "us,fi"; + kb_options = "grp:alt_shift_toggle"; + scroll_method = "on_button_down"; + scroll_button = 274; + sensitivity = 0; # -1.0 - 1.0, 0 means no modification + repeat_delay = 180; + repeat_rate = 150; + touchpad = { + natural_scroll = true; + disable_while_typing = true; + tap-to-click = true; + middle_button_emulation = true; + }; + }; + decoration = { + dim_inactive = true; + }; + cursor = { + no_hardware_cursors = true; + }; + misc = { + disable_hyprland_logo = true; + disable_splash_rendering = true; + middle_click_paste = true; }; - "$mainMod" = "SUPER"; bind = [ - "$mainMod, Return, exec, alacritty" - "$mainMod, d, exec, wofi --show drun" - "$mainMod, B, exec, firefox" + "$mainMod, V, exec, ${pkgs.ghostty}/bin/ghostty --class clipse -e 'clipse' " + "$mainMod, Return, exec, ${pkgs.ghostty}/bin/ghostty" + "$mainMod, d, exec, ${pkgs.walker}/bin/walker --modules applications,translation,webesearch,clipboard,finder" + "$mainMod, B, exec, ${pkgs.firefox}/bin/firefox" "$mainMod, F, fullscreen" "$mainMod, C, killactive," + "$mainMod, Tab, cyclenext" + ", Print, exec, ${pkgs.grim}/bin/grim - | wl-copy && wl-paste > ~/Pictures/screenshots/Screenshot-$(date +%F_%T).png && dunstify 'Screenshot of the whole screen taken' -t 1000" + ", XF86MonBrightnessUp, exec, brightnessctl s -e 5%+" + ", XF86MonBrightnessDown, exec, brightnessctl s -e 5%-" + ", XF86AudioRaiseVolume,exec,wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+" + ", XF86AudioLowerVolume,exec,wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-" + "$mainMod SHIFT, L, exec, hyprlock" # Move focus with mainMod + arrow keys "$mainMod, left, movefocus, l" @@ -30,6 +116,11 @@ "$mainMod, K, movefocus, u" "$mainMod, J, movefocus, d" + "$mainMod SHIFT, left, swapwindow, l" + "$mainMod SHIFT, right, swapwindow, r" + "$mainMod SHIFT, up, swapwindow, u" + "$mainMod SHIFT, down, swapwindow, d" + # Switch workspaces with mainMod + [0-9] "$mainMod, 1, workspace, 1" "$mainMod, 2, workspace, 2" @@ -54,6 +145,7 @@ "$mainMod SHIFT, 9, movetoworkspace, 9" "$mainMod SHIFT, 0, movetoworkspace, 10" ]; + binde = [ ",XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle" ]; bindm = [ # Move/resize windows with mainMod + LMB/RMB and dragging "$mainMod, mouse:272, movewindow" @@ -61,6 +153,4 @@ ]; }; }; - - home.file.".config/hypr/hyprpaper.conf".source = ./hyprpaper.conf; } diff --git a/home/hyprland/hyprpaper.conf b/home/hyprland/hyprpaper.conf deleted file mode 100644 index 67a04ed..0000000 --- a/home/hyprland/hyprpaper.conf +++ /dev/null @@ -1,2 +0,0 @@ -preload = ~/wallpapers/metsapalo.jpg -wallpaper = eDP-1,~/wallpapers/metsapalo.jpg diff --git a/home/hyprlock/default.nix b/home/hyprlock/default.nix new file mode 100644 index 0000000..4627556 --- /dev/null +++ b/home/hyprlock/default.nix @@ -0,0 +1,72 @@ +{ vars, pkgs, ... }: + +{ + programs.hyprlock = { + enable = true; + settings = { + general = { + grace = 300; + hide_cursor = true; + ignore_empty_input = true; + }; + + animations = { + enabled = true; + bezier = "linear, 1, 1, 0, 0"; + animation = [ + "fadeIn, 1, 5, linear" + "fadeOut, 1, 5, linear" + "inputFieldDots, 1, 2, linear" + ]; + }; + + background = [ + { + path = "screenshot"; + blur_passes = 3; + blur_size = 8; + } + ]; + + input-field = [ + { + size = "200, 50"; + position = "0, -80"; + monitor = ""; + 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; + shadow_passes = 2; + } + ]; + + label = [ + # Clock with seconds + { + monitor = ""; + text = "cmd[update:1000] echo \"$(date +'%H:%M:%S')\""; + color = "rgb(202, 211, 245)"; + font_size = 90; + position = "0, 150"; + halign = "center"; + valign = "center"; + shadow_passes = 2; + } + # Date in ISO format + { + monitor = ""; + text = "cmd[update:1000] echo \"$(date +'%Y-%m-%d')\""; + color = "rgb(202, 211, 245)"; + font_size = 25; + position = "0, 50"; + halign = "center"; + valign = "center"; + shadow_passes = 2; + } + ]; + }; + }; +} diff --git a/home/icons b/home/icons new file mode 100644 index 0000000..4022691 --- /dev/null +++ b/home/icons @@ -0,0 +1,377 @@ +# vim:ft=conf + +# These examples require Nerd Fonts or a compatible font to be used. +# See https://www.nerdfonts.com for more information. + +# default values from lf (with matching order) +# ln l # LINK +# or l # ORPHAN +# tw t # STICKY_OTHER_WRITABLE +# ow d # OTHER_WRITABLE +# st t # STICKY +# di d # DIR +# pi p # FIFO +# so s # SOCK +# bd b # BLK +# cd c # CHR +# su u # SETUID +# sg g # SETGID +# ex x # EXEC +# fi - # FILE + +# file types (with matching order) +ln  # LINK +or  # ORPHAN +tw t # STICKY_OTHER_WRITABLE +ow  # OTHER_WRITABLE +st t # STICKY +di  # DIR +pi p # FIFO +so s # SOCK +bd b # BLK +cd c # CHR +su u # SETUID +sg g # SETGID +ex  # EXEC +fi  # FILE + +# disable some default filetype icons, let them choose icon by filename +# ln  # LINK +# or  # ORPHAN +# tw # STICKY_OTHER_WRITABLE +# ow # OTHER_WRITABLE +# st # STICKY +# di  # DIR +# pi # FIFO +# so # SOCK +# bd # BLK +# cd # CHR +# su # SETUID +# sg # SETGID +# ex # EXEC +# fi  # FILE + +# file extensions (vim-devicons) +*.styl  +*.sass  +*.scss  +*.htm  +*.html  +*.slim  +*.haml  +*.ejs  +*.css  +*.less  +*.md  +*.mdx  +*.markdown  +*.rmd  +*.json  +*.webmanifest  +*.js  +*.mjs  +*.jsx  +*.rb  +*.gemspec  +*.rake  +*.php  +*.py  +*.pyc  +*.pyo  +*.pyd  +*.coffee  +*.mustache  +*.hbs  +*.conf  +*.ini  +*.yml  +*.yaml  +*.toml  +*.bat  +*.mk  +*.jpg  +*.jpeg  +*.bmp  +*.png  +*.webp  +*.gif  +*.ico  +*.twig  +*.cpp  +*.c++  +*.cxx  +*.cc  +*.cp  +*.c  +*.cs 󰌛 +*.h  +*.hh  +*.hpp  +*.hxx  +*.hs  +*.lhs  +*.nix  +*.lua  +*.java  +*.sh  +*.fish  +*.bash  +*.zsh  +*.ksh  +*.csh  +*.awk  +*.ps1  +*.ml λ +*.mli λ +*.diff  +*.db  +*.sql  +*.dump  +*.clj  +*.cljc  +*.cljs  +*.edn  +*.scala  +*.go  +*.dart  +*.xul  +*.sln  +*.suo  +*.pl  +*.pm  +*.t  +*.rss  +'*.f#'  +*.fsscript  +*.fsx  +*.fs  +*.fsi  +*.rs  +*.rlib  +*.d  +*.erl  +*.hrl  +*.ex  +*.exs  +*.eex  +*.leex  +*.heex  +*.vim  +*.ai  +*.psd  +*.psb  +*.ts  +*.tsx  +*.jl  +*.pp  +*.vue  +*.elm  +*.swift  +*.xcplayground  +*.tex 󰙩 +*.r 󰟔 +*.rproj 󰗆 +*.sol 󰡪 +*.pem  + +# file names (vim-devicons) (case-insensitive not supported in lf) +*gruntfile.coffee  +*gruntfile.js  +*gruntfile.ls  +*gulpfile.coffee  +*gulpfile.js  +*gulpfile.ls  +*mix.lock  +*dropbox  +*.ds_store  +*.gitconfig  +*.gitignore  +*.gitattributes  +*.gitlab-ci.yml  +*.bashrc  +*.zshrc  +*.zshenv  +*.zprofile  +*.vimrc  +*.gvimrc  +*_vimrc  +*_gvimrc  +*.bashprofile  +*favicon.ico  +*license  +*node_modules  +*react.jsx  +*procfile  +*dockerfile  +*docker-compose.yml  +*docker-compose.yaml  +*compose.yml  +*compose.yaml  +*rakefile  +*config.ru  +*gemfile  +*makefile  +*cmakelists.txt  +*robots.txt 󰚩 + +# file names (case-sensitive adaptations) +*Gruntfile.coffee  +*Gruntfile.js  +*Gruntfile.ls  +*Gulpfile.coffee  +*Gulpfile.js  +*Gulpfile.ls  +*Dropbox  +*.DS_Store  +*LICENSE  +*React.jsx  +*Procfile  +*Dockerfile  +*Docker-compose.yml  +*Docker-compose.yaml  +*Rakefile  +*Gemfile  +*Makefile  +*CMakeLists.txt  + +# file patterns (vim-devicons) (patterns not supported in lf) +# .*jquery.*\.js$  +# .*angular.*\.js$  +# .*backbone.*\.js$  +# .*require.*\.js$  +# .*materialize.*\.js$  +# .*materialize.*\.css$  +# .*mootools.*\.js$  +# .*vimrc.*  +# Vagrantfile$  + +# file patterns (file name adaptations) +*jquery.min.js  +*angular.min.js  +*backbone.min.js  +*require.min.js  +*materialize.min.js  +*materialize.min.css  +*mootools.min.js  +*vimrc  +Vagrantfile  + +# archives or compressed (extensions from dircolors defaults) +*.tar  +*.tgz  +*.arc  +*.arj  +*.taz  +*.lha  +*.lz4  +*.lzh  +*.lzma  +*.tlz  +*.txz  +*.tzo  +*.t7z  +*.zip  +*.z  +*.dz  +*.gz  +*.lrz  +*.lz  +*.lzo  +*.xz  +*.zst  +*.tzst  +*.bz2  +*.bz  +*.tbz  +*.tbz2  +*.tz  +*.deb  +*.rpm  +*.jar  +*.war  +*.ear  +*.sar  +*.rar  +*.alz  +*.ace  +*.zoo  +*.cpio  +*.7z  +*.rz  +*.cab  +*.wim  +*.swm  +*.dwm  +*.esd  + +# image formats (extensions from dircolors defaults) +*.jpg  +*.jpeg  +*.mjpg  +*.mjpeg  +*.gif  +*.bmp  +*.pbm  +*.pgm  +*.ppm  +*.tga  +*.xbm  +*.xpm  +*.tif  +*.tiff  +*.png  +*.svg  +*.svgz  +*.mng  +*.pcx  +*.mov  +*.mpg  +*.mpeg  +*.m2v  +*.mkv  +*.webm  +*.ogm  +*.mp4  +*.m4v  +*.mp4v  +*.vob  +*.qt  +*.nuv  +*.wmv  +*.asf  +*.rm  +*.rmvb  +*.flc  +*.avi  +*.fli  +*.flv  +*.gl  +*.dl  +*.xcf  +*.xwd  +*.yuv  +*.cgm  +*.emf  +*.ogv  +*.ogx  + +# audio formats (extensions from dircolors defaults) +*.aac  +*.au  +*.flac  +*.m4a  +*.mid  +*.midi  +*.mka  +*.mp3  +*.mpc  +*.ogg  +*.ra  +*.wav  +*.oga  +*.opus  +*.spx  +*.xspf  + +# other formats +*.pdf  diff --git a/home/lf/default.nix b/home/lf/default.nix new file mode 100644 index 0000000..dae7e7f --- /dev/null +++ b/home/lf/default.nix @@ -0,0 +1,41 @@ +{ pkgs, ... }: +{ + programs.lf = { + enable = true; + commands = { + editor-open = ''$$EDITOR $f''; + }; + settings = { + preview = true; + hidden = true; + drawbox = true; + icons = true; + ignorecase = true; + timefmt = "2006-01-02T15:04:05.999Z"; + }; + previewer.source = "/home/petri/.config/lf/pv.sh"; + keybindings = { + ee = "editor-open"; + }; + }; + + xdg.configFile."/home/petri/.config/lf/icons".source = ./icons; + xdg.configFile."/home/petri/.config/lf/pv.sh" = { + executable = true; + text = '' + #!/bin/sh + case "$1" in + *.jpg*) timg -I "$1";; + *.png*) timg -I "$1";; + *.webp*) timg -I "$1";; + *.avif*) timg -I "$1";; + *.tar*) tar tf "$1";; + *.zip) unzip -l "$1";; + *.rar) unrar l "$1";; + *.7z) 7z l "$1";; + *.pdf) pdftotext "$1" -;; + *) pistol "$1";; + esac + ''; + }; +} diff --git a/home/lock/default.nix b/home/lock/default.nix deleted file mode 100644 index 188d4b7..0000000 --- a/home/lock/default.nix +++ /dev/null @@ -1,62 +0,0 @@ -{ pkgs, ... }: - -{ - programs.swaylock = { - enable = true; - - package = pkgs.swaylock-effects; - settings = { - ignore-empty-password = true; - disable-caps-lock-text = true; - # font = "MonaspiceAr Nerd Font"; - grace = 3; - - clock = true; - timestr = "%R"; - datestr = "%a, %e of %B"; - - fade-in = "0.2"; - - effect-blur = "10x2"; - effect-scale = "0.1"; - - indicator = true; - indicator-radius = 240; - indicator-thickness = 20; - indicator-caps-lock = true; - - key-hl-color = "#8aadf4"; - bs-hl-color = "#ed8796"; - caps-lock-key-hl-color = "#f5a97f"; - caps-lock-bs-hl-color = "#ed8796"; - - separator-color = "#181926"; - - inside-color = "#24273a"; - inside-clear-color = "#24273a"; - inside-caps-lock-color = "#24273a"; - inside-ver-color = "#24273a"; - inside-wrong-color = "#24273a"; - - ring-color = "#1e2030"; - ring-clear-color = "#8aadf4"; - ring-caps-lock-color = "231f20D9"; - ring-ver-color = "#1e2030"; - ring-wrong-color = "#ed8796"; - - line-color = "#8aadf4"; - line-clear-color = "#8aadf4"; - line-caps-lock-color = "#f5a97f"; - line-ver-color = "#181926"; - line-wrong-color = "#ed8796"; - - text-color = "#8aadf4"; - text-clear-color = "#24273a"; - text-caps-lock-color = "#f5a97f"; - text-ver-color = "#24273a"; - text-wrong-color = "#24273a"; - - debug = true; - }; - }; -} diff --git a/home/mail/default.nix b/home/mail/default.nix new file mode 100644 index 0000000..2b2b031 --- /dev/null +++ b/home/mail/default.nix @@ -0,0 +1,244 @@ +{ pkgs, config, ... }: + +let + # Common configuration for Gmail-based accounts + mkGmailAccount = + { + name, + address, + userName, + passwordCommand, + primary ? false, + }: + let + accountConfig = { + inherit + primary + address + userName + passwordCommand + ; + realName = "Petri Hienonen"; + + imap = { + host = "imap.gmail.com"; + port = 993; + tls.enable = true; + }; + + smtp = { + host = "smtp.gmail.com"; + port = 587; + tls.enable = true; + }; + + maildir = { + path = name; + }; + + mbsync = { + enable = true; + create = "both"; + expunge = "both"; + remove = "both"; + patterns = [ + "*" + "!Drafts" + "!Sent Mail" + ]; + extraConfig.channel = { + CopyArrivalDate = "yes"; + SyncState = "*"; + }; + }; + + notmuch.enable = true; + + himalaya = { + enable = true; + settings = { + inherit primary; + display-name = "Petri Hienonen"; + signature = "Regards,\nPetri Hienonen"; + signature-delim = "-- \n"; + + "backend.type" = "notmuch"; + "backend.db-path" = "${config.home.homeDirectory}/Mail/${name}"; + + "folder.aliases.inbox" = "INBOX"; + "folder.aliases.sent" = "Sent Mail"; + "folder.aliases.drafts" = "Drafts"; + "folder.aliases.trash" = "Trash"; + + "message.write.headers" = [ + "From" + "To" + "Cc" + "Bcc" + "Subject" + ]; + "message.send.save-copy" = true; + "message.delete.style" = "folder"; + + "template.new.signature-style" = "inlined"; + "template.reply.posting-style" = "top"; + "template.reply.signature-style" = "below-quote"; + "template.reply.quote-headline-fmt" = "On %d/%m/%Y %H:%M, {senders} wrote:\n"; + + "message.send.backend.type" = "smtp"; + "message.send.backend.host" = "smtp.gmail.com"; + "message.send.backend.port" = 465; + "message.send.backend.login" = userName; + "message.send.backend.auth.type" = "password"; + "message.send.backend.auth.cmd" = passwordCommand; + + "pgp.type" = "commands"; + "pgp.encrypt-cmd" = "${pkgs.gnupg}/bin/gpg --encrypt --armor --quiet -r '%r'"; + "pgp.decrypt-cmd" = "${pkgs.gnupg}/bin/gpg --decrypt --quiet"; + "pgp.sign-cmd" = "${pkgs.gnupg}/bin/gpg --sign --armor --quiet --default-key '%s'"; + "pgp.verify-cmd" = "${pkgs.gnupg}/bin/gpg --verify --quiet"; + }; + }; + + aerc = { + enable = true; + }; + + imapnotify = { + enable = true; + boxes = [ "INBOX" ]; + onNotify = emailNotifyScript name; + extraConfig.wait = 60; + }; + }; + in + accountConfig; + + # Simplified notification script that only extracts sender and subject + emailNotifyScript = + account: + pkgs.writeShellScript "email-notify-${account}" '' + set -euo pipefail + + # Sync this account specifically + ${pkgs.isync}/bin/mbsync "${account}" + + # Wait a moment for notmuch to index + sleep 2 + ${pkgs.notmuch}/bin/notmuch new + + LATEST_MSG=$(${pkgs.notmuch}/bin/notmuch search --output=messages --limit=1 "tag:unread and folder:${account}/INBOX" | head -1) + + if [ -n "$LATEST_MSG" ]; then + # Extract sender and subject using notmuch show + SENDER=$(${pkgs.notmuch}/bin/notmuch show --format=json "$LATEST_MSG" | ${pkgs.jq}/bin/jq -r '.[][0].headers.From // "Unknown sender"') + SUBJECT=$(${pkgs.notmuch}/bin/notmuch show --format=json "$LATEST_MSG" | ${pkgs.jq}/bin/jq -r '.[][0].headers.Subject // "No subject"') + + # Send notification + ${pkgs.libnotify}/bin/notify-send -i mail-unread -a "Email" \ + "New email in ${account}" \ + "From: $SENDER\nSubject: $SUBJECT" \ + -t 10000 # 10 second timeout + fi + ''; + +in +{ + accounts.email = { + maildirBasePath = "${config.home.homeDirectory}/Mail"; + + accounts = { + gmail = mkGmailAccount { + name = "gmail"; + primary = true; + address = "petri.hienonen@gmail.com"; + userName = "petri.hienonen@gmail.com"; + passwordCommand = "${pkgs.coreutils}/bin/cat ${config.age.secrets.gmail.path}"; + }; + + relesoft = mkGmailAccount { + name = "relesoft"; + primary = false; + address = "petri.hienonen@relesoft.io"; + userName = "petri.hienonen@relesoft.io"; + passwordCommand = "${pkgs.coreutils}/bin/cat ${config.age.secrets.relesoft.path}"; + }; + }; + }; + + # Global settings for programs (not account-specific) + programs.mbsync.enable = true; + + programs.notmuch = { + enable = true; + hooks = { + preNew = "${pkgs.isync}/bin/mbsync -a || true"; + }; + new = { + tags = [ + "new" + "unread" + ]; + ignore = [ + "/.*[.](json|lock|bak)$/" + ".uidvalidity" + ".mbsyncstate" + ".mbsyncstate.journal" + ".msoepln" + ".mbsyncstate.new" + ".mbsyncstate.lock" + ]; + }; + }; + + programs.himalaya = { + enable = true; + package = pkgs.himalaya.override { + withFeatures = [ + "notmuch" + "pgp-gpg" + ]; + }; + }; + + # aerc configuration + programs.aerc = { + enable = true; + # aerc will automatically pick up accounts from accounts.email + # Additional aerc-wide configuration can go here + extraConfig = { + general = { + unsafe-accounts-conf = true; + # Example aerc configuration + # ui.message-list-time-format = "2006-01-02 15:04" + # ui.timestamp-format = "2006-01-02 15:04" + }; + }; + }; + + systemd.user.services.mbsync = { + Unit = { + Description = "Sync mail with mbsync"; + After = [ "network-online.target" ]; + Wants = [ "network-online.target" ]; + }; + Service = { + Type = "oneshot"; + ExecStart = "${pkgs.isync}/bin/mbsync -a"; + }; + Install.WantedBy = [ "default.target" ]; + }; + + systemd.user.timers.mbsync = { + Unit = { + Description = "Timer for mbsync mail synchronization"; + Requires = "mbsync.service"; + }; + Timer = { + OnBootSec = "5m"; + OnUnitInactiveSec = "5m"; + Unit = "mbsync.service"; + }; + Install.WantedBy = [ "timers.target" ]; + }; +} diff --git a/home/mpv/default.nix b/home/mpv/default.nix new file mode 100644 index 0000000..4cdb3e9 --- /dev/null +++ b/home/mpv/default.nix @@ -0,0 +1,25 @@ +{ inputs, pkgs, ... }: +{ + programs.mpv = { + enable = true; + + package = ( + pkgs.mpv-unwrapped.wrapper { + scripts = with pkgs.mpvScripts; [ + uosc + sponsorblock + ]; + + mpv = pkgs.mpv-unwrapped.override { waylandSupport = true; }; + } + ); + + config = { + profile = "high-quality"; + ytdl-format = "bestvideo+bestaudio"; + cache = "yes"; + demuxer-max-bytes = "512MiB"; + demuxer-readahead-secs = "20"; + }; + }; +} diff --git a/home/newsboat/default.nix b/home/newsboat/default.nix new file mode 100644 index 0000000..c95b95a --- /dev/null +++ b/home/newsboat/default.nix @@ -0,0 +1,59 @@ +{ + vars, + config, + pkgs, + ... +}: + +{ + xdg.configFile."/home/petri/.config/newsboat/urls".text = '' + "query:Unread Articles:unread = \"yes\"" + ''; + + programs.newsboat = { + enable = true; + autoReload = true; + browser = "\"${pkgs.chawan}/bin/cha %u\""; + reloadTime = 2; + extraConfig = '' + # special + macro o set browser "rdrview -T title,body -B cha %u" ; open-in-browser ; set browser "cha %u" + + # download + prepopulate-query-feeds yes + download-full-page yes + urls-source "miniflux" + miniflux-url "https://flux.tammi.cc" + miniflux-tokenfile ${config.age.secrets.miniflux_api_key.path} + + # operation + goto-next-feed no + miniflux-show-special-feeds "no" + feed-sort-order unreadarticlecount-asc + article-sort-order date-asc + + # keys + bind-key j down + bind-key k up + bind-key j next articlelist + bind-key k prev articlelist + bind-key J next-feed articlelist + bind-key K prev-feed articlelist + bind-key G end + bind-key g home + bind-key d pagedown + bind-key u pageup + bind-key l open + bind-key h quit + bind-key a toggle-article-read + bind-key n next-unread + bind-key N prev-unread + bind-key D pb-download + bind-key U show-urls + bind-key x pb-delete + bind-key o open-in-browser + + include ${pkgs.newsboat}/share/doc/newsboat/contrib/colorschemes/solarized-dark + ''; + }; +} diff --git a/home/nvim/autocommands.lua b/home/nvim/autocommands.lua new file mode 100644 index 0000000..b8bf173 --- /dev/null +++ b/home/nvim/autocommands.lua @@ -0,0 +1,272 @@ +local augroup = vim.api.nvim_create_augroup("UserConfig", {}) + +vim.api.nvim_create_autocmd("TextYankPost", { + desc = "Highlight when yanking (copying) text", + group = vim.api.nvim_create_augroup("kickstart-highlight-yank", { clear = true }), + callback = function() vim.highlight.on_yank() end, +}) + +vim.api.nvim_create_autocmd({ "BufWritePre" }, { + pattern = { "*" }, + command = [[%s/\s\+$//e]], +}) + +-- Return to last edit position when opening files +vim.api.nvim_create_autocmd("BufReadPost", { + group = augroup, + callback = function() + local mark = vim.api.nvim_buf_get_mark(0, '"') + local lcount = vim.api.nvim_buf_line_count(0) + if mark[1] > 0 and mark[1] <= lcount then pcall(vim.api.nvim_win_set_cursor, 0, mark) end + end, +}) + +-- Auto-close terminal when process exits +vim.api.nvim_create_autocmd("TermClose", { + group = augroup, + callback = function() + if vim.v.event.status == 0 then vim.api.nvim_buf_delete(0, {}) end + end, +}) + +-- Disable line numbers in terminal +vim.api.nvim_create_autocmd("TermOpen", { + group = augroup, + callback = function() + vim.opt_local.number = false + vim.opt_local.relativenumber = false + vim.opt_local.signcolumn = "no" + end, +}) + +-- Auto-resize splits when window is resized +vim.api.nvim_create_autocmd("VimResized", { + group = augroup, + callback = function() vim.cmd("tabdo wincmd =") end, +}) + +local og_virt_text +local og_virt_line + +vim.api.nvim_create_autocmd({ "CursorMoved", "DiagnosticChanged" }, { + group = vim.api.nvim_create_augroup("diagnostic_only_virtlines", { clear = true }), + callback = function() + if og_virt_line == nil then og_virt_line = vim.diagnostic.config().virtual_lines end + + -- ignore if virtual_lines.current_line is disabled + if not (og_virt_line and og_virt_line.current_line) then + if og_virt_text then + vim.diagnostic.config({ virtual_text = og_virt_text }) + og_virt_text = nil + end + return + end + + if og_virt_text == nil then og_virt_text = vim.diagnostic.config().virtual_text end + + local lnum = vim.api.nvim_win_get_cursor(0)[1] - 1 + + if vim.tbl_isempty(vim.diagnostic.get(0, { lnum = lnum })) then + vim.diagnostic.config({ virtual_text = og_virt_text }) + else + vim.diagnostic.config({ virtual_text = false }) + end + end, +}) + +vim.api.nvim_create_autocmd("LspAttach", { + group = vim.api.nvim_create_augroup("lsp-attach", { clear = true }), + callback = function(event) + local map = function(keys, func, desc) + vim.keymap.set("n", keys, func, { buffer = event.buf, desc = "LSP: " .. desc }) + end + + local client = vim.lsp.get_client_by_id(event.data.client_id) + + if client and client:supports_method("textDocument/implementation") then + -- defaults: + -- https://neovim.io/doc/user/news-0.11.html#_defaults + map("gl", vim.diagnostic.open_float, "Open Diagnostic Float") + map("K", vim.lsp.buf.hover, "Hover Documentation") + map("gs", vim.lsp.buf.signature_help, "Signature Documentation") + map("gD", vim.lsp.buf.declaration, "Goto Declaration") + map("la", vim.lsp.buf.code_action, "Code Action") + map("lr", vim.lsp.buf.rename, "Rename all references") + map("lf", vim.lsp.buf.format, "Format") + map( + "v", + "vsplit | lua vim.lsp.buf.definition()", + "Goto Definition in Vertical Split" + ) + map("gd", vim.lsp.buf.definition, "Goto Definition") + map("gr", vim.lsp.buf.references, "Goto References") + map("gI", vim.lsp.buf.implementation, "Goto Implementation") + end + + if client and client:supports_method("textDocument/completion") then + vim.lsp.completion.enable(true, client.id, event.buf, { + autotrigger = true, + convert = function(item) return { abbr = item.label:gsub("%b()", "") } end, + }) + vim.keymap.set("i", "", function() vim.lsp.completion.get() end) + client.server_capabilities.completionProvider = client.server_capabilities.completionProvider or {} + local trigger_chars = {} + for i = 32, 126 do + table.insert(trigger_chars, string.char(i)) + end + client.server_capabilities.completionProvider.triggerCharacters = vim.list_extend( + client.server_capabilities.completionProvider.triggerCharacters or {}, + trigger_chars + ) + end + + if client and client:supports_method("textDocument/formatting") then + vim.api.nvim_create_autocmd("BufWritePre", { + group = vim.api.nvim_create_augroup("my.lsp", { clear = false }), + buffer = event.buf, + callback = function() + vim.lsp.buf.format({ bufnr = event.buf, id = client.id, timeout_ms = 1000 }) + end, + }) + end + + if client and client:supports_method("textDocument/inlayHint") then + vim.lsp.inlay_hint.enable(true, { bufnr = event.buf }) + end + + if client and client:supports_method("textDocument/documentHighlight") then + local highlight_augroup = + vim.api.nvim_create_augroup("lsp-highlight", { clear = false }) + + -- When cursor stops moving: Highlights all instances of the symbol under the cursor + -- When cursor moves: Clears the highlighting + vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, { + buffer = event.buf, + group = highlight_augroup, + callback = vim.lsp.buf.document_highlight, + }) + vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, { + buffer = event.buf, + group = highlight_augroup, + callback = vim.lsp.buf.clear_references, + }) + + -- When LSP detaches: Clears the highlighting + vim.api.nvim_create_autocmd("LspDetach", { + group = vim.api.nvim_create_augroup("lsp-detach", { clear = true }), + callback = function(event2) + vim.lsp.buf.clear_references() + vim.api.nvim_clear_autocmds({ group = "lsp-highlight", buffer = event2.buf }) + end, + }) + end + end, +}) + +vim.api.nvim_create_autocmd("ModeChanged", { + group = vim.api.nvim_create_augroup("diagnostic_redraw", {}), + callback = function() pcall(vim.diagnostic.show) end, +}) + +-- terminal +local terminal_state = { + buf = nil, + win = nil, + is_open = false, +} + +local function FloatingTerminal() + -- If terminal is already open, close it (toggle behavior) + if terminal_state.is_open and vim.api.nvim_win_is_valid(terminal_state.win) then + vim.api.nvim_win_close(terminal_state.win, false) + terminal_state.is_open = false + return + end + + -- Create buffer if it doesn't exist or is invalid + if not terminal_state.buf or not vim.api.nvim_buf_is_valid(terminal_state.buf) then + terminal_state.buf = vim.api.nvim_create_buf(false, true) + -- Set buffer options for better terminal experience + vim.api.nvim_buf_set_option(terminal_state.buf, "bufhidden", "hide") + end + + -- Calculate window dimensions + local width = math.floor(vim.o.columns * 0.8) + local height = math.floor(vim.o.lines * 0.8) + local row = math.floor((vim.o.lines - height) / 2) + local col = math.floor((vim.o.columns - width) / 2) + + -- Create the floating window + terminal_state.win = vim.api.nvim_open_win(terminal_state.buf, true, { + relative = "editor", + width = width, + height = height, + row = row, + col = col, + style = "minimal", + border = "rounded", + }) + + -- Set transparency for the floating window + vim.api.nvim_win_set_option(terminal_state.win, "winblend", 0) + + -- Set transparent background for the window + vim.api.nvim_win_set_option( + terminal_state.win, + "winhighlight", + "Normal:FloatingTermNormal,FloatBorder:FloatingTermBorder" + ) + + -- Define highlight groups for transparency + vim.api.nvim_set_hl(0, "FloatingTermNormal", { bg = "none" }) + vim.api.nvim_set_hl(0, "FloatingTermBorder", { bg = "none" }) + + -- Start terminal if not already running + local has_terminal = false + local lines = vim.api.nvim_buf_get_lines(terminal_state.buf, 0, -1, false) + for _, line in ipairs(lines) do + if line ~= "" then + has_terminal = true + break + end + end + + if not has_terminal then vim.fn.termopen(os.getenv("SHELL")) end + + terminal_state.is_open = true + vim.cmd("startinsert") + + -- Set up auto-close on buffer leave + vim.api.nvim_create_autocmd("BufLeave", { + buffer = terminal_state.buf, + callback = function() + if terminal_state.is_open and vim.api.nvim_win_is_valid(terminal_state.win) then + vim.api.nvim_win_close(terminal_state.win, false) + terminal_state.is_open = false + end + end, + once = true, + }) +end + +-- Function to explicitly close the terminal +local function CloseFloatingTerminal() + if terminal_state.is_open and vim.api.nvim_win_is_valid(terminal_state.win) then + vim.api.nvim_win_close(terminal_state.win, false) + terminal_state.is_open = false + end +end + +-- Key mappings +vim.keymap.set( + "n", + "t", + FloatingTerminal, + { noremap = true, silent = true, desc = "Toggle floating terminal" } +) +vim.keymap.set("t", "", function() + if terminal_state.is_open then + vim.api.nvim_win_close(terminal_state.win, false) + terminal_state.is_open = false + end +end, { noremap = true, silent = true, desc = "Close floating terminal from terminal mode" }) diff --git a/home/nvim/default.nix b/home/nvim/default.nix new file mode 100644 index 0000000..038d8d6 --- /dev/null +++ b/home/nvim/default.nix @@ -0,0 +1,93 @@ +{ pkgs, pkgs-unstable, ... }: + +{ + programs.neovim = + let + toLua = str: "lua << EOF\n${str}\nEOF\n"; + toLuaFile = file: "lua << EOF\n${builtins.readFile file}\nEOF\n"; + in + { + enable = true; + defaultEditor = true; + viAlias = true; + vimAlias = true; + vimdiffAlias = true; + extraPackages = with pkgs-unstable; [ + inotify-tools + + # debuggers + delve # golang debugger + lldb # rust, c, etc, debugger + + # format + rustfmt + dprint # platform for many formatters + yamlfmt + + # LSP + biome # javascript, biome + clippy # rust error checking + clang-tools # C + dprint # format engine for multiple langeuages + dprint-plugins.dprint-plugin-markdown # markdown + dprint-plugins.dprint-plugin-toml # toml + dprint-plugins.g-plane-malva # css + dprint-plugins.g-plane-markup_fmt # html + dprint-plugins.g-plane-pretty_yaml # yaml + fish-lsp # fish + gopls # golang + ltex-ls # latex, markdown + lua-language-server # lua + nil # lsp server for nix + nodePackages.bash-language-server # bash + nodePackages.typescript-language-server # javascript validation + ruff # python format and lint + rust-analyzer + tex-fmt # latex + texlab # latex lsp + tree-sitter # generate tree-sitter grammars + ty # python type checker written in rust + vale-ls # prose (md, asciidoc) + ]; + + extraPython3Packages = ps: [ + ps.debugpy + ps.pynvim + ]; + plugins = with pkgs-unstable.vimPlugins; [ + { + plugin = nvim-dap; + config = toLuaFile ./plugins/dap.lua; + } + { + plugin = which-key-nvim; + config = toLuaFile ./plugins/which.lua; + } + { + plugin = undotree; + config = toLuaFile ./plugins/undotree.lua; + } + { + plugin = mini-nvim; + config = toLuaFile ./plugins/mini.lua; + } + { + plugin = nvim-treesitter.withAllGrammars; + config = toLuaFile ./plugins/treesitter.lua; + } + hardtime-nvim + nvim-dap-view + nvim-dap-virtual-text + nord-nvim + ]; + + extraLuaConfig = '' + ${builtins.readFile ./lsp.lua} + ${builtins.readFile ./autocommands.lua} + ${builtins.readFile ./keymaps.lua} + ${builtins.readFile ./options.lua} + ${builtins.readFile ./plugins/other.lua} + ''; + }; + +} diff --git a/home/nvim/keymaps.lua b/home/nvim/keymaps.lua new file mode 100644 index 0000000..d8907bf --- /dev/null +++ b/home/nvim/keymaps.lua @@ -0,0 +1,86 @@ +vim.g.mapleader = " " +vim.g.maplocalleader = " " +vim.keymap.set("v", "<", "", ">gv", { desc = "Indent right" }) + +vim.keymap.set("n", "", "Pick buffers", { desc = "Search open files" }) +vim.keymap.set("n", "ff", "Pick files", { desc = "Search all files" }) +vim.keymap.set("n", "fh", "Pick help", { desc = "Search help tags" }) + +-- Alternative navigation (more intuitive) +vim.keymap.set("n", "tn", ":tabnew", { desc = "New tab" }) +vim.keymap.set("n", "tx", ":tabclose", { desc = "Close tab" }) + +-- Tab moving +vim.keymap.set("n", "tm", ":tabmove", { desc = "Move tab" }) +vim.keymap.set("n", "t>", ":tabmove +1", { desc = "Move tab right" }) +vim.keymap.set("n", "t<", ":tabmove -1", { desc = "Move tab left" }) + +vim.keymap.set("n", "dq", vim.diagnostic.disable) +vim.keymap.set("n", "ds", vim.diagnostic.enable) + +vim.keymap.set({ "n", "x" }, "gy", '"+y', { desc = "Copy to clipboard" }) +vim.keymap.set({ "n", "x" }, "gp", '"+p', { desc = "Paste clipboard text" }) + +vim.keymap.set("n", "", "nohlsearch") +vim.keymap.set( + "n", + "q", + vim.diagnostic.setloclist, + { desc = "Open diagnostic [Q]uickfix list" } +) +vim.keymap.set("n", "q", ":bpspbnbd", { desc = "Close buffer" }) +vim.keymap.set("n", "Q", ":bd!", { desc = "Force close buffer" }) +vim.keymap.set("t", "", "", { desc = "Exit terminal mode" }) + +vim.keymap.set("n", "", "", { desc = "Move focus to the left window" }) +vim.keymap.set("n", "", "", { desc = "Move focus to the right window" }) +vim.keymap.set("n", "", "", { desc = "Move focus to the lower window" }) +vim.keymap.set("n", "", "", { desc = "Move focus to the upper window" }) + +vim.keymap.set("n", "e", ":lua MiniFiles.open()", { desc = "Open [E]xplorer" }) + +vim.keymap.set("n", "", "DapContinue", { desc = "DAP: Continue" }) +vim.keymap.set("n", "bp", "DapToggleBreakpoint", { desc = "DAP: Toggle Breakpoint" }) +vim.keymap.set("n", "", "DapStepOver", { desc = "DAP: Step Over" }) +vim.keymap.set("n", "", "DapStepInto", { desc = "DAP: Step Into" }) +vim.keymap.set("n", "", "DapStepOut", { desc = "DAP: Step Out" }) +vim.keymap.set("n", "dt", "DapTerminate", { desc = "DAP: Terminate" }) + +local function tab_complete() + if vim.fn.pumvisible() == 1 then + -- navigate to next item in completion menu + return "" + end + + local c = vim.fn.col(".") - 1 + local is_whitespace = c == 0 or vim.fn.getline("."):sub(c, c):match("%s") + + if is_whitespace then + -- insert tab + return "" + end + + local lsp_completion = vim.bo.omnifunc == "v:lua.vim.lsp.omnifunc" + + if lsp_completion then + -- trigger lsp code completion + return "" + end + + -- suggest words in current buffer + return "" +end + +local function tab_prev() + if vim.fn.pumvisible() == 1 then + -- navigate to previous item in completion menu + return "" + end + + -- insert tab + return "" +end + +vim.keymap.set("i", "", tab_complete, { expr = true }) +vim.keymap.set("i", "", tab_prev, { expr = true }) diff --git a/home/nvim/lsp.lua b/home/nvim/lsp.lua new file mode 100644 index 0000000..07665bc --- /dev/null +++ b/home/nvim/lsp.lua @@ -0,0 +1,305 @@ +-- example configurations available https://github.com/neovim/nvim-lspconfig/tree/master/lsp +vim.lsp.set_log_level(vim.log.levels.WARN) +vim.lsp.log.set_format_func(vim.inspect) + +vim.diagnostic.config({ + virtual_text = true, + virtual_lines = { current_line = true }, + underline = true, + update_in_insert = false, + severity_sort = true, + float = { + border = "rounded", + source = true, + }, + signs = { + text = { + [vim.diagnostic.severity.ERROR] = "󰅚 ", + [vim.diagnostic.severity.WARN] = "󰀪 ", + [vim.diagnostic.severity.INFO] = "󰋽 ", + [vim.diagnostic.severity.HINT] = "󰌶 ", + }, + numhl = { + [vim.diagnostic.severity.ERROR] = "ErrorMsg", + [vim.diagnostic.severity.WARN] = "WarningMsg", + }, + }, +}) + +local capabilities = vim.lsp.protocol.make_client_capabilities() + +capabilities = vim.tbl_deep_extend("force", capabilities, { + textDocument = { + inlayHint = { + dynamicRegistration = false, -- Static registration + resolveSupport = { + properties = { "textEdits", "tooltip", "label" }, -- Resolve additional hint details + }, + }, + synchronization = { + dynamicRegistration = false, -- Static registration + willSave = true, -- Notify server before saving + willSaveWaitUntil = true, -- Allow server to provide edits before saving + didSave = true, -- Notify server after saving + }, + hover = { + dynamicRegistration = false, -- Static registration + contentFormat = { "markdown", "plaintext" }, -- Prefer markdown, fallback to plaintext + }, + documentSymbol = { + dynamicRegistration = false, -- Static registration + hierarchicalDocumentSymbolSupport = true, -- Support nested symbols + symbolKind = { + valueSet = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + }, -- All standard symbol kinds (file, module, namespace, etc.) + }, + }, + completion = { + completionItem = { + snippetSupport = true, + preselectSupport = true, + insertReplaceSupport = true, + labelDetailsSupport = true, + deprecatedSupport = true, + commitCharactersSupport = true, + tagSupport = { valueSet = { 1 } }, + resolveSupport = { + properties = { "documentation", "detail", "additionalTextEdits" }, + }, + }, + }, + diagnostic = { + documentDiagnosticProvider = true, -- Enable document-level diagnostics + relatedInformation = true, -- Show related diagnostic information + tagSupport = { valueSet = { 1, 2 } }, -- Support deprecated (1) and unused (2) tags + dataSupport = true, -- Allow custom data in diagnostics + }, + semanticTokens = { + multilineTokenSupport = true, + overlappingTokenSupport = true, + augmentsSyntaxTokens = true, + }, + foldingRange = { + dynamicRegistration = false, + lineFoldingOnly = true, + }, + }, + workspace = { + configuration = true, + workspaceFolders = true, + didChangeWatchedFiles = { + dynamicRegistration = true, + }, + fileOperations = { + didRename = true, + willRename = true, + didDelete = true, + didCreate = true, + }, + symbol = { + dynamicRegistration = false, -- Static registration + symbolKind = { + valueSet = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + }, -- All standard symbol kinds + }, + }, + diagnostic = { + workspaceDiagnosticsProvider = true, -- Enable workspace-level diagnostics + }, + }, +}) + +vim.lsp.config("*", { + capabilities = capabilities, + root_markers = { ".git" }, +}) + +vim.lsp.config("lua_ls", { + cmd = { "lua-language-server" }, + filetypes = { "lua" }, + root_markers = { ".luarc.json", ".luarc.jsonc" }, + settings = { + Lua = { + format = { + enable = true, + defaultConfig = { + indent_style = "tab", + indent_size = 1, + quote_style = "double", + max_line_length = 120 + }, + }, + runtime = { version = "LuaJIT" }, + diagnostics = { globals = { "vim", "luassert" }, enable = true }, + workspace = { + checkThirdParty = true, + library = vim.api.nvim_get_runtime_file("", true), + }, + telemetry = { enable = false }, + hint = { + enable = true, + setType = true, + paramType = true, + paramName = "All", + }, + }, + }, +}) + +vim.lsp.config("nil_ls", { + cmd = { "nil" }, + root_markers = { "flake.nix" }, + filetypes = { "nix" }, + settings = { + ["nil"] = { + formatting = { command = { "nixfmt" } }, + }, + }, +}) + +vim.lsp.config("ts_ls", { + cmd = { "typescript-language-server", "--stdio" }, + root_markers = { ".editorconfig", "jsconfig.json" }, + filetypes = { "javascript", "javascriptreact", "typescript", "typescriptreact", "vue" }, + init_options = { + preferences = { + disableSuggestions = false, + includeCompletionsForModuleExports = true, + }, + }, + capabilities = { + textDocument = { + formatting = false, + }, + }, + on_attach = function(client, bufnr) + client.server_capabilities.documentFormattingProvider = false + client.server_capabilities.documentRangeFormattingProvider = false + end, +}) + +vim.lsp.config("ruff", { + cmd = { "ruff", "server" }, + root_markers = { "pyproject.toml" }, + filetypes = { "python" }, + init_options = { + settings = { + configurationPreference = "filesystemFirst", + fixAll = true, + lineLength = 100, + lint = { enable = true }, + organizeImports = true, + }, + }, +}) + +vim.lsp.config("dprint", { + cmd = { "dprint", "lsp" }, + filetypes = { "toml", "yaml", "markdown", "css" }, + settings = {}, +}) + +vim.lsp.config("clangd", { + cmd = { "clangd" }, + filetypes = { "c", "cpp" }, + root_markers = { + ".clangd", ".git" + }, +}) + +vim.lsp.config("vale_ls", { + cmd = { "vale-ls" }, + filetypes = { "markdown", "text", "tex", "rst", "adoc", "asciidoc" }, + root_markers = { ".vale.ini" }, +}) + +vim.lsp.config("ty", { + cmd = { "ty", "server" }, + root_markers = { "pyproject.toml" }, + filetypes = { "python" }, + settings = { + ty = { + diagnosticMode = "workspace", + experimental = { + rename = true, + autoImport = true, + completions = true, + }, + }, + }, +}) + +vim.lsp.config("rust_analyzer", { + cmd = { "rust-analyzer" }, + root_markers = { "Cargo.toml" }, + filetypes = { "rust" }, + settings = { + ["rust-analyzer"] = { + check = { + command = "clippy", + }, + }, + }, +}) + +vim.lsp.config("biome", { + cmd = { "biome", "lsp-proxy" }, + workspace_required = true, + filetypes = { + "graphql", + "javascript", + "json", + "html" + }, + root_markers = { "biome.json" }, + capabilities = { + textDocument = { + formatting = { + dynamicRegistration = false, + }, + }, + }, + single_file_support = false +}) + +vim.lsp.config("gopls", { + cmd = { "gopls" }, + root_markers = { "go.mod" }, + filetypes = { "go", "gomod", "gowork", "gotmpl" }, + settings = { + gopls = { + analyses = { + unusedparams = true, + }, + staticcheck = true, + }, + }, +}) + +vim.lsp.config("bashls", { + cmd = { "bash-language-server", "start" }, + filetypes = { "sh" }, +}) + +vim.lsp.config("texlab", { + cmd = { "texlab" }, + filetypes = { "tex", "plaintex", "bib" }, +}) + +vim.lsp.enable({ + "bashls", + "biome", + "clangd", + "dprint", + "gopls", + "lua_ls", + "nil_ls", + "ruff", + "rust_analyzer", + "texlab", + "ts_ls", + "ty", + "vale_ls", +}) diff --git a/home/nvim/options.lua b/home/nvim/options.lua new file mode 100644 index 0000000..ee2fac2 --- /dev/null +++ b/home/nvim/options.lua @@ -0,0 +1,93 @@ +vim.opt.title = true -- set the title of window to the value of the titlestring +vim.opt.titlestring = "%<%F%=%l/%L - nvim" -- what the title of the window will be set to +vim.g.have_nerd_fonts = true +vim.o.shell = "fish" +vim.o.fileencoding = "utf-8" +vim.opt.conceallevel = 0 +vim.opt.clipboard:append("unnamedplus") -- copy & paste +vim.o.termguicolors = true -- Enable GUI colors for the terminal to get truecolor +vim.o.mouse = "a" -- turn on mouse interaction +vim.o.signcolumn = "yes" +vim.o.guicursor = table.concat({ + "n-v-c:block-Cursor/lCursor-blinkwait1000-blinkon100-blinkoff100", + "i-ci:ver25-Cursor/lCursor-blinkwait1000-blinkon100-blinkoff100", + "r:hor50-Cursor/lCursor-blinkwait100-blinkon100-blinkoff100", +}, ",") + +vim.opt.completeopt = { "menu", "menuone", "noselect", "noinsert", "preview" } -- completion options +vim.opt.shortmess:append("c") +vim.o.updatetime = 100 -- CursorHold interval +vim.opt.wrap = true +vim.opt.linebreak = true +vim.opt.breakindent = true +vim.opt.inccommand = "split" +vim.opt.virtualedit = "block" +vim.opt.grepprg = "rg --vimgrep" +vim.opt.grepformat = "%f:%l:%c:%m" +vim.o.textwidth = 100 +vim.o.tabstop = 4 +vim.o.softtabstop = 4 +vim.o.shiftwidth = 4 +vim.o.expandtab = true +vim.o.smartindent = true +vim.opt.smartcase = true +vim.o.shiftwidth = 4 +vim.o.autoindent = true +vim.o.smarttab = true -- / indent/dedent in leading whitespace +vim.o.list = true -- show hidden characters by default +vim.opt.hidden = true -- required to keep multiple buffers and open multiple buffers + +vim.o.undofile = true +vim.o.undodir = "/home/petri/.config/nvim/undo/" +vim.o.backupdir = "/home/petri/.config/nvim/backup/" +vim.o.directory = "/home/petri/.config/nvim//swp/" + +vim.o.number = true -- show line numbers +vim.o.showmode = false -- we are already showing mode +vim.o.relativenumber = true -- relative line numbers +vim.o.hlsearch = true -- highlighted search results +vim.o.incsearch = true -- incremental search +vim.o.ignorecase = true -- ignore case sensetive while searching +vim.o.colorcolumn = "100" +vim.o.cursorline = true -- highlight current line +vim.opt.showmatch = true -- show matching bracket +vim.opt.matchtime = 2 -- how long to show matching bracket +vim.opt.pumblend = 10 -- popup menu transparency +vim.opt.winblend = 0 +vim.opt.winborder = "rounded" +vim.opt.synmaxcol = 300 + +vim.opt.swapfile = false +vim.opt.autoread = true +vim.opt.path:append("**") -- include subdirectories in search +vim.opt.selection = "exclusive" -- Selection behavior +vim.opt.showtabline = 2 -- show when multiple open + +vim.opt.foldmethod = "syntax" +vim.opt.foldlevel = 99 -- Start with all folds open +vim.opt.foldenable = true -- Enable folding + +vim.opt.scrolloff = 8 +vim.opt.sidescrolloff = 8 + +vim.opt.formatoptions:remove({ "c", "t" }) +vim.opt.listchars = { tab = "» ", trail = "·", nbsp = "␣" } +vim.opt.backspace = "indent,start,eol" -- make backspace behave like normal again +vim.opt.splitbelow = true -- open horizontal splits below current window +vim.opt.splitright = true -- open vertical splits to the right of the current window +vim.opt.laststatus = 2 -- always show status line +vim.opt.wildignore = vim.opt.wildignore + "*.o,*.rej,*.so" -- patterns to ignore during file-navigation +vim.opt.lazyredraw = false -- faster scrolling + +vim.opt.spell = false +vim.opt.spelllang = "en" +vim.opt.wildmenu = true +vim.opt.wildmode = "longest:full,full" +vim.opt.wildignore:append({ "*.pyc" }) + +vim.opt.diffopt:append("linematch:60") + +vim.opt.redrawtime = 10000 +vim.opt.maxmempattern = 50000 + +vim.cmd.colorscheme("nord") diff --git a/home/nvim/plugins/dap.lua b/home/nvim/plugins/dap.lua new file mode 100644 index 0000000..c20ae36 --- /dev/null +++ b/home/nvim/plugins/dap.lua @@ -0,0 +1,147 @@ +-- Store DAP configuration in a function to load on demand +local function setup_dap() + local dap = require("dap") + local dapview = require("dap-view") + local dapvt = require("nvim-dap-virtual-text") + + dapview.setup({}) + + dapvt.setup { + enabled = true, + enabled_commands = true, + highlight_changed_variables = true, + highlight_new_as_changed = false, + show_stop_reason = true, + commented = false, + only_first_definition = true, + all_references = false, + clear_on_continue = false, + display_callback = function(variable, buf, stackframe, node, options) + if options.virt_text_pos == "inline" then + return " = " .. variable.value:gsub("%s+", " ") + else + return variable.name .. " = " .. variable.value:gsub("%s+", " ") + end + end, + all_frames = true, + virt_lines = true, + virt_text_win_col = nil, + } + + -- === PYTHON === + dap.adapters.python = { + type = "executable", + command = "python", + args = { "-m", "debugpy.adapter" }, + } + dap.configurations.python = { + { + type = "python", + request = "launch", + name = "Launch file", + program = "${file}", + console = "integratedTerminal", + justMyCode = true, + }, + { + type = "python", + request = "attach", + name = "Attach to process", + connect = { host = "127.0.0.1", port = 5678 }, + }, + } + + -- === RUST === + dap.adapters.lldb = { + type = "executable", + command = "lldb-dap", + name = "lldb", + } + dap.configurations.rust = { + { + name = "Launch (LLDB)", + type = "lldb", + request = "launch", + program = function() + return vim.fn.input("Path to executable: ", vim.fn.getcwd() .. "/target/debug/", "file") + end, + cwd = "${workspaceFolder}", + stopOnEntry = false, + args = {}, + runInTerminal = false, + }, + { + name = "Attach to process (LLDB)", + type = "lldb", + request = "attach", + pid = require("dap.utils").pick_process, + args = {}, + }, + } + + -- === GO === + dap.adapters.go = { + type = "executable", + command = "dlv", + args = { "dap" }, + } + dap.configurations.go = { + { type = "go", name = "Debug main.go", request = "launch", program = "${file}" }, + { type = "go", name = "Debug package", request = "launch", program = "${workspaceFolder}" }, + { type = "go", name = "Attach to process", request = "attach", processId = require("dap.utils").pick_process }, + } + + -- === EVENT LISTENERS === + dap.listeners.after.event_initialized["dapview_config"] = function() dapview.open() end + dap.listeners.before.event_terminated["dapview_config"] = function() dapview.close() end + dap.listeners.before.event_exited["dapview_config"] = function() dapview.close() end +end + +-- Define custom commands to trigger DAP setup +local function define_dap_commands() + vim.api.nvim_create_user_command("DapContinue", function() + setup_dap() + require("dap").continue() + end, {}) + vim.api.nvim_create_user_command("DapToggleBreakpoint", function() + setup_dap() + require("dap").toggle_breakpoint() + end, {}) + vim.api.nvim_create_user_command("DapStepOver", function() + setup_dap() + require("dap").step_over() + end, {}) + vim.api.nvim_create_user_command("DapStepInto", function() + setup_dap() + require("dap").step_into() + end, {}) + vim.api.nvim_create_user_command("DapStepOut", function() + setup_dap() + require("dap").step_out() + end, {}) + vim.api.nvim_create_user_command("DapTerminate", function() + setup_dap() + require("dap").terminate() + end, {}) +end + +-- Create autocommand group for DAP +local augroup = vim.api.nvim_create_augroup("DapLazyLoad", { clear = true }) + +-- Load DAP on filetypes +vim.api.nvim_create_autocmd("FileType", { + group = augroup, + pattern = { "python", "rust", "go" }, + callback = function() + define_dap_commands() + end, +}) + +-- Load DAP on specific commands +vim.api.nvim_create_autocmd("CmdUndefined", { + group = augroup, + pattern = { "DapContinue", "DapToggleBreakpoint", "DapStepOver", "DapStepInto", "DapStepOut", "DapTerminate" }, + callback = function() + define_dap_commands() + end, +}) diff --git a/home/nvim/plugins/mini.lua b/home/nvim/plugins/mini.lua new file mode 100644 index 0000000..f41f1b4 --- /dev/null +++ b/home/nvim/plugins/mini.lua @@ -0,0 +1,14 @@ +require("mini.animate").setup() +require("mini.diff").setup() +require("mini.files").setup() +require("mini.git").setup() +require("mini.icons").setup() +require("mini.notify").setup() +require("mini.pick").setup() +require("mini.sessions").setup() +require("mini.starter").setup() +require("mini.statusline").setup() +require("mini.tabline").setup({ + show_icons = true +}) +require("mini.completion").setup() diff --git a/home/nvim/plugins/other.lua b/home/nvim/plugins/other.lua new file mode 100644 index 0000000..10efd0e --- /dev/null +++ b/home/nvim/plugins/other.lua @@ -0,0 +1,5 @@ +-- hardtime +require("hardtime").setup() + +vim.g.nord_italic = true +require("nord").set() diff --git a/home/nvim/plugins/treesitter.lua b/home/nvim/plugins/treesitter.lua new file mode 100644 index 0000000..968af11 --- /dev/null +++ b/home/nvim/plugins/treesitter.lua @@ -0,0 +1,81 @@ +local function disable(lang, buf) + local max_filesize = 100 * 1024 -- 100 KB + local ok, stats = pcall(vim.loop.fs_stat, vim.api.nvim_buf_get_name(buf)) + if ok and stats and stats.size > max_filesize then + return true + end +end + +require("nvim-treesitter.configs").setup({ + ensure_installed = {}, + sync_install = false, + ignore_install = {}, + modules = {}, + auto_install = false, + highlight = { + enable = true, + disable = disable, + additional_vim_regex_highlighting = false, + }, + indent = { enable = true, disable = { "rust", "lua", "python", "golang", "nix", "json", "html", "javascript" } }, + incremental_selection = { + enable = true, + keymaps = { + init_selection = "vv", + node_incremental = "+", + scope_incremental = false, + node_decremental = "_", + }, + }, + textobjects = { + select = { + enable = true, + lookahead = true, + keymaps = { + -- You can use the capture groups defined in textobjects.scm + ["af"] = { query = "@function.outer", desc = "around a function" }, + ["if"] = { query = "@function.inner", desc = "inner part of a function" }, + ["ac"] = { query = "@class.outer", desc = "around a class" }, + ["ic"] = { query = "@class.inner", desc = "inner part of a class" }, + ["ai"] = { query = "@conditional.outer", desc = "around an if statement" }, + ["ii"] = { query = "@conditional.inner", desc = "inner part of an if statement" }, + ["al"] = { query = "@loop.outer", desc = "around a loop" }, + ["il"] = { query = "@loop.inner", desc = "inner part of a loop" }, + ["ap"] = { query = "@parameter.outer", desc = "around parameter" }, + ["ip"] = { query = "@parameter.inner", desc = "inside a parameter" }, + }, + selection_modes = { + ["@parameter.outer"] = "v", -- charwise + ["@parameter.inner"] = "v", -- charwise + ["@function.outer"] = "v", -- charwise + ["@conditional.outer"] = "V", -- linewise + ["@loop.outer"] = "V", -- linewise + ["@class.outer"] = "", -- blockwise + }, + include_surrounding_whitespace = false, + }, + move = { + enable = true, + set_jumps = true, -- whether to set jumps in the jumplist + goto_previous_start = { + ["[f"] = { query = "@function.outer", desc = "Previous function" }, + ["[c"] = { query = "@class.outer", desc = "Previous class" }, + ["[p"] = { query = "@parameter.inner", desc = "Previous parameter" }, + }, + goto_next_start = { + ["]f"] = { query = "@function.outer", desc = "Next function" }, + ["]c"] = { query = "@class.outer", desc = "Next class" }, + ["]p"] = { query = "@parameter.inner", desc = "Next parameter" }, + }, + }, + swap = { + enable = true, + swap_next = { + ["a"] = "@parameter.inner", + }, + swap_previous = { + ["A"] = "@parameter.inner", + }, + }, + }, +}) diff --git a/home/nvim/plugins/undotree.lua b/home/nvim/plugins/undotree.lua new file mode 100644 index 0000000..b6b9276 --- /dev/null +++ b/home/nvim/plugins/undotree.lua @@ -0,0 +1 @@ +vim.keymap.set("n", "u", vim.cmd.UndotreeToggle) diff --git a/home/nvim/plugins/which.lua b/home/nvim/plugins/which.lua new file mode 100644 index 0000000..09aa796 --- /dev/null +++ b/home/nvim/plugins/which.lua @@ -0,0 +1,6 @@ +local wk = require("which-key") +wk.add({ + "?", + function() require("which-key").show({ global = false }) end, + desc = "Buffer Local Keymaps (which-key)", +}) diff --git a/home/quickshell/PopupContext.qml b/home/quickshell/PopupContext.qml new file mode 100644 index 0000000..6f007c8 --- /dev/null +++ b/home/quickshell/PopupContext.qml @@ -0,0 +1,6 @@ +import QtQuick + +// Tracks which popup of a set is active. +QtObject { + property var popup: null; +} diff --git a/home/quickshell/README.md b/home/quickshell/README.md new file mode 100644 index 0000000..0458afa --- /dev/null +++ b/home/quickshell/README.md @@ -0,0 +1,13 @@ +## Quickshell Titus Config + +This is a minimal DWM style bar for Hyprland. HOWEVER, most of the examples online do a lot of crazy things. If you can think it up you can do it in QUICKSHELL! + +Try it today! + +### Dependencies + +Arch Linux + +``` +yay -S qt6-5compat quickshell +``` diff --git a/home/quickshell/Theme.qml b/home/quickshell/Theme.qml new file mode 100644 index 0000000..e8777db --- /dev/null +++ b/home/quickshell/Theme.qml @@ -0,0 +1,87 @@ +pragma Singleton + +import QtQuick +import Quickshell + +Singleton { + property Item get: nordic + + Item { + id: windowsXP + + property string barBgColor: "#88235EDC" + property string buttonBorderColor: "#99000000" + property bool buttonBorderShadow: false + property string buttonBackgroundColor: "#1111CC" + property bool onTop: false + property string iconColor: "green" + property string iconPressedColor: "green" + property Gradient barGradient: black.barGradient + } + + Item { + id: black + + property string barBgColor: "#cc000000" + property string buttonBorderColor: "#BBBBBB" + property string buttonBackgroundColor: "#222222" + property bool buttonBorderShadow: true + property bool onTop: true + property string iconColor: "blue" + property string iconPressedColor: "dark_blue" + } + + Item { + id: nordic + + // Nord color palette + property string barBgColor: "#aa2E3440" // Nord0 - Polar Night + property string buttonBorderColor: "#4C566A" // Nord3 - Polar Night + property string buttonBackgroundColor: "#3D4550" + property bool buttonBorderShadow: true + property bool onTop: true + property string iconColor: "#88C0D0" // Nord7 - Frost + property string iconPressedColor: "#81A1C1" // Nord9 - Frost + } + + Item { + id: cyberpunk + + // Tokyo Neon color palette + property string barBgColor: "#881A0B2E" // Deep purple-black + property string buttonBorderColor: "#FF2A6D" // Neon pink + property string buttonBackgroundColor: "#1A1A2E" // Dark blue-black + property bool buttonBorderShadow: true + property bool onTop: true + property string iconColor: "#05D9E8" // Electric blue + property string iconPressedColor: "#FF2A6D" // Neon pink + } + + Item { + id: material + + // Material Design 3 color palette + property string barBgColor: "#cc1F1F1F" // Surface dark + property string buttonBorderColor: "#2D2D2D" // Surface variant + property string buttonBackgroundColor: "#2D2D2D" // Surface variant + property bool buttonBorderShadow: true + property bool onTop: true + property string iconColor: "#90CAF9" // Primary light + property string iconPressedColor: "#64B5F6" // Primary medium + } + + Item { + id: catppuccin + + // Catppuccin Mocha color palette + property string barBgColor: "#aa1E1E2E" // Base + property string buttonBorderColor: "#313244" // Surface0 + property string buttonBackgroundColor: "#313244" // Surface0 + property bool buttonBorderShadow: true + property bool onTop: true + property string iconColor: "#89B4FA" // Blue + property string iconPressedColor: "#74C7EC" // Sapphire + } + +} + diff --git a/home/quickshell/bar/Bar.qml b/home/quickshell/bar/Bar.qml new file mode 100644 index 0000000..5f5cae8 --- /dev/null +++ b/home/quickshell/bar/Bar.qml @@ -0,0 +1,115 @@ +import Quickshell +import Quickshell.Io +import Quickshell.Hyprland +import QtQuick +import QtQuick.Layouts +import "blocks" as Blocks +import "root:/" + +Scope { + IpcHandler { + target: "bar" + + function toggleVis(): void { + // Toggle visibility of all bar instances + for (let i = 0; i < Quickshell.screens.length; i++) { + barInstances[i].visible = !barInstances[i].visible; + } + } + } + + property var barInstances: [] + + Variants { + model: Quickshell.screens + + PanelWindow { + id: bar + property var modelData + screen: modelData + + Component.onCompleted: { + barInstances.push(bar); + } + + color: "transparent" + + Rectangle { + id: highlight + anchors.fill: parent + color: Theme.get.barBgColor + } + + height: 30 + + visible: true + + anchors { + top: Theme.get.onTop + bottom: !Theme.get.onTop + left: true + right: true + } + + RowLayout { + id: allBlocks + spacing: 0 + anchors.fill: parent + + // Left side + RowLayout { + id: leftBlocks + spacing: 10 + Layout.alignment: Qt.AlignLeft + Layout.fillWidth: true + + //Blocks.Icon {} + Blocks.Workspaces {} + } + + Blocks.ActiveWorkspace { + id: activeWorkspace + Layout.leftMargin: 10 + anchors.centerIn: undefined + + chopLength: { + var space = Math.floor(bar.width - (rightBlocks.implicitWidth + leftBlocks.implicitWidth)) + return space * 0.08; + } + + text: { + var str = activeWindowTitle + return str.length > chopLength ? str.slice(0, chopLength) + '...' : str; + } + + color: { + return Hyprland.focusedMonitor == Hyprland.monitorFor(screen) + ? "#FFFFFF" : "#CCCCCC" + } + } + + // Without this filler item, the active window block will be centered + // despite setting left alignment + Item { + Layout.fillWidth: true + } + + // Right side + RowLayout { + id: rightBlocks + spacing: 0 + Layout.alignment: Qt.AlignRight + Layout.fillWidth: true + + Blocks.SystemTray {} + Blocks.Memory {} + Blocks.Sound {} + Blocks.Battery {} + Blocks.Date {} + Blocks.Time {} + } + } + } + } +} + diff --git a/home/quickshell/bar/BarBlock.qml b/home/quickshell/bar/BarBlock.qml new file mode 100644 index 0000000..edd4aca --- /dev/null +++ b/home/quickshell/bar/BarBlock.qml @@ -0,0 +1,75 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell + +Rectangle { + id: root + Layout.preferredWidth: contentContainer.implicitWidth + 10 + Layout.preferredHeight: 30 + + property Item content + property Item mouseArea: mouseArea + + property string text + property bool dim: false + property bool underline + property var onClicked: function() {} + property int leftPadding + property int rightPadding + + property string hoveredBgColor: "#666666" + + // Background color + color: { + if (mouseArea.containsMouse) + return hoveredBgColor; + return "transparent"; + } + + states: [ + State { + when: mouseArea.containsMouse + PropertyChanges { + target: root + } + } + ] + + Behavior on color { + ColorAnimation { + duration: 200 + } + } + + Item { + // Contents of the bar block + id: contentContainer + implicitWidth: content.implicitWidth + implicitHeight: content.implicitHeight + anchors.centerIn: parent + children: content + } + + MouseArea { + id: mouseArea + anchors.fill: root + hoverEnabled: true + acceptedButtons: Qt.LeftButton + onClicked: root.onClicked() + } + + // While line underneath workspace + Rectangle { + id: wsLine + width: parent.width + height: 2 + + color: { + if (parent.underline) + return "white"; + return "transparent"; + } + anchors.bottom: parent.bottom + } +} + diff --git a/home/quickshell/bar/BarText.qml b/home/quickshell/bar/BarText.qml new file mode 100644 index 0000000..4cf42cc --- /dev/null +++ b/home/quickshell/bar/BarText.qml @@ -0,0 +1,57 @@ +import Quickshell +import Quickshell.Io +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import QtQuick.Effects +import Qt5Compat.GraphicalEffects + +Text { + property string mainFont: "FiraCode" + property string symbolFont: "Symbols Nerd Font Mono" + property int pointSize: 12 + property int symbolSize: pointSize * 1.4 + property string symbolText + property bool dim + text: wrapSymbols(symbolText) + anchors.centerIn: parent + color: dim ? "#CCCCCC" : "white" + textFormat: Text.RichText + font { + family: mainFont + pointSize: pointSize + } + + Text { + visible: false + id: textcopy + text: parent.text + textFormat: parent.textFormat + color: parent.color + font: parent.font + } + + DropShadow { + anchors.fill: parent + horizontalOffset: 1 + verticalOffset: 1 + color: "#000000" + source: textcopy + } + + function wrapSymbols(text) { + if (!text) + return "" + + const isSymbol = (codePoint) => + (codePoint >= 0xE000 && codePoint <= 0xF8FF) // Private Use Area + || (codePoint >= 0xF0000 && codePoint <= 0xFFFFF) // Supplementary Private Use Area-A + || (codePoint >= 0x100000 && codePoint <= 0x10FFFF); // Supplementary Private Use Area-B + + return text.replace(/./gu, (c) => isSymbol(c.codePointAt(0)) + ? `${c}` + // ? c + : c); + } +} + diff --git a/home/quickshell/bar/Notification.qml b/home/quickshell/bar/Notification.qml new file mode 100644 index 0000000..b86a966 --- /dev/null +++ b/home/quickshell/bar/Notification.qml @@ -0,0 +1,11 @@ +import QtQuick + +Text { + required property int id + required property string body + required property string summary + property int margin + + text: `- ${summary}: ${body}` +} + diff --git a/home/quickshell/bar/NotificationPanel.qml b/home/quickshell/bar/NotificationPanel.qml new file mode 100644 index 0000000..0ef8712 --- /dev/null +++ b/home/quickshell/bar/NotificationPanel.qml @@ -0,0 +1,101 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Quickshell +import Quickshell.Wayland +import Quickshell.Services.Notifications + +PanelWindow { + // required property font custom_font + required property color text_color + property list notification_objects + + width: 500 + height: 600 + + color: "#171a18" + + WlrLayershell.layer: WlrLayer.Overlay + + Rectangle { + border.width: 5 + border.color: "#8ec07c" + anchors.fill: parent + color: "transparent" + + ColumnLayout { + id: content + anchors { + left: parent.left + leftMargin: 10 + right: parent.right + rightMargin: 10 + top: parent.top + topMargin: 10 + } + + RowLayout { + Layout.fillWidth: true + + Text { + Layout.fillWidth: true + text: "Notifications:" + // font: custom_font + color: text_color + } + + Text { + text: "clear" + // font: custom_font + color: text_color + + TapHandler { + id: tapHandler + gesturePolicy: TapHandler.ReleaseWithinBounds + onTapped: { + server.trackedNotifications.values.forEach((notification) => { + notification.tracked = false + }) + notification_objects.forEach((object) => { + object.destroy(); + }) + notification_objects = []; + } + } + + HoverHandler { + id: mouse + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad + cursorShape: Qt.PointingHandCursor + } + } + } + } + } + + NotificationServer { + id: server + onNotification: (notification) => { + notification.tracked = true + console.log(JSON.stringify(notification)); + var notification_component = Qt.createComponent("Notification.qml"); + var notification_object = notification_component + .createObject(content, + { + id: notification.id, + body: notification.body, + summary: notification.summary, + // font: custom_font, + color: text_color, + margin: 10 + } + ) + if (notification_object == null) { + console.log("Error creating notification") + } else { + notification_objects.push(notification_object); + } + } + } +} + diff --git a/home/quickshell/bar/Tooltip.qml b/home/quickshell/bar/Tooltip.qml new file mode 100644 index 0000000..7ab247d --- /dev/null +++ b/home/quickshell/bar/Tooltip.qml @@ -0,0 +1,89 @@ +import QtQuick +import Quickshell +import "root:/" // for Globals + +LazyLoader { + id: root + + // The item to display the tooltip at. If set to null the tooltip will be hidden. + property Item relativeItem: null + + // Tracks the item after relativeItem is unset. + property Item displayItem: null + + property PopupContext popupContext: Globals.popupContext + + property bool hoverable: false; + readonly property bool hovered: item?.hovered ?? false + + // The content to show in the tooltip. + required default property Component contentDelegate + + active: displayItem != null && popupContext.popup == this + + onRelativeItemChanged: { + if (relativeItem == null) { + if (item != null) item.hideTimer.start(); + } else { + if (item != null) item.hideTimer.stop(); + displayItem = relativeItem; + popupContext.popup = this; + } + } + + PopupWindow { + anchor { + window: root.displayItem.QsWindow.window + rect.y: anchor.window.height + 3 + rect.x: anchor.window.contentItem.mapFromItem(root.displayItem, root.displayItem.width / 2, 0).x + edges: Edges.Top + gravity: Edges.Bottom + } + + visible: true + + property alias hovered: body.containsMouse; + + property Timer hideTimer: Timer { + interval: 250 + + // unloads the popup by causing active to become false + onTriggered: root.popupContext.popup = null; + } + + color: "transparent" + + // don't accept mouse input if !hoverable + Region { id: emptyRegion } + mask: root.hoverable ? null : emptyRegion + + width: body.implicitWidth + height: body.implicitHeight + + MouseArea { + id: body + + anchors.fill: parent + implicitWidth: content.implicitWidth + 10 + implicitHeight: content.implicitHeight + 10 + + hoverEnabled: root.hoverable + + Rectangle { + anchors.fill: parent + + radius: 5 + border.width: 1 + color: palette.active.toolTipBase + border.color: palette.active.light + + Loader { + id: content + anchors.centerIn: parent + sourceComponent: contentDelegate + active: true + } + } + } + } +} diff --git a/home/quickshell/bar/blocks/ActiveWorkspace.qml b/home/quickshell/bar/blocks/ActiveWorkspace.qml new file mode 100644 index 0000000..7969212 --- /dev/null +++ b/home/quickshell/bar/blocks/ActiveWorkspace.qml @@ -0,0 +1,34 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell.Io +import Quickshell.Hyprland +import "../" + +BarText { + // text: { + // var str = activeWindowTitle + // return str.length > chopLength ? str.slice(0, chopLength) + '...' : str; + // } + + property int chopLength + property string activeWindowTitle + + Process { + id: titleProc + command: ["sh", "-c", "hyprctl activewindow | grep title: | sed 's/^[^:]*: //'"] + running: true + + stdout: SplitParser { + onRead: data => activeWindowTitle = data + } + } + + Component.onCompleted: { + Hyprland.rawEvent.connect(hyprEvent) + } + + function hyprEvent(e) { + titleProc.running = true + } +} + diff --git a/home/quickshell/bar/blocks/Battery.qml b/home/quickshell/bar/blocks/Battery.qml new file mode 100644 index 0000000..dd52f7f --- /dev/null +++ b/home/quickshell/bar/blocks/Battery.qml @@ -0,0 +1,50 @@ +import QtQuick +import Quickshell.Io +import "../" + +BarBlock { + property string battery + property bool hasBattery: false + visible: hasBattery + + content: BarText { + symbolText: battery + } + + Process { + id: batteryCheck + command: ["sh", "-c", "test -d /sys/class/power_supply/BAT*"] + running: true + onExited: function(exitCode) { hasBattery = exitCode === 0 } + } + + Process { + id: batteryProc + // Modify command to get both capacity and status in one call + command: ["sh", "-c", "echo $(cat /sys/class/power_supply/BAT*/capacity),$(cat /sys/class/power_supply/BAT*/status)"] + running: hasBattery + + stdout: SplitParser { + onRead: function(data) { + const [capacityStr, status] = data.trim().split(',') + const capacity = parseInt(capacityStr) + let batteryIcon = "󰂂" + if (capacity <= 20) batteryIcon = "󰁺" + else if (capacity <= 40) batteryIcon = "󰁽" + else if (capacity <= 60) batteryIcon = "󰁿" + else if (capacity <= 80) batteryIcon = "󰂁" + else batteryIcon = "󰂂" + + const symbol = status === "Charging" ? "🔌" : batteryIcon + battery = `${symbol} ${capacity}%` + } + } + } + + Timer { + interval: 1000 + running: hasBattery + repeat: true + onTriggered: batteryProc.running = true + } +} diff --git a/home/quickshell/bar/blocks/Date.qml b/home/quickshell/bar/blocks/Date.qml new file mode 100644 index 0000000..11ce193 --- /dev/null +++ b/home/quickshell/bar/blocks/Date.qml @@ -0,0 +1,10 @@ +import QtQuick +import "../" + +BarBlock { + id: text + content: BarText { + symbolText: ` ${Datetime.date}` + } +} + diff --git a/home/quickshell/bar/blocks/Datetime.qml b/home/quickshell/bar/blocks/Datetime.qml new file mode 100644 index 0000000..743e785 --- /dev/null +++ b/home/quickshell/bar/blocks/Datetime.qml @@ -0,0 +1,31 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + property string time; + property string date; + + Process { + id: dateProc + command: ["date", "+%a %e %b|%R"] + running: true + + stdout: SplitParser { + onRead: data => { + date = data.split("|")[0] + time = data.split("|")[1] + } + } + } + + Timer { + interval: 1000 + running: true + repeat: true + onTriggered: dateProc.running = true + } +} + diff --git a/home/quickshell/bar/blocks/Icon.qml b/home/quickshell/bar/blocks/Icon.qml new file mode 100644 index 0000000..c111a7e --- /dev/null +++ b/home/quickshell/bar/blocks/Icon.qml @@ -0,0 +1,146 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Quickshell +import Quickshell.Io +import Quickshell.Widgets +import Qt5Compat.GraphicalEffects +import "../" +import "root:/" + +BarBlock { + id: root + Layout.preferredWidth: 20 + + content: BarText { + text: "󰣇" + pointSize: 24 + anchors.horizontalCenterOffset: 4 + anchors.verticalCenterOffset: 3 + } + + color: "transparent" + + Process { + id: appListProc + command: ["sh", "-c", "for f in /usr/share/applications/*.desktop; do if ! grep -qi 'terminal=true' \"$f\"; then name=$(grep -i '^Name=' \"$f\" | head -n1 | cut -d= -f2); basename=$(basename \"$f\" .desktop); echo \"$name|$basename|$f\"; fi; done"] + running: false + stdout: SplitParser { + onRead: data => { + const [appName, launchName, desktopFile] = data.trim().split("|") + if (appName && launchName && desktopFile) { + appListModel.append({ name: appName, launchName: launchName, path: desktopFile }) + } + } + } + } + + Process { + id: appLauncher + running: false + command: ["gtk-launch"] + } + + ListModel { + id: appListModel + } + + PopupWindow { + id: menuWindow + width: 300 + height: 400 + visible: false + + anchor { + window: root.QsWindow?.window + edges: Edges.Bottom + gravity: Edges.Top + } + + FocusScope { + anchors.fill: parent + focus: true + + MouseArea { + anchors.fill: parent + hoverEnabled: true + onExited: { + if (!containsMouse) { + closeTimer.start() + } + } + onEntered: closeTimer.stop() + + Timer { + id: closeTimer + interval: 500 + onTriggered: menuWindow.visible = false + } + + Rectangle { + anchors.fill: parent + color: "#2E3440" // Using Nord theme color + border.color: "#4C566A" + border.width: 1 + radius: 4 + + ColumnLayout { + anchors.fill: parent + anchors.margins: 10 + spacing: 5 + + ListView { + id: appListView + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + model: appListModel + delegate: Rectangle { + width: parent.width + height: 35 + color: mouseArea.containsMouse ? "#4C566A" : "transparent" + radius: 4 + + Text { + anchors.fill: parent + anchors.leftMargin: 10 + text: model.name + color: "white" + font.pixelSize: 12 + verticalAlignment: Text.AlignVCenter + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: { + console.log("Launching:", model.launchName, "from", model.path) + appLauncher.command = ["gtk-launch", model.launchName] + appLauncher.running = true + menuWindow.visible = false + } + } + } + } + } + } + } + } + } + + function filterApps() { + const searchText = searchField.text.toLowerCase() + for (let i = 0; i < appListModel.count; i++) { + const item = appListModel.get(i) + item.visible = item.name.toLowerCase().includes(searchText) + } + } + onClicked: function() { + if (!menuWindow.visible) { + appListModel.clear() + appListProc.running = true + } + menuWindow.visible = !menuWindow.visible + } +} \ No newline at end of file diff --git a/home/quickshell/bar/blocks/Memory.qml b/home/quickshell/bar/blocks/Memory.qml new file mode 100644 index 0000000..4a931c1 --- /dev/null +++ b/home/quickshell/bar/blocks/Memory.qml @@ -0,0 +1,31 @@ +import QtQuick +import QtQuick.Controls +import Quickshell +import Quickshell.Io +import "../" + +BarBlock { + id: text + content: BarText { + symbolText: `- ${Math.floor(percentFree)}%` + } + + property real percentFree + + Process { + id: memProc + command: ["sh", "-c", "free | grep Mem | awk '{print $3/$2 * 100.0}'"] + running: true + + stdout: SplitParser { + onRead: data => percentFree = data + } + } + + Timer { + interval: 2000 + running: true + repeat: true + onTriggered: memProc.running = true + } +} diff --git a/home/quickshell/bar/blocks/Notifications.qml b/home/quickshell/bar/blocks/Notifications.qml new file mode 100644 index 0000000..3871cc4 --- /dev/null +++ b/home/quickshell/bar/blocks/Notifications.qml @@ -0,0 +1,34 @@ +import QtQuick +import Quickshell.Services.Notifications +import "../" + +BarBlock { + id: root + property bool showNotification: false + + text: " " + notifServer.trackedNotifications.values.length + onClicked: function() { + showNotification = !showNotification + } + + NotificationServer { + id: notifServer + onNotification: (notification) => { + notification.tracked = true + } + } + + NotificationPanel { + text_color: root.color + visible: showNotification + + anchors { + top: parent.top + } + + margins { + top: 10 + } + } +} + diff --git a/home/quickshell/bar/blocks/Sound.qml b/home/quickshell/bar/blocks/Sound.qml new file mode 100644 index 0000000..e8be70b --- /dev/null +++ b/home/quickshell/bar/blocks/Sound.qml @@ -0,0 +1,176 @@ +import QtQuick +import QtQuick.Controls +import Quickshell +import Quickshell.Services.Pipewire +import Quickshell.Io +import "../" +import "root:/" + +BarBlock { + id: root + property var sink: Pipewire.defaultAudioSink + + PwObjectTracker { + objects: [Pipewire.defaultAudioSink] + onObjectsChanged: { + sink = Pipewire.defaultAudioSink + if (sink?.audio) { + sink.audio.volumeChanged.connect(updateVolume) + } + } + } + + function updateVolume() { + if (sink?.audio) { + const icon = sink.audio.muted ? "󰖁" : "󰕾" + content.symbolText = `${icon} ${Math.round(sink.audio.volume * 100)}%` + } + } + + content: BarText { symbolText: `${sink?.audio?.muted ? "󰖁" : "󰕾"} ${Math.round(sink?.audio?.volume * 100)}%` } + + MouseArea { + anchors.fill: parent + onClicked: toggleMenu() + onWheel: function(event) { + if (sink?.audio) { + sink.audio.volume = Math.max(0, Math.min(1, sink.audio.volume + (event.angleDelta.y / 120) * 0.05)) + } + } + } + + Process { + id: pavucontrol + command: ["pavucontrol"] + running: false + } + + PopupWindow { + id: menuWindow + width: 200 + height: 150 + visible: false + + anchor { + window: root.QsWindow?.window + edges: Edges.Bottom + gravity: Edges.Top + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + onExited: { + if (!containsMouse) { + closeTimer.start() + } + } + onEntered: closeTimer.stop() + + Timer { + id: closeTimer + interval: 500 + onTriggered: menuWindow.visible = false + } + + Rectangle { + anchors.fill: parent + color: "#2c2c2c" + border.color: "#3c3c3c" + border.width: 1 + radius: 4 + + Column { + anchors.fill: parent + anchors.margins: 10 + spacing: 10 + + // Volume Slider + Rectangle { + width: parent.width + height: 35 + color: "transparent" + + Slider { + id: volumeSlider + anchors.fill: parent + from: 0 + to: 1 + value: sink?.audio?.volume || 0 + onValueChanged: { + if (sink?.audio) { + sink.audio.volume = value + } + } + + background: Rectangle { + x: volumeSlider.leftPadding + y: volumeSlider.topPadding + volumeSlider.availableHeight / 2 - height / 2 + width: volumeSlider.availableWidth + height: 4 + radius: 2 + color: "#3c3c3c" + + Rectangle { + width: volumeSlider.visualPosition * parent.width + height: parent.height + color: "#4a9eff" + radius: 2 + } + } + + handle: Rectangle { + x: volumeSlider.leftPadding + volumeSlider.visualPosition * (volumeSlider.availableWidth - width) + y: volumeSlider.topPadding + volumeSlider.availableHeight / 2 - height / 2 + width: 16 + height: 16 + radius: 8 + color: volumeSlider.pressed ? "#4a9eff" : "#ffffff" + border.color: "#3c3c3c" + } + } + } + + Repeater { + model: [ + { text: sink?.audio?.muted ? "Unmute" : "Mute", action: () => sink?.audio && (sink.audio.muted = !sink.audio.muted) }, + { text: "Pavucontrol", action: () => { pavucontrol.running = true; menuWindow.visible = false } } + ] + + Rectangle { + width: parent.width + height: 35 + color: mouseArea.containsMouse ? "#3c3c3c" : "transparent" + radius: 4 + + Text { + anchors.fill: parent + anchors.leftMargin: 10 + text: modelData.text + color: "white" + font.pixelSize: 12 + verticalAlignment: Text.AlignVCenter + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: { + modelData.action() + } + } + } + } + } + } + } + } + + function toggleMenu() { + if (root.QsWindow?.window?.contentItem) { + menuWindow.anchor.rect = root.QsWindow.window.contentItem.mapFromItem(root, 0, -menuWindow.height - 5, root.width, root.height) + menuWindow.visible = !menuWindow.visible + } + } +} \ No newline at end of file diff --git a/home/quickshell/bar/blocks/SystemTray.qml b/home/quickshell/bar/blocks/SystemTray.qml new file mode 100644 index 0000000..15c4691 --- /dev/null +++ b/home/quickshell/bar/blocks/SystemTray.qml @@ -0,0 +1,80 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Widgets +import Quickshell.Services.SystemTray +import "root:/bar" + +RowLayout { + spacing: 5 + + Repeater { + model: ScriptModel { + values: {[...SystemTray.items.values] + .filter((item) => { + return (item.id != "spotify-client" + && item.id != "chrome_status_icon_1") + }) + } + } + + MouseArea { + id: delegate + required property SystemTrayItem modelData + property alias item: delegate.modelData + + Layout.fillHeight: true + implicitWidth: icon.implicitWidth + 5 + + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + hoverEnabled: true + + onClicked: event => { + if (event.button == Qt.LeftButton) { + item.activate(); + } else if (event.button == Qt.MiddleButton) { + item.secondaryActivate(); + } else if (event.button == Qt.RightButton) { + menuAnchor.open(); + } + } + + onWheel: event => { + event.accepted = true; + const points = event.angleDelta.y / 120 + item.scroll(points, false); + } + + IconImage { + id: icon + anchors.centerIn: parent + source: item.icon + implicitSize: 16 + } + + QsMenuAnchor { + id: menuAnchor + menu: item.menu + + anchor.window: delegate.QsWindow.window + anchor.adjustment: PopupAdjustment.Flip + + anchor.onAnchoring: { + const window = delegate.QsWindow.window; + const widgetRect = window.contentItem.mapFromItem(delegate, 0, delegate.height, delegate.width, delegate.height); + + menuAnchor.anchor.rect = widgetRect; + } + } + + Tooltip { + relativeItem: delegate.containsMouse ? delegate : null + + Label { + text: delegate.item.tooltipTitle || delegate.item.id + } + } + } + } +} diff --git a/home/quickshell/bar/blocks/Time.qml b/home/quickshell/bar/blocks/Time.qml new file mode 100644 index 0000000..5650fcb --- /dev/null +++ b/home/quickshell/bar/blocks/Time.qml @@ -0,0 +1,10 @@ +import QtQuick +import "../" + +BarBlock { + id: text + content: BarText { + symbolText: ` ${Datetime.time}` + } +} + diff --git a/home/quickshell/bar/blocks/Workspace.qml b/home/quickshell/bar/blocks/Workspace.qml new file mode 100644 index 0000000..232a3f3 --- /dev/null +++ b/home/quickshell/bar/blocks/Workspace.qml @@ -0,0 +1,28 @@ +import QtQuick +import QtQuick.Layouts + +Rectangle { + id: ws + + property bool hovered: false + + Layout.preferredWidth: 10 + Layout.preferredHeight: 10 + Layout.minimumWidth: 10 + Layout.minimumHeight: 10 + Layout.alignment: Qt.AlignHCenter + radius: height / 2 + + MouseArea { + anchors.fill: parent + hoverEnabled: true + + onEntered: () => { + ws.hovered = true; + } + onExited: () => { + ws.hovered = false; + } + onClicked: () => console.log(`workspace ?`) + } +} diff --git a/home/quickshell/bar/blocks/Workspaces.qml b/home/quickshell/bar/blocks/Workspaces.qml new file mode 100644 index 0000000..66d48a6 --- /dev/null +++ b/home/quickshell/bar/blocks/Workspaces.qml @@ -0,0 +1,74 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Hyprland +import Quickshell.Widgets +import Qt5Compat.GraphicalEffects +import "../utils" as Utils +import "root:/" + +RowLayout { + property HyprlandMonitor monitor: Hyprland.monitorFor(screen) + + Rectangle { + id: workspaceBar + Layout.preferredWidth: Math.max(50, Utils.HyprlandUtils.maxWorkspace * 25) + Layout.preferredHeight: 23 + radius: 7 + color: Theme.get.barBgColor + + Row { + anchors.centerIn: parent + spacing: 15 + + Repeater { + model: Utils.HyprlandUtils.maxWorkspace || 1 + + Item { + required property int index + property bool focused: Hyprland.focusedMonitor?.activeWorkspace?.id === (index + 1) + + width: workspaceText.width + height: workspaceText.height + + Text { + id: workspaceText + text: (index + 1).toString() + color: "white" + font.pixelSize: 15 + font.bold: focused + } + + Rectangle { + visible: focused + anchors { + left: workspaceText.left + right: workspaceText.right + top: workspaceText.bottom + topMargin: -3 + } + height: 2 + color: "white" + } + + DropShadow { + visible: focused + anchors.fill: workspaceText + horizontalOffset: 2 + verticalOffset: 2 + radius: 8.0 + samples: 20 + color: "#000000" + source: workspaceText + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + onClicked: Utils.HyprlandUtils.switchWorkspace(index + 1) + } + } + } + } + } +} \ No newline at end of file diff --git a/home/quickshell/bar/utils/HyprlandUtils.qml b/home/quickshell/bar/utils/HyprlandUtils.qml new file mode 100644 index 0000000..dde3b31 --- /dev/null +++ b/home/quickshell/bar/utils/HyprlandUtils.qml @@ -0,0 +1,54 @@ +pragma Singleton + +import Quickshell +import Quickshell.Hyprland +import QtQuick + +Singleton { + id: hyprland + + property list workspaces: sortWorkspaces(Hyprland.workspaces.values) + property int maxWorkspace: findMaxId() + + function sortWorkspaces(ws) { + return [...ws].sort((a, b) => a?.id - b?.id); + } + + function switchWorkspace(w: int): void { + Hyprland.dispatch(`workspace ${w}`); + } + + function findMaxId(): int { + if (hyprland.workspaces.length === 0) { + console.log("No workspaces found, defaulting to 1"); + return 1; // Return 1 if no workspaces exist + } + let num = hyprland.workspaces.length; + let maxId = hyprland.workspaces[num - 1]?.id || 1; + console.log("Current max workspace ID:", maxId); + return maxId; + } + + Connections { + target: Hyprland + function onRawEvent(event) { + let eventName = event.name; + console.log("Hyprland event received:", eventName); + + switch (eventName) { + case "createworkspacev2": + { + console.log("Workspace created, updating workspace list"); + hyprland.workspaces = hyprland.sortWorkspaces(Hyprland.workspaces.values); + hyprland.maxWorkspace = findMaxId(); + } + case "destroyworkspacev2": + { + console.log("Workspace destroyed, updating workspace list"); + hyprland.workspaces = hyprland.sortWorkspaces(Hyprland.workspaces.values); + hyprland.maxWorkspace = findMaxId(); + } + } + } + } +} diff --git a/home/quickshell/default.nix b/home/quickshell/default.nix new file mode 100644 index 0000000..43f7d76 --- /dev/null +++ b/home/quickshell/default.nix @@ -0,0 +1,20 @@ +{ + pkgs, + pkgs-unstable, + lib, + config, + ... +}: +{ + imports = [ ./quickshell.nix ]; + programs.quickshell = { + enable = true; + systemd.enable = true; + package = pkgs-unstable.quickshell; + systemd.target = "hyprland-session.target"; + }; + xdg.configFile."quickshell/shell.qml".source = ./shell.qml; + xdg.configFile."quickshell/Theme.qml".source = ./Theme.qml; + xdg.configFile."quickshell/PopupContext.qml".source = ./PopupContext.qml; + xdg.configFile."quickshell/bar".source = ./bar; +} diff --git a/home/quickshell/quickshell.nix b/home/quickshell/quickshell.nix new file mode 100644 index 0000000..87cc52c --- /dev/null +++ b/home/quickshell/quickshell.nix @@ -0,0 +1,90 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.programs.quickshell; +in +{ + meta.maintainers = [ lib.maintainers.justdeeevin ]; + + options.programs.quickshell = { + enable = lib.mkEnableOption "quickshell, a flexbile QtQuick-based desktop shell toolkit."; + package = lib.mkPackageOption pkgs "quickshell" { nullable = true; }; + configs = lib.mkOption { + type = lib.types.attrsOf lib.types.path; + default = { }; + description = '' + A set of configs to include in the quickshell config directory. The key is the name of the config. + + The configuration that quickshell should use can be specified with the `activeConfig` option. + ''; + }; + activeConfig = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = '' + The name of the config to use. + + If `null`, quickshell will attempt to use a config located in `$XDG_CONFIG_HOME/quickshell` instead of one of the named sub-directories. + ''; + }; + + systemd = { + enable = lib.mkEnableOption "quickshell systemd service"; + target = lib.mkOption { + type = lib.types.str; + default = config.wayland.systemd.target; + defaultText = lib.literalExpression "config.wayland.systemd.target"; + example = "hyprland-session.target"; + description = '' + The systemd target that will automatically start quickshell. + + If you set this to a WM-specific target, make sure that systemd integration for that WM is enabled (e.g. `wayland.windowManager.hyprland.systemd.enable`). **This is typically true by default**. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + (lib.mkIf (cfg.configs != { }) { + xdg.configFile = lib.mapAttrs' (name: path: { + name = "quickshell/${name}"; + value.source = path; + }) cfg.configs; + }) + { + assertions = [ + (lib.hm.assertions.assertPlatform "programs.quickshell" pkgs lib.platforms.linux) + { + assertion = !(builtins.any (name: lib.hasInfix "/" name) (builtins.attrNames cfg.configs)); + message = "The names of configs in `programs.quickshell.configs` must not contain slashes."; + } + ]; + + home.packages = [ cfg.package ]; + + } + (lib.mkIf cfg.systemd.enable { + systemd.user.services.quickshell = { + Unit = { + Description = "quickshell"; + Documentation = "https://quickshell.outfoxxed.me/docs/"; + After = [ cfg.systemd.target ]; + }; + + Service = { + ExecStart = + lib.getExe cfg.package + (if cfg.activeConfig == null then "" else " --config ${cfg.activeConfig}"); + Restart = "on-failure"; + }; + + Install.WantedBy = [ cfg.systemd.target ]; + }; + }) + ] + ); +} diff --git a/home/quickshell/shell.qml b/home/quickshell/shell.qml new file mode 100644 index 0000000..43bb3e9 --- /dev/null +++ b/home/quickshell/shell.qml @@ -0,0 +1,8 @@ +//@ pragma UseQApplication +import "bar" + +import Quickshell + +ShellRoot { + Bar {} +} diff --git a/home/tenere/default.nix b/home/tenere/default.nix new file mode 100644 index 0000000..f7cfa29 --- /dev/null +++ b/home/tenere/default.nix @@ -0,0 +1,16 @@ +{ + config, + inputs, + pkgs, + ... +}: +{ + xdg.configFile."/tenere/config.toml".text = '' + llm = "chatgpt" + + [chatgpt] + openai_api_key = $(${pkgs.coreutils}/bin/cat ${config.age.secrets.openai_auth_token.path}) + model = "gpt-4.1" + url = "https://api.openai.com/v1/chat/completions" + ''; +} diff --git a/home/ticker/default.nix b/home/ticker/default.nix new file mode 100644 index 0000000..be2f509 --- /dev/null +++ b/home/ticker/default.nix @@ -0,0 +1,41 @@ +{ inputs, pkgs, ... }: +{ + xdg.configFile."/home/petri/.config/ticker/config.yaml".text = '' + show-summary: true + show-tags: true + show-fundamentals: true + show-separator: true + show-holdings: true + interval: 5 + currency: EUR + currency-summary-only: false + watchlist: + - NET + - TEAM + - ESTC + - BTC-USD # Bitcoin price via Yahoo + - SOL.X # Solana price via CoinGecko + - SAMOYEDCOIN.CG # Samoyed price via CoinGecko + - CARDANO.CC # Samoyed price via CoinCap + lots: + - symbol: "ABNB" + quantity: 35.0 + unit_cost: 146.00 + - symbol: "ARKW" + quantity: 20.0 + unit_cost: 152.25 + - symbol: "ARKW" + quantity: 20.0 + unit_cost: 145.35 + fixed_cost: 7.00 # e.g. brokerage commission fee + groups: + - name: crypto + watchlist: + - SHIB-USD + - VGX-USD + holdings: + - symbol: SOL1-USD + quantity: 17 + unit_cost: 159.10 + ''; +} diff --git a/home/vale/default.nix b/home/vale/default.nix new file mode 100644 index 0000000..79712ea --- /dev/null +++ b/home/vale/default.nix @@ -0,0 +1,31 @@ +{ inputs, pkgs, ... }: +{ + + xdg.configFile."/home/petri/.config/vale/.vale.ini".text = '' + MinAlertLevel = suggestion + StylesPath = ${pkgs.valeStyles.microsoft}/share/vale/styles + Packages = Microsoft + # Vocab = myterms does not work because expects styles to be in the same folder + + [asciidoctor] + experimental = YES + attribute-missing = drop + + [*.adoc] + BasedOnStyles = Vale, Microsoft + + [*.{md,rst}] + BasedOnStyles = Vale, Microsoft + ''; + + xdg.configFile."/home/petri/.config/vale/config/vocabularies/myterms/accept.txt".text = '' + Relesoft + ERTMS + ETCS + YAML + TOML + FTIA + GRK + EULYNX + ''; +} diff --git a/home/walker/config.toml b/home/walker/config.toml new file mode 100644 index 0000000..5c2b1ef --- /dev/null +++ b/home/walker/config.toml @@ -0,0 +1,251 @@ +app_launch_prefix = "" +terminal_title_flag = "" +locale = "" +close_when_open = false +theme = "default" +monitor = "" +hotreload_theme = false +as_window = false +timeout = 0 +disable_click_to_close = false +force_keyboard_focus = false + +[keys] +accept_typeahead = ["tab"] +trigger_labels = "lalt" +next = ["down"] +prev = ["up"] +close = ["esc"] +remove_from_history = ["shift backspace"] +resume_query = ["ctrl r"] +toggle_exact_search = ["ctrl m"] + +[keys.activation_modifiers] +keep_open = "shift" +alternate = "alt" + +[keys.ai] +clear_session = ["ctrl x"] +copy_last_response = ["ctrl c"] +resume_session = ["ctrl r"] +run_last_response = ["ctrl e"] + +[events] +on_activate = "" +on_selection = "" +on_exit = "" +on_launch = "" +on_query_change = "" + +[list] +dynamic_sub = true +keyboard_scroll_style = "emacs" +max_entries = 50 +show_initial_entries = true +single_click = true +visibility_threshold = 20 +placeholder = "No Results" + +[search] +argument_delimiter = "#" +placeholder = "Search..." +delay = 0 +resume_last_query = false + +[activation_mode] +labels = "jkl;asdf" + +[builtins.applications] +weight = 5 +name = "applications" +placeholder = "Applications" +prioritize_new = true +hide_actions_with_empty_query = true +context_aware = true +refresh = true +show_sub_when_single = true +show_icon_when_single = true +show_generic = true +history = true + +[builtins.applications.actions] +enabled = true +hide_category = false +hide_without_query = true + +[builtins.bookmarks] +weight = 5 +placeholder = "Bookmarks" +name = "bookmarks" +icon = "bookmark" +switcher_only = true + +[[builtins.bookmarks.entries]] +label = "Walker" +url = "https://github.com/abenz1267/walker" +keywords = ["walker", "github"] + +[builtins.xdph_picker] +hidden = true +weight = 5 +placeholder = "Screen/Window Picker" +show_sub_when_single = true +name = "xdphpicker" +switcher_only = true + +[builtins.ai] +weight = 5 +placeholder = "AI" +name = "ai" +icon = "help-browser" +switcher_only = true +show_sub_when_single = true + +[[builtins.ai.anthropic.prompts]] +model = "claude-3-7-sonnet-20250219" +temperature = 1 +max_tokens = 1_000 +label = "General Assistant" +prompt = "You are a helpful general assistant. Keep your answers short and precise." + +[builtins.calc] +require_number = true +weight = 5 +name = "calc" +icon = "accessories-calculator" +placeholder = "Calculator" +min_chars = 4 + +[builtins.windows] +weight = 5 +icon = "view-restore" +name = "windows" +placeholder = "Windows" +show_icon_when_single = true + +[builtins.clipboard] +always_put_new_on_top = true +exec = "wl-copy" +weight = 5 +name = "clipboard" +avoid_line_breaks = true +placeholder = "Clipboard" +image_height = 300 +max_entries = 10 +switcher_only = true + +[builtins.commands] +weight = 5 +icon = "utilities-terminal" +switcher_only = true +name = "commands" +placeholder = "Commands" + +[builtins.custom_commands] +weight = 5 +icon = "utilities-terminal" +name = "custom_commands" +placeholder = "Custom Commands" + +[builtins.emojis] +exec = "wl-copy" +weight = 5 +name = "emojis" +placeholder = "Emojis" +switcher_only = true +history = true +typeahead = true +show_unqualified = false + +[builtins.symbols] +after_copy = "" +weight = 5 +name = "symbols" +placeholder = "Symbols" +switcher_only = true +history = true +typeahead = true + +[builtins.finder] +use_fd = false +fd_flags = "--ignore-vcs --type file" +weight = 5 +icon = "file" +name = "finder" +placeholder = "Finder" +switcher_only = true +ignore_gitignore = true +refresh = true +concurrency = 8 +show_icon_when_single = true +preview_images = false + +[builtins.runner] +eager_loading = true +weight = 5 +icon = "utilities-terminal" +name = "runner" +placeholder = "Runner" +typeahead = true +history = true +generic_entry = false +refresh = true +use_fd = false + +[builtins.ssh] +weight = 5 +icon = "preferences-system-network" +name = "ssh" +placeholder = "SSH" +switcher_only = true +history = true +refresh = true + +[builtins.switcher] +weight = 5 +name = "switcher" +placeholder = "Switcher" +prefix = "/" + +[builtins.websearch] +keep_selection = true +weight = 5 +icon = "applications-internet" +name = "websearch" +placeholder = "Websearch" + +[[builtins.websearch.entries]] +name = "Google" +url = "https://www.google.com/search?q=%TERM%" + +[[builtins.websearch.entries]] +name = "DuckDuckGo" +url = "https://duckduckgo.com/?q=%TERM%" +switcher_only = true + +[[builtins.websearch.entries]] +name = "Ecosia" +url = "https://www.ecosia.org/search?q=%TERM%" +switcher_only = true + +[[builtins.websearch.entries]] +name = "Yandex" +url = "https://yandex.com/search/?text=%TERM%" +switcher_only = true + +[builtins.dmenu] +hidden = true +weight = 5 +name = "dmenu" +placeholder = "Dmenu" +switcher_only = true +show_icon_when_single = true + +[builtins.translation] +delay = 1000 +weight = 5 +name = "translation" +icon = "accessories-dictionary" +placeholder = "Translation" +switcher_only = true +provider = "googlefree" diff --git a/home/walker/default.nix b/home/walker/default.nix new file mode 100644 index 0000000..e28780f --- /dev/null +++ b/home/walker/default.nix @@ -0,0 +1,9 @@ +{ config, pkgs, ... }: + +{ + home.file = { + "/home/petri/.config/walker/config.toml" = { + source = ./config.toml; + }; + }; +} diff --git a/home/wallpapers/crow.jpg b/home/wallpapers/crow.jpg new file mode 100644 index 0000000..7eec09d Binary files /dev/null and b/home/wallpapers/crow.jpg differ diff --git a/home/wallpapers/crow2.avif b/home/wallpapers/crow2.avif new file mode 100644 index 0000000..6353b15 Binary files /dev/null and b/home/wallpapers/crow2.avif differ diff --git a/home/wallpapers/default.nix b/home/wallpapers/default.nix new file mode 100644 index 0000000..458f711 --- /dev/null +++ b/home/wallpapers/default.nix @@ -0,0 +1,87 @@ +{ config, pkgs, ... }: +let + wallpaperScript = pkgs.writeShellScript "update-wallpaper.sh" '' + set -euo pipefail + + if [ -z "''${UNSPLASH_ACCESS_KEY:-}" ]; then + echo "Error: UNSPLASH_ACCESS_KEY is not set" + exit 1 + fi + + WALLPAPER_DIR="$HOME/.local/share/wallpapers" + "${pkgs.coreutils}/bin/mkdir" -p "$WALLPAPER_DIR" + + TMPFILE="$("${pkgs.coreutils}/bin/mktemp")" + + echo "Fetching random Unsplash image URL..." + URL=$("${pkgs.curl}/bin/curl" -s \ + "https://api.unsplash.com/photos/random?query=nature,landscape&orientation=landscape&client_id=$UNSPLASH_ACCESS_KEY" \ + | "${pkgs.jq}/bin/jq" -r '.urls.raw') + + if [ -z "$URL" ] || [ "$URL" = "null" ]; then + echo "Error: could not retrieve Unsplash URL" + exit 1 + fi + + EXT=$("${pkgs.coreutils}/bin/basename" "$URL" | "${pkgs.gawk}/bin/awk" -F. '{print tolower($NF)}') + [[ "$EXT" =~ ^(jpg|jpeg|png)$ ]] || EXT="jpg" + + TMPFILE_EXT="$TMPFILE.$EXT" + OUTFILE="$WALLPAPER_DIR/$("${pkgs.coreutils}/bin/date" +%Y%m%d-%H%M%S).webp" + + echo "Downloading original Unsplash image..." + "${pkgs.curl}/bin/curl" -L --fail --retry 3 -o "$TMPFILE_EXT" "$URL" + + echo "Converting to WebP..." + "${pkgs.libwebp}/bin/cwebp" -mt -preset photo -hint photo -metadata all -pass 10 -quiet -q 80 -m 6 "$TMPFILE_EXT" -o "$OUTFILE" + "${pkgs.coreutils}/bin/rm" -f "$TMPFILE_EXT" + + echo "Selecting a wallpaper different from current..." + CURRENT_WALL=$("${pkgs.hyprland}/bin/hyprctl" hyprpaper listloaded | "${pkgs.gawk}/bin/awk" '{print $NF}' || true) + NEW_WALL=$("${pkgs.findutils}/bin/find" "$WALLPAPER_DIR" -type f ! -name "$("${pkgs.coreutils}/bin/basename" "$CURRENT_WALL")" | "${pkgs.coreutils}/bin/shuf" -n 1) + + echo "Reloading hyprpaper with: $NEW_WALL" + "${pkgs.hyprland}/bin/hyprctl" hyprpaper reload ,"$NEW_WALL" + ''; +in +{ + # Ensure required packages are available + home.packages = with pkgs; [ + coreutils + curl + findutils + hyprland + jq + libwebp + ]; + + systemd.user.services."wallpaper-fetch" = { + Unit = { + Description = "Fetch and update 4K nature wallpaper for Hyprpaper"; + After = [ "graphical-session.target" ]; + }; + + Service = { + Environment = [ + "UNSPLASH_ACCESS_KEY=$(${pkgs.coreutils}/bin/cat ${config.age.secrets.unsplash_access_key.path})" + ]; + Type = "oneshot"; + ExecStart = "${wallpaperScript}"; + }; + }; + + # Timer to run periodically (every 3 hours) + systemd.user.timers."wallpaper-fetch" = { + Unit = { + Description = "Periodic Unsplash wallpaper fetch timer"; + }; + Timer = { + OnBootSec = "2min"; + OnUnitActiveSec = "3h"; + Persistent = true; + }; + Install = { + WantedBy = [ "timers.target" ]; + }; + }; +} diff --git a/home/wallpapers/owl1.webp b/home/wallpapers/owl1.webp new file mode 100644 index 0000000..f3c64d1 Binary files /dev/null and b/home/wallpapers/owl1.webp differ diff --git a/home/wallpapers/owl2.webp b/home/wallpapers/owl2.webp new file mode 100644 index 0000000..fa053a5 Binary files /dev/null and b/home/wallpapers/owl2.webp differ diff --git a/home/wallpapers/owl3.webp b/home/wallpapers/owl3.webp new file mode 100644 index 0000000..8861509 Binary files /dev/null and b/home/wallpapers/owl3.webp differ diff --git a/home/waybar/config b/home/waybar/config deleted file mode 100644 index 779a9a1..0000000 --- a/home/waybar/config +++ /dev/null @@ -1,160 +0,0 @@ -{ - // ------------------------------------------------------------------------- - // Global configuration - // ------------------------------------------------------------------------- - "ipc": true, - "position": "bottom", - "layer": "top", - "height": 30, - "mode": "dock", - "modules-left": [ - "hyprland/hide", - "hyprland/mode", - "hyprland/workspaces", - "disk", - "memory", - "cpu", - "temperature", - "custom/spotify" - ], - "modules-center": [ - "hyprland/window" - ], - "modules-right": [ - "pulseaudio", - "battery", - "backlight", - "clock#date", - "clock#time", - "network", - "tray" - ], - // ------------------------------------------------------------------------- - // Modules - // ------------------------------------------------------------------------- - "hyprland/hide": { - "hide-on-startup": true - }, - "battery": { - "interval": 1, - "states": { - "low": 30, - "warning": 15, - "critical": 5 - }, - "format": "{icon} {capacity}%", - "format-discharging": "{icon} {capacity}%", - "format-charging": "󰂄 {capacity}%", - "tooltip-format": "{time} left", - "format-icons": [ - "󰁺", - "󰁻", - "󰁼", - "󰁽", - "󰁾", - "󰁿", - "󰂀", - "󰂁", - "󰂂", - "󰁹", - ], - "tooltip": true, - "full-at": 95 - }, - "clock#time": { - "interval": 10, - "format": "{:%H:%M}", - "tooltip": false - }, - "clock#date": { - "interval": 60, - "format": "{:%A, %e %b %Y}", - "tooltip": true - }, - "cpu": { - "interval": 2, - "tooltip": true, - "format": " {usage}%", - "states": { - "low": 0, - "normal": 20, - "warning": 70, - "critical": 90 - } - }, - "memory": { - "interval": 5, - "format": " {used:0.1f}G", - "tooltip-format": "{used:0.1f}G / {total:0.1f}G", - "states": { - "warning": 70, - "critical": 90 - } - }, - "network": { - "interval": 1, - "format-wifi": "{icon}", - "format-disconnected": "󱖣", - "format-icons": [ - "", - "", - "", - "", - "" - ], - "tooltip-format": "{essid} ({signalStrength}%) - {ifname} - {ipaddr} - {bandwidthDownBits} {bandwidthUpBits}", - "tooltip": true, - }, - "hyprland/mode": { - "format": " {}", - "tooltip": false - }, - "hyprland/window": { - "format": "{}", - "max-length": 60, - "tooltip": true - }, - "hyprland/workspaces": { - "all-outputs": true, - "format": "{icon}" - }, - "pulseaudio": { - "scroll-step": 1, - "format": "{icon} {volume}%", - "format-muted": "", - "format-bluetooth": " {icon} {volume}%", - "format-bluetooth-muted": "", - "on-click": "pulseaudio-control togmute", - "on-click-middle": "pulseaudio-control --sink-blacklist 'alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__hw_sofhdadsp_3__sink,alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__hw_sofhdadsp_4__sink,alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__hw_sofhdadsp_5__sink' next-sink" - }, - "temperature": { - "critical-threshold": 90, - "interval": 5, - "format": "{icon} {temperatureC}°C", - "format-icons": [ - "", - "", - "", - "", - "" - ], - "tooltip": true - }, - "disk": { - "interval": 10, - "format": "{free}" - }, - "backlight": { - "device": "intel_backlight", - "format": "{icon} {percent}", - "format-icons": [ - "" - ], - "on-scroll-up": "brightnessctl set +1% -e 6 -n 1", - "on-scroll-down": "brightnessctl set 1%- -e 6 -n 1" - }, - "tray": { - "icon-size": 24, - "spacing": 10 - } -} diff --git a/home/waybar/default.nix b/home/waybar/default.nix index bfe3c39..fd9a735 100644 --- a/home/waybar/default.nix +++ b/home/waybar/default.nix @@ -1,6 +1,304 @@ +{ pkgs, lib, ... }: + +let + waybarTimer = pkgs.writeShellScript "waybar_timer.sh" '' + #!/bin/sh + CUR_TIME=$(date +%s) + STATUS=$(cat /var/tmp/waybar_timer) + + if [ $STATUS == "READY" ]; then + echo "" + elif [ $STATUS == "FINISHED" ]; then + mpv $HOME/.config/waybar/modules/timer.wav & + echo "READY" > /var/tmp/waybar_timer + echo "" + elif [[ $STATUS > $CUR_TIME ]]; then + DIFF=$(( (STATUS - CUR_TIME) )) + echo $( date -d @$DIFF +%M:%S ) + else + if [ -f "/var/tmp/waybar_timer" ]; then + echo "FINISHED" > /var/tmp/waybar_timer + echo "" + else + echo "READY" > /var/tmp/waybar_timer + echo "" + fi + fi + ''; +in + { - programs.waybar = { enable = true; }; + programs.waybar = { + systemd.enable = true; + enable = true; + settings = [ + { + ipc = true; + layer = "top"; + position = "top"; + height = 36; + margin = "5 5 0 5"; + modules-left = [ + "custom/startmenu" + "hyprland/workspaces" + "idle_inhibitor" + "keyboard-state" + "hyprland/language" + "systemd-failed-units" + "wireplumber" + "privacy" + "hyprland/window" + ]; + modules-center = [ + "clock" + "custom/timer" + "mpris" + ]; + modules-right = [ + "network" + "temperature" + "load" + "group/system-status" + "bluetooth" + "tray" + "custom/weather" + "custom/exit" + ]; + + "hyprland/workspaces" = { + format = "{name}"; + format-icons = { + default = " "; + active = " "; + urgent = " "; + }; + on-scroll-up = "${pkgs.hyprland}/bin/hyprctl dispatch workspace e+1"; + on-scroll-down = "${pkgs.hyprland}/bin/hyprctl dispatch workspace e-1"; + }; + + clock = { + interval = 1; + format = "{:%A, %Y-%m-%d %H:%M:%S}"; + tooltip-format = "{:%Y %B}\n{calendar}"; + calendar = { + mode = "year"; + weeks-pos = "right"; + mode-mon-col = 3; + format = { + months = "{}"; + days = "{}"; + weeks = "W{}"; + weekdays = "{}"; + today = "{}"; + }; + }; + }; + + "hyprland/window" = { + max-length = 80; + separate-outputs = false; + rewrite = { + "" = "🙈 No Windows?"; + }; + }; + + "hyprland/language" = { + format = "{long}"; + min-length = 14; + }; + + "keyboard-state" = { + capslock = true; + format = "{icon}"; + format-icons = { + locked = ""; + unlocked = ""; + }; + tooltip = false; + }; + + "custom/weather" = { + format = "{}°C"; + tooltip = true; + interval = 3600; + exec = "${pkgs.wttrbar}/bin/wttrbar --date-format=%d.%m.%Y --location=Helsinki"; + return-type = "json"; + }; + + "group/system-status" = { + orientation = "horizontal"; + modules = [ + "cpu" + "memory" + "battery" + "backlight" + ]; + }; + memory = { + interval = 1; + format = " {}%"; + tooltip-format = "{used:0.1f}G / {total:0.1f}G"; + states = { + warning = 70; + critical = 90; + }; + }; + + load = { + interval = 1; + format = "load: {load1:>4}"; + max-length = 10; + }; + + cpu = { + interval = 1; + format = " {usage:>3}%"; + tooltip-format = "{usage}%"; + tooltip = true; + states = { + warning = 70; + critical = 90; + }; + }; + + backlight = { + device = "intel_backlight"; + format = "{icon} {percent}%"; + format-icons = [ "" ]; + on-scroll-up = "${pkgs.brightnessctl}/bin/brightnessctl set +1%"; + on-scroll-down = "${pkgs.brightnessctl}/bin/brightnessctl set 1%-"; + }; + + systemd-failed-units = { + hide-on-ok = false; + format = "✗ {nr_failed}"; + format-ok = "✓"; + system = true; + }; + + temperature = { + format = "{temperatureC}°C "; + }; + + privacy = { + icon-spacing = 4; + icon-size = 18; + transition-duration = 250; + modules = [ + { + type = "screenshare"; + tooltip = true; + tooltip-icon-size = 24; + } + { + type = "audio-out"; + tooltip = true; + tooltip-icon-size = 24; + } + { + type = "audio-in"; + tooltip = true; + tooltip-icon-size = 24; + } + ]; + ignore-monitor = true; + }; + + network = { + tooltip = true; + interval = 1; + format-wifi = "{icon} {essid} ({signalStrength}) up: {bandwidthUpBits:>6} down: {bandwidthDownBits:>6}"; + format-ethernet = "{icon} up: {bandwidthUpBits:>6} down: {bandwidthDownBits:>6}"; + format-disconnected = "⚠ Disconnected"; + tooltip-format = "{ifname}: {ipaddr}/{cidr}\nUp: {bandwidthUpBits:>6}\nDown: {bandwidthDownBits:>6}"; + format-icons = { + wifi = ""; + ethernet = ""; + }; + }; + tray = { + spacing = 12; + }; + bluetooth = { + format = " {status}"; + format-connected = " {device_alias}"; + format-connected-battery = " {device_alias} {device_battery_percentage}%"; + tooltip-format = "{controller_alias}\t{controller_address}\n\n{num_connections} connected"; + tooltip-format-connected = "{controller_alias}\t{controller_address}\n\n{num_connections} connected\n\n{device_enumerate}"; + tooltip-format-enumerate-connected = "{device_alias}\t{device_address}"; + tooltip-format-enumerate-connected-battery = "{device_alias}\t{device_address}\t{device_battery_percentage}%"; + }; + mpris = { + format = "DEFAULT: {player_icon} {dynamic}"; + format-paused = "DEFAULT: {status_icon} {dynamic}"; + interval = 1; + player-icons = { + default = "▶"; + mpv = "🎵"; + }; + status-icons = { + paused = "⏸"; + }; + }; + wireplumber = { + format = "{icon} {volume}%"; + format-muted = " {volume}%"; + format-icons = { + default = [ + "" + "" + "" + ]; + }; + on-click = "${pkgs.lxqt.pavucontrol-qt}/bin/pavucontrol-qt"; + }; + + "custom/timer" = { + tooltip = false; + min-length = 5; + exec = "${waybarTimer}"; + on-click = "date --date='5 minutes' +%s > /var/tmp/waybar_timer"; + on-click-right = "echo READY > /var/tmp/waybar_timer"; + on-click-middle = "date --date='1 minute' +%s > /var/tmp/waybar_timer"; + on-scroll-up = "date --date='5 seconds' +%s > /var/tmp/waybar_timer"; + on-scroll-down = "date --date='30 minutes' +%s > /var/tmp/waybar_timer"; + interval = 1; + }; + + "custom/exit" = { + format = ""; + on-click = "${pkgs.wlogout}/bin/wlogout"; + }; + + "custom/startmenu" = { + format = "⚡"; + on-click = "${pkgs.walker}/bin/walker"; + }; - home.file."./config/waybar/config".source = ./config; - home.file."./config/waybar/style.css".source = ./style.css; + "idle_inhibitor" = { + format = "{icon}"; + format-icons = { + activated = ""; + deactivated = ""; + }; + }; + battery = { + states = { + warning = 30; + critical = 15; + }; + format = "{icon} {capacity}%"; + format-charging = " {capacity}%"; + format-plugged = " {capacity}%"; + format-full = " {capacity}%"; + format-icons = [ + "" + "" + "" + ]; + }; + } + ]; + style = builtins.readFile ./style.css; + }; } diff --git a/home/waybar/style.css b/home/waybar/style.css index 8fe60c7..7e6e821 100644 --- a/home/waybar/style.css +++ b/home/waybar/style.css @@ -1,258 +1,140 @@ -@keyframes blink-low { - 70% { - color: @foreground; - } - - to { - color: @foreground; - background-color: #744E0D; - } -} - -@keyframes blink-warning { - 70% { - color: @foreground; - } - - to { - color: @foreground; - background-color: @warning; - } -} - -@keyframes blink-critical { - 70% { - color: @foreground; - } - - to { - color: @foreground; - background-color: @critical; - } -} - - -/* ----------------------------------------------------------------------------- - * Styles - * -------------------------------------------------------------------------- */ - -/* Nord */ -/* Gruvbox */ -@define-color foreground #D4BE98; -@define-color background #202020; -@define-color backgroundlight #2A2A2A; -@define-color mode #a89984; -@define-color workspaces #458588; -@define-color workspacesfocused #83a598; -@define-color sound #E78A4E; -@define-color network #A9B665; -@define-color memory #7DAEA3; -@define-color cpu #8EC07C; -@define-color layout #689d6a; -@define-color battery #A9B665; -@define-color date #282828; -@define-color time #ebdbb2; -@define-color warning #DE655E; -@define-color critical #FB4934; -@define-color temp #A9B665; - -/* Reset all styles */ +/* Nord Theme Colors */ +@define-color nord0 #2e3440; +@define-color nord1 #3b4252; +@define-color nord2 #434c5e; +@define-color nord3 #4c566a; +@define-color nord4 #d8dee9; +@define-color nord5 #e5e9f0; +@define-color nord6 #eceff4; +@define-color nord7 #8fbcbb; +@define-color nord8 #88c0d0; +@define-color nord9 #81a1c1; +@define-color nord10 #5e81ac; +@define-color nord11 #bf616a; +@define-color nord13 #ebcb8b; + +/* Base styles */ * { - border: none; - border-radius: 0; - min-height: 0; - margin: 0; - padding: 0; + font-family: 'Iosevka Nerd Font', monospace; + font-size: 18px; + border: none; + border-radius: 8px; + margin: 0; + padding: 0; + min-height: 0; + transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out, opacity 0.2s ease-in-out; } -/* The whole bar */ #waybar { - background: @background; - color: @foreground; - font-family: Sarasa Term K, JetBrainsMono Nerd Font, Material Design Icons, unifont, Fira Code, Terminus, Siji; - font-size: 12pt; - font-weight: bold; + background-color: transparent; + color: @nord5; } -/* Each module */ -#battery, -#clock, -#cpu, -#memory, -#custom-clockify, -#custom-spotify, -#backlight, -#mode, -#network, -#disk, -#pulseaudio, -#workspaces, -#temperature { - padding: 0 10px; - margin: 5px 5px; - border-radius: 10em; - background-color: @backgroundlight; - color: @foreground; +#systemd-failed-units, #temperature, #load, #privacy, #mpris, +#workspaces, #window, #cpu, #memory, #battery, #backlight, +#wireplumber, #network, #bluetooth, #clock, #tray, +#custom-startmenu, #custom-exit, #custom-weather, #idle_inhibitor, #custom-timer, +#language, #keyboard-state { + background-color: rgba(46, 52, 64, 0.9); /* nord0 with opacity */ + color: @nord5; + padding: 0 12px; + margin: 4px 2px; + border-radius: 8px; } -/* Each module that should blink */ -#mode, -#memory, -#temperature, -#battery { - animation-timing-function: ease-out; - animation-iteration-count: infinite; - animation-direction: alternate; +/* Module grouping */ +#wireplumber { + margin-right: 8px; /* Separate from system-status group */ } - -/* Each critical module */ -#memory.critical, -#cpu.critical, -#temperature.critical, -#battery.critical { - color: @critical; +#group-system-status > * { + background-color: @nord2; + margin: 4px 1px; } - -/* Each critical that should blink */ -#mode, -#memory.critical, -#temperature.critical, -#battery.critical.discharging { - animation-name: blink-critical; - animation-duration: 2s; -} - -/* Each warning */ -#network.disconnected, -#memory.warning, -#cpu.warning, -#temperature.warning, -#battery.warning { - color: @warning; -} - -#cpu.low { - color: @memory; -} - -/* Each warning that should blink */ -#battery.warning.discharging { - animation-name: blink-warning; - animation-duration: 3s; -} - -#battery.low.discharging { - animation-name: blink-low; - animation-duration: 5s; -} - -/* And now modules themselves in their respective order */ - -#mode { /* Shown current Sway mode (resize etc.) */ - color: @foreground; - background: @mode; -} - -/* Workspaces stuff */ -#workspaces { - background: #2A2A2A; +#network, #bluetooth { + background-color: @nord3; + margin-left: 8px; /* Separate network group */ } +/* Module-specific colors and styles */ #workspaces button { - padding: 0; - color: #D4BE98; - font-size: 16pt; + color: @nord7; + font-size: 16px; + padding: 0 8px; + border-radius: 8px; } - -#workspaces button.persistent { - color: #3E3E3E; -} - #workspaces button.visible { - color: #FE8019; -} - -#network { - color: @network; -} - -#disk { - color: #FABD2F; - border-radius: 10em 0 0 10em; - margin-right: 0; -} - -#memory { - color: @memory; - margin-right: 0; - margin-left: 0; - border-radius: 0; -} - -#cpu { - color: @cpu; - margin-right: 0; - margin-left: 0; - border-radius: 0; -} - -#temperature { - color: @temp; - border-radius: 0 10em 10em 0; - margin-left: 0; -} - -#pulseaudio { - color: @sound; - margin-right: 0; - border-radius: 10em 0 0 10em; -} - -#pulseaudio.muted { - color: #3E3E3E; -} - -#battery { - color: @battery; - margin-right: 0; - margin-left: 0; - border-radius: 0; -} - -#backlight { - color: #D3869B; - margin-left: 0; - border-radius: 0 10em 10em 0; -} - -#clock.date { - background: @date; - color: @foreground; - margin-right: 0; - border-radius: 10em 0 0 10em; -} - -#clock.time { - background: @time; - color: @background; - margin-left: 0; - border-radius: 0 10em 10em 0; + color: @nord8; + background-color: @nord1; +} +#workspaces button:hover { + background-color: @nord2; + color: @nord6; + opacity: 0.9; +} + #workspaces button.active { + color: @nord6; +} +#cpu { color: @nord9; } +#memory { color: @nord7; } +#battery { color: @nord7; } +#mpris { color: @nord7; } +#backlight { color: @nord9; } +#wireplumber { color: @nord9; } +#network { color: @nord7; min-width: 220px; } /* Fixed width for consistent alignment */ +#bluetooth { color: @nord10; } +#language { + color: @nord10; + min-width: 40px; /* Ensure visibility */ + background-color: rgba(46, 52, 64, 0.9); /* Explicit nord0 background */ +} +#keyboard-state { color: @nord10; } +#custom-weather { color: @nord7; } +#clock { background-color: @nord1; } +#custom-startmenu, #custom-exit, #idle_inhibitor { + font-size: 16px; +} +#custom-startmenu:hover, #custom-exit:hover, #idle_inhibitor:hover { + background-color: @nord2; + color: @nord6; + opacity: 0.9; +} + +/* Warning and Critical States */ +#cpu.warning, #memory.warning, #battery.warning { + color: @nord13; + animation: blink-warning 2s ease-in-out infinite alternate; +} +#cpu.critical, #memory.critical, #battery.critical { + color: @nord11; + animation: blink-critical 1s ease-in-out infinite alternate; +} +#network.disconnected { + color: @nord11; +} + +/* Animations */ +@keyframes blink-warning { + to { background-color: @nord13; color: @nord0; } } - -#tray { - margin: 0 5px; +@keyframes blink-critical { + to { background-color: @nord11; color: @nord0; } } +/* Tooltip */ tooltip { - color: @foreground; - background-color: @background; - font-weight: 400; - font-family: Fira Code; - margin: 0 10px; - border-radius: 1em; + background-color: @nord0; + color: @nord5; + border-radius: 8px; + padding: 5px 10px; } - tooltip label { - color: @foreground; - padding: 0 5px; + color: @nord5; +} + +/* Tray */ +#tray > .passive { + color: @nord3; } +#tray > .active { + color: @nord8; + } diff --git a/hosts/kataja/default.nix b/hosts/kataja/default.nix new file mode 100644 index 0000000..f664cab --- /dev/null +++ b/hosts/kataja/default.nix @@ -0,0 +1,141 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running ‘nixos-help’). + +{ + inputs, + outputs, + lib, + config, + pkgs, + vars, + ... +}: + +{ + imports = [ ./hardware-configuration.nix ]; + networking = { + hostName = "kataja"; + interfaces.eno1.wakeOnLan.enable = true; + }; + + systemd = { + network = { + enable = true; + wait-online.enable = false; + config = { + networkConfig = { + SpeedMeter = true; + }; + }; + networks = { + "10-wlan" = { + matchConfig = { + MACAddress = "10:6f:d9:28:3f:b3"; + }; + linkConfig = { + Multicast = true; + }; + networkConfig = { + DHCP = true; + IPv6AcceptRA = true; + MulticastDNS = true; + UseDomains = true; + }; + dhcpV4Config = { + RouteMetric = 600; + UseMTU = true; + }; + ipv6AcceptRAConfig = { + RouteMetric = 600; + UseMTU = true; + }; + linkConfig.RequiredForOnline = "no"; + }; + "11-lan" = { + matchConfig = { + MACAddress = "70:70:fc:00:29:25"; + }; + linkConfig = { + Multicast = true; + }; + networkConfig = { + DHCP = true; + IPv6AcceptRA = true; + MulticastDNS = true; + UseDomains = true; + }; + dhcpV4Config = { + RouteMetric = 100; + UseMTU = true; + }; + ipv6AcceptRAConfig = { + RouteMetric = 100; + UseMTU = true; + }; + linkConfig.RequiredForOnline = "no"; + }; + "12-lan" = { + matchConfig = { + MACAddress = "70:70:fc:00:29:26"; + }; + networkConfig = { + DHCP = true; + IPv6AcceptRA = true; + UseDomains = true; + }; + ipv6AcceptRAConfig = { + UseMTU = true; + }; + linkConfig.RequiredForOnline = "no"; + }; + }; + }; + sleep.extraConfig = "HibernateDelaySec=90m"; + }; + + environment = { + sessionVariables = { + LIBVA_DRIVER_NAME = "radeonsi"; + }; + }; + + services = { + godns = { + enable = true; + settings = { + domains = [ + { + domain_name = "www.duckdns.org"; + sub_domains = [ "kataja" ]; + } + ]; + ip_interface = "eno1"; + interval = 300; + ip_type = "IPv6"; + login_token_file = config.age.secrets.duckdns.path; + provider = "DuckDNS"; + }; + }; + xserver = { + deviceSection = '' + Option "DRI" "3" + Option "VariableRefresh" "True" + Option "TearFree" "False" + ''; + }; + }; + + hardware = { + graphics = { + extraPackages = with pkgs; [ + amdvlk + rocmPackages.clr.icd + ]; + }; + + bluetooth.settings.General.Name = "kataja"; + }; + + system.stateVersion = "24.05"; +} diff --git a/hosts/kataja/hardware-configuration.nix b/hosts/kataja/hardware-configuration.nix new file mode 100644 index 0000000..5d1d1b7 --- /dev/null +++ b/hosts/kataja/hardware-configuration.nix @@ -0,0 +1,79 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + pkgs, + modulesPath, + ... +}: + +{ + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; + + boot = { + kernelPackages = pkgs.linuxPackages_zen; + initrd = { + luks.devices."luks-b3e9864c-2a40-43d7-b1a0-51f3b2ec42bc".device = + "/dev/disk/by-uuid/b3e9864c-2a40-43d7-b1a0-51f3b2ec42bc"; + availableKernelModules = [ + "ahci" + "amdgpu" + "mt7921e" + "nvme" + "r8169" + "sd_mod" + "usb_storage" + "usbhid" + "xhci_pci" + "cdc_acm" + ]; + }; + kernelParams = [ + "amdgpu.modeset=1" + "default_hugepagesz=2M" + "mitigations=off" + "nospectre_v2" + "transparent_hugepage=always" + ]; + kernelModules = [ + "k10temp" + "kvm-amd" + "snd_hda_intel" + "tcp_bbr" + ]; + extraModulePackages = [ ]; + }; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/3e7f6b6b-b656-4f42-b314-f447e2562718"; + fsType = "ext4"; + }; + + boot.initrd.luks.devices."luks-b9b738dc-8554-41d9-82f9-042663b52e79".device = + "/dev/disk/by-uuid/b9b738dc-8554-41d9-82f9-042663b52e79"; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/4121-BEC3"; + fsType = "vfat"; + options = [ + "fmask=0077" + "dmask=0077" + ]; + }; + + swapDevices = [ { device = "/dev/disk/by-uuid/97641877-607c-46cd-853d-e431c8a90dc2"; } ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + # networking.useDHCP = lib.mkDefault true; + # networking.interfaces.eno1.useDHCP = lib.mkDefault true; + # networking.interfaces.enp2s0.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp3s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/pihlaja/default.nix b/hosts/pihlaja/default.nix new file mode 100644 index 0000000..8101815 --- /dev/null +++ b/hosts/pihlaja/default.nix @@ -0,0 +1,269 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running ‘nixos-help’). + +{ + inputs, + outputs, + lib, + config, + pkgs, + vars, + ... +}: + +{ + imports = [ ./hardware-configuration.nix ]; + + hardware = { + bluetooth.enable = true; + keyboard.qmk.enable = true; + logitech.wireless.enable = true; + nvidia = { + modesetting.enable = true; + powerManagement = { + enable = true; + finegrained = false; + }; + open = true; + nvidiaSettings = false; + package = config.boot.kernelPackages.nvidiaPackages.latest; + }; + graphics = { + extraPackages = with pkgs; [ + nvidia-vaapi-driver + cudatoolkit + ]; + }; + + bluetooth.settings.General.Name = "pihlaja"; + }; + + networking = { + hostName = "pihlaja"; + interfaces.enp5s0.wakeOnLan.enable = true; + }; + + environment = { + sessionVariables = { + LIBVA_DRIVER_NAME = "nvidia"; + VK_DRIVER_FILES = "/run/opengl-driver/share/vulkan/icd.d/nvidia_icd.x86_64.json"; + GBM_BACKEND = "nvidia-drm"; + __GLX_VENDOR_LIBRARY_NAME = "nvidia"; + NVD_BACKEND = "direct"; + }; + systemPackages = with pkgs; [ + logiops + qmk_hid + qmk + via + qmk-udev-rules + ]; + }; + + services.hardware.openrgb = { + enable = true; + package = pkgs.openrgb-with-all-plugins; + motherboard = "amd"; + server = { + port = 6742; + }; + }; + + systemd = { + network = { + enable = true; + wait-online.enable = false; + config = { + networkConfig = { + SpeedMeter = true; + }; + }; + networks = { + "10-wlan" = { + matchConfig.MACAddress = "34:cf:f6:25:c7:db"; + linkConfig = { + Multicast = true; + }; + networkConfig = { + DHCP = "yes"; + IPv6AcceptRA = true; + MulticastDNS = true; + LinkLocalAddressing = "ipv6"; + DNSSEC = true; + UseDomains = true; + }; + dhcpV4Config = { + RouteMetric = 100; + UseDNS = true; + UseMTU = true; + }; + ipv6AcceptRAConfig = { + UseMTU = true; + }; + linkConfig.RequiredForOnline = "yes"; + }; + "11-lan" = { + matchConfig.MACAddress = "18:c0:4d:04:cf:e9"; + linkConfig = { + Multicast = true; + }; + networkConfig = { + DHCP = "yes"; + IPv6AcceptRA = true; + MulticastDNS = true; + LinkLocalAddressing = "ipv6"; + DNSSEC = true; + UseDomains = true; + }; + dhcpV4Config = { + RouteMetric = 90; + UseDNS = true; + UseMTU = true; + }; + ipv6AcceptRAConfig = { + RouteMetric = 80; + UseMTU = true; + }; + linkConfig.RequiredForOnline = "no"; + }; + }; + }; + services = { + logiops = { + enable = true; + description = "An unofficial userspace driver for HID++ Logitech devices"; + serviceConfig = { + Type = "simple"; + ExecStart = "${pkgs.logiops}/bin/logid"; + }; + wantedBy = [ "multi-user.target" ]; + }; + }; + }; + + services = { + godns = { + enable = true; + settings = { + domains = [ + { + domain_name = "www.duckdns.org"; + sub_domains = [ "pihlaja" ]; + } + ]; + ip_interface = "enp5s0"; + interval = 300; + ip_type = "IPv6"; + login_token_file = config.age.secrets.duckdns.path; + provider = "DuckDNS"; + }; + }; + xserver = { + videoDrivers = [ "nvidia" ]; + }; + udev.packages = with pkgs; [ + qmk + qmk_hid + qmk-udev-rules + via + ]; + llama-cpp = { + enable = false; + openFirewall = true; + model = "/home/petri/Programming/DeepSeek-R1-Distill-Qwen-32B-Q8_0.gguf"; + host = "0.0.0.0"; + }; + }; + fonts.fontconfig.subpixel.rgba = "bgr"; + + # Configuration for logiops + environment.etc."logid.cfg".text = '' + devices: ({ + name: "Wireless Mouse MX Master 3"; + smartshift: { + on: true; + threshold: 12; + }; + hiresscroll: { + hires: true; + target: false; + }; + thumbwheel: { + divert: true; + invert: false; + left: { + threshold: 1; + interval: 1; + direction: "Left"; + mode: "OnInterval"; + action = { + type: "Keypress"; + keys: ["KEY_VOLUMEDOWN"]; + }; + }; + right: { + threshold: 1; + interval: 1; + direction: "Right"; + mode: "OnInterval"; + action = { + type: "Keypress"; + keys: ["KEY_VOLUMEUP"]; + }; + }; + }; + dpi: 1500; + buttons: ({ + cid: 0xc3; + action = { + type: "Gestures"; + gestures: ({ + direction: "Left"; + mode: "OnRelease"; + action = { + type = "Keypress"; + keys: ["KEY_F15"]; + }; + }, { + direction: "Right"; + mode: "OnRelease"; + action = { + type = "Keypress"; + keys: ["KEY_F16"]; + }; + }, { + direction: "Down"; + mode: "OnRelease"; + action = { + type: "Keypress"; + keys: ["KEY_F17"]; + }; + }, { + direction: "Up"; + mode: "OnRelease"; + action = { + type: "Keypress"; + keys: ["KEY_F18"]; + }; + }, { + direction: "None"; + mode: "OnRelease"; + action = { + type = "Keypress"; + keys: ["KEY_PLAYPAUSE"]; + }; + }); + }; + }, { + cid: 0xc4; + action = { + type: "Keypress"; + keys: ["KEY_F19"]; + }; + }); + }); + ''; + + system.stateVersion = "24.05"; # Did you read the comment? +} diff --git a/hosts/pihlaja/hardware-configuration.nix b/hosts/pihlaja/hardware-configuration.nix new file mode 100644 index 0000000..1e81932 --- /dev/null +++ b/hosts/pihlaja/hardware-configuration.nix @@ -0,0 +1,80 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + pkgs, + modulesPath, + ... +}: + +{ + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; + + boot = { + kernelPackages = pkgs.linuxPackages; + kernelParams = [ + "NVreg_PreserveVideoMemoryAllocations=1" + "mitigations=off" + "nospectre_v2" + "nvidia_drm.fbdev=1" + "nvidia_drm.modeset=1" + "transparent_hugepage=always" + ]; + initrd = { + luks.devices."luks-a47a6087-e6bf-4e8d-a034-2229259c38f5".device = + "/dev/disk/by-uuid/a47a6087-e6bf-4e8d-a034-2229259c38f5"; + availableKernelModules = [ + "cdc_acm" + "ahci" + "iwldvm" + "iwlwifi" + "nvme" + "sd_mod" + "usb_storage" + "usbhid" + "xhci_pci" + "nvidia" + "nvidia_drm" + "nvidia_modeset" + "nvidia_uvm" + ]; + luks.devices."luks-1efa1182-2964-49bf-a413-fb51bd7b107f".device = + "/dev/disk/by-uuid/1efa1182-2964-49bf-a413-fb51bd7b107f"; + }; + kernelModules = [ + "tcp_bbr" + "iwldvm" + "iwlwifi" + "k10temp" + "kvm-amd" + ]; + extraModulePackages = [ ]; + }; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/eecfd181-138c-4c90-add6-2ef528d5dbb4"; + fsType = "ext4"; + }; + + fileSystems."/data" = { + device = "/dev/disk/by-uuid/a02a4e78-32ea-40e6-8398-087bfd8dca93"; + fsType = "ext4"; + options = [ "nofail" ]; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/A4F5-0899"; + fsType = "vfat"; + options = [ + "fmask=0077" + "dmask=0077" + ]; + }; + + swapDevices = [ { device = "/dev/disk/by-uuid/d0e5a93d-18a7-4d24-893c-d2417c3d5043"; } ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/saarni/default.nix b/hosts/saarni/default.nix index 010a8eb..5252e6f 100644 --- a/hosts/saarni/default.nix +++ b/hosts/saarni/default.nix @@ -2,249 +2,147 @@ # your system. Help is available in the configuration.nix(5) man page # and in the NixOS manual (accessible by running ‘nixos-help’). -{ inputs, outputs, lib, config, pkgs, vars, ... }: +{ + inputs, + outputs, + lib, + config, + pkgs, + vars, + ... +}: { - imports = [ - ./hardware-configuration.nix - inputs.home-manager.nixosModules.home-manager - ]; + imports = [ ./hardware-configuration.nix ]; - nix = { - nixPath = [ "/etc/nix/path" ]; - gc = { - automatic = true; - }; - settings = { - auto-optimise-store = true; - experimental-features = "nix-command flakes"; + hardware = { + graphics = { + extraPackages = with pkgs; [ + libvpl + libvdpau-va-gl + sof-firmware + vpl-gpu-rt + ]; }; - registry = (lib.mapAttrs (_: flake: { inherit flake; })) - ((lib.filterAttrs (_: lib.isType "flake")) inputs); - }; - nixpkgs.config.allowUnfree = true; - security.rtkit.enable = true; - - home-manager = { - extraSpecialArgs = { inherit inputs outputs vars; }; - users = { ${vars.user} = import ../../home; }; - }; - - powerManagement = { - enable = true; - powertop.enable = true; - }; - # Bootloader. - boot = { - loader = { - systemd-boot.enable = true; - efi.canTouchEfiVariables = true; - }; - kernelPackages = pkgs.linuxPackages_latest; - plymouth.enable = true; - kernelParams = [ "quiet" "splash" ]; + bluetooth.settings.General.Name = "saarni"; }; networking = { - nameservers = [ "1.1.1.1#one.one.one.one" "1.0.0.1#one.one.one.one" ]; hostName = "saarni"; - useNetworkd = true; - wireless.iwd.enable = true; }; systemd = { - watchdog = { - device = "/dev/watchdog"; - runtimeTime = "30s"; + services."enable-wifi-on-boot" = { + description = "Enable wifi on boot"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkgs.util-linux}/bin/rfkill unblock all"; + Type = "oneshot"; + }; }; - sleep.extraConfig = "HibernateDelaysSec=90m"; network = { enable = true; wait-online.enable = false; + config = { + networkConfig = { + SpeedMeter = true; + }; + }; networks = { "10-lan" = { - matchConfig.Name = "enp0s20f0u9"; - networkConfig.DHCP = "yes"; + matchConfig = { + Name = "enps0"; + }; + linkConfig = { + Multicast = true; + }; + networkConfig = { + DHCP = true; + IPv6AcceptRA = true; + MulticastDNS = true; + LinkLocalAddressing = "ipv6"; + DNSSEC = true; + UseDomains = true; + }; + dhcpV4Config = { + RouteMetric = 20; + UseDNS = true; + UseMTU = true; + }; + ipv6AcceptRAConfig = { + UseMTU = true; + }; }; - "11-lan" = { - matchConfig.Name = "wlan0"; - networkConfig.DHCP = "yes"; + "11-wlan" = { + matchConfig = { + MACAddress = "64:d6:9a:9e:06:60"; + }; + linkConfig = { + Multicast = true; + }; + networkConfig = { + DHCP = true; + IPv6AcceptRA = true; + MulticastDNS = true; + LinkLocalAddressing = "ipv6"; + DNSSEC = true; + UseDomains = true; + }; + dhcpV4Config = { + RouteMetric = 100; + UseDNS = true; + UseMTU = true; + SendHostname = true; + }; + dhcpV6Config = { + WithoutRA = "solicit"; + }; + ipv6AcceptRAConfig = { + UseMTU = true; + }; }; }; }; }; - system.autoUpgrade = { - enable = true; - }; - - sound.enable = true; - - hardware = { - opengl = { - enable = true; - driSupport = true; - extraPackages = with pkgs; [ - intel-media-driver - libvdpau-va-gl - ]; - }; - bluetooth = { - enable = true; - powerOnBoot = true; - }; - }; - - # Set your time zone. - time.timeZone = "Europe/Helsinki"; - - # Select internationalisation properties. - i18n = { - defaultLocale = "en_US.UTF-8"; - extraLocaleSettings = { - LC_ADDRESS = "fi_FI.UTF-8"; - LC_IDENTIFICATION = "fi_FI.UTF-8"; - LC_MEASUREMENT = "fi_FI.UTF-8"; - LC_MONETARY = "fi_FI.UTF-8"; - LC_NAME = "fi_FI.UTF-8"; - LC_NUMERIC = "fi_FI.UTF-8"; - LC_PAPER = "fi_FI.UTF-8"; - LC_TELEPHONE = "fi_FI.UTF-8"; - LC_TIME = "fi_FI.UTF-8"; - }; - }; - - console.keyMap = "fi"; - - # Define a user account. Don't forget to set a password with ‘passwd’. - users.users.${vars.user} = { - isNormalUser = true; - description = "${vars.name}"; - extraGroups = [ "input" "network" "wheel" ]; - packages = with pkgs; [ ]; - ignoreShellProgramCheck = true; - shell = pkgs.${vars.shell}; - }; - - programs = { - firefox.enable = true; - hyprland.enable = true; - gnupg.agent = { - enable = true; - enableSSHSupport = true; - }; - mtr.enable = true; - }; - environment = { - sessionVariables = { - LIBVA_DRIVER_NAME = "iHD"; - }; - systemPackages = with pkgs; [ - fastfetch - vulkan-tools - libva-utils - wget - curl - git - gzip - btop - glxinfo - sqlite - openssh - gnupg - helix - nixfmt - ]; - etc = lib.mapAttrs' (name: value: { - name = "nix/path/${name}"; - value.source = value.flake; - }) config.nix.registry; - }; - - fonts = { - enableDefaultPackages = true; - packages = with pkgs; [ noto-fonts fira-code fira-code-symbols ]; - fontconfig = { - defaultFonts = { - serif = [ "Noto Serif" ]; - sansSerif = [ "Noto Sans" ]; - monospace = [ "Fira Code" ]; - }; - }; + sessionVariables = { }; }; - # List services that you want to enable: services = { - getty.autologinUser = "petri"; - resolved = { - enable = true; - dnsovertls = "true"; - }; - xserver = { - layout = "fi"; - xkbVariant = "normal"; - }; - pipewire = { + godns = { enable = true; - alsa.enable = true; - pulse.enable = true; - }; - openssh.enable = true; - printing.enable = true; - kmscon = { - enable = true; - hwRender = true; - extraOptions = "--xkb-layout=fi"; - }; - blueman.enable = true; - upower.enable = true; - upower.criticalPowerAction = "Hibernate"; - fstrim.enable = false; - thermald.enable = true; - auto-cpufreq.enable = true; - greetd = { - enable = true; - settings = rec { - initial_session = { - command = "${pkgs.hyprland}/bin/Hyprland"; - user = "petri"; - }; - default_session = initial_session; + settings = { + domains = [ + { + domain_name = "www.duckdns.org"; + sub_domains = [ "saarni" ]; + } + ]; + ip_interface = "wlan0"; + interval = 300; + ip_type = "IPv6"; + login_token_file = config.age.secrets.duckdns.path; + provider = "DuckDNS"; }; }; - }; - - xdg.portal = { - enable = true; - xdgOpenUsePortal = true; - extraPortals = [ - pkgs.xdg-desktop-portal-hyprland - pkgs.xdg-desktop-portal-gtk - ]; - wlr = { + tlp = { enable = true; settings = { - screencast = { - chooser_type = "simple"; - chooser_cmd = "${pkgs.slurp}/bin/slurp -f %o -ro"; - }; + CPU_PERF_POLICY_ON_AC = "performance"; + CPU_PERF_POLICY_ON_BAT = "power"; + CPU_SCALING_GOVERNOR_ON_AC = "performance"; + CPU_SCALING_GOVERNOR_ON_BAT = "powersave"; + START_CHARGE_THRESH_BAT0 = 40; + STOP_CHARGE_TRESH_BAT0 = 20; }; }; + upower = { + enable = true; + criticalPowerAction = "Hibernate"; + }; + thermald.enable = true; }; - - # Open ports in the firewall. - # networking.firewall.allowedTCPPorts = [ ... ]; - # networking.firewall.allowedUDPPorts = [ ... ]; - # Or disable the firewall altogether. - # networking.firewall.enable = false; - - # This value determines the NixOS release from which the default - # settings for stateful data, like file locations and database versions - # on your system were taken. It‘s perfectly fine and recommended to leave - # this value at the release version of the first install of this system. - # Before changing this value read the documentation for this option - # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). - system.stateVersion = "23.11"; # Did you read the comment? + system.stateVersion = "24.05"; } diff --git a/hosts/saarni/hardware-configuration.nix b/hosts/saarni/hardware-configuration.nix index 6aef572..798aa7b 100644 --- a/hosts/saarni/hardware-configuration.nix +++ b/hosts/saarni/hardware-configuration.nix @@ -1,37 +1,72 @@ # Do not modify this file! It was generated by ‘nixos-generate-config’ # and may be overwritten by future invocations. Please make changes # to /etc/nixos/configuration.nix instead. -{ config, lib, pkgs, modulesPath, ... }: - { - imports = - [ (modulesPath + "/installer/scan/not-detected.nix") ]; + config, + lib, + pkgs, + modulesPath, + ... +}: - boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-intel" ]; - boot.extraModulePackages = [ ]; +{ + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; - fileSystems."/" = - { device = "/dev/disk/by-uuid/3968a07a-5e37-4bdb-9e3a-6c74950fd03d"; - fsType = "ext4"; + boot = { + kernelPackages = pkgs.linuxPackages_zen; + initrd = { + availableKernelModules = [ + "xhci_pci" + "thunderbolt" + "nvme" + "usb_storage" + "sd_mod" + "i915" + "cdc_acm" + ]; }; + kernelModules = [ + "kvm-intel" + "iwlwifi" + "iwldvm" + "snd_hda_intel" + "snd_soc_avs" + "snd_sof_pci_intel_tgl" + "tcp_bbr" + ]; + extraModulePackages = [ ]; + kernelParams = [ + "default_hugepagesz=2M" + "i915.enable_guc=3" + "i915.fastboot=1" + "mitigations=off" + "nospectre_v2" + "snd-intel-dspcfg.dsp_driver=3" + "transparent_hugepage=always" + "usbcore.blinkenlights=1" + ]; + extraModprobeConfig = '' + options snd_hda_intel enable=0,1 + ''; + }; - fileSystems."/boot" = - { device = "/dev/disk/by-uuid/9B7E-3D1B"; - fsType = "vfat"; - options = [ "fmask=0022" "dmask=0022" ]; - }; + fileSystems."/" = { + device = "/dev/disk/by-uuid/3968a07a-5e37-4bdb-9e3a-6c74950fd03d"; + fsType = "ext4"; + }; - swapDevices = [ ]; + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/9B7E-3D1B"; + fsType = "vfat"; + options = [ + "fmask=0022" + "dmask=0022" + ]; + }; - # Enables DHCP on each ethernet and wireless interface. In case of scripted networking - # (the default) this is the recommended approach. When using systemd-networkd it's - # still possible to use this option, but it's recommended to use it in conjunction - # with explicit per-interface declarations with `networking.interfaces..useDHCP`. - # networking.useDHCP = lib.mkDefault true; - # networking.interfaces.wlan0.useDHCP = lib.mkDefault true; + hardware.firmware = [ pkgs.sof-firmware ]; + swapDevices = [ ]; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; } diff --git a/hosts/tammi/20-wired.network b/hosts/tammi/20-wired.network new file mode 100644 index 0000000..1a39f55 --- /dev/null +++ b/hosts/tammi/20-wired.network @@ -0,0 +1,31 @@ +# WAN +[Match] +Name=eth0 + +[Network] +DHCP=yes +IPv6PrivacyExtensions=no +IPv6AcceptRA=yes +IPMasquerade=both +DHCPPrefixDelegation=yes +IPForward=yes + +[DHCPv4] +UseMTU=yes +UseDNS=false +UseNTP=false + +[IPv6AcceptRA] +UseMTU=yes +UseDNS=false + +[DHCPv6] +WithoutRA=solicit +PrefixDelegationHint=::/56 +RapidCommit=yes + +[DHCPPrefixDelegation] +UplinkInterface=auto +SubnetId=auto +Announce=yes +Assign=yes diff --git a/hosts/tammi/21-wired.network b/hosts/tammi/21-wired.network new file mode 100644 index 0000000..4ab692d --- /dev/null +++ b/hosts/tammi/21-wired.network @@ -0,0 +1,48 @@ +[Match] +# Name=eth1 - LAN +MACAddress=6c:1f:f7:1b:f2:6c + +[Link] +Multicast=yes + +[Network] +DNS=10.1.1.1#adguard.tammi.cc +DNS=2001:14ba:a304:aff4::1#adguard.tammi.cc +NTP=10.1.1.1 +DHCP=no +LLDP=yes +LLMNR=yes +Address=10.1.1.1/24 +DHCPServer=true +MulticastDNS=true +IPv6SendRA=yes +IPv6AcceptRA=no +IPv6PrefixDelegation=yes +DHCPPrefixDelegation=yes +LinkLocalAddressing=yes +LLMNR=yes +IPForward=yes + +[DHCPServer] +PoolOffset=100 +PoolSize=40 +EmitDNS=yes +EmitNTP=yes +EmitTimezone=yes +DNS=_server_address +NTP=_server_address +DefaultLeaseTimeSec=3600 +MaxLeaseTimeSec=7200 + +[IPv6SendRA] +Managed=yes +OtherInformation=yes +EmitDNS=yes +DNS=_link_local +RouterPreference=high + +[DHCPPrefixDelegation] +UplinkInterface=eth0 +SubnetId=0 +Announce=yes +Assign=yes diff --git a/hosts/tammi/CM3588.md b/hosts/tammi/CM3588.md new file mode 100644 index 0000000..d62780a --- /dev/null +++ b/hosts/tammi/CM3588.md @@ -0,0 +1,284 @@ +--- +title: "Running the gateway for testing" +author: [Petri Hienonen] +date: "2023-03-31" +--- + +# CM3588 setup guide for Debian Bookworm + +[CM3588](https://www.friendlyelec.com/index.php?route=product/product&product_id=294) works as our reference hardware. + +`SDCARD` to `EMMC` image [should be used](https://drive.google.com/file/d/1CrYDAZFwGdZoFIRfrQGEVd6SEu6f0PwU/view) + +[Wiki documents things related to the device installation](https://wiki.friendlyelec.com/wiki/index.php/NanoPi_R5S) + +## Basic configuration + +Login with SSH (Username: `pi`, Password: `pi`) + +`/etc/systemd/network/20-wired.network` + +``` +[Match] +Name=eth0 + +[Network] +DHCP=yes +DNS=8.8.8.8 +MulticastDNS=true + +[Link] +MTUBytes=9000 +``` + +`/etc/systemd/timesyncd.conf` + +``` +[Time] +NTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org 2.arch.pool.ntp.org 3.arch.pool.ntp.org +FallbackNTP=0.pool.ntp.org 1.pool.ntp.org 0.fr.pool.ntp.org +``` + +```bash +sudo apt update && sudo apt dist-upgrade -y && sudo apt autoremove -y +sudo systemctl stop NetworkManager +sudo systemctl disable NetworkManager +sudo apt remove network-manager ntp wpa_supplicant +sudo systemctl enable systemd-timesyncd.service +sudo systemctl start systemd-timesyncd.service +sudo timedatectl set-timezone Europe/Helsinki +``` + +Modify `/etc/hostname` to wanted (tammi.cc). + +Modify `/etc/systemd/journald.conf` (following keys): + +``` +[Journal] +Storage=volatile +SystemMaxUse=20M +RuntimeMaxUse=20M +MaxRetentionSec=2day +``` + +Wireless network configuration (`wlan0` with [`iwd`](https://iwd.wiki.kernel.org/)) + +```bash +sudo apt remove wpasupplicant +sudo apt install iwd +sudo mkdir -p /var/lib/iwd/ +``` + +`/etc/systemd/network/20-wired.network` + +``` +[Match] +Name=eth0 + +[Network] +DHCP=yes +DNSSEC=allow-downgrade +DNS=9.9.9.9 2620:fe::fe +LinkLocalAddresssing=yes +``` + +`/etc/systemd/network/26-wireless.network` + +``` +[Match] +Name=wlan0 + +[Network] +DHCP=yes +DNSSEC=allow-downgrade +DNS=9.9.9.9 2620:fe::fe +LinkLocalAddresssing=yes +``` + +`/var/lib/iwd/example_network.psk`: + +``` +[Security] +Passphrase=Relynx8WP +``` + +```bash +sudo systemctl start iwd.service +sudo systemctl enable iwd.service +sudo systemctl restart systemd-networkd.service +``` + +Create petri user: + +```bash +sudo useradd -m petri +sudo passwd petri (password) +sudo usermod -a -G sudo petri +sudo usermod -a -G systemd-journal petri +sudo chsh -s /bin/bash petri +sudo reboot +``` + +Stop autologin for user `petri` by commenting out user `petri` in `/etc/lightdm/lightdm.conf`. + +Login with `petri` user. + +Check that network looks sane: + +```bash +networkctl status --all +``` + +Delete `pi` user: + +```bash +sudo userdel -r pi +``` + +Create necessary keys and clone and build rust packages: + +```bash +sudo apt install llvm clang libssl-dev -y +curl --proto '=https' --tlsv1.3 -sSf https://sh.rustup.rs | sh +source "$HOME/.cargo/env" +ssh-keygen -t ed25519 +cat .ssh/id_ed25519.pub +``` + +## Applications + +### SSH + +Guideline from: https://infosec.mozilla.org/guidelines/openssh + +```bash +sudo apt install mosh +``` + +### Backports + +```bash +echo "deb http://deb.debian.org/debian bookworm-backports main contrib non-free-firmware">/etc/apt/sources.list.d/debian-12-backports.list +``` + +### BTRFS + +```bash +sudo apt install btrfs-progs +sudo mkfs.btrfs -m raid1 -d raid1 /dev/nvme1n1 /dev/nvme0n1 +sudo mkdir /media/data +echo "UUID=f566eaa0-f004-4acc-9d0d-f6fb97daca5e /media/data btrfs defaults,discard=async,compress=zstd 0 0">>/etc/fstab + +sudo mkdir /media/data/db +sudo chattr -R +C /media/data/db # make the DB not COW + +sudo mkdir /media/data/logs +sudo chattr -R +C /media/data/logs # make the DB not COW +``` + +/etc/systemd/system/btrfs-scrub@.service + +```systemd +[Unit] +Description=Btrfs scrub on %f +ConditionPathIsMountPoint=%f +RequiresMountsFor=%f + +[Service] +Nice=19 +IOSchedulingClass=idle +KillSignal=SIGINT +ExecStart=/usr/bin/btrfs scrub start -B %f +``` + +/etc/systemd/system/btrfs-scrub@.timer + +```systemd +[Unit] +Description=Btrfs scrub on %f twice per month + +[Timer] +OnCalendar=*-*-1,15 +AccuracySec=1d +RandomizedDelaySec=1w +Persistent=true + +[Install] +WantedBy=timers.target +``` + +```bash +sudo systemctl start btrfs-scrub@(systemd-escape -p /media/data).service +sudo systemctl enable --now btrfs-scrub@(systemd-escape -p /media/data).timer +``` + +### Docker + +```bash +sudo apt install docker.io docker-compose +sudo usermod -aG docker $USER +sudo systemctl enable docker.service +``` + +### Postgresql (edit the datapaths) + +```bash +sudo apt install postgresql postgresql-contrib +sudo mkdir /media/data/db/postgresql/16/main +sudo vim /etc/postgresql/16/main/postgresql.conf +sudo chown -R postgres:postgres postgresql/ +``` +Add Environment=PGDATA=/media/data/db/postgresql/%I/main to /lib/systemd/system/postgresql@.service under [Service] + +### Miniflux + +```bash +echo "deb [trusted=yes] https://repo.miniflux.app/apt/ * *" | sudo tee /etc/apt/sources.list.d/miniflux.list > /dev/null +apt update && apt install miniflux +systemctl status miniflux.service + +sudo -u postgres psql +CREATE USER miniflix with PASSWORD 'miniflux'; +CREATE DATABASE miniflux2 OWNER miniflux; +``` + +### Vaultwarden (/etc/vaultwarden): + +```bash +wget -O /etc/apt/trusted.gpg.d/bananian-keyring.gpg https://bitwarden-deb.tech-network.de/bananian-keyring.gpg +echo "deb http://bitwarden-deb.tech-network.de bookworm main" > /etc/apt/sources.list.d/vaultwarden.list +apt update && apt install vaultwarden + +sudo -u postgres psql +CREATE USER vaultwarden WITH ENCRYPTED PASSWORD 'yourpassword'; +CREATE DATABASE vaultwarden OWNER vaultwarden; + +(vaultwarden binary will have to be compiled with hand to enable postgresql, this is irritating) +sudo apt install libpq-dev +(add following systemd service environment variable) +Environment="DATABASE_URL=postgresql://vaultwarden:yourpassword@127.0.0.1:5432/vaultwarden" +systemctl enable vaultwarden.service +``` + +/etc/enviroment + +```bash +PATH="/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin" +``` + +### Webmin + +```bash +curl -o setup-repos.sh https://raw.githubusercontent.com/webmin/webmin/master/setup-repos.sh +sh setup-repos.sh +apt install webmin + +(configure using /etc/webmin/miniserv.conf) +``` + +### Minio + +```bash +wget https://dl.min.io/server/minio/release/linux-arm64/minio_20240611031330.0.0_arm64.deb -O minio.deb +sudo dpkg -i minio.deb +``` diff --git a/hosts/tammi/Caddyfile b/hosts/tammi/Caddyfile new file mode 100644 index 0000000..fe9d437 --- /dev/null +++ b/hosts/tammi/Caddyfile @@ -0,0 +1,319 @@ +# The Caddyfile is an easy way to configure your Caddy web server. +# +# Unless the file starts with a global options block, the first +# uncommented line is always the address of your site. +# +# To use your own domain name (with automatic HTTPS), first make +# sure your domain's A/AAAA DNS records are properly pointed to +# this machine's public IP, then replace ":80" below with your +# domain name. +(cors) { + @cors_preflight method OPTIONS + + header { + Access-Control-Allow-Origin "{header.origin}" + Vary Origin + Access-Control-Expose-Headers "Authorization" + Access-Control-Allow-Credentials "true" + } + + handle @cors_preflight { + header { + Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE" + Access-Control-Max-Age "3600" + } + respond "" 204 + } +} + +{ + metrics + log { + output file /var/log/caddy/caddy_main.log { + roll_size 20MiB + roll_keep 5 + roll_keep_for 100d + } + format json + level INFO + } +} + +tammi.cc { + root * /media/data/hienotammi + file_server browse + encode zstd gzip + log { + output file /media/data/logs/tammi.log { + roll_size 1mb + roll_keep 1 + } + } +} + +holvi.tammi.cc { + root * /media/data/holvi + file_server browse + encode zstd gzip + log { + output file /media/data/logs/holvi.log { + roll_size 1mb + roll_keep 1 + } + } +} + +grafana.tammi.cc { + reverse_proxy 127.0.0.1:3010 + encode zstd gzip + log { + output file /media/data/logs/grafana.log { + roll_size 1mb + roll_keep 1 + } + } +} + +ntfy.tammi.cc { + reverse_proxy 127.0.0.1:3070 + encode zstd gzip + log { + output file /media/data/logs/ntfy.log { + roll_size 1mb + roll_keep 1 + } + } +} + +adguard.tammi.cc { + basic_auth { + petri $2a$14$1gj396cBvvMoC7kW0qSZBOF9Qzwt8ewyujua1EpdDJm9gXdBFsfEe + } + reverse_proxy 127.0.0.1:3000 + encode zstd gzip + log { + output file /media/data/logs/adguard.log { + roll_size 1mb + roll_keep 1 + } + } +} + +n8n.tammi.cc { + reverse_proxy 127.0.0.1:5678 + encode zstd gzip + log { + output file /media/data/logs/n8n.log { + roll_size 1mb + roll_keep 1 + } + } +} + +couch.tammi.cc { + reverse_proxy 127.0.0.1:5984 + encode zstd gzip + log { + output file /media/data/logs/couch.log { + roll_size 1mb + roll_keep 1 + } + } +} + +shiori.tammi.cc { + reverse_proxy 127.0.0.1:7766 + encode zstd gzip + log { + output file /media/data/logs/shiori.log { + roll_size 1mb + roll_keep 1 + } + } +} + +read.tammi.cc { + reverse_proxy 127.0.0.1:7767 + encode zstd gzip + log { + output file /media/data/logs/read.log { + roll_size 1mb + roll_keep 1 + } + } +} + +atuin.tammi.cc { + reverse_proxy 127.0.0.1:4444 + encode zstd gzip + log { + output file /media/data/logs/atuin.log { + roll_size 1mb + roll_keep 1 + } + } +} + +relationship.tammi.cc { + root * /media/data/relationship + file_server + encode zstd gzip + log { + output file /media/data/logs/relationship.log { + roll_size 1mb + roll_keep 1 + } + } +} + +start.tammi.cc { + basic_auth { + petri $2a$14$1gj396cBvvMoC7kW0qSZBOF9Qzwt8ewyujua1EpdDJm9gXdBFsfEe + } + reverse_proxy 127.0.0.1:5555 + encode zstd gzip + log { + output file /media/data/logs/start.log { + roll_size 1mb + roll_keep 1 + } + } +} + +bin.tammi.cc { + reverse_proxy 127.0.0.1:8820 + encode zstd gzip + import cors {header.origin} + log { + output file /media/data/logs/bin.log { + roll_size 1mb + roll_keep 1 + } + } +} + +llm.tammi.cc { + reverse_proxy 127.0.0.1:12500 + encode zstd gzip + log { + output file /media/data/logs/llm.log { + roll_size 1mb + roll_keep 1 + } + } +} + +base.tammi.cc { + reverse_proxy 127.0.0.1:980 + encode zstd gzip + log { + output file /media/data/logs/base.log { + roll_size 1mb + roll_keep 1 + } + } +} + +threat.tammi.cc { + reverse_proxy 127.0.0.1:3050 + encode zstd gzip + log { + output file /media/data/logs/threat.log { + roll_size 1mb + roll_keep 1 + } + } +} + +flux.tammi.cc { + reverse_proxy 127.0.0.1:8080 + encode zstd gzip + log { + output file /media/data/logs/flux.log { + roll_size 1mb + roll_keep 1 + } + } +} + +haku.tammi.cc { + reverse_proxy 127.0.0.1:8888 + encode zstd gzip + log { + output file /media/data/logs/haku.log { + roll_size 1mb + roll_keep 1 + } + } +} + +memos.tammi.cc { + reverse_proxy 127.0.0.1:8081 + encode zstd gzip + log { + output file /media/data/logs/memos.log { + roll_size 1mb + roll_keep 1 + } + } +} + +dav.tammi.cc { + reverse_proxy 127.0.0.1:5232 + encode zstd gzip + log { + output file /media/data/logs/haku.log { + roll_size 1mb + roll_keep 1 + } + } +} + +admin.tammi.cc { + reverse_proxy 127.0.0.1:10000 + encode zstd gzip + log { + output file /media/data/logs/webmin.log { + roll_size 1mb + roll_keep 1 + } + } +} + +minio.tammi.cc { + reverse_proxy localhost:9001 +} + +s3.tammi.cc { + reverse_proxy localhost:9199 +} + +vault.tammi.cc { + encode zstd gzip + reverse_proxy /notifications/hub/negotiate 127.0.0.1:8000 + reverse_proxy /notifications/hub 127.0.0.1:3012 + reverse_proxy 127.0.0.1:8000 { + header_up X-Real-IP {remote_host} + } + log { + output file /media/data/logs/vault.log { + roll_size 1mb + roll_keep 1 + } + } +} + +audio.tammi.cc { + reverse_proxy 127.0.0.1:3333 + encode zstd gzip + log { + output file /media/data/logs/audio.log { + roll_size 1mb + roll_keep 1 + } + } +} + +import conf.d/* + +# Refer to the Caddy docs for more information: diff --git a/hosts/tammi/cgitrc b/hosts/tammi/cgitrc new file mode 100644 index 0000000..caa011d --- /dev/null +++ b/hosts/tammi/cgitrc @@ -0,0 +1,47 @@ +# +# cgit config +# + +# The defaults +#css=/cgit.css +#logo=/cgit.png +cache-size=0 +branch-sort=age +commit-sort=date +max-stats=quarter +root-title=tammi.cc git repositories +robots=noindex, nofollow +snapshots=tar.zst +clone-url=ssh://git@tammi.cc:/git/$CGIT_REPO_URL.git +virtual-root=/ + +# options +enable-index-owner=true +enable-index-links=true +enable-commit-graph=1 +enable-log-filecount=1 +enable-log-linecount=1 +enable-html-serving=1 +enable-http-clone=1 +enable-blame=1 + +# mimes +mimetype.gif=image/gif +mimetype.html=text/html +mimetype.jpg=image/jpeg +mimetype.webp=image/webp +mimetype.jpeg=image/jpeg +mimetype.pdf=application/pdf +mimetype.png=image/png +mimetype.svg=image/svg+xml + +# plugins +head-include=/usr/local/lib/cgit/head_include.html +source-filter=/usr/local/lib/cgit/filters/syntax-highlighting.js +about-filter=/usr/local/lib/cgit/filters/about-formatting-custom.sh +auth-filter=lua:/usr/local/lib/cgit/filters/simple-authentication-modified.lua + +# repositories +readme=:README.adoc +readme=:README.md +remove-suffix=1 diff --git a/hosts/tammi/feeds.opml b/hosts/tammi/feeds.opml new file mode 100644 index 0000000..b0ea84f --- /dev/null +++ b/hosts/tammi/feeds.opml @@ -0,0 +1,118 @@ + + + + Miniflux + Wed, 29 Oct 2025 10:42:41 EET + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hosts/tammi/iptable-nat.service b/hosts/tammi/iptable-nat.service new file mode 100644 index 0000000..f5ecd63 --- /dev/null +++ b/hosts/tammi/iptable-nat.service @@ -0,0 +1,11 @@ +[Unit] +Description=Apply NAT rules for IPv4 +After=network.target + +[Service] +Type=oneshot +ExecStart=/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/hosts/tammi/syntax-highlighting.js b/hosts/tammi/syntax-highlighting.js new file mode 100644 index 0000000..362994a --- /dev/null +++ b/hosts/tammi/syntax-highlighting.js @@ -0,0 +1,23 @@ +#!/usr/bin/node +// Server side syntax highlight with Shiki https://shiki.matsu.io/ +// This script is replacement for pygments/highlight for cgit +// Shiki is installed with `npm install -g shiki` +// input: filename, stdin - source file. Outputs the highligted html to stdout. +import { argv, stdin, stdout } from 'node:process'; +import { codeToHtml } from "/usr/lib/node_modules/shiki/dist/index.mjs"; + +async function highlight(syntax) { + stdin.on("data", async (data) => { + const text = Buffer.from(data).toString("utf8"); + const html = await codeToHtml(text, { + lang: syntax, + theme: "gruvbox-dark-soft" + }); + stdout.write(html); + }); + return true +} + +const filename = argv[1]; +const lang = filename.split(".")[1]; +highlight(lang); diff --git a/roles/shared.nix b/roles/shared.nix new file mode 100644 index 0000000..47aaf6f --- /dev/null +++ b/roles/shared.nix @@ -0,0 +1,818 @@ +{ + pkgs, + vars, + lib, + inputs, + config, + agenix, + ... +}: + +{ + age = { + identityPaths = [ "/home/petri/.ssh/id_ed25519" ]; + secrets = { + s3fs.file = ../secrets/s3fs.age; + duckdns.file = ../secrets/duckdns_login_token.age; + }; + }; + + nixpkgs.config = { + allowUnfree = true; + qt.enable = true; + }; + nix = { + optimise = { + automatic = true; + }; + sshServe = { + trusted = true; + enable = true; + }; + daemonCPUSchedPolicy = "idle"; + daemonIOSchedClass = "idle"; + gc = { + automatic = true; + }; + settings = { + #substituters = [ "https://nix-community.cachix.org" ]; + #trusted-public-keys = [ "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" ]; + trusted-users = [ "${vars.user}" ]; + auto-optimise-store = true; + nix-path = [ "nixpkgs=${pkgs.path}" ]; + experimental-features = "nix-command flakes"; + system-features = [ + "benchmark" + "big-parallel" + "kvm" + "gccarch-x86-64-v3" + ]; + }; + registry = (lib.mapAttrs (_: flake: { inherit flake; })) ( + (lib.filterAttrs (_: lib.isType "flake")) inputs + ); + extraOptions = '' + http2 = true + keep-outputs = true + keep-derivations = true + ''; + }; + system.switch = { + enable = false; + enableNg = true; + }; + + system.activationScripts.diff = { + supportsDryActivation = true; + text = '' + ${pkgs.nvd}/bin/nvd --nix-bin-dir=${pkgs.nix}/bin diff \ + /run/current-system "$systemConfig" + ''; + }; + + zramSwap = { + enable = true; + algorithm = "zstd"; + }; + + boot = { + tmp = { + tmpfsHugeMemoryPages = "within_size"; + useTmpfs = true; + }; + binfmt.emulatedSystems = [ + "aarch64-linux" + "riscv64-linux" + ]; + kernel.sysctl = { + "kernel.sysrq" = 1; + "net.core.netdev_max_backlog" = 25000; + "net.core.rmem_default" = 67108864; # allow network stack 64MB + "net.core.rmem_max" = 67108864; # allow network stack 64MB + "net.core.wmem_default" = 67108864; + "net.core.wmem_max" = 67108864; + "net.core.default_qdisc" = "fq"; + + "net.ipv4.tcp_congestion_control" = "bbr"; + "net.ipv4.tcp_ecn" = 1; + "net.ipv4.tcp_fastopen" = 3; + "net.ipv4.tcp_fin_timeout" = 10; + "net.ipv4.tcp_low_latency" = 1; + "net.ipv4.tcp_mtu_probing" = 2; # recommended for hosts with jumbo frames enabled + "net.ipv4.tcp_no_metrics_save" = 1; + "net.ipv4.tcp_rmem" = "4096 87380 33554432"; # increase Linux autotuning TCP buffer limit to 32MB + "net.ipv4.tcp_slow_start_after_idle" = 0; + "net.ipv4.tcp_syncookies" = 1; + "net.ipv4.tcp_timestamps" = 1; + "net.ipv4.tcp_wmem" = "4096 65536 33554432"; + "net.ipv6.conf.default.accept_ra" = 2; + "net.ipv6.conf.default.router_solicitations" = 3; + "net.ipv6.conf.default.router_solicitation_interval" = 1; + "net.ipv6.conf.default.router_solicitation_delay" = 0; + "net.ipv6.conf.default.dad_transmits" = 1; + "net.ipv6.conf.default.accept_dad" = 1; + "net.ipv6.conf.default.optimistic_dad" = 1; + "net.mptcp.enabled" = 1; + + "vm.nr_hugepages" = 512; + "vm.dirty_background_ratio" = 5; + "vm.swappiness" = 10; + "kernel.sched_wakeup_granularity_ns" = 500000; + }; + loader = { + systemd-boot = { + memtest86.enable = true; + configurationLimit = lib.mkDefault 8; + consoleMode = lib.mkDefault "max"; + enable = true; + }; + efi.canTouchEfiVariables = true; + }; + initrd = { + systemd = { + enable = true; + dbus.enable = true; + network = { + enable = true; + networks."99-dhcp" = { + matchConfig.Name = "*"; + networkConfig.DHCP = "yes"; + }; + }; + }; + }; + }; + + networking = { + nftables.enable = true; + useDHCP = false; + firewall = { + enable = true; + allowPing = true; + allowedTCPPorts = [ + 22 + 443 + 5353 + ]; + }; + wireless.iwd = { + enable = true; + settings = { + Network = { + EnableIPv6 = true; + }; + }; + }; + useNetworkd = true; + nameservers = [ + "2001:14ba:a300:e5ba::1#adguard.tammi.cc" + "87.92.90.90#adguard.tammi.cc" + ]; + }; + + systemd = { + user.tmpfiles.users = { + ${vars.user}.rules = [ "D %C - - - 7d" ]; + }; + tmpfiles.rules = [ + "d /tmp 1777 root root 10d" + "d /run/pam_timestamp 0700 root root -" + ]; + services = { + "systemd-networkd".environment.SYSTEMD_LOG_LEVEL = "debug"; + }; + extraConfig = '' + DefaultTimeoutStopSec=10 + DefaultLimitNOFILE=2048 + ''; + # watchdog = { + # device = "/dev/watchdog"; + # runtimeTime = "30s"; + #}; + sleep.extraConfig = '' + AllowSuspend=yes + AllowHibernation=yes + AllowHybridSleep=yes + AllowSuspendThenHibernate=yes + HibernateDelaySec=3600 + ''; + + services.nix-daemon = { + environment.TMPDIR = "/var/tmp"; + }; + }; + + powerManagement = { + enable = true; + }; + + console = { + font = "${pkgs.tamzen}/share/consolefonts/Tamzen8x16.psf"; + packages = with pkgs; [ tamzen ]; + earlySetup = true; + colors = [ + "3b4252" + "bf616a" + "a3be8c" + "ebcb8b" + "81a1c1" + "b48ead" + "88c0d0" + "e5e9f0" + "4c566a" + "bf616a" + "a3be8c" + "ebcb8b" + "81a1c1" + "b48ead" + "8fbcbb" + "eceff4" + ]; + keyMap = "us"; + }; + + security = { + pam.services = { + hyprlock = { }; + greetd = { + enableGnomeKeyring = true; + }; + }; + polkit = { + enable = true; + extraConfig = '' + polkit.addRule(function(action, subject) { + if (subject.isInGroup("wheel") && subject.local) { + // Always allow local wheel users without password + return polkit.Result.YES; + } + }); + ''; + }; + rtkit.enable = true; + sudo.extraConfig = '' + Defaults timestamp_timeout=60 + ''; + }; + + time.timeZone = "Europe/Helsinki"; + + i18n = { + defaultLocale = "en_US.UTF-8"; + extraLocaleSettings = { + LC_ADDRESS = "fi_FI.UTF-8"; + LC_IDENTIFICATION = "fi_FI.UTF-8"; + LC_MEASUREMENT = "fi_FI.UTF-8"; + LC_MONETARY = "fi_FI.UTF-8"; + LC_NAME = "fi_FI.UTF-8"; + LC_NUMERIC = "fi_FI.UTF-8"; + LC_PAPER = "fi_FI.UTF-8"; + LC_TELEPHONE = "fi_FI.UTF-8"; + LC_TIME = "fi_FI.UTF-8"; + }; + extraLocales = [ "fi_FI.UTF-8/UTF-8" ]; + }; + + users.users.${vars.user} = { + isNormalUser = true; + description = "${vars.name}"; + extraGroups = [ + "adm" + "audio" + "bluetooth" + "input" + "lp" + "network" + "plugdev" + "render" + "systemd-journal" + "video" + "wheel" + "wireshark" + "render" + ]; + ignoreShellProgramCheck = true; + packages = with pkgs; [ + alsa-utils + blis + bluez + bluez-tools + bluez-alsa + glfw + glm + glxinfo + gotop + libva + libva-utils + nixfmt-rfc-style + shaderc.static + shaderc.dev + vulkan-headers + vulkan-loader + vulkan-tools + vulkan-validation-layers + ]; + shell = pkgs.${vars.shell}; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHIXKjutIlv3CS9dmo9bDUUt3UR9O9xUKFXzci3LvNTQ petri.hienonen@gmail.com" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJzUFgqZF3U6RfbvQLKBdzNgWHGp3z+9FGvqjgTY8N6K petri@saarni" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIimbOBDKbTNi8b+P0wWaZRszRV59lnokqrGQRIdgqOj petri@kataja" + ]; + }; + + environment = { + systemPackages = with pkgs; [ + agenix.packages.${system}.default + clinfo + coreutils + curl + git + gnumake + gnupg + greetd.tuigreet + linux-firmware + lm_sensors + mimalloc + minio-client + neovim + nvd + procps + s3fs + sysfsutils + unrar + unzip + usbutils + zstd + ]; + variables = { + EDITOR = "${pkgs.neovim}/bin/nvim"; + LD_LIBRARY_PATH = "${pkgs.vulkan-loader}/lib:$LD_LIBRARY_PATH"; + NIXPKGS_ALLOW_UNFREE = 1; + QT_QPA_PLATFORM = "xcb"; + SYSTEMD_COLORS = 256; + SYSTEMD_LOG_COLOR = 1; + SYSTEMD_URLIFY = 1; + VULKAN_SDK = "${pkgs.vulkan-headers}"; + }; + }; + + fileSystems."/media/llm" = { + device = "llm"; + fsType = "fuse./run/current-system/sw/bin/s3fs"; + noCheck = true; + options = [ + "_netdev" + "allow_other" + "umask=0007" + "uid=1000" + "use_path_request_style" + "url=https://s3.tammi.cc" + "passwd_file=${config.age.secrets.s3fs.path}" + ]; + }; + + fileSystems."/media/skydrive" = { + device = "skydrive"; + fsType = "fuse./run/current-system/sw/bin/s3fs"; + noCheck = true; + options = [ + "_netdev" + "allow_other" + "umask=0007" + "uid=1000" + "use_path_request_style" + "url=https://s3.tammi.cc" + "passwd_file=${config.age.secrets.s3fs.path}" + ]; + }; + + fonts = { + enableDefaultPackages = true; + packages = with pkgs; [ + nerd-fonts.iosevka + nerd-fonts.iosevka-term + nerd-fonts.zed-mono + nixos-icons + roboto-serif + roboto-mono + roboto-flex + twitter-color-emoji + ]; + fontDir.enable = true; + fontconfig = { + enable = true; + hinting = { + enable = true; + autohint = true; + style = "medium"; + }; + useEmbeddedBitmaps = true; + cache32Bit = true; + antialias = true; + subpixel = { + rgba = lib.mkDefault "rgb"; + lcdfilter = "default"; + }; + defaultFonts = { + serif = [ "Roboto Serif" ]; + sansSerif = [ "Roboto Flex" ]; + monospace = [ "Iosevka Nerd Font" ]; + emoji = [ "Twitter Color Emoji" ]; + }; + }; + }; + + programs = { + ssh = { + extraConfig = '' + Compression = yes + ControlMaster = yes + Protocol = 2 + ServerAliveInterval = 1 + ServerAliveCountMax = 3 + TCPKeepAlive = yes + ''; + hostKeyAlgorithms = [ + "ssh-ed25519-cert-v01@openssh.com" + "ssh-rsa-cert-v01@openssh.com" + "ssh-ed25519" + "ssh-rsa" + "ecdsa-sha2-nistp521-cert-v01@openssh.com" + "ecdsa-sha2-nistp384-cert-v01@openssh.com" + "ecdsa-sha2-nistp256-cert-v01@openssh.com" + "ecdsa-sha2-nistp521" + "ecdsa-sha2-nistp384" + "ecdsa-sha2-nistp256" + ]; + kexAlgorithms = [ + "curve25519-sha256@libssh.org" + "ecdh-sha2-nistp521" + "ecdh-sha2-nistp384" + "ecdh-sha2-nistp256" + "diffie-hellman-group-exchange-sha256" + ]; + macs = [ + "hmac-sha2-512-etm@openssh.com" + "hmac-sha2-256-etm@openssh.com" + "umac-128-etm@openssh.com" + "hmac-sha2-512" + "hmac-sha2-256" + "umac-128@openssh.com" + ]; + ciphers = [ + "chacha20-poly1305@openssh.com" + "aes256-gcm@openssh.com" + "aes128-gcm@openssh.com" + "aes256-ctr" + "aes192-ctr" + "aes128-ctr" + ]; + + }; + arp-scan.enable = true; + appimage = { + enable = true; + binfmt = true; + }; + ccache.enable = true; + wireshark.enable = true; + command-not-found.enable = false; # enabled by default, does not work with flakes + dconf.enable = true; # needed by gnome application, such as firefox + mosh = { + enable = true; + withUtempter = true; + openFirewall = true; + }; + xwayland.enable = true; + gnupg.agent = { + enable = true; + enableSSHSupport = true; + }; + alvr = { + enable = true; + openFirewall = true; + }; + gamescope = { + enable = true; + }; + steam = { + enable = true; + gamescopeSession.enable = true; + remotePlay.openFirewall = true; # Open ports in the firewall for Steam Remote Play + dedicatedServer.openFirewall = true; # Open ports in the firewall for Source Dedicated Server + localNetworkGameTransfers.openFirewall = true; # Open ports in the firewall for Steam Local Network Ga + extraCompatPackages = [ pkgs.proton-ge-bin ]; + }; + }; + + systemd.network.networks."50-bluetooth-pan" = { + matchConfig.Name = "bnep*"; + networkConfig = { + DHCP = true; + IPv6AcceptRA = true; + }; + }; + + hardware = { + enableAllFirmware = true; + enableRedistributableFirmware = true; + graphics = { + enable = true; + }; + bluetooth = { + enable = true; + powerOnBoot = true; + settings = { + General = { + ControllerMode = "bredr"; + DiscoverableTimeout = 0; + Experimental = true; + FastConnectable = true; + JustWorksRepairing = "always"; + KernelExperimental = true; + MultiProfile = "multiple"; + Privacy = "off"; + Testing = true; + }; + Policy = { + AutoEnable = true; + }; + LE = { + ConnectionLatency = 0; + ConnectionSupervisionTimeout = 2000; + EnableAdvMonInterleaveScan = 1; + MaxConnectionInterval = 16; + MinConnectionInterval = 16; + ScanIntervalAutoConnect = 300; + }; + GATT = { + Channels = 6; + }; + }; + }; + }; + + services = { + pipewire = { + enable = true; + alsa.enable = true; + pulse = { + enable = true; + + }; + audio.enable = true; + wireplumber = { + enable = true; + extraConfig = { + "10-bluez" = { + "monitor.bluez.properties" = { + "bluez5.enable-sbc-xq" = true; + "bluez5.enable-msbc" = true; + "bluez5.enable-hw-volume" = true; + "bluez5.roles" = [ + "hsp_hs" + "hsp_ag" + "hfp_hf" + "hfp_ag" + ]; + }; + }; + }; + }; + extraConfig.pipewire-pulse = { + "switch-on-connect.conf" = { + "pulse.cmd" = [ + { + cmd = "load-module"; + args = "module-switch-on-connect"; + } + ]; + }; + }; + }; + libinput = { + enable = true; + }; + geoclue2 = { + package = pkgs.geoclue2-with-demo-agent; + enableDemoAgent = true; + enable = true; + }; + systembus-notify.enable = true; + dbus = { + implementation = "broker"; + packages = [ pkgs.bluez ]; + }; + timesyncd = { + enable = true; + servers = [ + "time1.mikes.fi" + "time2.mikes.fi" + ]; + }; + printing.enable = true; + upower = { + enable = true; + }; + devmon.enable = true; # automatic device mounting daemon + journald = { + audit = true; + extraConfig = '' + ReadKMsg=1 + SystemMaxUse=200M + ''; + }; + xserver = { + enable = true; # Required by steam + xkb = { + layout = "us"; + variant = ""; + }; + updateDbusEnvironment = true; + }; + udev.extraRules = '' + # Blinkstick nano + SUBSYSTEM=="usb", ATTR{idVendor}=="20a0", ATTR{idProduct}=="41e5", MODE:="0666" + # ESP32 waveshare + SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="55d3", MODE:="0666" + ''; + getty.autologinUser = "${vars.user}"; + kmscon = { + enable = true; + hwRender = true; + extraOptions = "--xkb-layout=fi"; + fonts = [ + { + name = "Iosevka Nerd Font"; + package = pkgs.nerd-fonts.iosevka; + } + ]; + }; + openssh = { + enable = true; + openFirewall = true; + settings = { + UseDns = true; + AllowUsers = [ "petri" ]; + KexAlgorithms = [ + "curve25519-sha256@libssh.org" + "ecdh-sha2-nistp521" + "ecdh-sha2-nistp384" + "ecdh-sha2-nistp256" + "diffie-hellman-group-exchange-sha256" + ]; + Ciphers = [ + "chacha20-poly1305@openssh.com" + "aes256-gcm@openssh.com" + "aes128-gcm@openssh.com" + "aes256-ctr" + "aes192-ctr" + "aes128-ctr" + ]; + Macs = [ + "hmac-sha2-512-etm@openssh.com" + "hmac-sha2-256-etm@openssh.com" + "umac-128-etm@openssh.com" + "hmac-sha2-512" + "hmac-sha2-256" + "umac-128@openssh.com" + ]; + PermitRootLogin = "no"; + PasswordAuthentication = false; + }; + extraConfig = '' + ClientAliveCountMax 0 + ClientAliveInterval 300 + + LoginGraceTime 60 + AllowTcpForwarding no + AllowAgentForwarding no + MaxAuthTries 3 + MaxSessions 2 + TCPKeepAlive no + ''; + }; + earlyoom = { + enableNotifications = true; + enable = true; + }; + ananicy = { + enable = true; + package = pkgs.ananicy-cpp; + rulesProvider = pkgs.ananicy-rules-cachyos; + }; + fwupd = { + enable = true; + extraRemotes = [ "lvfs-testing" ]; + }; + resolved = { + enable = true; + dnssec = "true"; + llmnr = "true"; + dnsovertls = "true"; + domains = [ "~." ]; + extraConfig = '' + MulticastDNS=true + Cache=no-negative + ''; + fallbackDns = [ + "2606:4700:4700::1111#cloudflare-dns.com" + "2606:4700:4700::1001#cloudflare-dns.com" + "1.1.1.1#cloudflare-dns.com" + "1.0.0.1#cloudflare-dns.com" + "9.9.9.9#dns.quad9.net" + "149.112.112.112#dns.quad9.net" + ]; + }; + fstrim.enable = true; + smartd = { + notifications = { + test = true; + systembus-notify.enable = true; + }; + enable = true; + }; + greetd = { + enable = true; + vt = 1; + restart = true; + settings = { + initial_session = { + command = "/etc/greetd/hyprland-wrapper.sh"; + user = "${vars.user}"; + }; + default_session = { + command = "${pkgs.greetd.tuigreet}/bin/tuigreet --cmd /etc/greetd/hyprland-wrapper.sh"; + }; + }; + }; + }; + + environment.etc = { + "greetd/hyprland-wrapper.sh" = { + text = '' + #!/bin/sh + # Session + export XDG_SESSION_TYPE=wayland + export XDG_SESSION_DESKTOP=Hyprland + export XDG_CURRENT_DESKTOP=Hyprland + + # Wayland stuff + export MOZ_ENABLE_WAYLAND=1 + export QT_QPA_PLATFORM=wayland + export SDL_VIDEODRIVER=wayland + + dbus-run-session ${pkgs.hyprland}/bin/Hyprland + ''; + mode = "0755"; + }; + "bluetooth-tether.sh" = { + mode = "0755"; + text = '' + #!/bin/sh + DEVICE_MAC="3C:01:EF:D9:0D:96" # Phone shares the internet + ADAPTER="hci0" # Replace if your adapter is different (check with `bluetoothctl list`) + + # Ensure Bluetooth is powered on + ${pkgs.bluez}/bin/bluetoothctl power on + + # Scan for the device briefly (5 seconds) + ${pkgs.bluez}/bin/bluetoothctl scan on & + sleep 5 + ${pkgs.bluez}/bin/bluetoothctl scan off + + # Check if the device is present + if ${pkgs.bluez}/bin/bluetoothctl devices | grep -q "$DEVICE_MAC"; then + echo "Device $DEVICE_MAC found, attempting to connect to NAP..." + # Ensure device is trusted (optional, for reliability) + ${pkgs.bluez}/bin/bluetoothctl trust "$DEVICE_MAC" + # Connect to NAP profile + ${pkgs.dbus}/bin/dbus-send --system --type=method_call --dest=org.bluez \ + /org/bluez/$ADAPTER/dev_$(echo $DEVICE_MAC | tr ':' '_') \ + org.bluez.Network1.Connect string:'nap' || { + echo "Failed to connect to NAP for $DEVICE_MAC" + exit 1 + } + echo "Connected to NAP for $DEVICE_MAC" + else + echo "Device $DEVICE_MAC not found, skipping connection" + exit 0 + fi + ''; + }; + }; + + systemd.services.bluetooth-tether = { + description = "Auto-connect to Bluetooth tethering PAN if device is detected"; + after = [ "bluetooth.service" ]; + partOf = [ "bluetooth.service" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "/etc/bluetooth-tether.sh"; + RemainAfterExit = true; + Restart = "on-failure"; + RestartSec = "30s"; # Retry every 30 seconds if the device isn't found + }; + }; +} diff --git a/roles/wallpaper.nix b/roles/wallpaper.nix new file mode 100644 index 0000000..3cc4f91 --- /dev/null +++ b/roles/wallpaper.nix @@ -0,0 +1,23 @@ +{ pkgs, ... }: + +{ + systemd.user.services.wallpaper = { + description = "wallpaper"; + script = '' + ${pkgs.hyprland}/bin/hyprctl hyprpaper wallpaper ,$(find -L /etc/nixos/home/wallpapers -type f | shuf -n 1) + ''; + serviceConfig = { + Type = "oneshot"; + }; + }; + + systemd.user.timers.wallpaper = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnBootSec = "10m"; + OnUnitActiveSec = "10m"; + Unit = "wallpaper.service"; + Persistent = true; + }; + }; +} diff --git a/secrets/duckdns_login_token.age b/secrets/duckdns_login_token.age new file mode 100644 index 0000000..a290de2 Binary files /dev/null and b/secrets/duckdns_login_token.age differ diff --git a/secrets/gmail.age b/secrets/gmail.age new file mode 100644 index 0000000..f9a3540 --- /dev/null +++ b/secrets/gmail.age @@ -0,0 +1,9 @@ +age-encryption.org/v1 +-> ssh-ed25519 SIk9MQ tG2XMK92K0BS4+6D/7f2FFnhx/XFcn0bc0qryrLZnkI +Dbl424Y2izE9qTENo0oC+KA7arK3jxs1sCmolpO7L4I +-> ssh-ed25519 nivnYg xhC2zowQQPKWIJFphgHCWK6Fv3or4gEWMmrq+Xt+wl4 +6PoyXh+MZ3uL9eds8R2w50o9qb+i0elB7eunKMzJImE +-> ssh-ed25519 egf4NA hceSfAb5vAGGor4zXLtQQrD64HygN13KTye6b58BFT0 +ua1LO4Y7gYhNhMGJ9nAG/f0OtQw7WygPoUsIGKTLee0 +--- AtIO61YC+CUcWLsk/3d8QiCOJo5NTnIn78cFg0MMiNg +^ؙ 04ɭFDc봮D'('ჲJk \ No newline at end of file diff --git a/secrets/miniflux_api_key.age b/secrets/miniflux_api_key.age new file mode 100644 index 0000000..2f53644 --- /dev/null +++ b/secrets/miniflux_api_key.age @@ -0,0 +1,9 @@ +age-encryption.org/v1 +-> ssh-ed25519 SIk9MQ BRp0yTco5Q4sOac5hFEUhBjaHppmvCTbXlduXRfJAjM +/tzdOv1JdMS/+wPEG14Os2e+msjTB0kE/BPBrCWeCUc +-> ssh-ed25519 egf4NA wLPwP/TzjstOjWp0YuM0qbPfjXBfW6vzI9RY6Kj3X2g +XjjDmWVo9I+cat4FnEIAiyOwXe5aG0AJW65m++Elby0 +-> ssh-ed25519 nivnYg 20vbXcFIy2mHpfVdwu/cQWydnJ4VGrETDEs1sjiKQD4 +x6dD/2btPNAyEU1oNFiBkLw9+I1bqU88NzJSuE0RNyI +--- xFZP/xTVMWe4RwhNB+RyjcNrkwVEPNpnzExx5uNuiOw +2$|*)lP<ɢi/dRzZf{t҃4ŚAD&ړ \ No newline at end of file diff --git a/secrets/openai_auth_token.age b/secrets/openai_auth_token.age new file mode 100644 index 0000000..0573d6d Binary files /dev/null and b/secrets/openai_auth_token.age differ diff --git a/secrets/relesoft.age b/secrets/relesoft.age new file mode 100644 index 0000000..1cd16d5 --- /dev/null +++ b/secrets/relesoft.age @@ -0,0 +1,9 @@ +age-encryption.org/v1 +-> ssh-ed25519 SIk9MQ hWfgfvibzmIpL5CVharIXW2qX6NN4ti/IWaxNBfCOlA +BJ2KsVFx/1Ra/gUfFSGqDH2xGtj3ZUCR2JtO9upObCM +-> ssh-ed25519 nivnYg +xvAmrXobATO5hswYotmBrJh40RpCi8UIQ8JBl1YVG4 +Q11BE4UCgmv/c9VQeUuKa97J/JmWB4v+YoxHIa9/EQE +-> ssh-ed25519 egf4NA IgVPAbf5pz/WvI7uI56VKAhtQbCm0A6R8e1QC1nXE0c +EGb0U+QxTREl4HhWxMLMZcqFsRKEXMqZRRSKdEhdYUU +--- +Sgmew6pn5ttSrqMwGIeWYZ1chQGUzDTRGvHJmBkDNA +?q8UgьeCsЗTEp'ZKo \ No newline at end of file diff --git a/secrets/relesoft_cargo_token.age b/secrets/relesoft_cargo_token.age new file mode 100644 index 0000000..b57354a --- /dev/null +++ b/secrets/relesoft_cargo_token.age @@ -0,0 +1,9 @@ +age-encryption.org/v1 +-> ssh-ed25519 SIk9MQ 6JF0u8WRDM26eTMxB8RHy7gHGD5DyVQO04BUjI8FKFI +rUSvDpdnbIjeDssPhJ4y3jiuwXfkda42gpRlb5MwZVE +-> ssh-ed25519 egf4NA 2M5u3dE0K0IODav88dkVu3TAfsv1upra3+TtY6eFYFM +gFcQyRADiG0ruf7OLBrUxOiXMkptpsm7Zo770xdtAnA +-> ssh-ed25519 nivnYg OucwYuH7Z6Ih+lUGEPSs1oh/ZsuqrDHttNVyzR5iXnM +zavvC+0FtsSAVMcpang0rY7MvWqEG92RZOdozOljb1s +--- LFI08syDoP7BhDymUtGSj26rlvlAIywYrDKs3Ff30N0 +eRBcT|m߹x*!VVn%ï0t([>ŴKyn.:Ԋ_45fh:l \ No newline at end of file diff --git a/secrets/s3fs.age b/secrets/s3fs.age new file mode 100644 index 0000000..49e782e Binary files /dev/null and b/secrets/s3fs.age differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix new file mode 100644 index 0000000..59159ec --- /dev/null +++ b/secrets/secrets.nix @@ -0,0 +1,21 @@ +let + katajaHostPub = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJzUFgqZF3U6RfbvQLKBdzNgWHGp3z+9FGvqjgTY8N6K petri@saarni"; + pihlajaHostPub = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIimbOBDKbTNi8b+P0wWaZRszRV59lnokqrGQRIdgqOj petri@kataja"; + saarniHostPub = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHIXKjutIlv3CS9dmo9bDUUt3UR9O9xUKFXzci3LvNTQ petri.hienonen@gmail.com"; + systems = [ + katajaHostPub + pihlajaHostPub + saarniHostPub + ]; +in +{ + "duckdns_login_token.age".publicKeys = systems; + "gmail.age".publicKeys = systems; + "miniflux_api_key.age".publicKeys = systems; + "openai_auth_token.age".publicKeys = systems; + "relesoft.age".publicKeys = systems; + "relesoft_cargo_token.age".publicKeys = systems; + "s3fs.age".publicKeys = systems; + "shiori_password.age".publicKeys = systems; + "unsplash_access_key.age".publicKeys = systems; +} diff --git a/secrets/shiori_password.age b/secrets/shiori_password.age new file mode 100644 index 0000000..ab0f3c2 --- /dev/null +++ b/secrets/shiori_password.age @@ -0,0 +1,10 @@ +age-encryption.org/v1 +-> ssh-ed25519 SIk9MQ NH850utZIMxFFNAZCZHsyjL5f+t3TnhThtVnExWpEHk +uYEf+jtdqZcr39Yj2vmBZap6lUVdHKSV3O0MYwFk2Xc +-> ssh-ed25519 egf4NA bUcc1F73WG3Jc5BxjG8L4w88uJsY+SbrXO5Yb1ZMzEw +uAiwubSlvXV+hH2qgQEEUNB69uEVISRgQzluIoV80Jc +-> ssh-ed25519 nivnYg 4Bzp4S/J17xt3pG8L70Kw5rtBjL+Q9r9mnjSMw6FV30 +TALKdu7Xn+p/p6aUifBCoEzian4IEWwYbx7F7X2CLBE +--- yD8ik0HkBt4IcbZxuH5R7Jqk2mqyCOfzqQ+WkI5Orv4 +Q@Øwg7#B) +U'B_λQy diff --git a/secrets/unsplash_access_key.age b/secrets/unsplash_access_key.age new file mode 100644 index 0000000..72dd04c Binary files /dev/null and b/secrets/unsplash_access_key.age differ -- cgit v1.2.3-70-g09d2