diff --git a/AGENTS.md b/AGENTS.md index 326678b..f70d7a4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,7 +9,7 @@ Instrucoes para agentes trabalhando neste repositorio. ## Estrutura - `hosts/Nixos/configuration.nix`: configuracao principal do sistema. - `hosts/Nixos/hardware-configuration.nix`: gerado pelo NixOS; edite somente se solicitado. -- `nixos/secrets.nix`: legado (nao usado mais). +- `secrets/secrets.nix`: regras do agenix (sem segredos em texto puro). - `secrets/secrets.nix`: regras do agenix (sem segredos em texto puro). - `configs/hypr/hyprland.conf`: configuracao do Hyprland. - `configs/hypr/hyprpaper.conf`: wallpaper do Hyprpaper. diff --git a/configs/doom/config.el b/configs/doom/config.el new file mode 100644 index 0000000..8675a58 --- /dev/null +++ b/configs/doom/config.el @@ -0,0 +1,175 @@ +;; (setq default-frame-alist '((undecorated . t))) +;;; $DOOMDIR/config.el -*- lexical-binding: t; -*- + +;; Place your private configuration here! Remember, you do not need to run 'doom +;; sync' after modifying this file! + + +;; Some functionality uses this to identify you, e.g. GPG configuration, email +;; clients, file templates and snippets. +(setq user-full-name "Lucas Tadeu Marculino" + user-mail-address "ltadeu6@pm.ne") + +(setq vterm-shell "fish") +(setq doom-modeline-major-mode-icon t) + +(after! orderless + (setq completion-styles '(orderless basic) + completion-category-defaults nil + completion-category-overrides '((file (styles partial-completion))))) + +;; Doom exposes five (optional) variables for controlling fonts in Doom. Here +;; are the three important ones: +;; +;; + `doom-font' +;; + `doom-variable-pitch-font' +;; + `doom-big-font' -- used for `doom-big-font-mode'; use this for +;; presentations or streaming. +;; +;; (setq doom-font (font-spec :family "FiraCode Nerd Font Mono" :size 17) +;; doom-variable-pitch-font (font-spec :family "Fira Code Symbol" :size 15) +;; doom-big-font (font-spec :family "FiraCode Nerd Font Mono" :size 24)) +(after! doom-themes + (setq doom-themes-enable-bold t + doom-themes-enable-italic t)) +(after! org + (require 'org-ref)) +;; lambda +(custom-set-faces! + '(font-lock-comment-face :slant italic) + '(font-lock-keyword-face :slant italic)) +(setq global-prettify-symbols-mode t) ; +;; They all accept either a font-spec, font string ("Input Mono-12"), or xlfd +;; font string. You generally only need these two: +(setq doom-font (font-spec :family "FiraCode Nerd Font Mono" :size 18 :weight 'Light) + doom-variable-pitch-font (font-spec :family "FiraCode Nerd Font Mono" :size 22) + ) + +;; There are two ways to load a theme. Both assume the theme is installed and +;; available. You can either set `doom-theme' or manually load a theme with the +;; `load-theme' function. This is the default: +;; (setq doom-theme 'doom-monokai-spectrum) +;; (setq doom-theme 'doom-city-lights) +(setq doom-theme 'doom-dracula) +;; deep +;; moonlight +;; grass +;; (setq doom-theme 'xresources) +(add-to-list 'default-frame-alist '(alpha-background . 90)) +;; (after! org +;; (use-package! org-ref +;; :config (progn +;; (require 'org-ref-pdf) +;; (require 'org-ref-bibtex) +;; (require 'org-ref-url-utils)))) +;; (org-ref-define-citation-link "citeonline" ?o)) + +;; (setq reftex-default-bibliography '("~/Modelos/org-abntex2-utfpr/references.bib")) +;; (setq org-ref-default-bibliography '("~Modelos/org-abntex2-utfpr/references.bib")) + +;; If you use `org' and don't want your org files in the default location below, +;; change `org-directory'. It must be set before org loads! +;; (setq org-directory "~/Documentos/org/" +;; org-journal-dir "~/Documentos/org/journal/") + +;; This determines the style of line numbers in effect. If set to `nil', line +;; numbers are disabled. For relative line numbers, set this to `relative'. +(setq display-line-numbers-type 'relative) + +;; (setq org-agenda-include-diary t) +;; Here are some additional functions/macros that could help you configure Doom: +;; +;; - `load!' for loading external *.el files relative to this one +;; - `use-package!' for configuring packages +;; - `after!' for running code after a package has loaded +;; - `add-load-path!' for adding directories to the `load-path', relative to +;; this file. Emacs searches the `load-path' when you load packages with +;; `require' or `use-package'. +;; - `map!' for binding new keys +;; +;; To get information about any of these functions/macros, move the cursor over +;; the highlighted symbol at press 'K' (non-evil users must press 'C-c c k'). +;; This will open documentation for it, including demos of how they are used. +;; +;; You can also try 'gd' (or 'C-c c d') to jump to their definition and see how +;; they are implemented. +;; (use-package! org-ref +;; :after org +;; :init +;; ; code to run before loading org-ref +;; ;; (setq org-latex-pdf-process +;; ;; '("pdflatex -interaction nonstopmode -output-directory %o %f" +;; ;; "bibtex %b" +;; ;; "pdflatex -interaction nonstopmode -output-directory %o %f" +;; ;; "pdflatex -interaction nonstopmode -output-directory %o %f")) +;; ;; :config (progn +;; ;; (require 'org-ref-pdf) +;; ;; ;; (require 'org-ref-bibtex) +;; ;; (require 'org-ref-url-utils)) +;; ) +(setq system-time-locale "C") +;;cc lsp server whith clangd + +(setq lsp-clients-clangd-args '("-j=3" + "--background-index" + "--clang-tidy" + "--completion-style=detailed" + "--header-insertion=never" + "--header-insertion-decorators=0")) +(after! lsp-clangd (set-lsp-priority! 'clangd 2)) + + +(after! persp-mode + (setq persp-emacsclient-init-frame-behaviour-override "main")) + +(after! pdf-tools + (setq pdf-view-midnight-colors '("#f8f8f2" . "#272935"))) + +(setq +latex-viewers '(pdf-tools)) + +;; (setq +latex-viewers '(zathura)) +;; (add-hook 'pdf-tools-enabled-hook 'pdf-view-midnight-minor-mode) +;; (add-hook 'pdf-tools-enabled-hook 'pdf-view-fit-width-to-window) + +;; (after! projectile (setq projectile-project-root-files-bottom-up (remove +;; ".git" projectile-project-root-files-bottom-up))) + +;; (setq +format-on-save-enabled-modes '(not python-mode)) + +(after! dap-mode + (setq dap-python-debugger 'debugpy)) + +(setq doom-themes-treemacs-theme "doom-dracula") + +(with-eval-after-load 'ox-latex + (add-to-list 'org-latex-classes + '("abntex2" + "\\documentclass{abntex2} +\\usepackage[alf]{abntex2cite} +\\renewcommand{\\maketitlehookb}{}" + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}") + ("\\paragraph{%s}" . "\\paragraph*{%s}") + ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))) + +;; (assoc-delete-all "Open documentation" +doom-dashboard-menu-sections) +;; (assoc-delete-all "Reload last session" +doom-dashboard-menu-sections) +;; (assoc-delete-all "Jump to bookmark" +doom-dashboard-menu-sections) +;; (assoc-delete-all "Open org-agenda" +doom-dashboard-menu-sections) +;; (assoc-delete-all "Open private configuration" +doom-dashboard-menu-sections) +;; (assoc-delete-all "Recently opened files" +doom-dashboard-menu-sections) +(remove-hook '+doom-dashboard-functions #'doom-dashboard-widget-shortmenu) +(remove-hook '+doom-dashboard-functions #'doom-dashboard-widget-footer) + +(setq shell-file-name (executable-find "bash")) + + +;; (setq fancy-splash-image "~/.doom.d/doom.svg") + + +(setq httpd-port 1234) + +(after! lsp-mode + (setq lsp-semantic-tokens-enable t)) +(setq tree-sitter-hl-use-font-lock-keywords t) diff --git a/configs/doom/init.el b/configs/doom/init.el new file mode 100644 index 0000000..733079f --- /dev/null +++ b/configs/doom/init.el @@ -0,0 +1,209 @@ +;;; init.el -*- lexical-binding: t; -*- + +;; This file controls what Doom modules are enabled and what order they load +;; in. Remember to run 'doom sync' after modifying it! + +;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's +;; documentation. There you'll find a "Module Index" link where you'll find +;; a comprehensive list of Doom's modules and what flags they support. + +;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or +;; 'C-c c k' for non-vim users) to view its documentation. This works on +;; flags as well (those symbols that start with a plus). +;; +;; Alternatively, press 'gd' (or 'C-c c d') on a module to browse its +;; directory (for easy access to its source code). + +(doom! :input + ;;chinese + ;;japanese + ;;layout ; auie,ctsrnm is the superior home row + + :completion + ;; (company +tng +childframe) ; the ultimate code completion backend + ;;helm ; the *other* search engine for love and life + ;;ido ; the other *other* search engine... + ;; (ivy +icons + ;; +fuzzy + ;; +prescient + ;; ) ; a search engine for love and life + (vertico +icons) + (corfu +icons) + + :ui + ;;deft ; notational velocity for Emacs + doom ; what makes DOOM look the way it does + doom-dashboard ; a nifty splash screen for Emacs + doom-quit ; DOOM quit-message prompts when you quit Emacs + (emoji +unicode + +ascii + +github) ; πŸ™‚ + ;;fill-column ; a `fill-column' indicator + hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW + hydra + indent-guides ; highlighted indent columns + (ligatures +fira) ; ligatures and symbols to make your code pretty again + ;;minimap ; show a map of the code on the side + modeline ; snazzy, Atom-inspired modeline, plus API + ;;nav-flash ; blink cursor line after big motions + ;;neotree ; a project drawer, like NERDTree for vim + ophints ; highlight the region an operation acts on + (popup +defaults) ; tame sudden yet inevitable temporary windows + ;;tabs ; a tab bar for Emacs + (treemacs +lsp) ; a project drawer, like neotree but cooler + ;;unicode ; extended unicode support for various languages + ;;vc-gutter ; vcs diff in the fringe + vi-tilde-fringe ; fringe tildes to mark beyond EOB + window-select ; visually switch windows + workspaces ; tab emulation, persistence & separate workspaces + zen ; distraction-free coding or writing + + :editor + (evil +everywhere); come to the dark side, we have cookies + file-templates ; auto-snippets for empty files + fold ; (nigh) universal code folding + (format +onsave) ; automated prettiness + ;;god ; run Emacs commands without modifier keys + ;;lispy ; vim for lisp, for people who don't like vim + multiple-cursors ; editing in many places at once + ;;objed ; text object editing for the innocent + ;;parinfer ; turn lisp into python, sort of + ;;rotate-text ; cycle region at point between text candidates + snippets ; my elves. They type so I don't have to + word-wrap ; soft wrapping with language-aware indent + + :emacs + (dired + +icons) ; making dired pretty [functional] + electric ; smarter, keyword-based electric-indent + (ibuffer +icons) ; interactive buffer management + undo ; persistent, smarter undo for your inevitable mistakes + vc ; version-control and Emacs, sitting in a tree + + :term + eshell ; the elisp shell that works everywhere + ;; shell ; simple shell REPL for Emacs + ;; term ; basic terminal emulator for Emacs + vterm ; the best terminal emulation in Emacs + + :checkers + syntax ; tasing you for every semicolon you forget + (spell +flyspell) ; tasing you for misspelling mispelling + grammar ; tasing grammar mistake every you make + + :tools + (lsp +peek) + ;;ansible + debugger ; FIXME stepping through code, to help you add bugs + ;;direnv + ;;docker + editorconfig ; let someone else argue about tabs vs spaces + ;;ein ; tame Jupyter notebooks with emacs + (eval +overlay) ; run code, run (also, repls) + ;;gist ; interacting with github gists + (lookup +dictionary) ; navigate your code and its documentation + (magit +forge) ; a git porcelain for Emacs + make ; run make tasks from Emacs + pass ; password manager for nerds + pdf ; pdf enhancements + ;;prodigy ; FIXME managing external services & code builders + rgb ; creating color strings + ;;taskrunner ; taskrunner for all your projects + ;;terraform ; infrastructure as code + ;;tmux ; an API for interacting with tmux + ;;upload ; map local to remote projects via ssh/ftp + biblio + tree-sitter + + :os + (:if IS-MAC macos) ; improve compatibility with macOS + (tty +osc) ; improve the terminal Emacs experience + + :lang + ;;agda ; types of types of types of types... + ;;beancount ; mind the GAAP + (cc +lsp) ; C > C++ == 1 + ;;clojure ; java with a lisp + ;;common-lisp ; if you've seen one lisp, you've seen them all + ;;coq ; proofs-as-programs + ;;crystal ; ruby at the speed of c + ;;csharp ; unity, .NET, and mono shenanigans + data ; config/data formats + ;;(dart +flutter) ; paint ui and not much else + ;;elixir ; erlang done right + ;;elm ; care for a cup of TEA? + emacs-lisp ; drown in parentheses + ;;erlang ; an elegant language for a more civilized age + ess ; emacs speaks statistics + ;;factor + ;;faust ; dsp, but you get to keep your soul + ;;fsharp ; ML stands for Microsoft's Language + ;;fstar ; (dependent) types and (monadic) effects and Z3 + (gdscript +lsp) ; the language you waited for + ;;(go +lsp) ; the hipster dialect + ;;(haskell +dante) ; a language that's lazier than I am + ;;hy ; readability of scheme w/ speed of python + ;;idris ; a language you can depend on + (json +lsp) ; At least it ain't XML + (java +lsp +tree-sitter) ; the poster child for carpal tunnel syndrome + (javascript +lsp) ; all(hope(abandon(ye(who(enter(here)))))) + ;;julia ; a better, faster MATLAB + (kotlin +lsp) ; a better, slicker Java(Script) + (latex +lsp + +fold) ; writing papers in Emacs has never been so fun + ;;lean ; for folks with too much to prove + ;;ledger ; be audit you can be + lua ; one-based indices? one-based indices + markdown ; writing docs for people to ignore + ;;nim ; python + lisp at the speed of c + (nix + +lsp) + ;;ocaml ; an objective camel + (org +present + +dragndrop + +gnuplot + +journal + +noter + +pretty + +jupyter + +roam2 + +brain) ; organize your plain life in plain text + ;;php ; perl's insecure younger brother + ;;plantuml ; diagrams for confusing people more + ;;purescript ; javascript, but functional + (python +lsp + +pyright) ; beautiful is better than ugly + qt ; the 'cutest' gui framework ever + ;;racket ; a DSL for DSLs + raku ; the artist formerly known as perl6 + ;;rest ; Emacs as a REST client + ;;rst ; ReST in peace + ;;(ruby +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"} + (rust +lsp) ; Fe2O3.unwrap().unwrap().unwrap().unwrap() + ;;scala ; java, but good + ;;(scheme +guile) ; a fully conniving family of lisps + (sh +lsp +fish) ; she sells {ba,z,fi}sh shells on the C xor + ;;sml + ;;solidity ; do you need a blockchain? No. + ;;swift ; who asked for emoji variables? + ;;terra ; Earth and Moon in alignment for performance. + (web +lsp) ; the tubes + yaml ; JSON, but readable + ;;zig ; C, but simpler + + :email + ;;(mu4e +gmail) + ;;notmuch + ;;(wanderlust +gmail) + + :app + calendar + ;emms + ;;everywhere ; *leave* Emacs!? You must be joking + irc ; how neckbeards socialize + ;;(rss +org) ; emacs as an RSS reader + ;;twitter ; twitter client https://twitter.com/vnought + + :config + ;;literate + (default +bindings +smartparens)) diff --git a/configs/doom/packages.el b/configs/doom/packages.el new file mode 100644 index 0000000..5ba508e --- /dev/null +++ b/configs/doom/packages.el @@ -0,0 +1,55 @@ +;; -*- no-byte-compile: t; -*- +;;; $DOOMDIR/packages.el + +;; To install a package with Doom you must declare them here and run 'doom sync' +;; on the command line, then restart Emacs for the changes to take effect -- or +;; use 'M-x doom/reload'. + + +;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror: +;(package! some-package) + +;; To install a package directly from a remote git repo, you must specify a +;; `:recipe'. You'll find documentation on what `:recipe' accepts here: +;; https://github.com/raxod502/straight.el#the-recipe-format +;(package! another-package +; :recipe (:host github :repo "username/repo")) + +;; If the package you are trying to install does not contain a PACKAGENAME.el +;; file, or is located in a subdirectory of the repo, you'll need to specify +;; `:files' in the `:recipe': +;(package! this-package +; :recipe (:host github :repo "username/repo" +; :files ("some-file.el" "src/lisp/*.el"))) + +;; If you'd like to disable a package included with Doom, you can do so here +;; with the `:disable' property: +;(package! builtin-package :disable t) + +;; You can override the recipe of a built in package without having to specify +;; all the properties for `:recipe'. These will inherit the rest of its recipe +;; from Doom or MELPA/ELPA/Emacsmirror: +;(package! builtin-package :recipe (:nonrecursive t)) +;(package! builtin-package-2 :recipe (:repo "myfork/package")) + +;; Specify a `:branch' to install a package from a particular branch or tag. +;; This is required for some packages whose default branch isn't 'master' (which +;; our package manager can't deal with; see raxod502/straight.el#279) +;(package! builtin-package :recipe (:branch "develop")) + +;; Use `:pin' to specify a particular commit to install. +;(package! builtin-package :pin "1a2b3c4d5e") + + +;; Doom's packages are pinned to a specific commit and updated from release to +;; release. The `unpin!' macro allows you to unpin single packages... +;(unpin! pinned-package) +;; ...or multiple packages +;(unpin! pinned-package another-pinned-package) +;; ...Or *all* packages (NOT RECOMMENDED; will likely break things) +;(unpin! t) + +(package! org-ref) +(package! vue-mode) +(package! kivy-mode) +(package! treemacs-all-the-icons) diff --git a/configs/hypr/hyprland.conf b/configs/hypr/hyprland.conf new file mode 100644 index 0000000..460e7cc --- /dev/null +++ b/configs/hypr/hyprland.conf @@ -0,0 +1,287 @@ + +# ####################################################################################### +# AUTOGENERATED HYPR CONFIG. +# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT, +# OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS. +# ####################################################################################### + +# +# Please note not all available settings / options are set here. + # For a full list, see the wiki +# + +# autogenerated = 1 # remove this line to remove the warning + +# See https://wiki.hyprland.org/Configuring/Monitors/ +$ULTRA = desc:LG Electronics LG ULTRAWIDE 512AZWSDD473 +$SIDE = desc:STD Computer Inc LED + +monitor = $ULTRA,3440x1440@159.96,0x0,1, bitdepth, 10, cm, hdr, sdrbrightness, 1.3 +# monitor = $ULTRA,3440x1440@159.96,0x0,1 +monitor = $SIDE,1920x1080@60,-1400x-1080,1 + + +# See https://wiki.hyprland.org/Configuring/Keywords/ for more + +# Autostart +exec-once = waybar & hyprpaper & dbus-launch kdeconnect-indicator + +# Source a file (multi-file configs) +# source = ~/.config/hypr/myColors.conf + +# Programs +$terminal = kitty +$fileManager = nautilus +# $menu = /home/ltadeu6/.config/rofi/launcher +$menu = wofi --show drun + +# Environment +env = XCURSOR_SIZE,30 +# env = QT_QPA_PLATFORMTHEME,qt6ct # change to qt6ct if you have that +# env = XDG_CURRENT_DESKTOP,Hyprland +# env = XDG_SESSION_TYPE,wayland +# env = XDG_SESSION_DESKTOP,Hyprland +# env = ADW_DISABLE_PORTAL,1 +# env = WLR_NO_HARDWARE_CURSORS,1 + +# Input +# For all categories, see https://wiki.hyprland.org/Configuring/Variables/ +input { + kb_layout = br + kb_variant = + kb_model = abnt2 + kb_options = + kb_rules = + + follow_mouse = 0 + mouse_refocus = false + + touchpad { + natural_scroll = no + } + + sensitivity = 0 # -1.0 to 1.0, 0 means no modification. + numlock_by_default = 1 +} + +general { + # See https://wiki.hyprland.org/Configuring/Variables/ for more + + gaps_in = 5 + gaps_out = 20 + border_size = 3 + # col.active_border = rgba(ff5555ff) rgba(8BE9FDff) 45deg + col.active_border = rgba(69ff94ff) + col.inactive_border = rgba(6272A4FF) + + layout = master + + # Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on + allow_tearing = false + # cursor_inactive_timeout = 5 +} + +cursor { + + inactive_timeout = 5 + +} + +decoration { + # See https://wiki.hyprland.org/Configuring/Variables/ for more + + rounding = 10 + + blur { + enabled = true + size = 6 + passes = 4 + xray = true + special = true + } + + # drop_shadow = yes + # shadow_range = 4 + # shadow_render_power = 3 + # col.shadow = rgba(1a1a1aee) +} + +animations { + enabled = yes + + # Some default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more + + bezier = myBezier, 0.05, 0.9, 0.1, 1.05 + + animation = windows, 1, 7, myBezier + animation = windowsOut, 1, 7, default, popin 80% + animation = border, 1, 10, default + animation = borderangle, 1, 8, default + animation = fade, 1, 7, default + animation = workspaces, 1, 6, default +} + +# Layouts +dwindle { + # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more + pseudotile = yes # master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below + preserve_split = yes # you probably want this +} + +master { + # See https://wiki.hyprland.org/Configuring/Master-Layout/ for more + # new_is_master = true + orientation = center + slave_count_for_center_master = 2 +} + +gestures { + # See https://wiki.hyprland.org/Configuring/Variables/ for more + # workspace_swipe = off +} + +misc { + # See https://wiki.hyprland.org/Configuring/Variables/ for more + force_default_wallpaper = 0 # Set to 0 or 1 to disable the anime mascot wallpapers + disable_hyprland_logo = true + disable_splash_rendering = true + focus_on_activate = false +} + + +# Example per-device config +# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more +# device { +# name = epic-mouse-v1 +# sensitivity = -0.5 +# } + +# Window rules +# Example windowrule v1 +# windowrule = float, ^(kitty)$ +# Example windowrule v2 +# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ +# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more +# windowrulev2 = suppressevent maximize, class:.* # You'll probably like this. +# Steam client β†’ workspace 4 +windowrulev2 = workspace 4 silent, class:^(steam)$ +windowrulev2 = workspace 4 silent, title:^Steam + + +# TF2 β†’ workspace 4 + +windowrulev2 = workspace 4 silent, class:^(tf_linux64)$ +windowrulev2 = monitor $ULTRA, class:^(tf_linux64)$ + +# Proton / Windows Steam games β†’ workspace 4 +windowrulev2 = workspace 4 silent, class:^(steam_app_.*)$ + +# Emacs β†’ workspace 2 silently +windowrulev2 = workspace 2 silent, class:^(Emacs)$ + +# layerrule = unset, notificationse + +workspace = 1, monitor:$ULTRA, default:true +workspace = 2, monitor:$ULTRA +workspace = 3, monitor:$ULTRA +workspace = 4, monitor:$ULTRA +workspace = 5, monitor:$ULTRA +workspace = 6, monitor:$ULTRA +workspace = 7, monitor:$ULTRA +workspace = 8, monitor:$ULTRA +workspace = 9, monitor:$ULTRA + +workspace = 10, monitor:$SIDE + + +# Keybinds +# See https://wiki.hyprland.org/Configuring/Keywords/ for more +$mainMod = SUPER + +# Launchers and actions +# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more +bind = $mainMod, Return, exec, $terminal +bind = $mainMod SHIFT, Return, exec, app.zen_browser.zen +bind = $mainMod, D, exec, emacs +bind = $mainMod SHIFT, Q, killactive, +bind = $mainMod, M, exit, +bind = $mainMod, N, exec, $fileManager +bind = $mainMod SHIFT, F, togglefloating, +bind = $mainMod, SPACE, exec, $menu +bind = $mainMod, P, pseudo, # dwindle +bind = $mainMod, W, togglesplit, # dwindle +bind = $mainMod, F, fullscreen +bind = $mainMod CTRL, F, fullscreenstate, 0, 2 +bind = $mainMod, C, centerwindow, 1 + +# Focus and movement +# Move focus with mainMod + arrow keys +bind = $mainMod, right, movefocus, l +bind = $mainMod, left, movefocus, r +bind = $mainMod, up, movefocus, u +bind = $mainMod, down, movefocus, d + +# Resize +bind = $mainMod SHIFT, right, resizeactive, 30 0 +bind = $mainMod SHIFT, left, resizeactive, -30 0 +bind = $mainMod SHIFT, up, resizeactive, 0 -30 +bind = $mainMod SHIFT, down, resizeactive, 0 30 + +# Move windows (vim-style) +bind = SUPER SHIFT, H, movewindow, l +bind = SUPER SHIFT, L, movewindow, r +bind = SUPER SHIFT, K, movewindow, u +bind = SUPER SHIFT, J, movewindow, d + +# Workspaces +# Switch workspaces with mainMod + [0-9] +bind = $mainMod, 1, workspace, 1 +bind = $mainMod, 2, workspace, 2 +bind = $mainMod, 3, workspace, 3 +bind = $mainMod, 4, workspace, 4 +bind = $mainMod, 5, workspace, 5 +bind = $mainMod, 6, workspace, 6 +bind = $mainMod, 7, workspace, 7 +bind = $mainMod, 8, workspace, 8 +bind = $mainMod, 9, workspace, 9 +bind = $mainMod, 0, workspace, 10 + +# Move active window to a workspace with mainMod + ALT + [0-9] +bind = $mainMod ALT, 1, movetoworkspace, 1 +bind = $mainMod ALT, 2, movetoworkspace, 2 +bind = $mainMod ALT, 3, movetoworkspace, 3 +bind = $mainMod ALT, 4, movetoworkspace, 4 +bind = $mainMod ALT, 5, movetoworkspace, 5 +bind = $mainMod ALT, 6, movetoworkspace, 6 +bind = $mainMod ALT, 7, movetoworkspace, 7 +bind = $mainMod ALT, 8, movetoworkspace, 8 +bind = $mainMod ALT, 9, movetoworkspace, 9 +bind = $mainMod ALT, 0, movetoworkspace, 10 + +# Example special workspace (scratchpad) +bind = $mainMod, S, togglespecialworkspace, magic +bind = $mainMod ALT, S, movetoworkspace, special:magic + +# Workspace navigation +# Cycle workspaces with mainMod + TAB / SHIFT + TAB (and previous with mainMod + Q) +bind = $mainMod, TAB, workspace, +1 +bind = $mainMod SHIFT, TAB, workspace, -1 +bind = $mainMod, Q, workspace, previous + +# Mouse +# Move/resize windows with mainMod + LMB/RMB and dragging +bindm = $mainMod, mouse:272, movewindow +bindm = $mainMod, mouse:273, resizewindow + +# Media and hardware keys + +bindel=, XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ +bindel=, XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- +bindl=, XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle + +bindl=, XF86AudioPlay, exec, playerctl play-pause +bindl=, XF86AudioNext, exec, playerctl next +bindl=, XF86AudioPrevious, exec, playerctl previous +bindl=, XF86AudioStop, exec, playerctl stop + +bind=, XF86Calculator, exec, gnome-calculator diff --git a/configs/hypr/hyprpaper.conf b/configs/hypr/hyprpaper.conf new file mode 100644 index 0000000..2f047a0 --- /dev/null +++ b/configs/hypr/hyprpaper.conf @@ -0,0 +1,9 @@ +# preload = /home/ltadeu6/Imagens/wallpaper/second-collection/spooky-minimal/dracula-spooky-44475a.png +preload = /home/ltadeu6/Imagens/wallpaper/first-collection/nixos.png +#if more than one preload is desired then continue to preload other backgrounds + +#set the default wallpaper(s) seen on initial workspace(s) --depending on the number of monitors used +# wallpaper = , /home/ltadeu6/Imagens/wallpaper/second-collection/spooky-minimal/dracula-spooky-44475a.png +wallpaper = , /home/ltadeu6/Imagens/wallpaper/first-collection/nixos.png + +splash = false diff --git a/configs/waybar/air_control.py b/configs/waybar/air_control.py new file mode 100755 index 0000000..6c7b581 --- /dev/null +++ b/configs/waybar/air_control.py @@ -0,0 +1,634 @@ +#!/run/current-system/sw/bin/python3 + +import sys +import os +import json +import time +import subprocess +import urllib.request +import urllib.error +import fcntl + +HA_URL = "http://localhost:8123" +ENTITY = "climate.ar" +TOKEN_FILE = os.path.expanduser("~/.config/secrets/ha_token") + +STEP = 1 +MIN_TEMP = 18 +MAX_TEMP = 30 +SEND_DELAY = 3 +PENDING_TTL = 15 +CONFIRM_TTL = 20 + +CACHE_DIR = os.path.expanduser("~/.cache") +STATE_FILE = os.path.join(CACHE_DIR, "waybar_air_state.json") +STATE_LOCK = os.path.join(CACHE_DIR, "waybar_air_state.lock") + + +def get_token(): + with open(TOKEN_FILE) as f: + return f.read().strip() + + +HEADERS = {"Authorization": f"Bearer {get_token()}", "Content-Type": "application/json"} + + +def get_state(): + return request_json("GET", f"/api/states/{ENTITY}") + + +def set_temperature(temp): + request_json( + "POST", + "/api/services/climate/set_temperature", + {"entity_id": ENTITY, "temperature": temp}, + ) + + +def set_mode(mode): + request_json( + "POST", + "/api/services/climate/set_hvac_mode", + {"entity_id": ENTITY, "hvac_mode": mode}, + ) + + +def set_fan_mode(mode): + request_json( + "POST", + "/api/services/climate/set_fan_mode", + {"entity_id": ENTITY, "fan_mode": mode}, + ) + + +PENDING = { + "temp": { + "key": "temp", + "cast": float, + "setter": set_temperature, + "after": None, + }, + "mode": { + "key": "mode", + "cast": str, + "setter": set_mode, + "after": lambda: schedule("flush"), + }, + "fan": { + "key": "fan", + "cast": str, + "setter": set_fan_mode, + "after": None, + }, +} + + +def request_json(method, path, payload=None): + url = f"{HA_URL}{path}" + data = None + headers = dict(HEADERS) + if payload is not None: + data = json.dumps(payload).encode("utf-8") + headers["Content-Type"] = "application/json" + req = urllib.request.Request(url, data=data, headers=headers, method=method) + try: + with urllib.request.urlopen(req, timeout=10) as resp: + body = resp.read() + except (urllib.error.URLError, urllib.error.HTTPError, TimeoutError, ValueError): + return None + if not body: + return None + try: + return json.loads(body) + except json.JSONDecodeError: + return None + + +def load_json(path): + try: + with open(path) as f: + return json.load(f) + except FileNotFoundError: + return None + except (OSError, ValueError, json.JSONDecodeError): + return None + + +def save_json(path, payload): + os.makedirs(os.path.dirname(path), exist_ok=True) + with open(path, "w") as f: + json.dump(payload, f) + +def save_json_atomic(path, payload): + os.makedirs(os.path.dirname(path), exist_ok=True) + tmp_path = f"{path}.{os.getpid()}.tmp" + with open(tmp_path, "w") as f: + json.dump(payload, f) + os.replace(tmp_path, path) + + +def load_state(): + data = load_json(STATE_FILE) + if not isinstance(data, dict): + return {} + return data + + +def save_state(state): + save_json_atomic(STATE_FILE, state) + + +def update_state(update_fn): + os.makedirs(CACHE_DIR, exist_ok=True) + with open(STATE_LOCK, "w") as lockf: + fcntl.flock(lockf, fcntl.LOCK_EX) + state = load_state() + if not isinstance(state, dict): + state = {} + new_state = update_fn(state) + if new_state is not None: + state = new_state + save_state(state) + + +def get_state_section(state, key): + section = state.get(key) + if isinstance(section, dict): + return section + return {} + + +def read_pending(key): + state = load_state() + pending_map = get_state_section(state, "pending") + data = pending_map.get(key) + if not isinstance(data, dict): + return None + value = data.get("value") + ts = data.get("ts") + sent = data.get("sent", False) + sent_ts = data.get("sent_ts") + if not isinstance(value, (int, float, str)) or not isinstance(ts, (int, float)): + return None + sent_ts_val = None + if isinstance(sent_ts, (int, float)): + sent_ts_val = float(sent_ts) + return { + "value": value, + "ts": float(ts), + "sent": bool(sent), + "sent_ts": sent_ts_val, + } + + +def write_pending(key, value, sent=False, sent_ts=None, ts=None): + if ts is None: + ts = time.time() + payload = {"value": value, "ts": float(ts), "sent": bool(sent)} + if sent_ts is not None: + payload["sent_ts"] = float(sent_ts) + def apply(state): + pending_map = get_state_section(state, "pending") + pending_map[key] = payload + state["pending"] = pending_map + return state + + update_state(apply) + + +def clear_pending(key): + def apply(state): + pending_map = get_state_section(state, "pending") + if key in pending_map: + pending_map.pop(key, None) + state["pending"] = pending_map + return state + + update_state(apply) + + +def read_last_mode(): + state = load_state() + last_map = get_state_section(state, "last") + mode = last_map.get("mode") + if isinstance(mode, str): + return mode + return None + + +def write_last_mode(mode): + def apply(state): + last_map = get_state_section(state, "last") + last_map["mode"] = mode + state["last"] = last_map + return state + + update_state(apply) + + +def read_last_target(): + state = load_state() + last_map = get_state_section(state, "last") + value = last_map.get("target") + if isinstance(value, (int, float)): + return float(value) + return None + + +def write_last_target(value): + def apply(state): + last_map = get_state_section(state, "last") + last_map["target"] = float(value) + state["last"] = last_map + return state + + update_state(apply) + + +def pending_active(pending): + now = time.time() + show = now - pending["ts"] <= PENDING_TTL + if pending["sent"] and pending.get("sent_ts") is not None: + show = show or (now - pending["sent_ts"] <= CONFIRM_TTL) + return show + + +def mode_change_pending(state=None): + pending = read_pending(PENDING["mode"]["key"]) + if not pending: + return False + if state and state.get("state") == pending.get("value"): + return False + return bool(pending_active(pending)) + + +_MISSING = object() + + +def pending_value(key, cast=None, current_value=_MISSING, preserve_if_mode_pending=False): + pending = read_pending(key) + if pending is None: + return (current_value, None) if current_value is not _MISSING else None + value = cast(pending["value"]) if cast else pending["value"] + if current_value is not _MISSING: + if current_value == value: + if preserve_if_mode_pending and mode_change_pending(): + return value, pending + clear_pending(key) + return current_value, None + if pending_active(pending): + return value, pending + clear_pending(key) + return current_value, None + if pending_active(pending): + return value + clear_pending(key) + return None + + +def pending_value_with_current(key, cast, current_value, preserve_if_mode_pending=False): + result = pending_value( + key, + cast, + current_value=current_value, + preserve_if_mode_pending=preserve_if_mode_pending, + ) + if result is None: + return current_value, None + return result + + +def get_effective_mode(state): + if state: + mode = state.get("state") + else: + mode = None + pending = pending_value(PENDING["mode"]["key"], PENDING["mode"]["cast"]) + return pending if pending is not None else mode + + +def clamp(value, low, high): + return max(low, min(high, value)) + + +def get_state_attrs(): + state = get_state() + if not state: + return None, {} + return state, state.get("attributes", {}) + + +def resolve_current_target(state): + current_target = None + if state: + attrs = state["attributes"] + current_target = attrs.get("temperature") + if current_target is None: + current_target = attrs.get("current_temperature") + pending_target = pending_value(PENDING["temp"]["key"], PENDING["temp"]["cast"]) + if pending_target is not None: + current_target = pending_target + if current_target is None: + current_target = read_last_target() + if current_target is None and state: + current_target = state["attributes"].get("current_temperature") + return current_target + + +def preserve_settings_on_mode_change(state): + target = resolve_current_target(state) + if isinstance(target, (int, float)) and read_pending(PENDING["temp"]["key"]) is None: + write_pending(PENDING["temp"]["key"], float(target), sent=False) + schedule("flush") + if state: + fan_mode = state["attributes"].get("fan_mode") + if isinstance(fan_mode, str) and read_pending(PENDING["fan"]["key"]) is None: + write_pending(PENDING["fan"]["key"], str(fan_mode), sent=False) + schedule("flush-fan") + + +def flush_pending_generic( + key, cast, setter, after=None, defer_cmd=None, state=None, force=False +): + if not force and key != PENDING["mode"]["key"] and mode_change_pending(state): + if defer_cmd is not None: + time.sleep(SEND_DELAY) + schedule(defer_cmd) + return False + pending = read_pending(key) + if pending is None: + return False + ts = pending["ts"] + remaining = SEND_DELAY - (time.time() - ts) + if remaining > 0: + time.sleep(remaining) + pending = read_pending(key) + if pending is None: + return False + if pending["ts"] != ts: + return False + value = cast(pending["value"]) + setter(value) + write_pending(key, value, sent=True, sent_ts=time.time(), ts=ts) + if after is not None: + after() + return True + + +def schedule(cmd): + subprocess.Popen( + [sys.executable, os.path.abspath(__file__), cmd], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + + +def display(): + state, attrs = get_state_attrs() + if not state: + print(json.dumps({"text": "-- - ", "class": "off"})) + return + mode = state["state"] + + current = attrs.get("current_temperature") + target = attrs.get("temperature") + target, _ = pending_value_with_current( + PENDING["temp"]["key"], + PENDING["temp"]["cast"], + target, + preserve_if_mode_pending=True, + ) + if target is not None: + write_last_target(target) + + mode, _ = pending_value_with_current( + PENDING["mode"]["key"], PENDING["mode"]["cast"], mode + ) + + fan_mode = attrs.get("fan_mode") + fan_mode, _ = pending_value_with_current( + PENDING["fan"]["key"], + PENDING["fan"]["cast"], + fan_mode, + preserve_if_mode_pending=True, + ) + + if current is None: + current = 0 + + if mode == "off": + print( + json.dumps( + { + "text": f" {current:.0f} - ", + "class": "off", + } + ) + ) + return + write_last_mode(mode) + + mode_map = { + "cool": ("ο‹œ", "cool"), + "heat": ("", "heat"), + "dry": ("", "dry"), + "fan_only": ("󰈐", "fan"), + } + mode_key = mode if isinstance(mode, str) else "unknown" + icon, css_class = mode_map.get(mode_key, ("", "other")) + + if mode in ("fan_only", "dry"): + target_text = f"{current:.0f}" + elif target is None: + target_text = f"{current:.0f}" + else: + target_text = f"{target:.0f}" + fan_text = "" + if fan_mode is not None: + fan_text = f"{fan_mode}" + print( + json.dumps( + { + "text": f"{icon}{fan_text} {target_text} - ", + "class": css_class, + } + ) + ) + + +def change(delta): + state, _ = get_state_attrs() + effective_mode = get_effective_mode(state) + if effective_mode in ("fan_only", "dry"): + change_fan(delta) + return + current_target = resolve_current_target(state) + if current_target is None: + return + + new_temp = clamp(current_target + delta, MIN_TEMP, MAX_TEMP) + write_pending(PENDING["temp"]["key"], float(new_temp), sent=False) + schedule("flush") + + +def change_fan(delta): + state, attrs = get_state_attrs() + if not state: + return + modes = attrs.get("fan_modes") + current = attrs.get("fan_mode") + if not modes or current is None: + return + pending_fan = pending_value(PENDING["fan"]["key"], PENDING["fan"]["cast"]) + if pending_fan is not None: + current = pending_fan + try: + idx = modes.index(current) + except ValueError: + idx = 0 + new_idx = (idx + delta) % len(modes) + if new_idx != idx: + write_pending(PENDING["fan"]["key"], modes[new_idx], sent=False) + schedule("flush-fan") + + +def cycle_mode(): + state, attrs = get_state_attrs() + if not state: + return + modes = attrs.get("hvac_modes") or [] + modes = [m for m in modes if m != "off"] + if not modes: + return + current = get_effective_mode(state) + try: + idx = modes.index(current) + except ValueError: + idx = -1 + new_idx = (idx + 1) % len(modes) + new_mode = modes[new_idx] + write_pending(PENDING["mode"]["key"], new_mode, sent=False) + preserve_settings_on_mode_change(state) + schedule("flush-mode") + + +def toggle_mode(): + state, attrs = get_state_attrs() + if not state: + return + modes = attrs.get("hvac_modes") or [] + current = get_effective_mode(state) + if current == "off": + last = read_last_mode() + if last in modes and last != "off": + write_pending(PENDING["mode"]["key"], last, sent=False) + preserve_settings_on_mode_change(state) + schedule("flush-mode") + return + for m in modes: + if m != "off": + write_pending(PENDING["mode"]["key"], m, sent=False) + preserve_settings_on_mode_change(state) + schedule("flush-mode") + return + else: + clear_pending(PENDING["temp"]["key"]) + clear_pending(PENDING["fan"]["key"]) + set_mode("off") + write_pending( + PENDING["mode"]["key"], "off", sent=True, sent_ts=time.time(), ts=time.time() + ) + + +def cycle_fan(): + change_fan(1) + + +def flush_pending(): + meta = PENDING["temp"] + state, _ = get_state_attrs() + flush_pending_generic( + meta["key"], + meta["cast"], + meta["setter"], + meta["after"], + defer_cmd="flush", + state=state, + ) + + +def flush_mode(): + meta = PENDING["mode"] + sent = flush_pending_generic( + meta["key"], meta["cast"], meta["setter"], meta["after"] + ) + if not sent: + return + temp_meta = PENDING["temp"] + flush_pending_generic( + temp_meta["key"], + temp_meta["cast"], + temp_meta["setter"], + temp_meta["after"], + force=True, + ) + fan_meta = PENDING["fan"] + flush_pending_generic( + fan_meta["key"], + fan_meta["cast"], + fan_meta["setter"], + fan_meta["after"], + force=True, + ) + + +def flush_fan(): + meta = PENDING["fan"] + state, _ = get_state_attrs() + flush_pending_generic( + meta["key"], + meta["cast"], + meta["setter"], + meta["after"], + defer_cmd="flush-fan", + state=state, + ) + + +def main(): + if len(sys.argv) == 1: + display() + return + + cmd = sys.argv[1] + + if cmd == "heat": + set_mode("heat") + elif cmd == "cool": + set_mode("cool") + elif cmd == "off": + set_mode("off") + elif cmd == "up": + change(STEP) + elif cmd == "down": + change(-STEP) + elif cmd == "fan-up": + change_fan(STEP) + elif cmd == "fan-down": + change_fan(-STEP) + elif cmd == "cycle-mode": + cycle_mode() + elif cmd == "toggle": + toggle_mode() + elif cmd == "cycle-fan": + cycle_fan() + elif cmd == "flush": + flush_pending() + elif cmd == "flush-mode": + flush_mode() + elif cmd == "flush-fan": + flush_fan() + + +if __name__ == "__main__": + main() diff --git a/configs/waybar/config b/configs/waybar/config new file mode 100644 index 0000000..29fa267 --- /dev/null +++ b/configs/waybar/config @@ -0,0 +1,201 @@ +{ + "layer": "top", + "position": "top", + "fixed-center": true, + "height": 48, + "margin-top": 20, + "margin-bottom": 0, + "output": ["DP-5", "DP-3"], + "modules-left": ["hyprland/workspaces", "cava"], + "modules-center": ["custom/ac", "clock"], + "modules-right": [ + "mpris", + "network", + "bluetooth", + "pulseaudio", + "backlight", + "battery", + "custom/poweroff" + ], + "group/power": { + "orientation": "inherit", + "drawer": { + "transition-duration": 500, + "transition-left-to-right": false + }, + "modules": [ + "custom/poweroff", + "custom/restart", + "custom/exit", + "custom/sleep", + "custom/lock" + ] + }, + "custom/poweroff": { + "format": "", + "on-click": "poweroff" + }, + "custom/restart": { + "format": "󰑐", + "on-click": "reboot" + }, + "custom/exit": { + "format": "σ°—Ό", + "on-click": "hyprctl dispatch exit" + }, + "custom/sleep": { + "format": "󰀄", + "on-click": "systemctl suspend" + }, + "custom/lock": { + "format": "ξ―§", + "on-click": "hyprlock" + }, + "custom/kde": { + "format": "ο„‹", + "on-click": "hyprlock" + }, + "hyprland/workspaces": { + "all-outputs": false, + "active-only": false, + "persistent-workspaces": { + "DP-3": [1, 2, 3, 4, 5, 6, 7, 8, 9], + "DP-5": [1, 2, 3, 4, 5, 6, 7, 8, 9], + "HDMI-A-1": [10] + }, + "format": "{icon}", + "format-icons": { + "1": "", + "2": "", + "3": "ο’‰", + "4": "σ°―‰", + "5": "σ°­Ή", + "6": "", + "7": "ο€Ύ", + "8": "", + "9": "ο€½", + "10": "ο†Ό" + }, + "on-scroll-up": "hyprctl dispatch workspace e+1", + "on-scroll-down": "hyprctl dispatch workspace e-1" + }, + "clock": { + "format": "{:%d/%m/%Y - %H:%M}", + "tooltip": false, + "locale": "pt_BR.utf8" + }, + "cpu": { + "interval": 5, + "format": "︁ {}%", + "max-length": 10 + }, + "cava": { + "framerate": 60, + "hide_on_silence": true, + "bars": 10, + "source": "auto", + "method": "pipewire", + "stereo": true, + "bar_delimiter": 0, + "monstercat": false, + "waves": true, + "noise_reduction": 0.2, + "sleep_timer": 1, + "input_delay": 0, + "format-icons": ["▁", "β–‚", "β–ƒ", "β–„", "β–…", "β–†", "β–‡", "β–ˆ"], + "actions": { + "on-click-right": "mode" + } + }, + "memory": { + "interval": 15, + "format": "︁ {used:0.1f}G/{total:0.1f}G", + "tooltip": false + }, + "pulseaudio": { + "format": "{icon}", + "format-bluetooth": "{icon}", + "format-muted": "", + "format-icons": { + // "headphone": "ο€₯", + // "hands-free": "ο€₯", + // "headset": "󱑒", + // "phone": "ο‚•", + // "portable": "ο‚•", + // "car": "ο†Ή", + "default": ["σ°•Ώ", "σ°–€", "σ°–€", "σ°•Ύ", "σ°•Ύ", "σ°•Ύ"] + }, + "scroll-step": 10, + "on-click": "pavucontrol", + "on-click-right": "$HOME/nixos-config/configs/waybar/switch_sink.sh", + "ignored-sinks": ["Easy Effects Sink"], + "tooltip-format": "{icon} {volume}" + }, + "bluetooth": { + "format": "σ°‚―", + "format-connected": "σ°‚±", + "format-connected-battery": "σ°‚±", + "tooltip-format": "{controller_alias}\t{controller_address}\n\n{num_connections} connected", + "tooltip-format-connected": "{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}%", + "on-click": "bluetoothctl disconnect", + "on-click-right": "bluetoothctl connect B6:97:1A:3D:6A:B2" + }, + "backlight": { + "device": "intel_backlight", + "format": "{icon}", + "scroll-step": 5, + "format-icons": ["󰃛", "σ°ƒœ", "󰃝", "σ°ƒž", "σ°ƒŸ", "σ°ƒ "] + }, + "mpris": { + "format": "{player_icon} {dynamic}", + "format-paused": "{status_icon} {dynamic}", + "tooltip-format": "{status_icon} {dynamic}", + "player-icons": { + "default": "", + "mpv": "🎡" + }, + "status-icons": { + "paused": "ξ«‘" + }, + "dynamic-len": 40, + "dynamic-order": ["title", "artist", "album"], + "player": "spotify", + "ignored-players": ["firefox*"], + "on-scroll-up": "playerctl -i firefox volume 0.1+", + "on-scroll-down": "playerctl -i firefox volume 0.1-" + }, + "battery": { + "format": "{icon} ", + "format-icons": ["", "", "", "", ""], + "format-charging": "{icon}", + "format-full": "{icon}", + "interval": 15, + "states": { + "warning": 25, + "critical": 10 + }, + "tooltip": false + }, + "network": { + "format": "{icon}", + "format-alt": "󰲝 {ipaddr}", + "format-alt-click": "click-left", + "format-wifi": " ", + "format-ethernet": "󰲝", + "format-disconnected": "⚠", + "tooltip": false + }, + "custom/ac": { + "exec": "$HOME/nixos-config/configs/waybar/air_control.py", + "interval": 3, + "return-type": "json", + "markup": "true", + "on-click": "$HOME/nixos-config/configs/waybar/air_control.py toggle", + "on-click-right": "$HOME/nixos-config/configs/waybar/air_control.py cycle-mode", + "on-click-middle": "$HOME/nixos-config/configs/waybar/air_control.py cycle-fan", + "on-scroll-up": "$HOME/nixos-config/configs/waybar/air_control.py up", + "on-scroll-down": "$HOME/nixos-config/configs/waybar/air_control.py down" +} +} diff --git a/configs/waybar/dracula.css b/configs/waybar/dracula.css new file mode 100644 index 0000000..f184c93 --- /dev/null +++ b/configs/waybar/dracula.css @@ -0,0 +1,31 @@ +@define-color base #24273a; +@define-color mantle #1e2030; +@define-color crust #181926; + +@define-color text #f2f3f7; +@define-color subtext0 #a5adcb; +@define-color subtext1 #b8c0e0; + +@define-color surface0 #282A36; +@define-color surface1 #494d64; +@define-color surface2 #6272A4; + +@define-color overlay0 #6e738d; +@define-color overlay1 #8087a2; +@define-color overlay2 #939ab7; + +@define-color blue #8aadf4; +@define-color lavender #b7bdf8; +@define-color sapphire #7dc4e4; +@define-color sky #91d7e3; +@define-color teal #8BE9FD; +@define-color green #50fa7E; +@define-color yellow #f1fa8c; +@define-color peach #f5a97f; +@define-color maroon #ee99a0; +@define-color red #ff5555; +@define-color mauve #c6a0f6; +@define-color purple #d6acff; +@define-color pink #f5bde6; +@define-color flamingo #f0c6c6; +@define-color rosewater #f4dbd6; diff --git a/configs/waybar/launch.sh b/configs/waybar/launch.sh new file mode 100755 index 0000000..db07846 --- /dev/null +++ b/configs/waybar/launch.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env sh + +# Terminate already running bar instances +killall -q waybar + +# Wait until the processes have been shut down +while pgrep -x waybar >/dev/null; do sleep 1; done + +# Launch main +waybar \ No newline at end of file diff --git a/configs/waybar/style.css b/configs/waybar/style.css new file mode 100644 index 0000000..9d3633b --- /dev/null +++ b/configs/waybar/style.css @@ -0,0 +1,135 @@ +@import "./dracula.css"; + +* { + font-family: FreeMono; + font-size: 17px; + font-weight: 600; + border: none; +} + +#waybar { + background: transparent; +} + +#workspaces { + color: @teal; +} + +#workspaces button { + color: @teal; + margin: 0 0.8rem 0 0.4rem; + padding: 0; + /* border-bottom-width: 1px; */ +} +#workspaces button:hover { + box-shadow: none; + text-shadow: none; + background: none; + transition: none; +} + +#workspaces button.empty { + color: @surface2; +} + +#workspaces button.visible { + color: @red; +} + +#custom-lock, +#custom-kde, +#custom-restart, +#custom-exit, +#custom-sleep, +#custom-poweroff, +#mpris, +#battery, +#pulseaudio, +#bluetooth, +#backlight, +#network { + padding: 0 1rem; +} +#mpris { + font-family: "GohuFont 11 Nerd Font Mono"; + font-weight: 700; + letter-spacing: 1.5px; +} + +#cava { + font-family: "GohuFont 11 Nerd Font Mono"; + font-weight: 700; + letter-spacing: 1.5px; + color: @teal; + margin: 0 5px 0 10px; +} + +#custom-sleep, +#battery, +#network { + color: @green; +} + +#custom-exit, +#mpris, +#pulseaudio, +#backlight { + color: @yellow; +} + +#custom-kde, +#custom-lock, +#bluetooth { + color: @teal; +} + +#custom-restart, +#custom-poweroff { + color: @red; +} + +#clock, +#custom-ac { + color: @text; + color: @yellow; + font-family: "GohuFont 11 Nerd Font Mono"; + font-weight: 700; + letter-spacing: 1.5px; +} + +#battery.warning:not(.charging) { + color: @red; +} + +/* .modules-left, */ +/* .modules-center, */ +/* .modules-right { */ +/* border: double 3px transparent; */ +/* border-radius: 10px; */ +/* background-image: */ +/* linear-gradient(rgba(12, 10, 32, 1), rgba(12, 10, 32, 1)), */ +/* linear-gradient( */ +/* to bottom right, */ +/* rgba(254, 4, 117, 0.93), */ +/* rgba(32, 241, 253, 0.93) */ +/* ); */ +/* background-origin: border-box; */ +/* background-clip: padding-box, border-box; */ +/* padding: 0 1rem; */ +/* margin: 0 20px; */ +/* } */ + +.modules-left, +.modules-center, +.modules-right { + border: solid 3px; + border-color: @lavender; + border-radius: 10px; + padding: 0 1rem; + background: @surface0; +} + +.modules-right, +.modules-left { + margin: 0 20px; +} diff --git a/configs/waybar/switch_sink.sh b/configs/waybar/switch_sink.sh new file mode 100755 index 0000000..996de96 --- /dev/null +++ b/configs/waybar/switch_sink.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env sh + +# Cycle default sink and move existing inputs. +if ! command -v pactl >/dev/null 2>&1; then + exit 1 +fi + +current="$(pactl get-default-sink 2>/dev/null)" +[ -z "$current" ] && exit 1 + +sinks="$(pactl list short sinks | awk '{print $2}')" +[ -z "$sinks" ] && exit 1 + +next="" +found=0 +for s in $sinks; do + if [ "$found" -eq 1 ]; then + next="$s" + break + fi + if [ "$s" = "$current" ]; then + found=1 + fi +done + +# If current is last or not found, wrap to first. +if [ -z "$next" ]; then + next="$(printf '%s\n' "$sinks" | head -n 1)" +fi + +pactl set-default-sink "$next" || exit 1 + +# Move existing audio streams to the new sink. +for input in $(pactl list short sink-inputs | awk '{print $1}'); do + pactl move-sink-input "$input" "$next" >/dev/null 2>&1 || true +done diff --git a/home/ltadeu6.nix b/home/ltadeu6.nix index 7cb8fde..7dc6f31 100644 --- a/home/ltadeu6.nix +++ b/home/ltadeu6.nix @@ -107,9 +107,9 @@ executable = true; }; - ".doom.d/config.el".source = ../configs/doom/config.el; - ".doom.d/init.el".source = ../configs/doom/init.el; - ".doom.d/packages.el".source = ../configs/doom/packages.el; + ".config/doom/config.el".source = ../configs/doom/config.el; + ".config/doom/init.el".source = ../configs/doom/init.el; + ".config/doom/packages.el".source = ../configs/doom/packages.el; }; programs.home-manager.enable = true; diff --git a/hosts/Nixos/configuration.nix b/hosts/Nixos/configuration.nix new file mode 100644 index 0000000..a784f98 --- /dev/null +++ b/hosts/Nixos/configuration.nix @@ -0,0 +1,484 @@ +# 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’). + +{ config, pkgs, lib, agenix, ... }: + +{ + imports = [ # Include the results of the hardware scan. + ./hardware-configuration.nix + ]; + + age = { + identityPaths = [ "/home/ltadeu6/.ssh/id_ed25519" ]; + secrets = + { } + // lib.optionalAttrs (builtins.pathExists ../../secrets/openai_api_key.age) { + openai_api_key.file = ../../secrets/openai_api_key.age; + } + // lib.optionalAttrs (builtins.pathExists ../../secrets/minecraft_rcon_password.age) { + minecraft_rcon_password.file = ../../secrets/minecraft_rcon_password.age; + } + // lib.optionalAttrs (builtins.pathExists ../../secrets/syncthing_pixel_id.age) { + syncthing_pixel_id.file = ../../secrets/syncthing_pixel_id.age; + } + // lib.optionalAttrs (builtins.pathExists ../../secrets/syncthing_tv_id.age) { + syncthing_tv_id.file = ../../secrets/syncthing_tv_id.age; + } + // lib.optionalAttrs (builtins.pathExists ../../secrets/wireguard_private_key.age) { + wireguard_private_key.file = ../../secrets/wireguard_private_key.age; + }; + }; + + powerManagement.cpuFreqGovernor = "performance"; + # Bootloader. + boot = { + loader.systemd-boot.enable = true; + loader.efi.canTouchEfiVariables = true; + loader.timeout = 0; + # plymouth.themePackages = [ + # (pkgs.adi1090x-plymouth-themes.override { + # selected_themes = [ "colorful_loop" ]; + # }) + # ]; + plymouth.enable = true; + # plymouth.theme = "colorful_loop"; + consoleLogLevel = 0; + initrd.verbose = false; + kernelParams = [ + "quiet" + "splash" + "rd.systemd.show_status=false" + "rd.udev.log_level=3" + "udev.log_priority=3" + "boot.shell_on_fail" + ]; + }; + + networking = { + hostName = "Nixos"; # Define your hostname. + networkmanager.enable = true; + firewall.enable = false; + interfaces = { + enp4s0.ipv4.addresses = [{ + address = "192.168.1.150"; + prefixLength = 16; + }]; + }; + defaultGateway = "192.168.1.1"; + nameservers = [ "8.8.8.8" "1.1.1.1" ]; + extraHosts = '' + 191.252.194.81 vps + ''; + # Enable WireGuard + # wireguard.interfaces = { + # wg0 = { + # ips = [ "10.0.0.2/24" ]; + # listenPort = 51820; + # privateKey = builtins.readFile config.age.secrets.wireguard_private_key.path; + # peers = [{ + # publicKey = (import ../../secrets/secrets.nix).wireguard.peerPublicKey; + # allowedIPs = [ "10.0.0.1" ]; + # endpoint = (import ../../secrets/secrets.nix).wireguard.endpoint; + # persistentKeepalive = 25; + # }]; + # }; + # }; + }; + + time.timeZone = "America/Sao_Paulo"; + + i18n = { + defaultLocale = "pt_BR.UTF-8"; + extraLocaleSettings = { + LC_ADDRESS = "pt_BR.UTF-8"; + LC_IDENTIFICATION = "pt_BR.UTF-8"; + LC_MEASUREMENT = "pt_BR.UTF-8"; + LC_MONETARY = "pt_BR.UTF-8"; + LC_NAME = "pt_BR.UTF-8"; + LC_NUMERIC = "pt_BR.UTF-8"; + LC_PAPER = "pt_BR.UTF-8"; + LC_TELEPHONE = "pt_BR.UTF-8"; + LC_TIME = "pt_BR.UTF-8"; + }; + }; + + programs = { + + gamescope = { + enable = true; + # capSysNice = true; + }; + + virt-manager.enable = true; + + gnupg.agent.enable = true; + nautilus-open-any-terminal = { + enable = true; + terminal = "kitty"; + }; + fish = { + enable = true; + shellAliases = { + la = "exa --icons --git"; + ls = "exa --icons --git"; + tree = "exa --tree"; + rm = "trash"; + }; + }; + hyprland = { + enable = true; + xwayland.enable = true; + }; + neovim = { + enable = true; + defaultEditor = true; + }; + nix-ld = { + enable = true; + libraries = with pkgs; [ bash ]; + }; + dconf.enable = true; + kdeconnect.enable = true; + nano.enable = false; + steam = { + enable = true; + # gamescopeSession.enable = true; + }; + starship.enable = true; + java.enable = true; + htop.enable = true; + git.enable = true; + gamemode.enable = true; + firefox.enable = true; + adb.enable = true; + }; + + security.polkit.enable = true; + services = { + home-assistant = { + enable = true; + openFirewall = true; + extraComponents = [ "lg_thinq" ]; + config = { + homeassistant = { + name = "Casa"; + unit_system = "metric"; + time_zone = "America/Sao_Paulo"; + }; + + default_config = { }; + }; + }; + dbus.enable = true; + displayManager.gdm.enable = true; + # Optional but recommended if using Nautilus or Thunar + gvfs.enable = true; + gnome.gnome-keyring.enable = true; + udisks2.enable = true; + + mysql = { + enable = false; + package = pkgs.mariadb; + }; + # getty.autologinUser = "ltadeu6"; + flatpak.enable = true; + terraria = { + enable = false; + openFirewall = true; + worldPath = + "/var/lib/terraria/.local/share/Terraria/Worlds/Vision_of_the_Stooge.wld"; + + }; + minecraft-server = { + enable = false; + eula = true; # Accept Minecraft EULA + package = pkgs.minecraft-server; # Use papermc for modded servers + openFirewall = true; # Open port 25565 + + declarative = true; + serverProperties = { + motd = "Welcome to my NixOS Minecraft Server!"; + enable-command-block = true; + gamemode = "survival"; + difficulty = "normal"; + max-players = 20; + white-list = false; + enable-rcon = true; + online-mode = false; + } // lib.optionalAttrs (config.services.minecraft-server.enable + && config.age.secrets ? minecraft_rcon_password) { + "rcon.password" = + builtins.readFile config.age.secrets.minecraft_rcon_password.path; + }; + }; + + xserver = { + enable = true; + # desktopManager.gnome.enable = true; + # evaluation warning: The option `services.xserver.displayManager.gdm.enable' + # defined in `/etc/nixos/configuration.nix' has been renamed to `services.displayManager.gdm.enable'. + }; + ollama = { + enable = false; + acceleration = "cuda"; + host = "[::]"; + # listenAddress = "10.0.0.2:11434"; + }; + open-webui = { + enable = false; + host = "0.0.0.0"; + }; + transmission = { + enable = true; + home = "/home/ltadeu6/Extra/Transmission/"; + package = pkgs.transmission_4; + settings = { + rpc-bind-address = "0.0.0.0"; + rpc-whitelist = "*.*.*.*"; + }; + }; + jupyterhub = { + enable = false; + port = 8000; + host = "0.0.0.0"; + kernels = { + python3 = let + pyEnv = pkgs.python3.withPackages (ps: + with ps; [ + ipykernel + ipython + ipython-sql + sqlalchemy + mysqlclient + pandas # Optional β€” great for working with SQL results + prettytable + jinja2 + ]); + in { + displayName = "Python 3 (SQL enabled)"; + argv = [ + "${pyEnv.interpreter}" + "-m" + "ipykernel_launcher" + "-f" + "{connection_file}" + ]; + language = "python"; + logo32 = + "${pyEnv}/${pyEnv.sitePackages}/ipykernel/resources/logo-32x32.png"; + logo64 = + "${pyEnv}/${pyEnv.sitePackages}/ipykernel/resources/logo-64x64.png"; + }; + + R = let + rEnv = pkgs.rWrapper.override { + packages = with pkgs.rPackages; [ + IRkernel # kernel do Jupyter + ggplot2 # opcional, muito ΓΊtil + dplyr # idem + tidyr + readr + ]; + }; + in { + displayName = "R"; + language = "R"; + argv = [ + "${rEnv}/bin/R" + "--slave" + "-e" + "IRkernel::main()" + "--args" + "{connection_file}" + ]; + + # O IRkernel nΓ£o inclui logos β€” pode deixar vazio ou remover + }; + python3-sci = let + sciEnv = pkgs.python3.withPackages (ps: + with ps; [ + ipykernel + numpy + scipy + ipython + jinja2 + matplotlib + pandas # opcional, bom para tabelas + pillow # recomendado p/ alguns backends do matplotlib + ]); + in { + displayName = "Python 3 (SciPy + Matplotlib)"; + argv = [ + "${sciEnv.interpreter}" + "-m" + "ipykernel_launcher" + "-f" + "{connection_file}" + ]; + language = "python"; + logo32 = + "${sciEnv}/${sciEnv.sitePackages}/ipykernel/resources/logo-32x32.png"; + logo64 = + "${sciEnv}/${sciEnv.sitePackages}/ipykernel/resources/logo-64x64.png"; + }; + }; + extraConfig = '' + c.Authenticator.allowed_users = {"ltadeu6"}; + c.JupyterHub.admin_users = {"ltadeu6"}; + ''; + }; + displayManager.autoLogin.enable = true; + displayManager.autoLogin.user = "ltadeu6"; + + openssh = { + enable = true; + settings.PasswordAuthentication = false; + }; + emacs = { enable = true; }; + printing.enable = true; + pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + # If you want to use JACK applications, uncomment this + jack.enable = true; + + # use the example session manager (no others are packaged yet so this is enabled by default, + # no need to redefine it in your config for now) + #media-session.enable = true; + }; + syncthing = { + enable = false; + user = "ltadeu6"; + dataDir = "/home/ltadeu6"; # Default folder for new synced folders + configDir = "/home/ltadeu6/.config/syncthing"; + settings = { + devices = + { } + // lib.optionalAttrs (config.services.syncthing.enable + && config.age.secrets ? syncthing_pixel_id) { + "Pixel" = { + id = builtins.readFile config.age.secrets.syncthing_pixel_id.path; + }; + } + // lib.optionalAttrs (config.services.syncthing.enable + && config.age.secrets ? syncthing_tv_id) { + "TV" = { + id = builtins.readFile config.age.secrets.syncthing_tv_id.path; + }; + }; + folders = { + "RetroArch" = { # Name of folder in Syncthing, also the folder ID + path = + "/home/ltadeu6/.config/retroarch"; # Which folder to add to Syncthing + devices = [ "Pixel" "TV" ]; # Which devices to share the folder with + versioning = { + type = "simple"; + params = { + keep = "5"; + cleanoutDays = "15"; + }; + }; + }; + }; + }; + }; + }; + + console.keyMap = "br-abnt2"; + + # Enable sound with pipewire. + # sound.enable = true; + services.pulseaudio.enable = false; + hardware.bluetooth.enable = true; + security.rtkit.enable = true; + + environment.sessionVariables = { }; + + users.groups.libvirtd.members = [ "ltadeu6" ]; + + users.users.ltadeu6 = { + isNormalUser = true; + description = "Lucas Tadeu"; + extraGroups = [ + "terraria" + "mysql" + "networkmanager" + "wheel" + "syncthing" + "transmission" + "storage" + ]; + shell = pkgs.fish; + }; + + system.autoUpgrade.enable = true; + + systemd.services."getty@tty1".enable = false; + systemd.services."autovt@tty1".enable = false; + + nixpkgs.config.allowUnfree = true; + + # nixpkgs.config.cudaSupport = true; + + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + + environment.systemPackages = with pkgs; [ + most + agenix.packages.${pkgs.stdenv.hostPlatform.system}.default + # mangohud + hyfetch + cacert + hyprcursor + dunst + libnotify + pulseaudio + nautilus + eog + gnome-calculator + qt6Packages.qtwayland + glib + gsettings-desktop-schemas + wine64 + ((emacsPackagesFor emacs).emacsWithPackages (epkgs: [ epkgs.vterm ])) + libvterm + (python3.withPackages (ps: with ps; [ requests ])) + cmake + gcc + gnumake + nodePackages.prettier + nodePackages.pnpm + fishPlugins.z + ]; + + # environment.loginShellInit = '' + # [[ "$(tty)" = "/dev/tty1" ]] && ./gs.sh + # ''; + + virtualisation.docker.enable = false; + virtualisation.waydroid.enable = false; + virtualisation.libvirtd.enable = true; + # virtualisation.spiceUSBRedirection.enable = true; + + fonts.packages = with pkgs; [ nerd-fonts.fira-code nerd-fonts.gohufont ]; + + xdg.portal = { + enable = true; + wlr.enable = true; + extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; + }; + # # wlr.enable = true; + # # config.common.default = [ "gtk" ]; + # }; + + # 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? + +} diff --git a/hosts/Nixos/hardware-configuration.nix b/hosts/Nixos/hardware-configuration.nix new file mode 100644 index 0000000..4d7d575 --- /dev/null +++ b/hosts/Nixos/hardware-configuration.nix @@ -0,0 +1,101 @@ +# 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.initrd.availableKernelModules = + [ "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-amd" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/50622847-6ad1-4d3b-8a3e-8f1abe60d3ed"; + fsType = "ext4"; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/168A-930E"; + fsType = "vfat"; + }; + + fileSystems."/mnt/games" = { + device = "/home/ltadeu6/Extra"; + fsType = "none"; + options = [ "bind" "exec" ]; + }; + + fileSystems."/home/ltadeu6/Extra" = { + device = "/dev/disk/by-label/games"; + fsType = "ext4"; + options = [ "exec" "users" "defaults" ]; + }; + + # fileSystems."/mnt/data" = { + # device = "/dev/disk/by-uuid/a8c80fc2-b841-4427-b29b-0b6c07d0a2be"; + # fsType = "ext4"; + # options = [ "defaults" ]; + # }; + + # fileSystems."/mnt/backup" = { + # device = "/dev/disk/by-uuid/f10bc836-ab7e-4278-b20a-40c366848871"; + # fsType = "ext4"; + # options = [ "defaults" ]; + # }; + + swapDevices = + [{ device = "/dev/disk/by-uuid/0f489c58-6c10-40e8-b2d3-9c73712a9d73"; }]; + + # 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.enp3s0.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp1s0f0u7u2.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = + lib.mkDefault config.hardware.enableRedistributableFirmware; + + # Enable OpenGL + hardware.graphics = { enable = true; }; + + + # Load nvidia driver for Xorg and Wayland + services.xserver.videoDrivers = [ "nvidia" ]; + + hardware.nvidia = { + + # Modesetting is required. + modesetting.enable = true; + + # Nvidia power management. Experimental, and can cause sleep/suspend to fail. + # Enable this if you have graphical corruption issues or application crashes after waking + # up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead + # of just the bare essentials. + powerManagement.enable = false; + + # Fine-grained power management. Turns off GPU when not in use. + # Experimental and only works on modern Nvidia GPUs (Turing or newer). + powerManagement.finegrained = false; + + # Use the NVidia open source kernel module (not to be confused with the + # independent third-party "nouveau" open source driver). + # Support is limited to the Turing and later architectures. Full list of + # supported GPUs is at: + # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus + # Only available from driver 515.43.04+ + open = true; + + # Enable the Nvidia settings menu, + # accessible via `nvidia-settings`. + nvidiaSettings = true; + + # Optionally, you may need to select the appropriate driver version for your specific GPU. + package = config.boot.kernelPackages.nvidiaPackages.stable; + }; +}