From 7993d5619c6fc96f8efe170c112c5ab8f30db14d Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Thu, 2 May 2024 21:36:17 -0400 Subject: [PATCH] updates --- .sops.yaml | 5 + README.md | 8 +- _/home-manager/_mixins/common/alacritty.nix | 4 - _/home-manager/_mixins/common/default.nix | 17 - _/home-manager/_mixins/common/deluge.nix | 3 - _/home-manager/_mixins/common/discord.nix | 221 -- _/home-manager/_mixins/common/dragon.nix | 3 - _/home-manager/_mixins/common/firefox.nix | 127 - _/home-manager/_mixins/common/font.nix | 13 - .../_mixins/common/gnome-wm/default.nix | 41 - _/home-manager/_mixins/common/gtk.nix | 29 - _/home-manager/_mixins/common/kdeconnect.nix | 46 - _/home-manager/_mixins/common/pavucontrol.nix | 3 - _/home-manager/_mixins/common/playerctl.nix | 7 - _/home-manager/_mixins/common/qt.nix | 11 - _/home-manager/_mixins/common/slack.nix | 4 - .../_mixins/common/sublime-music.nix | 6 - .../_mixins/common/wayland-wm/default.nix | 39 - .../_mixins/common/wayland-wm/gammastep.nix | 13 - .../common/wayland-wm/hyprland-vnc.nix | 35 - .../_mixins/common/wayland-wm/kitty.nix | 66 - .../_mixins/common/wayland-wm/mako.nix | 23 - .../_mixins/common/wayland-wm/qutebrowser.nix | 177 -- .../_mixins/common/wayland-wm/swayidle.nix | 54 - .../_mixins/common/wayland-wm/swaylock.nix | 43 - .../_mixins/common/wayland-wm/waybar.nix | 392 --- .../_mixins/common/wayland-wm/wezterm.nix | 54 - .../common/wayland-wm/wofi-run-shell.patch | 20 - .../_mixins/common/wayland-wm/wofi.nix | 25 - .../_mixins/common/wayland-wm/zathura.nix | 32 - _/home-manager/_mixins/default.nix | 56 - _/home-manager/_mixins/gnome/default.nix | 19 - _/home-manager/_mixins/gnome/tty-init.nix | 19 - .../_mixins/users/gburd/generic.nix | 6 - .../_mixins/users/wireless/default.nix | 5 - _/home-manager/_mixins/wpa-gui.nix | 3 - _/modules/home-manager/default.nix | 9 - _/modules/home-manager/fonts.nix | 32 - _/modules/home-manager/monitors.nix | 57 - _/modules/home-manager/rgbdaemon.nix | 130 - _/modules/home-manager/shellcolor.nix | 110 - _/modules/home-manager/wallpaper.nix | 12 - _/modules/home-manager/xpo.nix | 25 - _/modules/nixos/default.nix | 4 - _/modules/nixos/openrgb.nix | 37 - _/modules/nixos/satisfactory.nix | 78 - _/nixos/_mixins/global/acme.nix | 16 - _/nixos/_mixins/global/auto-upgrade.nix | 29 - _/nixos/_mixins/global/default.nix | 67 - _/nixos/_mixins/global/fish.nix | 10 - _/nixos/_mixins/global/locale.nix | 22 - _/nixos/_mixins/global/nix.nix | 33 - _/nixos/_mixins/global/openssh.nix | 44 - _/nixos/_mixins/global/podman.nix | 18 - _/nixos/_mixins/global/ssh-serve-store.nix | 14 - _/nixos/_mixins/global/steam-hardware.nix | 3 - _/nixos/_mixins/global/systemd-initrd.nix | 3 - _/nixos/_mixins/global/tailscale.nix | 15 - _/nixos/_mixins/optional/ckb-next.nix | 16 - _/nixos/_mixins/optional/docker.nix | 5 - _/nixos/_mixins/optional/ephemeral-btrfs.nix | 83 - _/nixos/_mixins/optional/fail2ban.nix | 5 - _/nixos/_mixins/optional/gamemode.nix | 16 - _/nixos/_mixins/optional/gnome.nix | 35 - _/nixos/_mixins/optional/lol-acfix.nix | 6 - _/nixos/_mixins/optional/mysql.nix | 13 - _/nixos/_mixins/optional/nginx.nix | 47 - _/nixos/_mixins/optional/pantheon.nix | 30 - _/nixos/_mixins/optional/postgres.nix | 9 - .../_mixins/optional/starcitizen-fixes.nix | 8 - _/nixos/_mixins/optional/systemd-boot.nix | 9 - .../_mixins/optional/tailscale-exit-node.nix | 6 - _/nixos/_mixins/optional/wireless.nix | 66 - _/nixos/_mixins/optional/wireshark.nix | 5 - _/nixos/_mixins/optional/x11-no-suspend.nix | 7 - _/nixos/iso-console/default.nix | 4 - _/nixos/iso-desktop/default.nix | 9 - _/overlays/default.nix | 76 - _/overlays/offline-mode-prism-launcher.diff | 19 - _/overlays/pfetch.patch | 41 - _/overlays/qutebrowser-tree-tabs.diff | 2455 ----------------- .../vim-numbertoggle-command-mode.patch | 13 - _/overlays/xdg-open-spawn-terminal.diff | 20 - flake.lock | 66 +- flake.nix | 7 +- home-manager/_mixins/cli/gh.nix | 4 +- home-manager/_mixins/cli/ssh.nix | 4 +- home-manager/_mixins/console/default.nix | 6 +- .../_mixins/desktop/jetbrains-clion.nix | 2 +- home-manager/_mixins/desktop/mate.nix | 4 +- home-manager/_mixins/games/steam.nix | 2 +- home-manager/_mixins/pass/default.nix | 4 +- home-manager/_mixins/productivity/mail.nix | 2 +- .../_mixins/productivity/vdirsyncer.nix | 4 +- home-manager/_mixins/users/_gburd/.gitconfig | 55 + .../_mixins/users/_gburd/alacritty.yml | 492 ++++ home-manager/_mixins/users/_gburd/default.nix | 144 + home-manager/_mixins/users/_gburd/desktop.nix | 20 + home-manager/_mixins/users/_gburd/face.png | Bin 0 -> 33951 bytes .../_mixins/users/_gburd/hosts/floki.nix | 8 + home-manager/_mixins/users/_gburd/init.nvim | 565 ++++ home-manager/_mixins/users/_gburd/pgp.asc | 63 + home-manager/_mixins/users/_gburd/ssh.pub | 1 + .../_mixins/users/_gburd/symas-ssh.pub | 1 + home-manager/_mixins/users/gburd/default.nix | 9 +- nixos/_mixins/desktop/vscode.nix | 2 + nixos/_mixins/secrets.yaml | 7 +- nixos/_mixins/users/_gburd/default.nix | 69 + nixos/default.nix | 2 + 109 files changed, 1498 insertions(+), 5445 deletions(-) delete mode 100644 _/home-manager/_mixins/common/alacritty.nix delete mode 100644 _/home-manager/_mixins/common/default.nix delete mode 100644 _/home-manager/_mixins/common/deluge.nix delete mode 100644 _/home-manager/_mixins/common/discord.nix delete mode 100644 _/home-manager/_mixins/common/dragon.nix delete mode 100644 _/home-manager/_mixins/common/firefox.nix delete mode 100644 _/home-manager/_mixins/common/font.nix delete mode 100644 _/home-manager/_mixins/common/gnome-wm/default.nix delete mode 100644 _/home-manager/_mixins/common/gtk.nix delete mode 100644 _/home-manager/_mixins/common/kdeconnect.nix delete mode 100644 _/home-manager/_mixins/common/pavucontrol.nix delete mode 100644 _/home-manager/_mixins/common/playerctl.nix delete mode 100644 _/home-manager/_mixins/common/qt.nix delete mode 100644 _/home-manager/_mixins/common/slack.nix delete mode 100644 _/home-manager/_mixins/common/sublime-music.nix delete mode 100644 _/home-manager/_mixins/common/wayland-wm/default.nix delete mode 100644 _/home-manager/_mixins/common/wayland-wm/gammastep.nix delete mode 100644 _/home-manager/_mixins/common/wayland-wm/hyprland-vnc.nix delete mode 100644 _/home-manager/_mixins/common/wayland-wm/kitty.nix delete mode 100644 _/home-manager/_mixins/common/wayland-wm/mako.nix delete mode 100644 _/home-manager/_mixins/common/wayland-wm/qutebrowser.nix delete mode 100644 _/home-manager/_mixins/common/wayland-wm/swayidle.nix delete mode 100644 _/home-manager/_mixins/common/wayland-wm/swaylock.nix delete mode 100644 _/home-manager/_mixins/common/wayland-wm/waybar.nix delete mode 100644 _/home-manager/_mixins/common/wayland-wm/wezterm.nix delete mode 100644 _/home-manager/_mixins/common/wayland-wm/wofi-run-shell.patch delete mode 100644 _/home-manager/_mixins/common/wayland-wm/wofi.nix delete mode 100644 _/home-manager/_mixins/common/wayland-wm/zathura.nix delete mode 100644 _/home-manager/_mixins/default.nix delete mode 100644 _/home-manager/_mixins/gnome/default.nix delete mode 100644 _/home-manager/_mixins/gnome/tty-init.nix delete mode 100644 _/home-manager/_mixins/users/gburd/generic.nix delete mode 100644 _/home-manager/_mixins/users/wireless/default.nix delete mode 100644 _/home-manager/_mixins/wpa-gui.nix delete mode 100644 _/modules/home-manager/default.nix delete mode 100644 _/modules/home-manager/fonts.nix delete mode 100644 _/modules/home-manager/monitors.nix delete mode 100644 _/modules/home-manager/rgbdaemon.nix delete mode 100644 _/modules/home-manager/shellcolor.nix delete mode 100644 _/modules/home-manager/wallpaper.nix delete mode 100644 _/modules/home-manager/xpo.nix delete mode 100644 _/modules/nixos/default.nix delete mode 100644 _/modules/nixos/openrgb.nix delete mode 100644 _/modules/nixos/satisfactory.nix delete mode 100644 _/nixos/_mixins/global/acme.nix delete mode 100644 _/nixos/_mixins/global/auto-upgrade.nix delete mode 100644 _/nixos/_mixins/global/default.nix delete mode 100644 _/nixos/_mixins/global/fish.nix delete mode 100644 _/nixos/_mixins/global/locale.nix delete mode 100644 _/nixos/_mixins/global/nix.nix delete mode 100644 _/nixos/_mixins/global/openssh.nix delete mode 100644 _/nixos/_mixins/global/podman.nix delete mode 100644 _/nixos/_mixins/global/ssh-serve-store.nix delete mode 100644 _/nixos/_mixins/global/steam-hardware.nix delete mode 100644 _/nixos/_mixins/global/systemd-initrd.nix delete mode 100644 _/nixos/_mixins/global/tailscale.nix delete mode 100644 _/nixos/_mixins/optional/ckb-next.nix delete mode 100644 _/nixos/_mixins/optional/docker.nix delete mode 100644 _/nixos/_mixins/optional/ephemeral-btrfs.nix delete mode 100644 _/nixos/_mixins/optional/fail2ban.nix delete mode 100644 _/nixos/_mixins/optional/gamemode.nix delete mode 100644 _/nixos/_mixins/optional/gnome.nix delete mode 100644 _/nixos/_mixins/optional/lol-acfix.nix delete mode 100644 _/nixos/_mixins/optional/mysql.nix delete mode 100644 _/nixos/_mixins/optional/nginx.nix delete mode 100644 _/nixos/_mixins/optional/pantheon.nix delete mode 100644 _/nixos/_mixins/optional/postgres.nix delete mode 100644 _/nixos/_mixins/optional/starcitizen-fixes.nix delete mode 100644 _/nixos/_mixins/optional/systemd-boot.nix delete mode 100644 _/nixos/_mixins/optional/tailscale-exit-node.nix delete mode 100644 _/nixos/_mixins/optional/wireless.nix delete mode 100644 _/nixos/_mixins/optional/wireshark.nix delete mode 100644 _/nixos/_mixins/optional/x11-no-suspend.nix delete mode 100644 _/nixos/iso-console/default.nix delete mode 100644 _/nixos/iso-desktop/default.nix delete mode 100644 _/overlays/default.nix delete mode 100644 _/overlays/offline-mode-prism-launcher.diff delete mode 100644 _/overlays/pfetch.patch delete mode 100644 _/overlays/qutebrowser-tree-tabs.diff delete mode 100644 _/overlays/vim-numbertoggle-command-mode.patch delete mode 100644 _/overlays/xdg-open-spawn-terminal.diff create mode 100644 home-manager/_mixins/users/_gburd/.gitconfig create mode 100644 home-manager/_mixins/users/_gburd/alacritty.yml create mode 100644 home-manager/_mixins/users/_gburd/default.nix create mode 100644 home-manager/_mixins/users/_gburd/desktop.nix create mode 100644 home-manager/_mixins/users/_gburd/face.png create mode 100644 home-manager/_mixins/users/_gburd/hosts/floki.nix create mode 100644 home-manager/_mixins/users/_gburd/init.nvim create mode 100644 home-manager/_mixins/users/_gburd/pgp.asc create mode 100644 home-manager/_mixins/users/_gburd/ssh.pub create mode 100644 home-manager/_mixins/users/_gburd/symas-ssh.pub create mode 100644 nixos/_mixins/users/_gburd/default.nix diff --git a/.sops.yaml b/.sops.yaml index ea9afcb..6ad9b4a 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -2,6 +2,7 @@ keys: # Users - &users: - &gburd D4BB42BE729AEFBD2EFEBF8822931AF7895E82DF + - &greg D4BB42BE729AEFBD2EFEBF8822931AF7895E82DF # Hosts - &hosts: - &floki age1z2x0g05q2erpux006vwhul70d8akj9avrj67s9p27fm4ce32ly8qt8nllz @@ -16,21 +17,25 @@ creation_rules: - *floki pgp: - *gburd + - *greg - path_regex: nixos/iso-console/secrets.ya?ml$ key_groups: - age: - *iso-console pgp: - *gburd + - *greg - path_regex: nixos/iso-desktop/secrets.ya?ml$ key_groups: - age: - *iso-desktop pgp: - *gburd + - *greg - path_regex: nixos/_mixins/secrets.ya?ml$ key_groups: - age: - *floki pgp: - *gburd + - *greg diff --git a/README.md b/README.md index 54589f0..b92ecfc 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,13 @@ nix develop `nix build` (or shell or run) To build and use packages -`sops` To manage secrets +`sops` To manage secrets, example: + +``` +export GPG_TTY=$(tty) +gpgconf --reload gpg-agent +EDITOR=vi sops --config .sops.yaml nixos/_mixins/secrets.yaml +``` ## Secrets diff --git a/_/home-manager/_mixins/common/alacritty.nix b/_/home-manager/_mixins/common/alacritty.nix deleted file mode 100644 index 9795f2f..0000000 --- a/_/home-manager/_mixins/common/alacritty.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ pkgs, ... }: -{ - home.packages = [ pkgs.alacritty ]; -} diff --git a/_/home-manager/_mixins/common/default.nix b/_/home-manager/_mixins/common/default.nix deleted file mode 100644 index a53127f..0000000 --- a/_/home-manager/_mixins/common/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - imports = [ - ./deluge.nix - ./discord.nix - ./firefox.nix - ./alacritty.nix - ./font.nix - ./gtk.nix - # ./kdeconnect.nix - ./pavucontrol.nix - ./playerctl.nix - ./qt.nix - ./slack.nix - ./sublime-music.nix - ./protonmail-bridge.nix - ]; -} diff --git a/_/home-manager/_mixins/common/deluge.nix b/_/home-manager/_mixins/common/deluge.nix deleted file mode 100644 index 3e4845c..0000000 --- a/_/home-manager/_mixins/common/deluge.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ pkgs, ... }: { - home.packages = with pkgs; [ deluge ]; -} diff --git a/_/home-manager/_mixins/common/discord.nix b/_/home-manager/_mixins/common/discord.nix deleted file mode 100644 index 97492f9..0000000 --- a/_/home-manager/_mixins/common/discord.nix +++ /dev/null @@ -1,221 +0,0 @@ -{ config, pkgs, ... }: - -let inherit (config.colorscheme) colors; -in { - home.packages = with pkgs; [ discord discocss ]; - - home.persistence = { - "/persist/home/gburd".directories = [ ".config/discord" ]; - }; - - xdg.configFile."discocss/custom.css".text = '' - .theme-dark { - --header-primary: #${colors.base05}; - --header-secondary: #${colors.base04}; - --text-normal: #${colors.base05}; - --text-muted: #${colors.base04}; - --text-link: #${colors.base08}; - --channels-default: #${colors.base05}; - --interactive-normal: #${colors.base04}; - --interactive-hover: #${colors.base05}; - --interactive-active: #${colors.base05}; - --interactive-muted: #${colors.base03}; - --background-primary: #${colors.base00}; - --background-secondary: #${colors.base01}; - --background-secondary-alt: #${colors.base02}; - --background-tertiary: #${colors.base01}; - --background-accent: #${colors.base01}; - --background-floating: #${colors.base00}; - --background-mobile-primary: var(--background-primary); - --background-mobile-secondary: var(--background-secondary); - --background-modifier-selected: var(--background-secondary); - --scrollbar-thin-thumb: #${colors.base02}; - --scrollbar-auto-thumb: #${colors.base02}; - --scrollbar-auto-track: #${colors.base01}; - --scrollbar-auto-scrollbar-color-thumb: #${colors.base02}; - --scrollbar-auto-scrollbar-color-track: #${colors.base01}; - --focus-primary: #${colors.base08}; - --channeltextarea-background: #${colors.base01}; - --deprecated-card-bg: #${colors.base01}; - --deprecated-quickswitcher-input-background: #${colors.base01}; - --deprecated-quickswitcher-input-placeholder: #${colors.base05}; - --background-modifier-hover: var(--background-secondary); - --background-modifier-active: var(--background-secondary-alt); - --activity-card-background: var(--background-secondary); - } - body { - font-family: ${config.fontProfiles.regular.family}, sans serif; - } - .scroller-1Bvpku { - background-color: var(--background-primary); - } - .scroller-2FKFPG { - background-color: var(--background-primary); - } - .headerPlaying-j0WQBV, .headerStreaming-2FjmGz { - background: var(--background-secondary-alt); - } - .theme-dark .headerNormal-T_seeN { - background-color: var(--background-primary); - } - .theme-dark .body-3iLsc4, .theme-dark .footer-1fjuF6 { - background-color: var(--background-primary); - color: var(--header-secondary); - } - .theme-dark .quickMessage-1yeL4E { - background-color: var(--background-secondary); - border-color: var(--background-secondary); - } - .theme-dark .inset-3sAvek { - background-color: var(--background-secondary); - } - .theme-dark .userSettingsAccount-2eMFVR .viewBody-2Qz-jg { - color: var(--header-primary); - } - .theme-dark .modal-yWgWj- { - background-color: var(--background-primary); - } - .theme-dark .footer-2gL1pp { - background-color: var(--background-primary); - } - .theme-dark .lookLink-9FtZy-.colorPrimary-3b3xI6 { - color: var(--header-primary); - } - .theme-dark .notDetected-33MY4s, .theme-light .notDetected-33MY4s { - background-color: var(--background-primary); - } - .theme-dark .notDetected-33MY4s .gameName-1RiWHm, .theme-light .notDetected-33MY4s .gameName-1RiWHm { - color: var(--header-primary); - } - .theme-dark .gameName-1RiWHm { - color: var(--header-primary); - } - .theme-dark .notDetected-33MY4s .lastPlayed-3bQ7Bo, .theme-light .notDetected-33MY4s .lastPlayed-3bQ7Bo { - color: var(--header-primary); - } - .theme-dark .nowPlayingAdd-1Kdmh_, .theme-light .nowPlayingAdd-1Kdmh_ { - color: var(--header-primary); - } - .css-1k00wn6-singleValue { - color: var(--header-primary); - } - .theme-dark .codeRedemptionRedirect-1wVR4b { - color: var(--header-primary); - background-color: var(--background-primary); - border-color: var(--background-primary); - } - .theme-dark .emptyStateHeader-248f_b { - color: var(--header-primary); - } - .theme-dark .emptyStateSubtext-2hdA9c { - color: var(--header-primary); - } - .theme-dark .root-1gCeng { - background-color: var(--background-primary); - } - .theme-dark .date-EErlv4 { - color: var(--header-primary); - } - .theme-dark .content-8bidB ol, .theme-dark .content-8biNdB p, .theme-dark .content-8biNdB ul li { - color: var(--header-primary); - } - .headerName-fajvi9, .headerTagUsernameNoNickname-2_H881 { - color: var(--header-primary); - } - .headerTag-2pZJzA { - color: var(--header-secondary); - } - .theme-dark .activityProfile-2bJRaP .headerText-1HLrL7, .theme-dark .activityUserPopout-2yItg2 .headerText-1HLrL7, .theme-light .activityProfile-2bJRaP .headerText-1HLrL7, .theme-light .activityUserPopout-2yItg2 .headerText-1HLrL7 { - color: var(--header-secondary); - } - .activityName-1IaRLn, .nameNormal-2lqVQK, .nameWrap-3Z4G_9 { - color: var(--header-secondary); - } - .theme-dark .activityProfile-2bJRaP .content-3JfFJh, .theme-dark .activityProfile-2bJRaP .details-38sfDr, .theme-dark .activityProfile-2bJRaP .name-29ETJS, .theme-dark .activityUserPopout-2yItg2 .content-3JfFJh, .theme-dark .activityUserPopout-2yItg2 .details-38sfDr, .theme-dark .activityUserPopout-2yItg2 .name-29ETJS, .theme-light .activityProfile-2bJRaP .content-3JfFJh, .theme-light .activityProfile-2bJRaP .details-38sfDr, .theme-light .activityProfile-2bJRaP .name-29ETJS, .theme-light .activityUserPopout-2yItg2 .content-3JfFJh, .theme-light .activityUserPopout-2yItg2 .details-38sfDr, .theme-light .activityUserPopout-2yItg2 .name-29ETJS { - color: var(--header-secondary); - } - .topSectionPlaying-1J5E4n { - background: var(--background-secondary-alt); - } - .username-3gJmXY { - color: var(--header-primary); - } - .discriminator-xUhQkU { - color: var(--header-secondary); - } - .tabBarItem-1b8RUP.item-PXvHYJ { - color: var(--header-secondary) !important; - border-color: transparent !important; - } - .theme-dark .keybind-KpFkfr { - color: var(--header-primary); - } - .theme-dark .closeButton-1tv5uR { - border-color: var(--header-primary); - } - .barFill-23-gu- { - background: var(--text-link); - } - .focused-3afm-j { - background-color: var(--background-secondary) !important; - color: var(--text-link) !important; - } - .colorDefault-2K3EoJ .checkbox-3s5GYZ, .colorDefault-2K3EoJ .radioSelection-1HmrQS { - color: var(--text-link); - } - .colorDefault-2K3EoJ .checkbox-3s5GYZ { - color: var(--text-link); - } - .colorDefault-2K3EoJ .check-1JyqgN { - color: var(--background-primary); - } - .colorDefault-2K3EoJ.focused-3afm-j .checkbox-3s5GYZ { - color: var(--background-primary) !important; - } - .colorDefault-2K3EoJ.focused-3afm-j .check-1JyqgN { - color: var(--text-link); - } - .wrapper-1BJsBx.selected-bZ3Lue .childWrapper-anI2G9, .wrapper-1BJsBx:hover .childWrapper-anI2G9 { - color: var(--background-primary); - background-color: var(--header-secondary); - } - .panels-j1Uci_ { - background-color: var(--background-primary); - } - .navButton-2gQCx- { - color: var(--interactive-normal); - } - .navButtonActive-1MkytQ { - color: var(--header-primary); - } - .input-3Xdcic { - color: var(--header-primary); - } - .clickable-2ap7je .header-2o-2hj { - background-color: var(--background-primary); - } - .peopleColumn-29fq28 { - background-color: var(--background-tertiary); - } - .theme-dark .outer-1AjyKL.active-1xchHY, .theme-dark .outer-1AjyKL.interactive-3B9GmY:hover { - background-color: var(--background-primary); - } - - .theme-dark .popout-38lTFE { - background-color: var(--background-primary); - } - - .theme-dark .scrollerThemed-2oenus.themedWithTrack-q8E3vB>.scroller-2FKFPG::-webkit-scrollbar-track-piece { - background-color: var(--background-primary); - border: 4px solid var(--background-secondary); - } - - .theme-dark .scrollerThemed-2oenus.themedWithTrack-q8E3vB>.scroller-2FKFPG::-webkit-scrollbar-thumb { - background-color: var(--background-secondary); - border-color: var(--background-secondary); - } - .theme-dark .header-sJd8D7 { - color: var(--text-normal) - } - ''; -} diff --git a/_/home-manager/_mixins/common/dragon.nix b/_/home-manager/_mixins/common/dragon.nix deleted file mode 100644 index 1f681fd..0000000 --- a/_/home-manager/_mixins/common/dragon.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ pkgs, ... }: { - home.packages = with pkgs; [ xdragon ]; -} diff --git a/_/home-manager/_mixins/common/firefox.nix b/_/home-manager/_mixins/common/firefox.nix deleted file mode 100644 index 23e1a1c..0000000 --- a/_/home-manager/_mixins/common/firefox.nix +++ /dev/null @@ -1,127 +0,0 @@ -{ pkgs, ... }: -{ - programs.browserpass.enable = true; - programs.firefox = { - enable = true; - - package = pkgs.wrapFirefox pkgs.firefox-unwrapped { - extraPolicies = { - CaptivePortal = false; - DisableFirefoxStudies = true; - DisablePocket = true; - DisableTelemetry = true; - DisableFirefoxAccounts = false; - NoDefaultBookmarks = true; - OfferToSaveLogins = false; - OfferToSaveLoginsDefault = false; - PasswordManagerEnabled = false; - FirefoxHome = { - Search = true; - Pocket = false; - Snippets = false; - TopSites = false; - Highlights = false; - }; - UserMessaging = { - ExtensionRecommendations = false; - SkipOnboarding = true; - }; - }; - }; - - profiles.gburd = { - id = 0; - bookmarks = { }; - extensions = with pkgs.inputs.firefox-addons; [ - # autoplay-no-more - bypass-paywalls-clean - i-dont-care-about-cookies - # kagi-search-for-firefox - clearurls - decentraleyes - disconnect - duckduckgo-privacy-essentials - floccus - ghostery - # https-everywhere - # languagetool - # onetab - privacy-badger - privacy-badger - privacy-redirect - proton-pass - react-devtools - ublock-origin - ]; - search = { - force = true; - default = "Kagi"; - engines = { - "Nix Packages" = { - urls = [{ - template = "https://search.nixos.org/packages"; - params = [ - { name = "type"; value = "packages"; } - { name = "query"; value = "{searchTerms}"; } - ]; - }]; - icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; - definedAliases = [ "@np" ]; - }; - "NixOS Wiki" = { - urls = [{ template = "https://nixos.wiki/index.php?search={searchTerms}"; }]; - iconUpdateURL = "https://nixos.wiki/favicon.png"; - updateInterval = 24 * 60 * 60 * 1000; - definedAliases = [ "@nw" ]; - }; - "Wikipedia (en)".metaData.alias = "@wiki"; - "Google".metaData.hidden = true; - "Amazon.com".metaData.hidden = true; - "Bing".metaData.hidden = true; - "eBay".metaData.hidden = true; - }; - }; - extraConfig = '' - user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true); - user_pref("full-screen-api.ignore-widgets", true); - user_pref("media.ffmpeg.vaapi.enabled", true); - user_pref("media.rdd-vpx.enabled", true); - ''; - userChrome = '' - # a css - ''; - userContent = '' - # Here too - ''; - settings = { - "general.smoothScroll" = true; - "browser.disableResetPrompt" = true; - "browser.download.panel.shown" = true; - "browser.download.useDownloadDir" = false; - "browser.newtabpage.activity-stream.showSponsoredTopSites" = false; - "browser.shell.checkDefaultBrowser" = false; - "browser.shell.defaultBrowserCheckCount" = 1; - "browser.startup.homepage" = "about:blank"; - "browser.uiCustomization.state" = ''{"placements":{"widget-overflow-fixed-list":[],"nav-bar":["back-button","forward-button","stop-reload-button","home-button","urlbar-container","downloads-button","library-button","ublock0_raymondhill_net-browser-action","_testpilot-containers-browser-action"],"toolbar-menubar":["menubar-items"],"TabsToolbar":["tabbrowser-tabs","new-tab-button","alltabs-button"],"PersonalToolbar":["import-button","personal-bookmarks"]},"seen":["save-to-pocket-button","developer-button","ublock0_raymondhill_net-browser-action","_testpilot-containers-browser-action"],"dirtyAreaCache":["nav-bar","PersonalToolbar","toolbar-menubar","TabsToolbar","widget-overflow-fixed-list"],"currentVersion":18,"newElementCount":4}''; - "dom.security.https_only_mode" = true; - "identity.fxaccounts.enabled" = false; - "privacy.trackingprotection.enabled" = true; - "signon.rememberSignons" = false; - }; - }; - }; - - home = { - persistence = { - # Not persisting is safer, but... - "/persist/home/gburd".directories = [ ".mozilla/firefox" ]; - }; - }; - - xdg.mimeApps.defaultApplications = { - "text/html" = [ "firefox.desktop" ]; - "text/xml" = [ "firefox.desktop" ]; - "x-scheme-handler/http" = [ "firefox.desktop" ]; - "x-scheme-handler/https" = [ "firefox.desktop" ]; - }; -} diff --git a/_/home-manager/_mixins/common/font.nix b/_/home-manager/_mixins/common/font.nix deleted file mode 100644 index 2befcf5..0000000 --- a/_/home-manager/_mixins/common/font.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ pkgs, ... }: { - fontProfiles = { - enable = true; - monospace = { - family = "FiraCode Nerd Font"; - package = pkgs.nerdfonts.override { fonts = [ "FiraCode" ]; }; - }; - regular = { - family = "Fira Sans"; - package = pkgs.fira; - }; - }; -} diff --git a/_/home-manager/_mixins/common/gnome-wm/default.nix b/_/home-manager/_mixins/common/gnome-wm/default.nix deleted file mode 100644 index 09785e3..0000000 --- a/_/home-manager/_mixins/common/gnome-wm/default.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ pkgs, ... }: -{ - imports = [ ]; - - home.packages = with pkgs; [ - # Gnome3 apps - # gnome3.eog # image viewer - # gnome3.evince # pdf reader - - # Desktop look & feel - # gnome.gnome-tweak-tool - - # Extensions - gnomeExtensions.appindicator - gnomeExtensions.dash-to-dock - ]; - - # environment.gnome.excludePackages = (with pkgs; [ - # gnome-photos - # gnome-tour - # ]) ++ (with pkgs.gnome; [ - # cheese # webcam tool - # gnome-music - # geary # email reader - # gnome-characters - # yelp # Help view - # gnome-contacts - # gnome-initial-setup - # ]); - # programs.dconf.enable = true; - # environment.systemPackages = with pkgs; [ - # gnome.gnome-tweaks - # ] - # }; - # dbus.packages = [ pkgs.gnome.dconf ]; - # udev.packages = [ pkgs.gnome.gnome-settings- - - home.sessionVariables = { - MOZ_ENABLE_WAYLAND = 1; - }; -} diff --git a/_/home-manager/_mixins/common/gtk.nix b/_/home-manager/_mixins/common/gtk.nix deleted file mode 100644 index 397a78d..0000000 --- a/_/home-manager/_mixins/common/gtk.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ config, pkgs, inputs, ... }: - -let - inherit (inputs.nix-colors.lib-contrib { inherit pkgs; }) gtkThemeFromScheme; -in -rec { - gtk = { - enable = true; - font = { - name = config.fontProfiles.regular.family; - size = 14; - }; - theme = { - name = "${config.colorscheme.slug}"; - package = gtkThemeFromScheme { scheme = config.colorscheme; }; - }; - iconTheme = { - name = "Papirus"; - package = pkgs.papirus-icon-theme; - }; - }; - services.xsettingsd = { - enable = true; - settings = { - "Net/ThemeName" = "${gtk.theme.name}"; - "Net/IconThemeName" = "${gtk.iconTheme.name}"; - }; - }; -} diff --git a/_/home-manager/_mixins/common/kdeconnect.nix b/_/home-manager/_mixins/common/kdeconnect.nix deleted file mode 100644 index 6512f3a..0000000 --- a/_/home-manager/_mixins/common/kdeconnect.nix +++ /dev/null @@ -1,46 +0,0 @@ -{ pkgs, ... }: - -let - - kdeconnect-cli = "${pkgs.plasma5Packages.kdeconnect-kde}/bin/kdeconnect-cli"; - fortune = "${pkgs.fortune}/bin/fortune"; - - script-fortune = pkgs.writeShellScriptBin "fortune" '' - ${kdeconnect-cli} -d $(${kdeconnect-cli} --list-available --id-only) --ping-msg "$(${fortune})" - ''; - -in -{ - # Hide all .desktop, except for org.kde.kdeconnect.settings - xdg.desktopEntries = { - "org.kde.kdeconnect.sms" = { - exec = ""; - name = "KDE Connect SMS"; - settings.NoDisplay = "true"; - }; - "org.kde.kdeconnect.nonplasma" = { - exec = ""; - name = "KDE Connect Indicator"; - settings.NoDisplay = "true"; - }; - "org.kde.kdeconnect.app" = { - exec = ""; - name = "KDE Connect"; - settings.NoDisplay = "true"; - }; - }; - - services.kdeconnect = { - enable = true; - indicator = true; - - }; - - xdg.configFile = { - "kdeconnect-scripts/fortune.sh".source = "${script-fortune}/bin/fortune"; - }; - - home.persistence = { - "/persist/home/gburd".directories = [ ".config/kdeconnect" ]; - }; -} diff --git a/_/home-manager/_mixins/common/pavucontrol.nix b/_/home-manager/_mixins/common/pavucontrol.nix deleted file mode 100644 index e86872f..0000000 --- a/_/home-manager/_mixins/common/pavucontrol.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ pkgs, ... }: { - home.packages = with pkgs; [ pavucontrol ]; -} diff --git a/_/home-manager/_mixins/common/playerctl.nix b/_/home-manager/_mixins/common/playerctl.nix deleted file mode 100644 index 8126526..0000000 --- a/_/home-manager/_mixins/common/playerctl.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ pkgs, ... }: -{ - home.packages = with pkgs; [ playerctl ]; - services.playerctld = { - enable = true; - }; -} diff --git a/_/home-manager/_mixins/common/qt.nix b/_/home-manager/_mixins/common/qt.nix deleted file mode 100644 index 1ceedde..0000000 --- a/_/home-manager/_mixins/common/qt.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ pkgs, ... }: -{ - qt = { - enable = true; - platformTheme = "gtk"; - style = { - name = "gtk2"; - package = pkgs.qt6gtk2; - }; - }; -} diff --git a/_/home-manager/_mixins/common/slack.nix b/_/home-manager/_mixins/common/slack.nix deleted file mode 100644 index 4ff5f05..0000000 --- a/_/home-manager/_mixins/common/slack.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ pkgs, ... }: -{ - home.packages = [ pkgs.slack ]; -} diff --git a/_/home-manager/_mixins/common/sublime-music.nix b/_/home-manager/_mixins/common/sublime-music.nix deleted file mode 100644 index 0bd6b04..0000000 --- a/_/home-manager/_mixins/common/sublime-music.nix +++ /dev/null @@ -1,6 +0,0 @@ -{ pkgs, ... }: { - home.packages = [ pkgs.sublime-music ]; - home.persistence = { - "/persist/home/gburd".directories = [ ".config/sublime-music" ]; - }; -} diff --git a/_/home-manager/_mixins/common/wayland-wm/default.nix b/_/home-manager/_mixins/common/wayland-wm/default.nix deleted file mode 100644 index 9b474ae..0000000 --- a/_/home-manager/_mixins/common/wayland-wm/default.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ pkgs, ... }: -{ - imports = [ - ./hyprland-vnc.nix - ./gammastep.nix - ./kitty.nix - ./mako.nix - ./qutebrowser.nix - ./swayidle.nix - ./swaylock.nix - ./waybar.nix - ./wofi.nix - ./zathura.nix - ]; - - xdg.mimeApps.enable = true; - home.packages = with pkgs; [ - grim - gtk3 # For gtk-launch - imv - mimeo - primary-xwayland - pulseaudio - slurp - waypipe - wf-recorder - wl-clipboard - wl-mirror - wl-mirror-pick - xdg-utils-spawn-terminal # Patched to open terminal - ydotool - ]; - - home.sessionVariables = { - MOZ_ENABLE_WAYLAND = 1; - QT_QPA_PLATFORM = "wayland"; - LIBSEAT_BACKEND = "logind"; - }; -} diff --git a/_/home-manager/_mixins/common/wayland-wm/gammastep.nix b/_/home-manager/_mixins/common/wayland-wm/gammastep.nix deleted file mode 100644 index 498756e..0000000 --- a/_/home-manager/_mixins/common/wayland-wm/gammastep.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ - services.gammastep = { - enable = true; - provider = "geoclue2"; - temperature = { - day = 6000; - night = 4600; - }; - settings = { - general.adjustment-method = "wayland"; - }; - }; -} diff --git a/_/home-manager/_mixins/common/wayland-wm/hyprland-vnc.nix b/_/home-manager/_mixins/common/wayland-wm/hyprland-vnc.nix deleted file mode 100644 index a920f88..0000000 --- a/_/home-manager/_mixins/common/wayland-wm/hyprland-vnc.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ pkgs, lib, config, ... }: -let - enabledMonitors = lib.filter (m: m.enabled) config.monitors; - # A nice VNC script for remotes running hyprland - vncsh = pkgs.writeShellScriptBin "vnc.sh" '' - ssh $1 bash <<'EOF' - pgrep "wayvnc" && exit - export HYPRLAND_INSTANCE_SIGNATURE="$(ls /tmp/hypr/ -lt | head -2 | tail -1 | rev | cut -d ' ' -f1 | rev)" - export WAYLAND_DISPLAY="wayland-1" - ip="$(ip addr show dev tailscale0 | grep 'inet ' | xargs | cut -d ' ' -f2 | cut -d '/' -f1)" - xpos="$(hyprctl monitors -j | jq -r 'sort_by(.x)[-1] | .x + .width')" - - ${lib.concatLines (lib.forEach enabledMonitors (m: '' - hyprctl output create headless - monitor="$(hyprctl monitors -j | jq -r 'map(.name)[-1]')" - hyprctl keyword monitor $monitor,${toString m.width}x${toString m.height}@${toString m.refreshRate},$(($xpos + ${toString m.x}))x${toString m.y},1 - screen -d -m wayvnc -k br -S /tmp/vnc-${m.workspace} -f 60 -o $monitor $ip 590${m.workspace} - sudo iptables -I INPUT -j ACCEPT -p tcp --dport 590${m.workspace} - ''))} - EOF - - ${lib.concatLines (lib.forEach enabledMonitors (m: '' - vncviewer $1::590${m.workspace} & - ''))} - - wait - ''; -in -{ - home.packages = with pkgs; [ - vncsh - wayvnc - tigervnc - ]; -} diff --git a/_/home-manager/_mixins/common/wayland-wm/kitty.nix b/_/home-manager/_mixins/common/wayland-wm/kitty.nix deleted file mode 100644 index 3528e1f..0000000 --- a/_/home-manager/_mixins/common/wayland-wm/kitty.nix +++ /dev/null @@ -1,66 +0,0 @@ -{ config, pkgs, ... }: - -let - inherit (config.colorscheme) colors; - kitty-xterm = pkgs.writeShellScriptBin "xterm" '' - ${config.programs.kitty.package}/bin/kitty -1 "$@" - ''; -in -{ - home = { - packages = [ kitty-xterm ]; - sessionVariables = { - TERMINAL = "kitty -1"; - }; - }; - - - programs.kitty = { - enable = true; - font = { - name = config.fontProfiles.monospace.family; - size = 12; - }; - settings = { - shell_integration = "no-rc"; # I prefer to do it manually - scrollback_lines = 4000; - scrollback_pager_history_size = 2048; - window_padding_width = 15; - foreground = "#${colors.base05}"; - background = "#${colors.base00}"; - selection_background = "#${colors.base05}"; - selection_foreground = "#${colors.base00}"; - url_color = "#${colors.base04}"; - cursor = "#${colors.base05}"; - active_border_color = "#${colors.base03}"; - inactive_border_color = "#${colors.base01}"; - active_tab_background = "#${colors.base00}"; - active_tab_foreground = "#${colors.base05}"; - inactive_tab_background = "#${colors.base01}"; - inactive_tab_foreground = "#${colors.base04}"; - tab_bar_background = "#${colors.base01}"; - color0 = "#${colors.base00}"; - color1 = "#${colors.base08}"; - color2 = "#${colors.base0B}"; - color3 = "#${colors.base0A}"; - color4 = "#${colors.base0D}"; - color5 = "#${colors.base0E}"; - color6 = "#${colors.base0C}"; - color7 = "#${colors.base05}"; - color8 = "#${colors.base03}"; - color9 = "#${colors.base08}"; - color10 = "#${colors.base0B}"; - color11 = "#${colors.base0A}"; - color12 = "#${colors.base0D}"; - color13 = "#${colors.base0E}"; - color14 = "#${colors.base0C}"; - color15 = "#${colors.base07}"; - color16 = "#${colors.base09}"; - color17 = "#${colors.base0F}"; - color18 = "#${colors.base01}"; - color19 = "#${colors.base02}"; - color20 = "#${colors.base04}"; - color21 = "#${colors.base06}"; - }; - }; -} diff --git a/_/home-manager/_mixins/common/wayland-wm/mako.nix b/_/home-manager/_mixins/common/wayland-wm/mako.nix deleted file mode 100644 index d98e904..0000000 --- a/_/home-manager/_mixins/common/wayland-wm/mako.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ config, ... }: -let inherit (config.colorscheme) colors kind; -in { - services.mako = { - enable = true; - iconPath = - if kind == "dark" then - "${config.gtk.iconTheme.package}/share/icons/Papirus-Dark" - else - "${config.gtk.iconTheme.package}/share/icons/Papirus-Light"; - font = "${config.fontProfiles.regular.family} 12"; - padding = "10,20"; - anchor = "top-center"; - width = 400; - height = 150; - borderSize = 2; - defaultTimeout = 12000; - backgroundColor = "#${colors.base00}dd"; - borderColor = "#${colors.base03}dd"; - textColor = "#${colors.base05}dd"; - layer = "overlay"; - }; -} diff --git a/_/home-manager/_mixins/common/wayland-wm/qutebrowser.nix b/_/home-manager/_mixins/common/wayland-wm/qutebrowser.nix deleted file mode 100644 index 43816a0..0000000 --- a/_/home-manager/_mixins/common/wayland-wm/qutebrowser.nix +++ /dev/null @@ -1,177 +0,0 @@ -{ config, ... }: - -let inherit (config.colorscheme) colors kind; -in -{ - home.persistence = { - "/persist/home/misterio".directories = [ - ".config/qutebrowser/bookmarks" - ".config/qutebrowser/greasemonkey" - ".local/share/qutebrowser" - ]; - }; - - - - xdg.mimeApps.defaultApplications = { - "text/html" = [ "org.qutebrowser.qutebrowser.desktop" ]; - "text/xml" = [ "org.qutebrowser.qutebrowser.desktop" ]; - "x-scheme-handler/http" = [ "org.qutebrowser.qutebrowser.desktop" ]; - "x-scheme-handler/https" = [ "org.qutebrowser.qutebrowser.desktop" ]; - "x-scheme-handler/qute" = [ "org.qutebrowser.qutebrowser.desktop" ]; - }; - - - programs.qutebrowser = { - enable = true; - loadAutoconfig = true; - settings = { - editor.command = [ "xdg-open" "{file}" ]; - tabs = { - show = "multiple"; - position = "left"; - tree_tabs = true; - }; - fonts = { - default_family = config.fontProfiles.regular.family; - default_size = "12pt"; - }; - colors = { - webpage = { - preferred_color_scheme = kind; - bg = "#ffffff"; - }; - completion = { - fg = "#${colors.base05}"; - match.fg = "#${colors.base09}"; - even.bg = "#${colors.base00}"; - odd.bg = "#${colors.base00}"; - scrollbar = { - bg = "#${colors.base00}"; - fg = "#${colors.base05}"; - }; - category = { - bg = "#${colors.base00}"; - fg = "#${colors.base0D}"; - border = { - bottom = "#${colors.base00}"; - top = "#${colors.base00}"; - }; - }; - item.selected = { - bg = "#${colors.base02}"; - fg = "#${colors.base05}"; - match.fg = "#${colors.base05}"; - border = { - bottom = "#${colors.base02}"; - top = "#${colors.base02}"; - }; - }; - }; - contextmenu = { - disabled = { - bg = "#${colors.base01}"; - fg = "#${colors.base04}"; - }; - menu = { - bg = "#${colors.base00}"; - fg = "#${colors.base05}"; - }; - selected = { - bg = "#${colors.base02}"; - fg = "#${colors.base05}"; - }; - }; - downloads = { - bar.bg = "#${colors.base00}"; - error.fg = "#${colors.base08}"; - start = { - bg = "#${colors.base0D}"; - fg = "#${colors.base00}"; - }; - stop = { - bg = "#${colors.base0C}"; - fg = "#${colors.base00}"; - }; - }; - hints = { - bg = "#${colors.base0A}"; - fg = "#${colors.base00}"; - match.fg = "#${colors.base05}"; - }; - keyhint = { - bg = "#${colors.base00}"; - fg = "#${colors.base05}"; - suffix.fg = "#${colors.base05}"; - }; - messages = { - error.bg = "#${colors.base08}"; - error.border = "#${colors.base08}"; - error.fg = "#${colors.base00}"; - info.bg = "#${colors.base00}"; - info.border = "#${colors.base00}"; - info.fg = "#${colors.base05}"; - warning.bg = "#${colors.base0E}"; - warning.border = "#${colors.base0E}"; - warning.fg = "#${colors.base00}"; - }; - prompts = { - bg = "#${colors.base00}"; - fg = "#${colors.base05}"; - border = "#${colors.base00}"; - selected.bg = "#${colors.base02}"; - }; - statusbar = { - caret.bg = "#${colors.base00}"; - caret.fg = "#${colors.base0D}"; - caret.selection.bg = "#${colors.base00}"; - caret.selection.fg = "#${colors.base0D}"; - command.bg = "#${colors.base01}"; - command.fg = "#${colors.base04}"; - command.private.bg = "#${colors.base01}"; - command.private.fg = "#${colors.base0E}"; - insert.bg = "#${colors.base00}"; - insert.fg = "#${colors.base0C}"; - normal.bg = "#${colors.base00}"; - normal.fg = "#${colors.base05}"; - passthrough.bg = "#${colors.base00}"; - passthrough.fg = "#${colors.base0A}"; - private.bg = "#${colors.base00}"; - private.fg = "#${colors.base0E}"; - progress.bg = "#${colors.base0D}"; - url.error.fg = "#${colors.base08}"; - url.fg = "#${colors.base05}"; - url.hover.fg = "#${colors.base09}"; - url.success.http.fg = "#${colors.base0B}"; - url.success.https.fg = "#${colors.base0B}"; - url.warn.fg = "#${colors.base0E}"; - }; - tabs = { - bar.bg = "#${colors.base00}"; - even.bg = "#${colors.base00}"; - even.fg = "#${colors.base05}"; - indicator.error = "#${colors.base08}"; - indicator.start = "#${colors.base0D}"; - indicator.stop = "#${colors.base0C}"; - odd.bg = "#${colors.base00}"; - odd.fg = "#${colors.base05}"; - pinned.even.bg = "#${colors.base0B}"; - pinned.even.fg = "#${colors.base00}"; - pinned.odd.bg = "#${colors.base0B}"; - pinned.odd.fg = "#${colors.base00}"; - pinned.selected.even.bg = "#${colors.base02}"; - pinned.selected.even.fg = "#${colors.base05}"; - pinned.selected.odd.bg = "#${colors.base02}"; - pinned.selected.odd.fg = "#${colors.base05}"; - selected.even.bg = "#${colors.base02}"; - selected.even.fg = "#${colors.base05}"; - selected.odd.bg = "#${colors.base02}"; - selected.odd.fg = "#${colors.base05}"; - }; - }; - }; - extraConfig = '' - c.tabs.padding = {"bottom": 10, "left": 10, "right": 10, "top": 10} - ''; - }; -} diff --git a/_/home-manager/_mixins/common/wayland-wm/swayidle.nix b/_/home-manager/_mixins/common/wayland-wm/swayidle.nix deleted file mode 100644 index c2b9892..0000000 --- a/_/home-manager/_mixins/common/wayland-wm/swayidle.nix +++ /dev/null @@ -1,54 +0,0 @@ -{ pkgs, lib, config, ... }: - -let - swaylock = "${config.programs.swaylock.package}/bin/swaylock"; - pgrep = "${pkgs.procps}/bin/pgrep"; - pactl = "${pkgs.pulseaudio}/bin/pactl"; - hyprctl = "${config.wayland.windowManager.hyprland.package}/bin/hyprctl"; - swaymsg = "${config.wayland.windowManager.sway.package}/bin/swaymsg"; - - isLocked = "${pgrep} -x ${swaylock}"; - lockTime = 4 * 60; # TODO: configurable desktop (10 min)/laptop (4 min) - - # Makes two timeouts: one for when the screen is not locked (lockTime+timeout) and one for when it is. - afterLockTimeout = { timeout, command, resumeCommand ? null }: [ - { timeout = lockTime + timeout; inherit command resumeCommand; } - { command = "${isLocked} && ${command}"; inherit resumeCommand timeout; } - ]; -in -{ - services.swayidle = { - enable = true; - systemdTarget = "graphical-session.target"; - timeouts = - # Lock screen - [{ - timeout = lockTime; - command = "${swaylock} -i ${config.wallpaper} --daemonize"; - }] ++ - # Mute mic - (afterLockTimeout { - timeout = 10; - command = "${pactl} set-source-mute @DEFAULT_SOURCE@ yes"; - resumeCommand = "${pactl} set-source-mute @DEFAULT_SOURCE@ no"; - }) ++ - # Turn off RGB - (lib.optionals config.services.rgbdaemon.enable (afterLockTimeout { - timeout = 20; - command = "systemctl --user stop rgbdaemon"; - resumeCommand = "systemctl --user start rgbdaemon"; - })) ++ - # Turn off displays (hyprland) - (lib.optionals config.wayland.windowManager.hyprland.enable (afterLockTimeout { - timeout = 40; - command = "${hyprctl} dispatch dpms off"; - resumeCommand = "${hyprctl} dispatch dpms on"; - })) ++ - # Turn off displays (sway) - (lib.optionals config.wayland.windowManager.sway.enable (afterLockTimeout { - timeout = 40; - command = "${swaymsg} 'output * dpms off'"; - resumeCommand = "${swaymsg} 'output * dpms on'"; - })); - }; -} diff --git a/_/home-manager/_mixins/common/wayland-wm/swaylock.nix b/_/home-manager/_mixins/common/wayland-wm/swaylock.nix deleted file mode 100644 index 738bbfd..0000000 --- a/_/home-manager/_mixins/common/wayland-wm/swaylock.nix +++ /dev/null @@ -1,43 +0,0 @@ -{ config, pkgs, ... }: - -let inherit (config.colorscheme) colors; -in -{ - programs.swaylock = { - enable = true; - package = pkgs.swaylock-effects; - settings = { - effect-blur = "20x3"; - fade-in = 0.1; - - font = config.fontProfiles.regular.family; - font-size = 15; - - line-uses-inside = true; - disable-caps-lock-text = true; - indicator-caps-lock = true; - indicator-radius = 40; - indicator-idle-visible = true; - indicator-y-position = 1000; - - ring-color = "#${colors.base02}"; - inside-wrong-color = "#${colors.base08}"; - ring-wrong-color = "#${colors.base08}"; - key-hl-color = "#${colors.base0B}"; - bs-hl-color = "#${colors.base08}"; - ring-ver-color = "#${colors.base09}"; - inside-ver-color = "#${colors.base09}"; - inside-color = "#${colors.base01}"; - text-color = "#${colors.base07}"; - text-clear-color = "#${colors.base01}"; - text-ver-color = "#${colors.base01}"; - text-wrong-color = "#${colors.base01}"; - text-caps-lock-color = "#${colors.base07}"; - inside-clear-color = "#${colors.base0C}"; - ring-clear-color = "#${colors.base0C}"; - inside-caps-lock-color = "#${colors.base09}"; - ring-caps-lock-color = "#${colors.base02}"; - separator-color = "#${colors.base02}"; - }; - }; -} diff --git a/_/home-manager/_mixins/common/wayland-wm/waybar.nix b/_/home-manager/_mixins/common/wayland-wm/waybar.nix deleted file mode 100644 index f0fa0a4..0000000 --- a/_/home-manager/_mixins/common/wayland-wm/waybar.nix +++ /dev/null @@ -1,392 +0,0 @@ -{ outputs, config, lib, pkgs, ... }: - -let - # Dependencies - cat = "${pkgs.coreutils}/bin/cat"; - cut = "${pkgs.coreutils}/bin/cut"; - find = "${pkgs.findutils}/bin/find"; - grep = "${pkgs.gnugrep}/bin/grep"; - pgrep = "${pkgs.procps}/bin/pgrep"; - tail = "${pkgs.coreutils}/bin/tail"; - wc = "${pkgs.coreutils}/bin/wc"; - xargs = "${pkgs.findutils}/bin/xargs"; - timeout = "${pkgs.coreutils}/bin/timeout"; - ping = "${pkgs.iputils}/bin/ping"; - - jq = "${pkgs.jq}/bin/jq"; - gamemoded = "${pkgs.gamemode}/bin/gamemoded"; - systemctl = "${pkgs.systemd}/bin/systemctl"; - journalctl = "${pkgs.systemd}/bin/journalctl"; - playerctl = "${pkgs.playerctl}/bin/playerctl"; - playerctld = "${pkgs.playerctl}/bin/playerctld"; - pavucontrol = "${pkgs.pavucontrol}/bin/pavucontrol"; - wofi = "${pkgs.wofi}/bin/wofi"; - - # Function to simplify making waybar outputs - jsonOutput = name: { pre ? "", text ? "", tooltip ? "", alt ? "", class ? "", percentage ? "" }: "${pkgs.writeShellScriptBin "waybar-${name}" '' - set -euo pipefail - ${pre} - ${jq} -cn \ - --arg text "${text}" \ - --arg tooltip "${tooltip}" \ - --arg alt "${alt}" \ - --arg class "${class}" \ - --arg percentage "${percentage}" \ - '{text:$text,tooltip:$tooltip,alt:$alt,class:$class,percentage:$percentage}' - ''}/bin/waybar-${name}"; -in -{ - programs.waybar = { - enable = true; - package = pkgs.waybar.overrideAttrs (oa: { - mesonFlags = (oa.mesonFlags or [ ]) ++ [ "-Dexperimental=true" ]; - }); - systemd.enable = true; - settings = { - primary = { - mode = "dock"; - layer = "top"; - height = 40; - margin = "6"; - position = "top"; - modules-left = [ - "custom/menu" - ] ++ (lib.optionals config.wayland.windowManager.sway.enable [ - "sway/workspaces" - "sway/mode" - ]) ++ (lib.optionals config.wayland.windowManager.hyprland.enable [ - "hyprland/workspaces" - "hyprland/submap" - ]) ++ [ - "custom/currentplayer" - "custom/player" - ]; - - modules-center = [ - "pulseaudio" - "battery" - "clock" - "custom/unread-mail" - "custom/gpg-agent" - ]; - - modules-right = [ - "network" - "custom/tailscale-ping" - "custom/gamemode" - # TODO: currently broken for some reason - # "custom/gammastep" - "tray" - "custom/hostname" - ]; - - clock = { - interval = 1; - format = "{:%d/%m %H:%M:%S}"; - format-alt = "{:%Y-%m-%d %H:%M:%S %z}"; - on-click-left = "mode"; - tooltip-format = '' - {:%Y %B} - {calendar}''; - }; - pulseaudio = { - format = "{icon} {volume}%"; - format-muted = " 0%"; - format-icons = { - headphone = "󰋋"; - headset = "󰋎"; - portable = ""; - default = [ "" "" "" ]; - }; - on-click = pavucontrol; - }; - idle_inhibitor = { - format = "{icon}"; - format-icons = { - activated = "󰒳"; - deactivated = "󰒲"; - }; - }; - battery = { - bat = "BAT0"; - interval = 10; - format-icons = [ "󰁺" "󰁻" "󰁼" "󰁽" "󰁾" "󰁿" "󰂀" "󰂁" "󰂂" "󰁹" ]; - format = "{icon} {capacity}%"; - format-charging = "󰂄 {capacity}%"; - onclick = ""; - }; - "sway/window" = { - max-length = 20; - }; - network = { - interval = 3; - format-wifi = " {essid}"; - format-ethernet = "󰈁 Connected"; - format-disconnected = ""; - tooltip-format = '' - {ifname} - {ipaddr}/{cidr} - Up: {bandwidthUpBits} - Down: {bandwidthDownBits}''; - on-click = ""; - }; - "custom/tailscale-ping" = { - interval = 10; - return-type = "json"; - exec = - let - inherit (builtins) concatStringsSep attrNames; - hosts = attrNames outputs.nixosConfigurations; - homeMachine = "merope"; - remoteMachine = "alcyone"; - in - jsonOutput "tailscale-ping" { - # Build variables for each host - pre = '' - set -o pipefail - ${concatStringsSep "\n" (map (host: '' - ping_${host}="$(${timeout} 2 ${ping} -c 1 -q ${host} 2>/dev/null | ${tail} -1 | ${cut} -d '/' -f5 | ${cut} -d '.' -f1)ms" || ping_${host}="Disconnected" - '') hosts)} - ''; - # Access a remote machine's and a home machine's ping - text = " $ping_${remoteMachine} /  $ping_${homeMachine}"; - # Show pings from all machines - tooltip = concatStringsSep "\n" (map (host: "${host}: $ping_${host}") hosts); - }; - format = "{}"; - on-click = ""; - }; - "custom/menu" = { - return-type = "json"; - exec = jsonOutput "menu" { - text = ""; - tooltip = ''$(${cat} /etc/os-release | ${grep} PRETTY_NAME | ${cut} -d '"' -f2)''; - }; - on-click = "${wofi} -S drun -x 10 -y 10 -W 25% -H 60%"; - }; - "custom/hostname" = { - exec = "echo $USER@$HOSTNAME"; - }; - "custom/unread-mail" = { - interval = 5; - return-type = "json"; - exec = jsonOutput "unread-mail" { - pre = '' - count=$(${find} ~/Mail/*/Inbox/new -type f | ${wc} -l) - if ${pgrep} mbsync &>/dev/null; then - status="syncing" - else if [ "$count" == "0" ]; then - status="read" - else - status="unread" - fi - fi - ''; - text = "$count"; - alt = "$status"; - }; - format = "{icon} ({})"; - format-icons = { - "read" = "󰇯"; - "unread" = "󰇮"; - "syncing" = "󰁪"; - }; - }; - "custom/gpg-agent" = { - interval = 2; - return-type = "json"; - exec = - let gpgCmds = import ../../../cli/gpg-commands.nix { inherit pkgs; }; - in - jsonOutput "gpg-agent" { - pre = ''status=$(${gpgCmds.isUnlocked} && echo "unlocked" || echo "locked")''; - alt = "$status"; - tooltip = "GPG is $status"; - }; - format = "{icon}"; - format-icons = { - "locked" = ""; - "unlocked" = ""; - }; - on-click = ""; - }; - "custom/gamemode" = { - exec-if = "${gamemoded} --status | ${grep} 'is active' -q"; - interval = 2; - return-type = "json"; - exec = jsonOutput "gamemode" { - tooltip = "Gamemode is active"; - }; - format = " "; - }; - "custom/gammastep" = { - interval = 5; - return-type = "json"; - exec = jsonOutput "gammastep" { - pre = '' - if unit_status="$(${systemctl} --user is-active gammastep)"; then - status="$unit_status ($(${journalctl} --user -u gammastep.service -g 'Period: ' | ${tail} -1 | ${cut} -d ':' -f6 | ${xargs}))" - else - status="$unit_status" - fi - ''; - alt = "\${status:-inactive}"; - tooltip = "Gammastep is $status"; - }; - format = "{icon}"; - format-icons = { - "activating" = "󰁪 "; - "deactivating" = "󰁪 "; - "inactive" = "? "; - "active (Night)" = " "; - "active (Nighttime)" = " "; - "active (Transition (Night)" = " "; - "active (Transition (Nighttime)" = " "; - "active (Day)" = " "; - "active (Daytime)" = " "; - "active (Transition (Day)" = " "; - "active (Transition (Daytime)" = " "; - }; - on-click = "${systemctl} --user is-active gammastep && ${systemctl} --user stop gammastep || ${systemctl} --user start gammastep"; - }; - "custom/currentplayer" = { - interval = 2; - return-type = "json"; - exec = jsonOutput "currentplayer" { - pre = '' - player="$(${playerctl} status -f "{{playerName}}" 2>/dev/null || echo "No player active" | ${cut} -d '.' -f1)" - count="$(${playerctl} -l | ${wc} -l)" - if ((count > 1)); then - more=" +$((count - 1))" - else - more="" - fi - ''; - alt = "$player"; - tooltip = "$player ($count available)"; - text = "$more"; - }; - format = "{icon}{}"; - format-icons = { - "No player active" = " "; - "Celluloid" = "󰎁 "; - "spotify" = "󰓇 "; - "ncspot" = "󰓇 "; - "qutebrowser" = "󰖟 "; - "firefox" = " "; - "discord" = " 󰙯 "; - "sublimemusic" = " "; - "kdeconnect" = "󰄡 "; - "chromium" = " "; - }; - on-click = "${playerctld} shift"; - on-click-right = "${playerctld} unshift"; - }; - "custom/player" = { - exec-if = "${playerctl} status"; - exec = ''${playerctl} metadata --format '{"text": "{{title}} - {{artist}}", "alt": "{{status}}", "tooltip": "{{title}} - {{artist}} ({{album}})"}' ''; - return-type = "json"; - interval = 2; - max-length = 30; - format = "{icon} {}"; - format-icons = { - "Playing" = "󰐊"; - "Paused" = "󰏤 "; - "Stopped" = "󰓛"; - }; - on-click = "${playerctl} play-pause"; - }; - }; - - }; - # Cheatsheet: - # x -> all sides - # x y -> vertical, horizontal - # x y z -> top, horizontal, bottom - # w x y z -> top, right, bottom, left - style = let inherit (config.colorscheme) colors; in /* css */ '' - * { - font-family: ${config.fontProfiles.regular.family}, ${config.fontProfiles.monospace.family}; - font-size: 12pt; - padding: 0 8px; - } - - .modules-right { - margin-right: -15px; - } - - .modules-left { - margin-left: -15px; - } - - window#waybar.top { - opacity: 0.95; - padding: 0; - background-color: #${colors.base00}; - border: 2px solid #${colors.base0C}; - border-radius: 10px; - } - window#waybar.bottom { - opacity: 0.90; - background-color: #${colors.base00}; - border: 2px solid #${colors.base0C}; - border-radius: 10px; - } - - window#waybar { - color: #${colors.base05}; - } - - #workspaces button { - background-color: #${colors.base01}; - color: #${colors.base05}; - padding: 5px 1px; - margin: 3px 0; - } - #workspaces button.hidden { - background-color: #${colors.base00}; - color: #${colors.base04}; - } - #workspaces button.focused, - #workspaces button.active { - background-color: #${colors.base0A}; - color: #${colors.base00}; - } - - #clock { - background-color: #${colors.base0C}; - color: #${colors.base00}; - padding-left: 15px; - padding-right: 15px; - margin-top: 0; - margin-bottom: 0; - border-radius: 10px; - } - - #custom-menu { - background-color: #${colors.base0C}; - color: #${colors.base00}; - padding-left: 15px; - padding-right: 22px; - margin: 0; - border-radius: 10px; - } - #custom-hostname { - background-color: #${colors.base0C}; - color: #${colors.base00}; - padding-left: 15px; - padding-right: 18px; - margin-right: 0; - margin-top: 0; - margin-bottom: 0; - border-radius: 10px; - } - #custom-currentplayer { - padding-right: 0; - } - #tray { - color: #${colors.base05}; - } - ''; - }; -} diff --git a/_/home-manager/_mixins/common/wayland-wm/wezterm.nix b/_/home-manager/_mixins/common/wayland-wm/wezterm.nix deleted file mode 100644 index ceb31bf..0000000 --- a/_/home-manager/_mixins/common/wayland-wm/wezterm.nix +++ /dev/null @@ -1,54 +0,0 @@ -{ config, ... }: - -let - inherit (config) colorscheme; - inherit (colorscheme) colors; -in -{ - programs.wezterm = { - enable = true; - colorSchemes = { - "${colorscheme.slug}" = { - foreground = "#${colors.base05}"; - background = "#${colors.base00}"; - - ansi = [ - "#${colors.base08}" - "#${colors.base09}" - "#${colors.base0A}" - "#${colors.base0B}" - "#${colors.base0C}" - "#${colors.base0D}" - "#${colors.base0E}" - "#${colors.base0F}" - ]; - brights = [ - "#${colors.base00}" - "#${colors.base01}" - "#${colors.base02}" - "#${colors.base03}" - "#${colors.base04}" - "#${colors.base05}" - "#${colors.base06}" - "#${colors.base07}" - ]; - cursor_fg = "#${colors.base00}"; - cursor_bg = "#${colors.base05}"; - selection_fg = "#${colors.base00}"; - selection_bg = "#${colors.base05}"; - }; - }; - extraConfig = /* lua */ '' - return { - font = wezterm.font("${config.fontProfiles.monospace.family}"), - font_size = 12.0, - color_scheme = "${colorscheme.slug}", - hide_tab_bar_if_only_one_tab = true, - window_close_confirmation = "NeverPrompt", - set_environment_variables = { - TERM = 'wezterm', - }, - } - ''; - }; -} diff --git a/_/home-manager/_mixins/common/wayland-wm/wofi-run-shell.patch b/_/home-manager/_mixins/common/wayland-wm/wofi-run-shell.patch deleted file mode 100644 index 930563b..0000000 --- a/_/home-manager/_mixins/common/wayland-wm/wofi-run-shell.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/src/wofi.c Mon Feb 22 23:53:57 2021 -0800 -+++ b/src/wofi.c Wed Aug 11 13:49:13 2021 -0300 -@@ -881,12 +881,15 @@ - } - - void wofi_term_run(const char* cmd) { -+ char *shell = getenv("SHELL"); -+ if (!shell) shell = "sh"; -+ - if(terminal != NULL) { -- execlp(terminal, terminal, "-e", cmd, NULL); -+ execlp(terminal, terminal, "-e", shell, "-c", cmd, NULL); - } - size_t term_count = sizeof(terminals) / sizeof(char*); - for(size_t count = 0; count < term_count; ++count) { -- execlp(terminals[count], terminals[count], "-e", cmd, NULL); -+ execlp(terminals[count], terminals[count], "-e", shell, "-c", cmd, NULL); - } - fprintf(stderr, "No terminal emulator found please set term in config or use --term\n"); - exit(1); diff --git a/_/home-manager/_mixins/common/wayland-wm/wofi.nix b/_/home-manager/_mixins/common/wayland-wm/wofi.nix deleted file mode 100644 index 4bd5836..0000000 --- a/_/home-manager/_mixins/common/wayland-wm/wofi.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ config, lib, pkgs, ... }: { - programs.wofi = { - enable = true; - package = pkgs.wofi.overrideAttrs (oa: { - patches = (oa.patches or [ ]) ++ [ - ./wofi-run-shell.patch # Fix for https://todo.sr.ht/~scoopta/wofi/174 - ]; - }); - settings = { - image_size = 48; - columns = 3; - allow_images = true; - insensitive = true; - run-always_parse_args = true; - run-cache_file = "/dev/null"; - run-exec_search = true; - }; - }; - - home.packages = - let - inherit (config.programs.password-store) package enable; - in - lib.optional enable (pkgs.pass-wofi.override { pass = package; }); -} diff --git a/_/home-manager/_mixins/common/wayland-wm/zathura.nix b/_/home-manager/_mixins/common/wayland-wm/zathura.nix deleted file mode 100644 index 8348cc1..0000000 --- a/_/home-manager/_mixins/common/wayland-wm/zathura.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ config, ... }: -let inherit (config.colorscheme) colors; -in { - programs.zathura = { - enable = true; - options = { - selection-clipboard = "clipboard"; - font = "${config.fontProfiles.regular.family} 12"; - recolor = true; - default-bg = "#${colors.base00}"; - default-fg = "#${colors.base01}"; - statusbar-bg = "#${colors.base02}"; - statusbar-fg = "#${colors.base04}"; - inputbar-bg = "#${colors.base00}"; - inputbar-fg = "#${colors.base07}"; - notification-bg = "#${colors.base00}"; - notification-fg = "#${colors.base07}"; - notification-error-bg = "#${colors.base00}"; - notification-error-fg = "#${colors.base08}"; - notification-warning-bg = "#${colors.base00}"; - notification-warning-fg = "#${colors.base08}"; - highlight-color = "#${colors.base0A}"; - highlight-active-color = "#${colors.base0D}"; - completion-bg = "#${colors.base01}"; - completion-fg = "#${colors.base05}"; - completions-highlight-bg = "#${colors.base0D}"; - completions-highlight-fg = "#${colors.base07}"; - recolor-lightcolor = "#${colors.base00}"; - recolor-darkcolor = "#${colors.base06}"; - }; - }; -} diff --git a/_/home-manager/_mixins/default.nix b/_/home-manager/_mixins/default.nix deleted file mode 100644 index 30edc2a..0000000 --- a/_/home-manager/_mixins/default.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ inputs, lib, pkgs, config, outputs, ... }: -{ - imports = [ - inputs.impermanence.nixosModules.home-manager.impermanence - ./cli - ./nvim - ] ++ (builtins.attrValues outputs.homeManagerModules); - - nixpkgs = { - overlays = builtins.attrValues outputs.overlays; - config = { - allowUnfree = true; - allowUnfreePredicate = _: true; - }; - }; - - nix = { - package = lib.mkDefault pkgs.nix; - settings = { - experimental-features = [ "nix-command" "flakes" "repl-flake" ]; - warn-dirty = false; - }; - }; - - systemd.user.startServices = "sd-switch"; - - programs = { - home-manager.enable = true; - git.enable = true; - autorandr.enable = true; - }; - - home = { - username = lib.mkDefault "gburd"; - homeDirectory = lib.mkDefault "/home/${config.home.username}"; - stateVersion = lib.mkDefault "23.05"; - sessionPath = [ "$HOME/.local/bin" ]; - sessionVariables = { - FLAKE = "$HOME/ws/nix-config"; - }; - - persistence = { - "/persist/home/gburd" = { - directories = [ - "Documents" - "Downloads" - "Pictures" - "Videos" - ".local/bin" - ]; - allowOther = true; - }; - }; - }; - -} diff --git a/_/home-manager/_mixins/gnome/default.nix b/_/home-manager/_mixins/gnome/default.nix deleted file mode 100644 index ebb0425..0000000 --- a/_/home-manager/_mixins/gnome/default.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ pkgs, ... }: { - imports = [ - ../common - ../common/gnome-wm - - ./tty-init.nix - ]; - - home.packages = with pkgs; [ - emacs - ungoogled-chromium - gnupg - pinentry - alacritty - ]; - # dconf - # settings reset org.gnome.desktop.input-sources xkb-options - # gsettings reset org.gnome.desktop.input-sources sources -} diff --git a/_/home-manager/_mixins/gnome/tty-init.nix b/_/home-manager/_mixins/gnome/tty-init.nix deleted file mode 100644 index 16763a9..0000000 --- a/_/home-manager/_mixins/gnome/tty-init.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - programs = { - fish.loginShellInit = '' - if test (tty) = "/dev/tty1" - exec Hyprland &> /dev/null - end - ''; - zsh.loginExtra = '' - if [ "$(tty)" = "/dev/tty1" ]; then - exec Hyprland &> /dev/null - fi - ''; - zsh.profileExtra = '' - if [ "$(tty)" = "/dev/tty1" ]; then - exec Hyprland &> /dev/null - fi - ''; - }; -} diff --git a/_/home-manager/_mixins/users/gburd/generic.nix b/_/home-manager/_mixins/users/gburd/generic.nix deleted file mode 100644 index 855844d..0000000 --- a/_/home-manager/_mixins/users/gburd/generic.nix +++ /dev/null @@ -1,6 +0,0 @@ -{ lib, ... }: -{ - imports = [ ./global ]; - # Disable impermanence - home.persistence = lib.mkForce { }; -} diff --git a/_/home-manager/_mixins/users/wireless/default.nix b/_/home-manager/_mixins/users/wireless/default.nix deleted file mode 100644 index c24d3c2..0000000 --- a/_/home-manager/_mixins/users/wireless/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ - imports = [ - ./wpa-gui.nix - ]; -} diff --git a/_/home-manager/_mixins/wpa-gui.nix b/_/home-manager/_mixins/wpa-gui.nix deleted file mode 100644 index 842c7a4..0000000 --- a/_/home-manager/_mixins/wpa-gui.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ pkgs, ... }: { - home.packages = [ pkgs.wpa_supplicant_gui ]; -} diff --git a/_/modules/home-manager/default.nix b/_/modules/home-manager/default.nix deleted file mode 100644 index 8bab257..0000000 --- a/_/modules/home-manager/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ - fonts = import ./fonts.nix; - monitors = import ./monitors.nix; - pass-secret-service = import ./pass-secret-service.nix; - rgbdaemon = import ./rgbdaemon.nix; - shellcolor = import ./shellcolor.nix; - wallpaper = import ./wallpaper.nix; - xpo = import ./xpo.nix; -} diff --git a/_/modules/home-manager/fonts.nix b/_/modules/home-manager/fonts.nix deleted file mode 100644 index 523ecae..0000000 --- a/_/modules/home-manager/fonts.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ lib, config, ... }: - -let - mkFontOption = kind: { - family = lib.mkOption { - type = lib.types.str; - default = null; - description = "Family name for ${kind} font profile"; - example = "Fira Code"; - }; - package = lib.mkOption { - type = lib.types.package; - default = null; - description = "Package for ${kind} font profile"; - example = "pkgs.fira-code"; - }; - }; - cfg = config.fontProfiles; -in -{ - options.fontProfiles = { - enable = lib.mkEnableOption "Whether to enable font profiles"; - monospace = mkFontOption "monospace"; - regular = mkFontOption "regular"; - }; - - - config = lib.mkIf cfg.enable { - fonts.fontconfig.enable = true; - home.packages = [ cfg.monospace.package cfg.regular.package ]; - }; -} diff --git a/_/modules/home-manager/monitors.nix b/_/modules/home-manager/monitors.nix deleted file mode 100644 index 21dd4a2..0000000 --- a/_/modules/home-manager/monitors.nix +++ /dev/null @@ -1,57 +0,0 @@ -{ lib, config, ... }: - -let - inherit (lib) mkOption types; -in -{ - options.monitors = mkOption { - type = types.listOf (types.submodule { - options = { - name = mkOption { - type = types.str; - example = "DP-1"; - }; - primary = mkOption { - type = types.bool; - default = false; - }; - width = mkOption { - type = types.int; - example = 1920; - }; - height = mkOption { - type = types.int; - example = 1080; - }; - refreshRate = mkOption { - type = types.int; - default = 60; - }; - x = mkOption { - type = types.int; - default = 0; - }; - y = mkOption { - type = types.int; - default = 0; - }; - enabled = mkOption { - type = types.bool; - default = true; - }; - workspace = mkOption { - type = types.nullOr types.str; - default = null; - }; - }; - }); - default = [ ]; - }; - config = { - assertions = [{ - assertion = ((lib.length config.monitors) != 0) -> - ((lib.length (lib.filter (m: m.primary) config.monitors)) == 1); - message = "Exactly one monitor must be set to primary."; - }]; - }; -} diff --git a/_/modules/home-manager/rgbdaemon.nix b/_/modules/home-manager/rgbdaemon.nix deleted file mode 100644 index 7de65dd..0000000 --- a/_/modules/home-manager/rgbdaemon.nix +++ /dev/null @@ -1,130 +0,0 @@ -{ lib, pkgs, config, ... }: -with lib; - -let cfg = config.services.rgbdaemon; -in { - options.services.rgbdaemon = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Enable rgbdaemon - ''; - }; - package = mkOption { - type = types.package; - default = pkgs.rgbdaemon; - }; - interval = mkOption { - type = types.float; - default = 0.8; - description = '' - Daemon main loop interval - ''; - }; - daemons = { - mute = mkOption { - type = types.bool; - default = false; - description = '' - Enable mute button daemon - ''; - }; - swayLock = mkOption { - type = types.bool; - default = false; - description = '' - Enable swaylock status daemon - ''; - }; - player = mkOption { - type = types.bool; - default = false; - description = '' - Enable media player status daemon - ''; - }; - }; - colors = - let - mkColorOption = name: { - inherit name; - value = mkOption { - type = types.strMatching "[a-fA-F0-9]{6}"; - description = "${name} color."; - default = "ffffff"; - }; - }; - in - listToAttrs (map mkColorOption [ - "background" - "foreground" - "secondary" - "tertiary" - "quaternary" - ]); - mouse = { - device = mkOption { - type = types.path; - description = "Mouse device cmd path"; - default = "/dev/input/ckb2/cmd"; - }; - dpi = mkOption { - type = types.int; - description = "Mouse DPI"; - default = 750; - }; - highlighted = mkOption { - type = types.listOf types.str; - description = "Always highlighted mouse keys"; - default = [ ]; - }; - }; - keyboard = { - device = mkOption { - type = types.path; - description = "Mouse device cmd path"; - default = "/dev/input/ckb1/cmd"; - }; - highlighted = mkOption { - type = types.listOf types.str; - description = "Always highlighted keyboard keys"; - default = [ ]; - }; - }; - }; - - config = mkIf cfg.enable { - xdg.configFile."rgbdaemon.conf" = { - text = '' - DAEMON_INTERVAL=${lib.strings.floatToString cfg.interval} - KEYBOARD_DEVICE=${cfg.keyboard.device} - MOUSE_DEVICE=${cfg.mouse.device} - KEYBOARD_HIGHLIGHTED=${ - lib.concatStringsSep "," cfg.keyboard.highlighted - } - MOUSE_HIGHLIGHTED=${lib.concatStringsSep "," cfg.mouse.highlighted} - COLOR_BACKGROUND=${cfg.colors.background} - COLOR_FOREGROUND=${cfg.colors.foreground} - COLOR_SECONDARY=${cfg.colors.secondary} - COLOR_TERTIARY=${cfg.colors.tertiary} - COLOR_QUATERNARY=${cfg.colors.quaternary} - ENABLE_SWAY_LOCK=${toString cfg.daemons.swayLock} - ENABLE_MUTE=${toString cfg.daemons.mute} - ENABLE_PLAYER=${toString cfg.daemons.player} - ''; - onChange = '' - ${pkgs.procps}/bin/pkill -u $USER -f -SIGHUP rgbdaemon || true - ''; - }; - systemd.user.services.rgbdaemon = { - Unit = { Description = "Misterio RGB Daemon"; }; - Service = { - ExecStart = "${cfg.package}/bin/rgbdaemon"; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - Restart = "always"; - }; - Install = { WantedBy = [ "graphical-session.target" ]; }; - }; - }; -} diff --git a/_/modules/home-manager/shellcolor.nix b/_/modules/home-manager/shellcolor.nix deleted file mode 100644 index c40c898..0000000 --- a/_/modules/home-manager/shellcolor.nix +++ /dev/null @@ -1,110 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - cfg = config.programs.shellcolor; - package = pkgs.shellcolord; - - renderSetting = key: value: '' - ${key}=${value} - ''; - renderSettings = settings: - lib.concatStrings (lib.mapAttrsToList renderSetting settings); - -in -{ - options.programs.shellcolor = { - enable = lib.mkEnableOption "shellcolor"; - - enableBashIntegration = lib.mkOption { - default = true; - type = lib.types.bool; - description = '' - Whether to enable Bash integration. - ''; - }; - enableZshIntegration = lib.mkOption { - default = true; - type = lib.types.bool; - description = '' - Whether to enable Zsh integration. - ''; - }; - enableFishIntegration = lib.mkOption { - default = true; - type = lib.types.bool; - description = '' - Whether to enable Fish integration. - ''; - }; - - enableBashSshFunction = lib.mkOption { - default = false; - type = lib.types.bool; - description = '' - Whether to enable SSH integration by replacing ssh with a bash function. - ''; - }; - enableFishSshFunction = lib.mkOption { - default = false; - type = lib.types.bool; - description = '' - Whether to enable SSH integration by replacing ssh with a fish function. - ''; - }; - - settings = lib.mkOption { - type = lib.types.attrsOf lib.types.str; - default = { }; - example = lib.literalExpression '' - { - base00 = "000000"; - base05 = "ffffff"; - } - ''; - description = '' - Options for shellcolord config file. Colors (without leading #) - from base00 until base0F. - ''; - }; - }; - - config = lib.mkIf cfg.enable { - home.packages = [ package ]; - - xdg.configFile."shellcolor.conf" = lib.mkIf (cfg.settings != { }) { - text = renderSettings cfg.settings; - onChange = '' - timeout 1 ${package}/bin/shellcolor apply || true - ''; - }; - - programs.bash.initExtra = lib.mkIf cfg.enableBashIntegration - (lib.mkBefore '' - ${package}/bin/shellcolord $$ & disown - ${lib.optionalString cfg.enableBashSshFunction '' - ssh() { - ${package}/bin/shellcolor disable $$ - command ssh "$@" - ${package}/bin/shellcolor enable $$ - ${package}/bin/shellcolor apply $$ - } - ''} - ''); - - programs.zsh.initExtra = lib.mkIf cfg.enableZshIntegration (lib.mkBefore '' - ${package}/bin/shellcolord $$ & disown - ''); - - programs.fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration - (lib.mkBefore '' - ${package}/bin/shellcolord $fish_pid & disown - ''); - - programs.fish.functions.ssh = lib.mkIf cfg.enableFishSshFunction '' - ${package}/bin/shellcolor disable $fish_pid - command ssh $argv - ${package}/bin/shellcolor enable $fish_pid - ${package}/bin/shellcolor apply $fish_pid - ''; - }; -} diff --git a/_/modules/home-manager/wallpaper.nix b/_/modules/home-manager/wallpaper.nix deleted file mode 100644 index 5ba52c0..0000000 --- a/_/modules/home-manager/wallpaper.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ lib, ... }: -let inherit (lib) types mkOption; -in -{ - options.wallpaper = mkOption { - type = types.path; - default = ""; - description = '' - Wallpaper path - ''; - }; -} diff --git a/_/modules/home-manager/xpo.nix b/_/modules/home-manager/xpo.nix deleted file mode 100644 index a4596d1..0000000 --- a/_/modules/home-manager/xpo.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ config, pkgs, lib, ... }: -let - cfg = config.programs.xpo; - package = pkgs.xpo; -in -{ - options.programs.xpo = { - enable = lib.mkEnableOption "xpo"; - - defaultServer = lib.mkOption { - default = null; - type = with lib.types; nullOr str; - description = '' - Default SSH server/endpoint to use when tunneling. - ''; - }; - }; - - config = lib.mkIf cfg.enable { - home = { - packages = [ package ]; - sessionVariables.XPO_SERVER = lib.optionalString (cfg.defaultServer != null) cfg.defaultServer; - }; - }; -} diff --git a/_/modules/nixos/default.nix b/_/modules/nixos/default.nix deleted file mode 100644 index f4353d0..0000000 --- a/_/modules/nixos/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ - openrgb = import ./openrgb.nix; - satisfactory = import ./satisfactory.nix; -} diff --git a/_/modules/nixos/openrgb.nix b/_/modules/nixos/openrgb.nix deleted file mode 100644 index f13ef10..0000000 --- a/_/modules/nixos/openrgb.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let cfg = config.hardware.openrgb; - -in { - options.hardware.openrgb = { - enable = mkEnableOption "OpenRGB"; - package = mkOption { - type = types.package; - default = pkgs.openrgb; - defaultText = "pkgs.openrgb"; - description = '' - The package implementing OpenRGB. - ''; - }; - }; - config = mkIf cfg.enable { - boot.kernelModules = [ "v4l2loopback" "i2c-dev" "i2c-piix4" ]; - environment.systemPackages = [ cfg.package ]; - services.udev.packages = [ cfg.package ]; - - systemd.services.openrgb = { - description = "OpenRGB Daemon"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - ExecStart = "${cfg.package}/bin/openrgb --server"; - Restart = "on-failure"; - }; - }; - }; - - meta = { - maintainers = with lib.maintainers; [ misterio77 ]; - }; -} diff --git a/_/modules/nixos/satisfactory.nix b/_/modules/nixos/satisfactory.nix deleted file mode 100644 index f4b9e84..0000000 --- a/_/modules/nixos/satisfactory.nix +++ /dev/null @@ -1,78 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; -let cfg = config.services.satisfactory-server; - -in { - options.services.satisfactory-server = { - enable = mkEnableOption "Satisfactory Dedicated Server"; - - steamcmdPackage = mkOption { - type = types.package; - default = pkgs.steamcmd; - defaultText = "pkgs.steamcmd"; - description = '' - The package implementing SteamCMD - ''; - }; - - dataDir = mkOption { - type = types.path; - description = "Directory to store game server"; - default = "/var/lib/satisfactory"; - }; - - launchOptions = mkOption { - type = types.str; - description = "Launch options to use."; - default = ""; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Whether to open ports in the firewall for the server - ''; - }; - }; - - config = mkIf cfg.enable { - - systemd.services.satisfactory-server = - let - steamcmd = "${cfg.steamcmdPackage}/bin/steamcmd"; - steam-run = "${pkgs.steam-run}/bin/steam-run"; - in - { - description = "Satisfactory Dedicated Server"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - - serviceConfig = { - TimeoutSec = "15min"; - ExecStart = - "${steam-run} ${cfg.dataDir}/FactoryServer.sh ${cfg.launchOptions}"; - Restart = "always"; - User = "satisfactory"; - WorkingDirectory = cfg.dataDir; - }; - - preStart = '' - ${steamcmd} +force_install_dir "${cfg.dataDir}" +login anonymous +app_update 1690800 validate +quit - ''; - }; - - users.users.satisfactory = { - description = "Satisfactory server service user"; - home = cfg.dataDir; - createHome = true; - isSystemUser = true; - group = "satisfactory"; - }; - users.groups.satisfactory = { }; - - networking.firewall = - mkIf cfg.openFirewall { allowedUDPPorts = [ 15777 7777 15000 ]; }; - }; -} diff --git a/_/nixos/_mixins/global/acme.nix b/_/nixos/_mixins/global/acme.nix deleted file mode 100644 index e86e714..0000000 --- a/_/nixos/_mixins/global/acme.nix +++ /dev/null @@ -1,16 +0,0 @@ -_: -{ - # Enable acme for usage with nginx vhosts - security.acme = { - defaults.email = "greg+acme@burd.me"; - acceptTerms = true; - }; - - environment.persistence = { - "/persist" = { - directories = [ - "/var/lib/acme" - ]; - }; - }; -} diff --git a/_/nixos/_mixins/global/auto-upgrade.nix b/_/nixos/_mixins/global/auto-upgrade.nix deleted file mode 100644 index 2e048b7..0000000 --- a/_/nixos/_mixins/global/auto-upgrade.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ config, inputs, pkgs, lib, ... }: -let - inherit (config.networking) hostName; - # Only enable auto upgrade if current config came from a clean tree - # This avoids accidental auto-upgrades when working locally. - isClean = inputs.self ? rev; -in -{ - system.autoUpgrade = { - enable = isClean; - dates = "hourly"; - flags = [ - "--refresh" - ]; - flake = "git://github.com/gburd/nix-config?ref=release-${hostName}"; - }; - - # Only run if current config (self) is older than the new one. - systemd.services.nixos-upgrade = lib.mkIf config.system.autoUpgrade.enable { - serviceConfig.ExecCondition = lib.getExe ( - pkgs.writeShellScriptBin "check-date" '' - lastModified() { - nix flake metadata "$1" --refresh --json | ${lib.getExe pkgs.jq} '.lastModified' - } - test "$(lastModified "${config.system.autoUpgrade.flake}")" -gt "$(lastModified "self")" - '' - ); - }; -} diff --git a/_/nixos/_mixins/global/default.nix b/_/nixos/_mixins/global/default.nix deleted file mode 100644 index 5359f69..0000000 --- a/_/nixos/_mixins/global/default.nix +++ /dev/null @@ -1,67 +0,0 @@ -# This file (and the global directory) holds config used on all hosts -{ inputs, outputs, ... }: { - - imports = [ - inputs.home-manager.nixosModules.home-manager - ./acme.nix - ./auto-upgrade.nix - ./fish.nix - ./locale.nix - ./nix.nix - ./openssh.nix - ./optin-persistence.nix - ./podman.nix - ./sops.nix - # ./ssh-serve-store.nix - ./steam-hardware.nix - ./systemd-initrd.nix - ./tailscale.nix - ] ++ (builtins.attrValues outputs.nixosModules); - - home-manager.extraSpecialArgs = { inherit inputs outputs; }; - - nixpkgs = { - overlays = builtins.attrValues outputs.overlays; - config = { - # Disable if you don't want unfree packages - allowUnfree = true; - # Accept the joypixels license - joypixels.acceptLicense = true; - }; - }; - - # Fix for qt6 plugins - # TODO: maybe upstream this? - environment.profileRelativeSessionVariables = { - QT_PLUGIN_PATH = [ "/lib/qt-6/plugins" ]; - }; - - environment.enableAllTerminfo = true; - - hardware.enableRedistributableFirmware = true; - networking.domain = "burd.me"; - - # Increase open file limit for sudoers - security.pam.loginLimits = [ - { - domain = "@wheel"; - item = "nofile"; - type = "soft"; - value = "524288"; - } - { - domain = "@wheel"; - item = "nofile"; - type = "hard"; - value = "1048576"; - } - ]; - - # Only install the docs I use - documentation.enable = true; - documentation.nixos.enable = false; - documentation.man.enable = true; - documentation.info.enable = false; - documentation.doc.enable = false; - -} diff --git a/_/nixos/_mixins/global/fish.nix b/_/nixos/_mixins/global/fish.nix deleted file mode 100644 index e53f255..0000000 --- a/_/nixos/_mixins/global/fish.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ - programs.fish = { - enable = true; - vendor = { - completions.enable = true; - config.enable = true; - functions.enable = true; - }; - }; -} diff --git a/_/nixos/_mixins/global/locale.nix b/_/nixos/_mixins/global/locale.nix deleted file mode 100644 index 67dbf39..0000000 --- a/_/nixos/_mixins/global/locale.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ lib, ... }: { - - # Select internationalisation properties. - i18n = { - defaultLocale = lib.mkDefault "en_US.UTF-8"; - extraLocaleSettings = { - LC_ADDRESS = "en_US.UTF-8"; - LC_IDENTIFICATION = "en_US.UTF-8"; - LC_MEASUREMENT = "en_US.UTF-8"; - LC_MONETARY = "en_US.UTF-8"; - LC_NAME = "en_US.UTF-8"; - LC_NUMERIC = "en_US.UTF-8"; - LC_PAPER = "en_US.UTF-8"; - LC_TELEPHONE = "en_US.UTF-8"; - LC_TIME = "en_US.UTF-8"; - }; - supportedLocales = lib.mkDefault [ - "en_US.UTF-8/UTF-8" - ]; - }; - time.timeZone = lib.mkDefault "America/New_York"; -} diff --git a/_/nixos/_mixins/global/nix.nix b/_/nixos/_mixins/global/nix.nix deleted file mode 100644 index ea49214..0000000 --- a/_/nixos/_mixins/global/nix.nix +++ /dev/null @@ -1,33 +0,0 @@ -{ inputs, lib, ... }: -{ - nix = { - settings = { - # substituters = [ - # "https://cache.burd.me" - # ]; - # trusted-public-keys = [ - # "cache.burd.me:kszZ/NSwE/TjhOcPPQ16IuUiuRSisdiIwhKZCxguaWg=" - # ]; - trusted-users = [ "root" "@wheel" ]; - auto-optimise-store = lib.mkDefault true; - experimental-features = [ "nix-command" "flakes" "repl-flake" ]; - warn-dirty = false; - system-features = [ "kvm" "big-parallel" "nixos-test" ]; - flake-registry = ""; # Disable global flake registry - }; - gc = { - automatic = true; - dates = "weekly"; - # Keep the last 3 generations - options = "--delete-older-than +3"; - }; - - # Add each flake input as a registry - # To make nix3 commands consistent with the flake - registry = lib.mapAttrs (_: value: { flake = value; }) inputs; - - # Add nixpkgs input to NIX_PATH - # This lets nix2 commands still use - nixPath = [ "nixpkgs=${inputs.nixpkgs.outPath}" ]; - }; -} diff --git a/_/nixos/_mixins/global/openssh.nix b/_/nixos/_mixins/global/openssh.nix deleted file mode 100644 index 5e6da75..0000000 --- a/_/nixos/_mixins/global/openssh.nix +++ /dev/null @@ -1,44 +0,0 @@ -{ outputs, lib, config, ... }: - -let - hosts = outputs.nixosConfigurations; - pubKey = host: ../../${host}/ssh_host_ed25519_key.pub; - - # Sops needs acess to the keys before the persist dirs are even mounted; so - # just persisting the keys won't work, we must point at /persist - hasOptinPersistence = config.environment.persistence ? "/persist"; -in -{ - services.openssh = { - enable = true; - settings = { - # Harden - PasswordAuthentication = false; - PermitRootLogin = "no"; - # Automatically remove stale sockets - StreamLocalBindUnlink = "yes"; - # Allow forwarding ports to everywhere - GatewayPorts = "clientspecified"; - }; - - hostKeys = [{ - path = "${lib.optionalString hasOptinPersistence "/persist"}/etc/ssh/ssh_host_ed25519_key"; - type = "ed25519"; - }]; - }; - - programs.ssh = { - # Each hosts public key - knownHosts = builtins.mapAttrs - (name: _: { - publicKeyFile = pubKey name; - # extraHostNames = - # (lib.optional (name == hostName) "localhost") ++ # Alias for localhost if it's the same host - # (lib.optionals (name == gitHost) [ "burd.me" "git.burd.me" ]); - }) - hosts; - }; - - # Passwordless sudo when SSH'ing with keys - security.pam.enableSSHAgentAuth = true; -} diff --git a/_/nixos/_mixins/global/podman.nix b/_/nixos/_mixins/global/podman.nix deleted file mode 100644 index 50c864a..0000000 --- a/_/nixos/_mixins/global/podman.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ config, ... }: -let - dockerEnabled = config.virtualisation.docker.enable; -in -{ - virtualisation.podman = { - enable = true; - dockerCompat = !dockerEnabled; - dockerSocket.enable = !dockerEnabled; - defaultNetwork.settings.dns_enabled = true; - }; - - environment.persistence = { - "/persist".directories = [ - "/var/lib/containers" - ]; - }; -} diff --git a/_/nixos/_mixins/global/ssh-serve-store.nix b/_/nixos/_mixins/global/ssh-serve-store.nix deleted file mode 100644 index 406d8bf..0000000 --- a/_/nixos/_mixins/global/ssh-serve-store.nix +++ /dev/null @@ -1,14 +0,0 @@ -_: -{ - nix = { - sshServe = { - enable = true; - keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAz0dIbaTuAihil/si33MQSFH5yBFoupwnV5gcq2CCbO nix-ssh" - ]; - protocol = "ssh"; - write = true; - }; - settings.trusted-users = [ "nix-ssh" ]; - }; -} diff --git a/_/nixos/_mixins/global/steam-hardware.nix b/_/nixos/_mixins/global/steam-hardware.nix deleted file mode 100644 index 6d160bd..0000000 --- a/_/nixos/_mixins/global/steam-hardware.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ - hardware.steam-hardware.enable = true; -} diff --git a/_/nixos/_mixins/global/systemd-initrd.nix b/_/nixos/_mixins/global/systemd-initrd.nix deleted file mode 100644 index 67ac124..0000000 --- a/_/nixos/_mixins/global/systemd-initrd.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ - boot.initrd.systemd.enable = true; -} diff --git a/_/nixos/_mixins/global/tailscale.nix b/_/nixos/_mixins/global/tailscale.nix deleted file mode 100644 index d9ced69..0000000 --- a/_/nixos/_mixins/global/tailscale.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ lib, ... }: -{ - services.tailscale = { - enable = true; - useRoutingFeatures = lib.mkDefault "client"; - }; - networking.firewall = { - checkReversePath = "loose"; - allowedUDPPorts = [ 41641 ]; # Facilitate firewall punching - }; - - environment.persistence = { - "/persist".directories = [ "/var/lib/tailscale" ]; - }; -} diff --git a/_/nixos/_mixins/optional/ckb-next.nix b/_/nixos/_mixins/optional/ckb-next.nix deleted file mode 100644 index 1e99036..0000000 --- a/_/nixos/_mixins/optional/ckb-next.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ pkgs, ... }: -{ - hardware.ckb-next = { - enable = true; - }; - - systemd.services.ckb-next-resume = { - description = "Restart ckb-next after hibernation"; - after = [ "suspend.target" ]; - wantedBy = [ "suspend.target" ]; - serviceConfig = { - Type = "simple"; - ExecStart = "${pkgs.systemd}/bin/systemctl --no-block restart ckb-next.service"; - }; - }; -} diff --git a/_/nixos/_mixins/optional/docker.nix b/_/nixos/_mixins/optional/docker.nix deleted file mode 100644 index a0f86ac..0000000 --- a/_/nixos/_mixins/optional/docker.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ - virtualisation.docker = { - enable = true; - }; -} diff --git a/_/nixos/_mixins/optional/ephemeral-btrfs.nix b/_/nixos/_mixins/optional/ephemeral-btrfs.nix deleted file mode 100644 index da6679c..0000000 --- a/_/nixos/_mixins/optional/ephemeral-btrfs.nix +++ /dev/null @@ -1,83 +0,0 @@ -# This file contains an ephemeral btrfs root configuration -# TODO: perhaps partition using disko in the future -{ lib, config, ... }: -let - hostname = config.networking.hostName; - wipeScript = '' - mkdir /tmp -p - MNTPOINT=$(mktemp -d) - ( - mount -t btrfs -o subvol=/ /dev/disk/by-label/${hostname} "$MNTPOINT" - trap 'umount "$MNTPOINT"' EXIT - - echo "Creating needed directories" - mkdir -p "$MNTPOINT"/persist/var/{log,lib/{nixos,systemd}} - - echo "Cleaning root subvolume" - btrfs subvolume list -o "$MNTPOINT/root" | cut -f9 -d ' ' | - while read -r subvolume; do - btrfs subvolume delete "$MNTPOINT/$subvolume" - done && btrfs subvolume delete "$MNTPOINT/root" - - echo "Restoring blank subvolume" - btrfs subvolume snapshot "$MNTPOINT/root-blank" "$MNTPOINT/root" - ) - ''; - phase1Systemd = config.boot.initrd.systemd.enable; -in -{ - boot.initrd = { - supportedFilesystems = [ "btrfs" ]; - postDeviceCommands = lib.mkIf (!phase1Systemd) (lib.mkBefore wipeScript); - systemd.services.restore-root = lib.mkIf phase1Systemd { - description = "Rollback btrfs rootfs"; - wantedBy = [ "initrd.target" ]; - requires = [ - "dev-disk-by\\x2dlabel-${hostname}.device" - ]; - after = [ - "dev-disk-by\\x2dlabel-${hostname}.device" - "systemd-cryptsetup@${hostname}.service" - ]; - before = [ "sysroot.mount" ]; - unitConfig.DefaultDependencies = "no"; - serviceConfig.Type = "oneshot"; - script = wipeScript; - }; - }; - - fileSystems = { - "/" = { - device = "/dev/disk/by-label/${hostname}"; - fsType = "btrfs"; - options = [ "subvol=root" "compress=zstd" ]; - }; - - "/nix" = { - device = "/dev/disk/by-label/${hostname}"; - fsType = "btrfs"; - options = [ "subvol=nix" "noatime" "compress=zstd" ]; - }; - - "/persist" = { - device = "/dev/disk/by-label/${hostname}"; - fsType = "btrfs"; - options = [ "subvol=persist" "compress=zstd" ]; - neededForBoot = true; - }; - - "/logs" = { - device = "/dev/disk/by-label/${hostname}"; - fsType = "btrfs"; - options = [ "subvol=logs" "noatime" "compress=zstd" ]; - neededForBoot = true; - }; - - "/swap" = { - device = "/dev/disk/by-label/${hostname}"; - fsType = "btrfs"; - options = [ "subvol=swap" "noatime" ]; - }; - }; - -} diff --git a/_/nixos/_mixins/optional/fail2ban.nix b/_/nixos/_mixins/optional/fail2ban.nix deleted file mode 100644 index 9731ef6..0000000 --- a/_/nixos/_mixins/optional/fail2ban.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ - services.fail2ban = { - enable = true; - }; -} diff --git a/_/nixos/_mixins/optional/gamemode.nix b/_/nixos/_mixins/optional/gamemode.nix deleted file mode 100644 index 2a07856..0000000 --- a/_/nixos/_mixins/optional/gamemode.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - programs.gamemode = { - enable = true; - settings = { - general = { - softrealtime = "on"; - inhibit_screensaver = 1; - }; - gpu = { - apply_gpu_optimisations = "accept-responsibility"; - gpu_device = 0; - amd_performance_level = "high"; - }; - }; - }; -} diff --git a/_/nixos/_mixins/optional/gnome.nix b/_/nixos/_mixins/optional/gnome.nix deleted file mode 100644 index 00eb3c0..0000000 --- a/_/nixos/_mixins/optional/gnome.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ pkgs, ... }: -{ - services = { - xserver = { - enable = true; - dpi = 180; - displayManager.gdm = { - enable = true; - wayland = true; - autoSuspend = false; - }; - desktopManager.gnome = { - enable = true; - }; - excludePackages = [ pkgs.xterm ]; - }; - geoclue2.enable = true; - gnome.games.enable = true; - }; - networking.networkmanager.enable = true; - services.avahi.enable = true; - - # console.font = "${pkgs.terminus_font}/share/consolefonts/ter-u28n.psf.gz"; - # environment.variables = { - # GDK_SCALE = "2"; - # GDK_DPI_SCALE = "0.5"; - # _JAVA_OPTIONS = "-Dsun.java2d.uiScale=2"; - # }; - - # Enable CUPS to print documents. - services.printing.enable = true; - services.avahi.nssmdns = true; - # for a WiFi printer - services.avahi.openFirewall = true; -} diff --git a/_/nixos/_mixins/optional/lol-acfix.nix b/_/nixos/_mixins/optional/lol-acfix.nix deleted file mode 100644 index 47e4932..0000000 --- a/_/nixos/_mixins/optional/lol-acfix.nix +++ /dev/null @@ -1,6 +0,0 @@ -{ - boot.kernel.sysctl = { - # Disable VDSO on 32-bits to avoid league of legends kick - "abi.vsyscall32" = 0; - }; -} diff --git a/_/nixos/_mixins/optional/mysql.nix b/_/nixos/_mixins/optional/mysql.nix deleted file mode 100644 index 9904a09..0000000 --- a/_/nixos/_mixins/optional/mysql.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ pkgs, ... }: -{ - services.mysql = { - enable = true; - package = pkgs.mariadb; - }; - - environment.persistence = { - "/persist".directories = [ - "/var/lib/mysql" - ]; - }; -} diff --git a/_/nixos/_mixins/optional/nginx.nix b/_/nixos/_mixins/optional/nginx.nix deleted file mode 100644 index 846d814..0000000 --- a/_/nixos/_mixins/optional/nginx.nix +++ /dev/null @@ -1,47 +0,0 @@ -{ lib, config, ... }: -let - inherit (config.networking) hostName; -in -{ - services = { - nginx = { - enable = true; - recommendedTlsSettings = true; - recommendedProxySettings = true; - recommendedGzipSettings = true; - recommendedOptimisation = true; - clientMaxBodySize = "300m"; - - virtualHosts."${hostName}.burd.me" = { - default = true; - forceSSL = true; - enableACME = true; - locations."/metrics" = { - proxyPass = "http://localhost:${toString config.services.prometheus.exporters.nginxlog.port}"; - }; - }; - }; - - prometheus.exporters.nginxlog = { - enable = true; - group = "nginx"; - settings.namespaces = [{ - name = "filelogger"; - source.files = [ "/var/log/nginx/access.log" ]; - format = "$remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\""; - }]; - }; - - uwsgi = { - enable = true; - user = "nginx"; - group = "nginx"; - plugins = [ "cgi" ]; - instance = { - type = "emperor"; - vassals = lib.mkBefore { }; - }; - }; - }; - networking.firewall.allowedTCPPorts = [ 80 443 ]; -} diff --git a/_/nixos/_mixins/optional/pantheon.nix b/_/nixos/_mixins/optional/pantheon.nix deleted file mode 100644 index d15be6f..0000000 --- a/_/nixos/_mixins/optional/pantheon.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ - services = { - xserver = { - enable = true; - desktopManager.pantheon = { - enable = true; - }; - displayManager.lightdm = { - enable = true; - greeters.pantheon.enable = true; - }; - }; - pantheon = { - apps.enable = true; - }; - geoclue2.enable = true; - }; - programs = { - pantheon-tweaks.enable = true; - }; - # Fix shutdown taking a long time - # https://gist.github.com/worldofpeace/27fcdcb111ddf58ba1227bf63501a5fe - systemd.extraConfig = '' - DefaultTimeoutStopSec=10s - DefaultTimeoutStartSec=10s - ''; - - services.avahi.enable = false; - networking.networkmanager.enable = false; -} diff --git a/_/nixos/_mixins/optional/postgres.nix b/_/nixos/_mixins/optional/postgres.nix deleted file mode 100644 index 059a420..0000000 --- a/_/nixos/_mixins/optional/postgres.nix +++ /dev/null @@ -1,9 +0,0 @@ -_: { - services.postgresql.enable = true; - - environment.persistence = { - "/persist".directories = [ - "/var/lib/postgresql" - ]; - }; -} diff --git a/_/nixos/_mixins/optional/starcitizen-fixes.nix b/_/nixos/_mixins/optional/starcitizen-fixes.nix deleted file mode 100644 index f0917ca..0000000 --- a/_/nixos/_mixins/optional/starcitizen-fixes.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ - # https://github.com/starcitizen-lug/information-howtos/wiki - - # Avoids crashes - boot.kernel.sysctl = { - "vm.max_map_count" = 16777216; - }; -} diff --git a/_/nixos/_mixins/optional/systemd-boot.nix b/_/nixos/_mixins/optional/systemd-boot.nix deleted file mode 100644 index 40d04b2..0000000 --- a/_/nixos/_mixins/optional/systemd-boot.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ - boot.loader = { - systemd-boot = { - enable = true; - consoleMode = "max"; - }; - efi.canTouchEfiVariables = true; - }; -} diff --git a/_/nixos/_mixins/optional/tailscale-exit-node.nix b/_/nixos/_mixins/optional/tailscale-exit-node.nix deleted file mode 100644 index 1779a59..0000000 --- a/_/nixos/_mixins/optional/tailscale-exit-node.nix +++ /dev/null @@ -1,6 +0,0 @@ -{ - imports = [ ../global/tailscale.nix ]; - services.tailscale = { - useRoutingFeatures = "both"; - }; -} diff --git a/_/nixos/_mixins/optional/wireless.nix b/_/nixos/_mixins/optional/wireless.nix deleted file mode 100644 index 6084961..0000000 --- a/_/nixos/_mixins/optional/wireless.nix +++ /dev/null @@ -1,66 +0,0 @@ -{ config, ... }: { - # Wireless secrets stored through sops - sops.secrets.wireless = { - sopsFile = ../secrets.yaml; - neededForUsers = true; - }; - - networking.wireless = { - enable = true; - fallbackToWPA2 = false; - # Declarative - environmentFile = config.sops.secrets.wireless.path; - networks = { - "JVGCLARO" = { - psk = "@JVGCLARO@"; - }; - "Kartodrorealm" = { - psk = "@KARTODROREALM@"; - }; - "Kartodrorealm-5G" = { - psk = "@KARTODROREALM@"; - }; - "Marcos_2.4Ghz" = { - pskRaw = "@MARCOS_24@"; - }; - "Marcos_5Ghz" = { - pskRaw = "@MARCOS_50@"; - }; - "Misterio" = { - pskRaw = "@MISTERIO@"; - }; - "VIVOFIBRA-FC41-5G" = { - pskRaw = "@MARCOS_SANTOS_5G@"; - }; - "zoocha" = { - pskRaw = "@ZOOCHA@"; - }; - "eduroam" = { - auth = '' - key_mgmt=WPA-EAP - pairwise=CCMP - auth_alg=OPEN - eap=PEAP - identity="10856803@usp.br" - password="@EDUROAM@" - phase2="auth=MSCHAPV2" - ''; - }; - }; - - # Imperative - allowAuxiliaryImperativeNetworks = true; - userControlled = { - enable = true; - group = "network"; - }; - extraConfig = '' - update_config=1 - ''; - }; - - # Ensure group exists - users.groups.network = { }; - - systemd.services.wpa_supplicant.preStart = "touch /etc/wpa_supplicant.conf"; -} diff --git a/_/nixos/_mixins/optional/wireshark.nix b/_/nixos/_mixins/optional/wireshark.nix deleted file mode 100644 index 44223ce..0000000 --- a/_/nixos/_mixins/optional/wireshark.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ - programs.wireshark = { - enable = true; - }; -} diff --git a/_/nixos/_mixins/optional/x11-no-suspend.nix b/_/nixos/_mixins/optional/x11-no-suspend.nix deleted file mode 100644 index 0005eed..0000000 --- a/_/nixos/_mixins/optional/x11-no-suspend.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ - services.xserver.serverFlagsSection = '' - Option "StandbyTime" "0" - Option "SuspendTime" "0" - Option "OffTime" "0" - ''; -} diff --git a/_/nixos/iso-console/default.nix b/_/nixos/iso-console/default.nix deleted file mode 100644 index 5589c62..0000000 --- a/_/nixos/iso-console/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ lib, ... }: -{ - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; -} diff --git a/_/nixos/iso-desktop/default.nix b/_/nixos/iso-desktop/default.nix deleted file mode 100644 index 8653889..0000000 --- a/_/nixos/iso-desktop/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ lib, ... }: -{ - imports = [ - ../_mixins/services/bluetooth.nix - ../_mixins/services/pipewire.nix - ]; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; -} diff --git a/_/overlays/default.nix b/_/overlays/default.nix deleted file mode 100644 index b5a0f8f..0000000 --- a/_/overlays/default.nix +++ /dev/null @@ -1,76 +0,0 @@ -{ inputs, ... }: -let - addPatches = pkg: patches: pkg.overrideAttrs (oldAttrs: { - patches = (oldAttrs.patches or [ ]) ++ patches; - }); -in -{ - # For every flake input, aliases 'pkgs.inputs.${flake}' to - # 'inputs.${flake}.packages.${pkgs.system}' or - # 'inputs.${flake}.legacyPackages.${pkgs.system}' - flake-inputs = final: _: { - inputs = builtins.mapAttrs - (_: flake: - let - legacyPackages = (flake.legacyPackages or { }).${final.system} or { }; - packages = (flake.packages or { }).${final.system} or { }; - in - if legacyPackages != { } then legacyPackages else packages - ) - inputs; - }; - - # Adds my custom packages - additions = final: prev: import ../pkgs { pkgs = final; } // { - formats = prev.formats // import ../pkgs/formats { pkgs = final; }; - vimPlugins = prev.vimPlugins // final.callPackage ../pkgs/vim-plugins { }; - }; - - # Modifies existing packages - modifications = final: prev: { - vimPlugins = prev.vimPlugins // { - vim-numbertoggle = addPatches prev.vimPlugins.vim-numbertoggle [ ./vim-numbertoggle-command-mode.patch ]; - }; - - passExtensions = prev.passExtensions // { - # https://github.com/tadfisher/pass-otp/pull/173 - pass-otp = addPatches prev.passExtensions.pass-otp [ ./pass-otp-fix-completion.patch ]; - }; - - # https://github.com/mdellweg/pass_secret_service/pull/37 - pass-secret-service = addPatches prev.pass-secret-service [ ./pass-secret-service-native.diff ]; - - # https://github.com/NixOS/nix/issues/5567#issuecomment-1193259926 - # nix = addPatches prev.nix [ ./nix-make-installables-expr-context.patch ]; - - # xdg-utils-spawn-terminal = addPatches prev.xdg-utils [ ./xdg-open-spawn-terminal.diff ]; - xdg-utils-spawn-terminal = prev.xdg-utils; - - pfetch = prev.pfetch.overrideAttrs (oldAttrs: { - version = "unstable-2021-12-10"; - src = final.fetchFromGitHub { - owner = "dylanaraps"; - repo = "pfetch"; - rev = "a906ff89680c78cec9785f3ff49ca8b272a0f96b"; - sha256 = "sha256-9n5w93PnSxF53V12iRqLyj0hCrJ3jRibkw8VK3tFDvo="; - }; - # Add term option, rename de to desktop, add scheme option - patches = (oldAttrs.patches or [ ]) ++ [ ./pfetch.patch ]; - }); - - qutebrowser = prev.qutebrowser.overrideAttrs (oldAttrs: { - patches = (oldAttrs.patches or [ ]) ++ [ ./qutebrowser-tree-tabs.diff ]; - }); - - # scgit = prev.cgit-pink.overrideAttrs (_: { - # pname = "scgit"; - # version = "0.1"; - # src = final.fetchFromSourcehut { - # owner = "~misterio"; - # repo = "scgit"; - # rev = "2cd05c95827fb94740e876733dc6f7fe88340de2"; - # sha256 = "sha256-95mRJ3ZCSkLHqehFQdwM2BY0h+YDhohwpnRiF6/lZtA="; - # }; - # }); - }; -} diff --git a/_/overlays/offline-mode-prism-launcher.diff b/_/overlays/offline-mode-prism-launcher.diff deleted file mode 100644 index 24a778a..0000000 --- a/_/overlays/offline-mode-prism-launcher.diff +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp -index 9e2fd11..3965913 100644 ---- a/launcher/minecraft/auth/AccountList.cpp -+++ b/launcher/minecraft/auth/AccountList.cpp -@@ -657,13 +657,7 @@ void AccountList::setListFilePath(QString path, bool autosave) - - bool AccountList::anyAccountIsValid() - { -- for(auto account: m_accounts) -- { -- if(account->ownsMinecraft()) { -- return true; -- } -- } -- return false; -+ return true; - } - - void AccountList::fillQueue() { diff --git a/_/overlays/pfetch.patch b/_/overlays/pfetch.patch deleted file mode 100644 index 8b4ee89..0000000 --- a/_/overlays/pfetch.patch +++ /dev/null @@ -1,41 +0,0 @@ -diff --git a/pfetch b/pfetch -index d47b878..79380da 100755 ---- a/pfetch -+++ b/pfetch -@@ -1055,14 +1055,14 @@ get_wm() { - } - - --get_de() { -+get_desktop() { - # This only supports Xorg related desktop environments though - # this is fine as knowing the desktop environment on Windows, - # macOS etc is useless (they'll always report the same value). - # - # Display the value of '$XDG_CURRENT_DESKTOP', if it's empty, - # display the value of '$DESKTOP_SESSION'. -- log de "${XDG_CURRENT_DESKTOP:-$DESKTOP_SESSION}" >&6 -+ log desktop "${XDG_CURRENT_DESKTOP:-$DESKTOP_SESSION}" >&6 - } - - get_shell() { -@@ -1078,6 +1078,19 @@ get_editor() { - log editor "${editor##*/}" >&6 - } - -+get_term() { -+ # Display the value of '$TERMINAL', if it's empty, display the -+ # value of '$TERM'. -+ term=${TERMINAL:-"$TERM"} -+ -+ log term "${term##*/}" >&6 -+} -+ -+get_scheme() { -+ # Display the '$SCHEME' environment variable. -+ log scheme "$(cat $HOME/.colorscheme)" >&6 -+} -+ - get_palette() { - # Print the first 8 terminal colors. This uses the existing - # sequences to change text color with a sequence prepended diff --git a/_/overlays/qutebrowser-tree-tabs.diff b/_/overlays/qutebrowser-tree-tabs.diff deleted file mode 100644 index b7a2f08..0000000 --- a/_/overlays/qutebrowser-tree-tabs.diff +++ /dev/null @@ -1,2455 +0,0 @@ -diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py -index 47cba592288..5630dc8cf18 100644 ---- a/qutebrowser/browser/browsertab.py -+++ b/qutebrowser/browser/browsertab.py -@@ -52,6 +52,8 @@ - from qutebrowser.browser import webelem - from qutebrowser.browser.inspector import AbstractWebInspector - -+from qutebrowser.mainwindow.treetabwidget import TreeTabWidget -+from qutebrowser.misc.notree import Node - - tab_id_gen = itertools.count(0) - _WidgetType = Union["QWebView", "QWebEngineView"] -@@ -1058,6 +1060,11 @@ def __init__(self, *, win_id: int, - self, parent=self) - self.backend: Optional[usertypes.Backend] = None - -+ if parent and isinstance(parent, TreeTabWidget): -+ self.node: AbstractTab = Node(self, parent=parent.tree_root) -+ else: -+ self.node: AbstractTab = Node(self, parent=None) -+ - # If true, this tab has been requested to be removed (or is removed). - self.pending_removal = False - self.shutting_down.connect(functools.partial( -diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py -index 3b38c44c05b..d1a1cf6be69 100644 ---- a/qutebrowser/browser/commands.py -+++ b/qutebrowser/browser/commands.py -@@ -20,6 +20,7 @@ - import os.path - import shlex - import functools -+import urllib.parse - from typing import cast, Callable, Dict, Union, Optional - - from qutebrowser.qt.widgets import QApplication, QTabBar -@@ -34,7 +35,7 @@ - from qutebrowser.utils import (message, usertypes, log, qtutils, urlutils, - objreg, utils, standarddir, debug) - from qutebrowser.utils.usertypes import KeyMode --from qutebrowser.misc import editor, guiprocess, objects -+from qutebrowser.misc import editor, guiprocess, objects, notree - from qutebrowser.completion.models import urlmodel, miscmodels - from qutebrowser.mainwindow import mainwindow, windowundo - -@@ -112,6 +113,7 @@ def _open( - background: bool = False, - window: bool = False, - related: bool = False, -+ sibling: bool = False, - private: Optional[bool] = None, - ) -> None: - """Helper function to open a page. -@@ -123,6 +125,7 @@ def _open( - window: Whether to open in a new window - private: If opening a new window, open it in private browsing mode. - If not given, inherit the current window's mode. -+ sibling: Open tab in a sibling node of the currently focused tab. - """ - urlutils.raise_cmdexc_if_invalid(url) - tabbed_browser = self._tabbed_browser -@@ -135,10 +138,16 @@ def _open( - tabbed_browser = self._new_tabbed_browser(private) - tabbed_browser.tabopen(url) - tabbed_browser.window().show() -- elif tab: -- tabbed_browser.tabopen(url, background=False, related=related) -- elif background: -- tabbed_browser.tabopen(url, background=True, related=related) -+ elif tab or background: -+ if tabbed_browser.is_treetabbedbrowser: -+ tabbed_browser.tabopen(url, background=background, -+ related=related, sibling=sibling) -+ elif sibling: -+ raise cmdutils.CommandError("--sibling flag only works with \ -+ tree-tab enabled") -+ else: -+ tabbed_browser.tabopen(url, background=background, -+ related=related) - else: - widget = self._current_widget() - widget.load_url(url) -@@ -220,7 +229,8 @@ def _get_selection_override(self, prev, next_, opposite): - "{!r}!".format(conf_selection)) - return None - -- def _tab_close(self, tab, prev=False, next_=False, opposite=False): -+ def _tab_close(self, tab, prev=False, next_=False, -+ opposite=False, new_undo=True): - """Helper function for tab_close be able to handle message.async. - - Args: -@@ -236,17 +246,17 @@ def _tab_close(self, tab, prev=False, next_=False, opposite=False): - opposite) - - if selection_override is None: -- self._tabbed_browser.close_tab(tab) -+ self._tabbed_browser.close_tab(tab, new_undo=new_undo) - else: - old_selection_behavior = tabbar.selectionBehaviorOnRemove() - tabbar.setSelectionBehaviorOnRemove(selection_override) -- self._tabbed_browser.close_tab(tab) -+ self._tabbed_browser.close_tab(tab, new_undo=new_undo) - tabbar.setSelectionBehaviorOnRemove(old_selection_behavior) - - @cmdutils.register(instance='command-dispatcher', scope='window') - @cmdutils.argument('count', value=cmdutils.Value.count) - def tab_close(self, prev=False, next_=False, opposite=False, -- force=False, count=None): -+ force=False, count=None, recursive=False): - """Close the current/[count]th tab. - - Args: -@@ -255,15 +265,37 @@ def tab_close(self, prev=False, next_=False, opposite=False, - opposite: Force selecting the tab in the opposite direction of - what's configured in 'tabs.select_on_remove'. - force: Avoid confirmation for pinned tabs. -+ recursive: Close all descendents (tree-tabs) as well as current tab - count: The tab index to close, or None - """ - tab = self._cntwidget(count) -+ tabbed_browser = self._tabbed_browser - if tab is None: - return -- close = functools.partial(self._tab_close, tab, prev, -- next_, opposite) -- -- self._tabbed_browser.tab_close_prompt_if_pinned(tab, force, close) -+ if (tabbed_browser.is_treetabbedbrowser and recursive and not -+ tab.node.collapsed): -+ # if collapsed, recursive is the same as normal close -+ new_undo = True # only for first one -+ for descendent in tab.node.traverse(notree.TraverseOrder.POST_R, -+ True): -+ if self._tabbed_browser.widget.indexOf(descendent.value) > -1: -+ close = functools.partial(self._tab_close, -+ descendent.value, prev, next_, -+ opposite, new_undo) -+ tabbed_browser.tab_close_prompt_if_pinned(tab, force, -+ close) -+ new_undo = False -+ else: -+ tab = descendent.value -+ tab.private_api.shutdown() -+ tab.deleteLater() -+ tab.layout().unwrap() -+ else: -+ # this also applied to closing collapsed tabs -+ # logic for that is in TreeTabbedBrowser -+ close = functools.partial(self._tab_close, tab, prev, -+ next_, opposite) -+ tabbed_browser.tab_close_prompt_if_pinned(tab, force, close) - - @cmdutils.register(instance='command-dispatcher', scope='window', - name='tab-pin') -@@ -288,8 +320,9 @@ def tab_pin(self, count=None): - @cmdutils.register(instance='command-dispatcher', name='open', - maxsplit=0, scope='window') - @cmdutils.argument('url', completion=urlmodel.url) -+ @cmdutils.argument('sibling', flag='S') - @cmdutils.argument('count', value=cmdutils.Value.count) -- def openurl(self, url=None, related=False, -+ def openurl(self, url=None, related=False, sibling=False, - bg=False, tab=False, window=False, count=None, secure=False, - private=False): - """Open a URL in the current/[count]th tab. -@@ -303,6 +336,8 @@ def openurl(self, url=None, related=False, - window: Open in a new window. - related: If opening a new tab, position the tab as related to the - current one (like clicking on a link). -+ sibling: If opening a new tab, position the as a sibling of the -+ current one. - count: The tab index to open the URL in, or None. - secure: Force HTTPS. - private: Open a new window in private browsing mode. -@@ -321,8 +356,8 @@ def openurl(self, url=None, related=False, - bg = True - - if tab or bg or window or private: -- self._open(cur_url, tab, bg, window, related=related, -- private=private) -+ self._open(cur_url, tab, bg, window, private=private, -+ related=related, sibling=sibling) - else: - curtab = self._cntwidget(count) - if curtab is None: -@@ -461,11 +496,40 @@ def tab_take(self, index, keep=False): - if not keep: - tabbed_browser.close_tab(tab, add_undo=False, transfer=True) - -+ def _tree_tab_give(self, tabbed_browser, keep): -+ """Helper function to simplify tab-give.""" -+ uid_map = {1: 1} -+ traversed = list(self._current_widget().node.traverse()) -+ # first pass: open tabs -+ for node in traversed: -+ tab = tabbed_browser.tabopen(node.value.url()) -+ -+ uid_map[node.uid] = tab.node.uid -+ -+ # second pass: copy tree structure over -+ newroot = tabbed_browser.widget.tree_root -+ oldroot = self._tabbed_browser.widget.tree_root -+ for node in traversed: -+ if node.parent is not oldroot: -+ uid = uid_map[node.uid] -+ new_node = newroot.get_descendent_by_uid(uid) -+ parent_uid = uid_map[node.parent.uid] -+ new_parent = newroot.get_descendent_by_uid(parent_uid) -+ new_node.parent = new_parent -+ -+ # third pass: remove tabs from old window -+ if not keep: -+ for _node in traversed: -+ self._tabbed_browser.close_tab(self._current_widget(), -+ add_undo=False, -+ transfer=True) -+ - @cmdutils.register(instance='command-dispatcher', scope='window') - @cmdutils.argument('win_id', completion=miscmodels.window) - @cmdutils.argument('count', value=cmdutils.Value.count) - def tab_give(self, win_id: int = None, keep: bool = False, -- count: int = None, private: bool = False) -> None: -+ count: int = None, private: bool = False, -+ recursive: bool = False) -> None: - """Give the current tab to a new or existing window if win_id given. - - If no win_id is given, the tab will get detached into a new window. -@@ -474,6 +538,7 @@ def tab_give(self, win_id: int = None, keep: bool = False, - win_id: The window ID of the window to give the current tab to. - keep: If given, keep the old tab around. - count: Overrides win_id (index starts at 1 for win_id=0). -+ recursive: Whether to move the entire subtree starting at the tab. - private: If the tab should be detached into a private instance. - """ - if config.val.tabs.tabs_are_windows: -@@ -505,13 +570,15 @@ def tab_give(self, win_id: int = None, keep: bool = False, - raise cmdutils.CommandError( - "The window with id {} is not private".format(win_id)) - -- tabbed_browser.tabopen(self._current_url()) -- tabbed_browser.window().show() -- -- if not keep: -- self._tabbed_browser.close_tab(self._current_widget(), -- add_undo=False, -- transfer=True) -+ if recursive and tabbed_browser.is_treetabbedbrowser: -+ self._tree_tab_give(tabbed_browser, keep) -+ else: -+ tabbed_browser.tabopen(self._current_url()) -+ tabbed_browser.window().show() -+ if not keep: -+ self._tabbed_browser.close_tab(self._current_widget(), -+ add_undo=False, -+ transfer=True) - - def _back_forward( - self, *, -@@ -889,43 +956,79 @@ def undo(self, window: bool = False, - - @cmdutils.register(instance='command-dispatcher', scope='window') - @cmdutils.argument('count', value=cmdutils.Value.count) -- def tab_prev(self, count=1): -+ def tab_prev(self, count=1, sibling=False): - """Switch to the previous tab, or switch [count] tabs back. - - Args: - count: How many tabs to switch back. -+ sibling: Whether to focus the previous tree sibling. - """ - if self._count() == 0: - # Running :tab-prev after last tab was closed - # See https://github.com/qutebrowser/qutebrowser/issues/1448 - return -- newidx = self._current_index() - count -- if newidx >= 0: -- self._set_current_index(newidx) -- elif config.val.tabs.wrap: -- self._set_current_index(newidx % self._count()) -+ if sibling and self._tabbed_browser.is_treetabbedbrowser: -+ cur_node = self._current_widget().node -+ siblings = list(cur_node.parent.children) -+ -+ if siblings and len(siblings) > 1: -+ node_idx = siblings.index(cur_node) -+ new_idx = node_idx - count -+ if new_idx >= 0 or config.val.tabs.wrap: -+ target_node = siblings[(node_idx-count) % len(siblings)] -+ idx = self._tabbed_browser.widget.indexOf( -+ target_node.value) -+ self._set_current_index(idx) -+ else: -+ log.webview.debug("First sibling") -+ else: -+ log.webview.debug("No siblings") - else: -- log.webview.debug("First tab") -+ newidx = self._current_index() - count -+ if newidx >= 0: -+ self._set_current_index(newidx) -+ elif config.val.tabs.wrap: -+ self._set_current_index(newidx % self._count()) -+ else: -+ log.webview.debug("First tab") - - @cmdutils.register(instance='command-dispatcher', scope='window') - @cmdutils.argument('count', value=cmdutils.Value.count) -- def tab_next(self, count=1): -+ def tab_next(self, count=1, sibling=False): - """Switch to the next tab, or switch [count] tabs forward. - - Args: - count: How many tabs to switch forward. -+ sibling: Whether to focus the next tree sibling. - """ - if self._count() == 0: - # Running :tab-next after last tab was closed - # See https://github.com/qutebrowser/qutebrowser/issues/1448 - return -- newidx = self._current_index() + count -- if newidx < self._count(): -- self._set_current_index(newidx) -- elif config.val.tabs.wrap: -- self._set_current_index(newidx % self._count()) -+ if sibling and self._tabbed_browser.is_treetabbedbrowser: -+ cur_node = self._current_widget().node -+ siblings = list(cur_node.parent.children) -+ -+ if siblings and len(siblings) > 1: -+ node_idx = siblings.index(cur_node) -+ new_idx = node_idx + count -+ if new_idx < len(siblings) or config.val.tabs.wrap: -+ target_node = siblings[new_idx % len(siblings)] -+ idx = self._tabbed_browser.widget.indexOf( -+ target_node.value) -+ self._set_current_index(idx) -+ else: -+ log.webview.debug("Last sibling") -+ else: -+ log.webview.debug("No siblings") - else: -- log.webview.debug("Last tab") -+ newidx = self._current_index() + count -+ if newidx < self._count(): -+ self._set_current_index(newidx) -+ elif config.val.tabs.wrap: -+ self._set_current_index(newidx % self._count()) -+ else: -+ log.webview.debug("Last tab") - - def _resolve_tab_index(self, index): - """Resolve a tab index to the tabbedbrowser and tab. -@@ -1005,7 +1108,8 @@ def tab_select(self, index=None, count=None): - tabbed_browser.widget.setCurrentWidget(tab) - - @cmdutils.register(instance='command-dispatcher', scope='window') -- @cmdutils.argument('index', choices=['last', 'stack-next', 'stack-prev'], -+ @cmdutils.argument('index', choices=['last', 'parent', -+ 'stack-next', 'stack-prev'], - completion=miscmodels.tab_focus) - @cmdutils.argument('count', value=cmdutils.Value.count) - def tab_focus(self, index: Union[str, int] = None, -@@ -1016,11 +1120,15 @@ def tab_focus(self, index: Union[str, int] = None, - If both are given, use count. - - Args: -- index: The tab index to focus, starting with 1. The special value -- `last` focuses the last focused tab (regardless of count), -- and `stack-prev`/`stack-next` traverse a stack of visited -- tabs. Negative indices count from the end, such that -1 is -- the last tab. -+ index: The tab index to focus, starting with 1. Negative indices -+ count from the end, such that -1 is the last tab. Special -+ values are: -+ - `last` focuses the last focused tab (regardless of -+ count). -+ - `parent` focuses the parent tab in the tree hierarchy, -+ if `tabs.tree_tabs` is enabled. -+ - `stack-prev`/`stack-next` traverse a stack of visited -+ tabs. - count: The tab index to focus, starting with 1. - no_last: Whether to avoid focusing last tab if already focused. - """ -@@ -1030,6 +1138,22 @@ def tab_focus(self, index: Union[str, int] = None, - assert isinstance(index, str) - self._tab_focus_stack(index) - return -+ elif index == 'parent' and self._tabbed_browser.is_treetabbedbrowser: -+ node = self._current_widget().node -+ path = node.path -+ if count: -+ if count < len(path): -+ path_idx = 0 - count - 1 # path[-1] is node, so shift by 1 -+ else: -+ path_idx = 1 # first non-root node -+ else: -+ path_idx = -2 # immediate parent (path[-1] is node) -+ -+ target_node = path[path_idx] -+ if node is target_node or target_node.value is None: -+ raise cmdutils.CommandError("Tab has no parent! ") -+ target_tab = target_node.value -+ index = self._tabbed_browser.widget.indexOf(target_tab) + 1 - elif index is None: - message.warning( - "Using :tab-focus without count is deprecated, " -@@ -1069,17 +1193,31 @@ def tab_move(self, index: Union[str, int] = None, count: int = None) -> None: - If moving absolutely: New position (default: 0). This - overrides the index argument, if given. - """ -+ # pylint: disable=invalid-unary-operand-type -+ # https://github.com/PyCQA/pylint/issues/1472 - if index in ["+", "-"]: - # relative moving - new_idx = self._current_index() - delta = 1 if count is None else count -- if index == "-": -- new_idx -= delta -- elif index == "+": # pragma: no branch -- new_idx += delta - -- if config.val.tabs.wrap: -- new_idx %= self._count() -+ if self._tabbed_browser.is_treetabbedbrowser: -+ node = self._current_widget().node -+ parent = node.parent -+ siblings = list(parent.children) -+ -+ if len(siblings) <= 1: -+ return -+ rel_idx = siblings.index(node) -+ rel_idx += delta if index == '+' else - delta -+ rel_idx %= len(siblings) -+ new_idx = self._tabbed_browser.widget.indexOf( -+ siblings[rel_idx].value) -+ -+ else: -+ new_idx += delta if index == '+' else - delta -+ -+ if config.val.tabs.wrap: -+ new_idx %= self._count() - else: - # pylint: disable=else-if-used - # absolute moving -@@ -1102,7 +1240,34 @@ def tab_move(self, index: Union[str, int] = None, count: int = None) -> None: - cur_idx = self._current_index() - cmdutils.check_overflow(cur_idx, 'int') - cmdutils.check_overflow(new_idx, 'int') -- self._tabbed_browser.widget.tabBar().moveTab(cur_idx, new_idx) -+ -+ if self._tabbed_browser.is_treetabbedbrowser: -+ # self._tree_tab_move(new_idx) -+ new_idx += 1 # tree-tabs indexes start at 1 (0 is hidden root tab) -+ tab = self._current_widget() -+ -+ # traverse order is the same as display order -+ # so indexing works correctly -+ tree_root = self._tabbed_browser.widget.tree_root -+ tabs = list(tree_root.traverse(render_collapsed=False)) -+ target_node = tabs[new_idx] -+ if tab.node in target_node.path: -+ raise cmdutils.CommandError("Can't move tab to a descendent" -+ " of itself") -+ -+ new_parent = target_node.parent -+ # we need index relative to parent for correct placement -+ dest_tab = tabs[new_idx] -+ new_idx_relative = new_parent.children.index(dest_tab) -+ -+ tab.node.parent = None # avoid duplicate errors -+ siblings = list(new_parent.children) -+ siblings.insert(new_idx_relative, tab.node) -+ new_parent.children = siblings -+ -+ self._tabbed_browser.widget.tree_tab_update() -+ else: -+ self._tabbed_browser.widget.tabBar().moveTab(cur_idx, new_idx) - - @cmdutils.register(instance='command-dispatcher', scope='window', - maxsplit=0, no_replace_variables=True) -@@ -1899,3 +2064,123 @@ def fullscreen(self, leave=False, enter=False): - - log.misc.debug('state before fullscreen: {}'.format( - debug.qflags_key(Qt, window.state_before_fullscreen))) -+ -+ @cmdutils.register(instance='command-dispatcher', scope='window', -+ tree_tab=True) -+ @cmdutils.argument('count', value=cmdutils.Value.count) -+ def tree_tab_promote(self, count=1): -+ """Promote a tab so it becomes next sibling of its parent. -+ -+ Observes tabs.new_position.tree.promote in positioning the tab among -+ new siblings. -+ -+ Args: -+ count: How many levels the tabs should be promoted to -+ """ -+ if not self._tabbed_browser.is_treetabbedbrowser: -+ raise cmdutils.CommandError('Tree-tabs are disabled') -+ config_position = config.val.tabs.new_position.tree.promote -+ try: -+ self._current_widget().node.promote(count, config_position) -+ except notree.TreeError: -+ raise cmdutils.CommandError('Tab has no parent!') -+ finally: -+ self._tabbed_browser.widget.tree_tab_update() -+ -+ @cmdutils.register(instance='command-dispatcher', scope='window', -+ tree_tab=True) -+ def tree_tab_demote(self): -+ """Demote a tab making it children of its previous adjacent sibling. -+ -+ Observes tabs.new_position.tree.demote in positioning the tab among new -+ siblings. -+ """ -+ if not self._tabbed_browser.is_treetabbedbrowser: -+ raise cmdutils.CommandError('Tree-tabs are disabled') -+ cur_node = self._current_widget().node -+ -+ config_position = config.val.tabs.new_position.tree.demote -+ try: -+ cur_node.demote(config_position) -+ except notree.TreeError: -+ raise cmdutils.CommandError('Tab has no previous sibling!') -+ finally: -+ self._tabbed_browser.widget.tree_tab_update() -+ -+ @cmdutils.register(instance='command-dispatcher', scope='window', -+ tree_tab=True) -+ @cmdutils.argument('count', value=cmdutils.Value.count) -+ def tree_tab_toggle_hide(self, count=None): -+ """If the current tab's children are shown hide them, and vice-versa. -+ -+ This toggles the current tab's node's `collapsed` attribute. -+ -+ Args: -+ count: Which tab to collapse -+ """ -+ if not self._tabbed_browser.is_treetabbedbrowser: -+ raise cmdutils.CommandError('Tree-tabs are disabled') -+ tab = self._cntwidget(count) -+ if not tab.node.children: -+ return -+ tab.node.collapsed = not tab.node.collapsed -+ -+ self._tabbed_browser.widget.tree_tab_update() -+ -+ @cmdutils.register(instance='command-dispatcher', scope='window', -+ tree_tab=True) -+ @cmdutils.argument('count', value=cmdutils.Value.count) -+ def tree_tab_cycle_hide(self, count=1): -+ """Hides levels of descendents: children, grandchildren, and so on. -+ -+ Args: -+ count: How many levels to hide. -+ """ -+ if not self._tabbed_browser.is_treetabbedbrowser: -+ raise cmdutils.CommandError('Tree-tabs are disabled') -+ while count > 0: -+ tab = self._current_widget() -+ self._tabbed_browser.cycle_hide_tab(tab.node) -+ count -= 1 -+ -+ self._tabbed_browser.widget.tree_tab_update() -+ -+ @cmdutils.register(instance='command-dispatcher', scope='window', -+ tree_tab=True) -+ def tree_tab_create_group(self, *name, related=False, -+ background=False): -+ """Wrapper around :open qute://treegroup/name. Correctly escapes names. -+ -+ Example: `:tree-tab-create-group Foo Bar` calls -+ `:open qute://treegroup/Foo%20Bar` -+ -+ Args: -+ name: Name of the group to create -+ related: whether to open as a child of current tab or under root -+ background: whether to open in a background tab -+ """ -+ title = ' '.join(name) -+ path = urllib.parse.quote(title) -+ if background: -+ self.openurl('qute://treegroup/' + path, related=related, bg=True) -+ else: -+ self.openurl('qute://treegroup/' + path, related=related, tab=True) -+ -+ @cmdutils.register(instance='command-dispatcher', scope='window', -+ tree_tab=True) -+ @cmdutils.argument('count', value=cmdutils.Value.count) -+ def tree_tab_suspend_children(self, count=None): -+ """Suspends all descendent of a tab to reduce memory usage. -+ -+ Args: -+ count: Target tab. -+ """ -+ tab = self._cntwidget(count) -+ for descendent in tab.node.traverse(): -+ cur_tab = descendent.value -+ if cur_tab and cur_tab is not tab: -+ cur_url = cur_tab.url().url() -+ if not cur_url.startswith("qute://"): -+ new_url = self._parse_url( -+ "qute://back/#" + cur_tab.title()) -+ cur_tab.load_url(new_url) -diff --git a/qutebrowser/browser/qutescheme.py b/qutebrowser/browser/qutescheme.py -index 25834670b11..15e4bc769e4 100644 ---- a/qutebrowser/browser/qutescheme.py -+++ b/qutebrowser/browser/qutescheme.py -@@ -588,6 +588,18 @@ def qute_warning(url: QUrl) -> _HandlerRet: - return 'text/html', src - - -+@add_handler('treegroup') -+def qute_treegroup(url): -+ """Handler for qute://treegroup/x. -+ -+ Makes an empty tab with a title, for use with tree-tabs as a grouping -+ feature. -+ """ -+ src = jinja.render('tree_group.html', -+ title=url.path()[1:]) -+ return 'text/html', src -+ -+ - @add_handler('resource') - def qute_resource(url: QUrl) -> _HandlerRet: - """Handler for qute://resource.""" -diff --git a/qutebrowser/commands/command.py b/qutebrowser/commands/command.py -index 655a5a336ad..76a44934e97 100644 ---- a/qutebrowser/commands/command.py -+++ b/qutebrowser/commands/command.py -@@ -65,6 +65,7 @@ class Command: - both) - no_replace_variables: Don't replace variables like {url} - modes: The modes the command can be executed in. -+ tree_tab: Whether the command is a tree-tabs command - _qute_args: The saved data from @cmdutils.argument - _count: The count set for the command. - _instance: The object to bind 'self' to. -@@ -78,7 +79,7 @@ class Command: - def __init__(self, *, handler, name, instance=None, maxsplit=None, - modes=None, not_modes=None, debug=False, deprecated=False, - no_cmd_split=False, star_args_optional=False, scope='global', -- backend=None, no_replace_variables=False): -+ backend=None, no_replace_variables=False, tree_tab=False): - if modes is not None and not_modes is not None: - raise ValueError("Only modes or not_modes can be given!") - if modes is not None: -@@ -107,6 +108,7 @@ def __init__(self, *, handler, name, instance=None, maxsplit=None, - self.handler = handler - self.no_cmd_split = no_cmd_split - self.backend = backend -+ self.tree_tab = tree_tab - self.no_replace_variables = no_replace_variables - - self.docparser = docutils.DocstringParser(handler) -diff --git a/qutebrowser/completion/models/util.py b/qutebrowser/completion/models/util.py -index 69a192f686e..16452d7b571 100644 ---- a/qutebrowser/completion/models/util.py -+++ b/qutebrowser/completion/models/util.py -@@ -21,6 +21,7 @@ - - from qutebrowser.utils import usertypes - from qutebrowser.misc import objects -+from qutebrowser.config import config - - - DeleteFuncType = Callable[[Sequence[str]], None] -@@ -44,8 +45,9 @@ def get_cmd_completions(info, include_hidden, include_aliases, prefix=''): - hide_debug = obj.debug and not objects.args.debug - hide_mode = (usertypes.KeyMode.normal not in obj.modes and - not include_hidden) -+ hide_tree = obj.tree_tab and not config.cache['tabs.tree_tabs'] - hide_ni = obj.name == 'Ni!' -- if not (hide_debug or hide_mode or obj.deprecated or hide_ni): -+ if not (hide_tree or hide_debug or hide_mode or obj.deprecated or hide_ni): - bindings = ', '.join(cmd_to_keys.get(obj.name, [])) - cmdlist.append((prefix + obj.name, obj.desc, bindings)) - -diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml -index 0b9d669dceb..05526260e02 100644 ---- a/qutebrowser/config/configdata.yml -+++ b/qutebrowser/config/configdata.yml -@@ -2224,6 +2224,40 @@ tabs.new_position.stacking: - Only applies for `next` and `prev` values of `tabs.new_position.related` - and `tabs.new_position.unrelated`. - -+tabs.new_position.tree.new_child: -+ default: first -+ type: NewChildPosition -+ desc: >- -+ Position of new children among siblings, e.g. after calling `:open -+ --relative ...` or following a link. -+ -+tabs.new_position.tree.new_sibling: -+ default: first -+ type: NewTabPosition -+ desc: >- -+ Position of siblings, e.g. after calling `:open --sibling ...`. -+ -+tabs.new_position.tree.new_toplevel: -+ default: last -+ type: NewTabPosition -+ desc: >- -+ Position of new top-level tabs related to the topmost ancestor of current -+ tab, e.g. when calling `:open ...` without `--relative` or `--sibling`. -+ -+tabs.new_position.tree.promote: -+ default: next -+ type: NewTabPosition -+ desc: >- -+ Position at which a tab is placed among its new siblings after being -+ promoted with `:tree-tab-promote` -+ -+tabs.new_position.tree.demote: -+ default: last -+ type: NewChildPosition -+ desc: >- -+ Position at which a tab is placed among its new siblings after being -+ demoted with `:tree-tab-demote` -+ - tabs.padding: - default: - top: 0 -@@ -2289,7 +2323,7 @@ tabs.title.elide: - desc: Position of ellipsis in truncated title of tabs. - - tabs.title.format: -- default: '{audio}{index}: {current_title}' -+ default: '{tree}{collapsed}{audio}{index}: {current_title}' - type: - name: FormatString - fields: -@@ -2307,12 +2341,16 @@ tabs.title.format: - - current_url - - protocol - - audio -+ - collapsed -+ - tree - none_ok: true - desc: | - Format to use for the tab title. - The following placeholders are defined: - - * `{perc}`: Percentage as a string like `[10%]`. -+ * `{collapsed}`: If children tabs are hidden, the string `[...]`, empty otherwise -+ * `{tree}`: The ASCII tree prefix of current tab. - * `{perc_raw}`: Raw percentage, e.g. `10`. - * `{current_title}`: Title of the current web page. - * `{title_sep}`: The string `" - "` if a title is set, empty otherwise. -@@ -2348,6 +2386,8 @@ tabs.title.format_pinned: - - current_url - - protocol - - audio -+ - collapsed -+ - tree - none_ok: true - desc: Format to use for the tab title for pinned tabs. The same placeholders - like for `tabs.title.format` are defined. -@@ -2446,6 +2486,12 @@ tabs.wrap: - type: Bool - desc: Wrap when changing tabs. - -+tabs.tree_tabs: -+ default: false -+ type: Bool -+ desc: Enable tree-tabs mode. -+ restart: true -+ - tabs.focus_stack_size: - default: 10 - type: -@@ -3831,6 +3877,17 @@ bindings.default: - all no-3rdparty never ;; reload - tCu: config-cycle -p -u {url} content.cookies.accept - all no-3rdparty never ;; reload -+ zH: tree-tab-promote -+ zL: tree-tab-demote -+ zJ: tab-next -s -+ zK: tab-prev -s -+ zd: tab-close -r -+ zg: set-cmd-text -s :tree-tab-create-group -r -+ zG: set-cmd-text -s :tree-tab-create-group -+ za: tree-tab-toggle-hide -+ zp: tab-focus parent -+ zo: set-cmd-text --space :open -tr -+ zO: set-cmd-text --space :open -tS - insert: - : edit-text - : insert-text -- {primary} -diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py -index b451744c338..a10f4aa3bb5 100644 ---- a/qutebrowser/config/configtypes.py -+++ b/qutebrowser/config/configtypes.py -@@ -1955,6 +1955,21 @@ def __init__( - ('last', "At the end.")) - - -+class NewChildPosition(String): -+ -+ """How new children are positioned.""" -+ -+ def __init__( -+ self, *, -+ none_ok: bool = False, -+ completions: _Completions = None, -+ ) -> None: -+ super().__init__(none_ok=none_ok, completions=completions) -+ self.valid_values = ValidValues( -+ ('first', "At the beginning."), -+ ('last', "At the end.")) -+ -+ - class LogLevel(String): - - """A logging level.""" -diff --git a/qutebrowser/html/tree_group.html b/qutebrowser/html/tree_group.html -new file mode 100644 -index 00000000000..b3717e52b6e ---- /dev/null -+++ b/qutebrowser/html/tree_group.html -@@ -0,0 +1,65 @@ -+{% extends "base.html" %} -+{% block style %} -+h1, p { -+ margin-left: 3rem; -+} -+ -+pre { -+ margin-left: 6em; -+} -+{% endblock %} -+{% block content %} -+

-+ {{ title }} -+

-+

-+ Group for tree tabs -+

-+
-+{% raw %}
-+                       _.
-+                _~.:'^%^ >@~.
-+             ,-~              ? =*=
-+           $^_`  `  , '   ,    +   -.,
-+        (*-^. , *            ;'       >
-+      >.      ,>    .     ' .,.,.      %-.,_ ,.-,
-+      #    ' ` " - "     *    .,.      *   .^    `
-+     *@!    ., *    ' '    ,    ;'   '         .  %!
-+      &       "  .`      :'              `   '   . `~,
-+     &    '        .`  '   '  .     '":   :          +.
-+     ^      .",  ,       `      '   `   * , '   `      |
-+      ]     *   .   , ""]   ..    ` . , `  , "  . . '  ,;,
-+      %  '         ::,  ,   /    ,            '   ,     ;
-+    .* ,*    /       *%     \  .  .  *'  `    ,    '     '.
-+   ?     > .   ,      ::. :;^^.     %`      '        `     @
-+  /   '   `/      `    &#@%^^      `&``   `     %;;       %
-+ ;:       :%   *  *  :$%)\      '  `@%$        @%^      ,).
-+ .    #    %&^     (!*^ .\,.   `      ^@%^  $#%%^  `   >
-+ \           :#$%  #^&#   :   `  *      %###$%@!       &
-+  |  '  *     %$#@)$*}]           `     `#@#%%^      *^
-+   :     *'  *  @%&&^:$   `  '   `%%.  #$$$^^-,     7
-+    &;            @#$~~   '   `     @#$%&      $,*.-
-+     *...*^  .._   %$$#@!   @ .,  *&&#@
-+         :..^   -   !%&@}{#&     @#$@%
-+                 --_..%#%%$#&% #&%$#;:
-+                        $%#^%#@@%%*&;;
-+                         a%##@%%@% ;:;
-+                           %####j#:::;
-+                            &#%Rj;%;;:
-+                            &#%%#;::;
-+                            $#%##:%::
-+                            "#%%#;:;
-+                           ."$###:::
-+                           #&$%%#:;:
-+                           %&#%%#::;
-+                           %&%###;::
-+                           &&#%%#:;;
-+                          *@&#%#};:;
-+                          $#%#%%^:::
-+                         *@#$#%#;::;:
-+                        %%@#$####@$:;:
-+                    ...%###pinusc@$%%:._____
-+{% endraw %}
-+
-+
-+{% endblock %} -diff --git a/qutebrowser/mainwindow/mainwindow.py b/qutebrowser/mainwindow/mainwindow.py -index 5e34a6649fe..405e9fd285b 100644 ---- a/qutebrowser/mainwindow/mainwindow.py -+++ b/qutebrowser/mainwindow/mainwindow.py -@@ -21,7 +21,7 @@ - import base64 - import itertools - import functools --from typing import List, MutableSequence, Optional, Tuple, cast -+from typing import List, MutableSequence, Optional, Tuple, cast, Union - - from qutebrowser.qt import machinery - from qutebrowser.qt.core import (pyqtBoundSignal, pyqtSlot, QRect, QPoint, QTimer, Qt, -@@ -208,7 +208,7 @@ def __init__(self, *, - super().__init__(parent) - # Late import to avoid a circular dependency - # - browsertab -> hints -> webelem -> mainwindow -> bar -> browsertab -- from qutebrowser.mainwindow import tabbedbrowser -+ from qutebrowser.mainwindow import treetabbedbrowser, tabbedbrowser - from qutebrowser.mainwindow.statusbar import bar - - self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) -@@ -237,8 +237,14 @@ def __init__(self, *, - - self.is_private = config.val.content.private_browsing or private - -- self.tabbed_browser: tabbedbrowser.TabbedBrowser = tabbedbrowser.TabbedBrowser( -- win_id=self.win_id, private=self.is_private, parent=self) -+ self.tabbed_browser: Union[tabbedbrowser.TabbedBrowser, -+ treetabbedbrowser.TreeTabbedBrowser] -+ if config.val.tabs.tree_tabs: -+ self.tabbed_browser = treetabbedbrowser.TreeTabbedBrowser( -+ win_id=self.win_id, private=self.is_private, parent=self) -+ else: -+ self.tabbed_browser = tabbedbrowser.TabbedBrowser( -+ win_id=self.win_id, private=self.is_private, parent=self) - objreg.register('tabbed-browser', self.tabbed_browser, scope='window', - window=self.win_id) - self._init_command_dispatcher() -@@ -510,8 +516,10 @@ def _connect_signals(self): - mode_manager.keystring_updated.connect( - self.status.keystring.on_keystring_updated) - self.status.cmd.got_cmd[str].connect(self._commandrunner.run_safely) -- self.status.cmd.got_cmd[str, int].connect(self._commandrunner.run_safely) -- self.status.cmd.returnPressed.connect(self.tabbed_browser.on_cmd_return_pressed) -+ self.status.cmd.got_cmd[str, int].connect( -+ self._commandrunner.run_safely) -+ self.status.cmd.returnPressed.connect( -+ self.tabbed_browser.on_cmd_return_pressed) - self.status.cmd.got_search.connect(self._command_dispatcher.search) - - # key hint popup -diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py -index da3392a7e81..61f75c2b5a1 100644 ---- a/qutebrowser/mainwindow/tabbedbrowser.py -+++ b/qutebrowser/mainwindow/tabbedbrowser.py -@@ -22,8 +22,8 @@ - import weakref - import datetime - import dataclasses --from typing import ( -- Any, Deque, List, Mapping, MutableMapping, MutableSequence, Optional, Tuple) -+from typing import (Any, Deque, List, Mapping, -+ MutableMapping, MutableSequence, Optional, Tuple) - - from qutebrowser.qt.widgets import QSizePolicy, QWidget, QApplication - from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QTimer, QUrl, QPoint -@@ -207,6 +207,7 @@ class TabbedBrowser(QWidget): - resized = pyqtSignal('QRect') - current_tab_changed = pyqtSignal(browsertab.AbstractTab) - new_tab = pyqtSignal(browsertab.AbstractTab, int) -+ is_treetabbedbrowser = False - shutting_down = pyqtSignal() - - def __init__(self, *, win_id, private, parent=None): -@@ -485,6 +486,7 @@ def _remove_tab(self, tab, *, add_undo=True, new_undo=True, crashed=False): - crashed: Whether we're closing a tab with crashed renderer process. - """ - idx = self.widget.indexOf(tab) -+ - if idx == -1: - if crashed: - return -@@ -553,17 +555,26 @@ def undo(self, depth=1): - entries = self.undo_stack[-depth] - del self.undo_stack[-depth] - -+ # we return the tab list because tree_tabs needs it in post_processing -+ new_tabs = [] - for entry in reversed(entries): - if use_current_tab: - newtab = self._tab_by_idx(0) - assert newtab is not None - use_current_tab = False - else: -- newtab = self.tabopen(background=False, idx=entry.index) -+ # FIXME:typing mypy thinks this is None due to @pyqtSlot -+ newtab = self.tabopen( -+ background=False, -+ related=False, -+ idx=entry.index -+ ) - - newtab.history.private_api.deserialize(entry.history) - newtab.set_pinned(entry.pinned) -+ new_tabs.append(newtab) - newtab.setFocus() -+ return new_tabs - - @pyqtSlot('QUrl', bool) - def load_url(self, url, newtab): -@@ -651,7 +662,7 @@ def tabopen( - - if idx is None: - idx = self._get_new_tab_idx(related) -- self.widget.insertTab(idx, tab, "") -+ idx = self.widget.insertTab(idx, tab, "") - - if url is not None: - tab.load_url(url) -diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py -index fe9ce1e0676..f2cb1765828 100644 ---- a/qutebrowser/mainwindow/tabwidget.py -+++ b/qutebrowser/mainwindow/tabwidget.py -@@ -26,7 +26,7 @@ - QTimer, QUrl) - from qutebrowser.qt.widgets import (QTabWidget, QTabBar, QSizePolicy, QProxyStyle, - QStyle, QStylePainter, QStyleOptionTab, -- QCommonStyle) -+ QCommonStyle, QWidget) - from qutebrowser.qt.gui import QIcon, QPalette, QColor - - from qutebrowser.utils import qtutils, objreg, utils, usertypes, log -@@ -36,7 +36,6 @@ - - - class TabWidget(QTabWidget): -- - """The tab widget used for TabbedBrowser. - - Signals: -@@ -59,14 +58,14 @@ def __init__(self, win_id, parent=None): - self.setStyle(TabBarStyle()) - self.setTabBar(bar) - bar.tabCloseRequested.connect(self.tabCloseRequested) -- bar.tabMoved.connect(functools.partial( -- QTimer.singleShot, 0, self.update_tab_titles)) -+ bar.tabMoved.connect(self.update_tab_titles) - bar.currentChanged.connect(self._on_current_changed) - bar.new_tab_requested.connect(self._on_new_tab_requested) - self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) - self.setDocumentMode(True) - self.setUsesScrollButtons(True) - bar.setDrawBase(False) -+ - self._init_config() - config.instance.changed.connect(self._init_config) - -@@ -92,8 +91,9 @@ def tab_bar(self) -> "TabBar": - assert isinstance(bar, TabBar), bar - return bar - -- def _tab_by_idx(self, idx: int) -> Optional[browsertab.AbstractTab]: -+ def _tab_by_idx(self, idx: int) -> Optional[QWidget]: - """Get the tab at the given index.""" -+ - tab = self.widget(idx) - if tab is not None: - assert isinstance(tab, browsertab.AbstractTab), tab -@@ -189,6 +189,9 @@ def get_tab_fields(self, idx): - fields['perc_raw'] = tab.progress() - fields['backend'] = objects.backend.name - fields['private'] = ' [Private Mode] ' if tab.is_private else '' -+ fields['tree'] = '' -+ fields['collapsed'] = '' -+ - try: - if tab.audio.is_muted(): - fields['audio'] = TabWidget.MUTE_STRING -@@ -347,7 +350,7 @@ def tab_url(self, idx): - qtutils.ensure_valid(url) - return url - -- def update_tab_favicon(self, tab: browsertab.AbstractTab) -> None: -+ def update_tab_favicon(self, tab: QWidget) -> None: - """Update favicon of the given tab.""" - idx = self.indexOf(tab) - -diff --git a/qutebrowser/mainwindow/treetabbedbrowser.py b/qutebrowser/mainwindow/treetabbedbrowser.py -new file mode 100644 -index 00000000000..c7e10ab180d ---- /dev/null -+++ b/qutebrowser/mainwindow/treetabbedbrowser.py -@@ -0,0 +1,350 @@ -+# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: -+ -+# Copyright 2014-2018 Giuseppe Stelluto (pinusc) -+# -+# This file is part of qutebrowser. -+# -+# qutebrowser is free software: you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation, either version 3 of the License, or -+# (at your option) any later version. -+# -+# qutebrowser is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with qutebrowser. If not, see . -+ -+"""Subclass of TabbedBrowser to provide tree-tab functionality.""" -+ -+import collections -+import dataclasses -+import datetime -+from typing import List, Dict -+from qutebrowser.qt.widgets import QSizePolicy -+from qutebrowser.qt.core import pyqtSlot, QUrl -+ -+from qutebrowser.config import config -+from qutebrowser.mainwindow.tabbedbrowser import TabbedBrowser -+from qutebrowser.mainwindow.treetabwidget import TreeTabWidget -+from qutebrowser.browser import browsertab -+from qutebrowser.misc import notree -+from qutebrowser.utils import log -+ -+ -+@dataclasses.dataclass -+class _TreeUndoEntry(): -+ """Information needed for :undo.""" -+ -+ url: QUrl -+ history: bytes -+ index: int -+ pinned: bool -+ uid: int -+ parent_node_uid: int -+ children_node_uids: List[int] -+ local_index: int # index of the tab relative to its siblings -+ created_at: datetime.datetime = dataclasses.field( -+ default_factory=datetime.datetime.now) -+ -+ @staticmethod -+ def from_node(node, idx): -+ """Make a TreeUndoEntry from a Node.""" -+ url = node.value.url() -+ try: -+ history_data = node.value.history.private_api.serialize() -+ except browsertab.WebTabError: -+ history_data = [] -+ pinned = node.value.data.pinned -+ uid = node.uid -+ parent_uid = node.parent.uid -+ children = [n.uid for n in node.children] -+ local_idx = node.index -+ return _TreeUndoEntry(url=url, -+ history=history_data, -+ index=idx, -+ pinned=pinned, -+ uid=uid, -+ parent_node_uid=parent_uid, -+ children_node_uids=children, -+ local_index=local_idx) -+ -+ -+class TreeTabbedBrowser(TabbedBrowser): -+ """Subclass of TabbedBrowser to provide tree-tab functionality. -+ -+ Extends TabbedBrowser methods (mostly tabopen, undo, and _remove_tab) so -+ that the internal tree is updated after every action. -+ -+ Provides methods to hide and show subtrees, and to cycle visibility. -+ """ -+ -+ is_treetabbedbrowser = True -+ -+ def __init__(self, *, win_id, private, parent=None): -+ super().__init__(win_id=win_id, private=private, parent=parent) -+ self.is_treetabbedbrowser = True -+ self.widget = TreeTabWidget(win_id, parent=self) -+ self.widget.tabCloseRequested.connect(self.on_tab_close_requested) -+ self.widget.new_tab_requested.connect(self.tabopen) -+ self.widget.currentChanged.connect(self._on_current_changed) -+ self.cur_fullscreen_requested.connect(self.widget.tabBar().maybe_hide) -+ self.widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) -+ self._reset_stack_counters() -+ -+ def _remove_tab(self, tab, *, add_undo=True, new_undo=True, crashed=False): -+ """Handle children positioning after a tab is removed.""" -+ node = tab.node -+ # FIXME after the fixme in _add_undo_entry is resolved, no need -+ # to save descendents -+ descendents = tuple(node.traverse(render_collapsed=True)) -+ -+ super()._remove_tab(tab, add_undo=False, new_undo=False, -+ crashed=crashed) -+ -+ if not tab.url().isEmpty() and tab.url().isValid() and add_undo: -+ idx = self.widget.indexOf(tab) -+ self._add_undo_entry(tab, idx, new_undo) -+ -+ parent = node.parent -+ -+ if node.collapsed: -+ # node will already be removed from tree -+ # but we need to manually close the tab processes -+ for descendent in descendents: -+ tab = descendent.value -+ tab.private_api.shutdown() -+ tab.deleteLater() -+ tab.layout().unwrap() -+ elif parent: -+ siblings = list(parent.children) -+ children = node.children -+ -+ if children: -+ next_node = children[0] -+ -+ for n in children[1:]: -+ n.parent = next_node -+ -+ # swap nodes -+ node_idx = siblings.index(node) -+ siblings[node_idx] = next_node -+ -+ parent.children = tuple(siblings) -+ node.children = () -+ -+ node.parent = None -+ self.widget.tree_tab_update() -+ -+ def _add_undo_entry(self, tab, idx, new_undo): -+ """Save undo entry with tree information. -+ -+ This function was removed in tabbedbrowser, but it is still useful here because -+ the mechanism is quite a bit more complex -+ """ -+ # TODO see if it's possible to remove duplicate code from -+ # super()._add_undo_entry -+ try: -+ history_data = tab.history.private_api.serialize() -+ except browsertab.WebTabError: -+ pass # special URL -+ else: -+ node = tab.node -+ uid = node.uid -+ parent_uid = node.parent.uid -+ if not node.collapsed: -+ children = [n.uid for n in node.children] -+ local_idx = node.index -+ entry = _TreeUndoEntry(url=tab.url(), -+ history=history_data, -+ index=idx, -+ pinned=tab.data.pinned, -+ uid=uid, -+ parent_node_uid=parent_uid, -+ children_node_uids=children, -+ local_index=local_idx) -+ if new_undo or not self.undo_stack: -+ self.undo_stack.append([entry]) -+ else: -+ self.undo_stack[-1].append(entry) -+ else: -+ entries = [] -+ for descendent in node.traverse(notree.TraverseOrder.POST_R): -+ entries.append(_TreeUndoEntry.from_node(descendent, 0)) -+ # ensure descendent is not later saved as child as well -+ descendent.parent = None # FIXME: Find a way not to change -+ # the tree -+ if new_undo: -+ self.undo_stack.append(entries) -+ else: -+ self.undo_stack[-1] += entries -+ -+ def undo(self, depth=1): -+ """Undo removing of a tab or tabs.""" -+ # TODO find a way to remove dupe code -+ # probably by getting entries from undo stack, THEN calling super -+ # then post-processing the entries -+ -+ # save entries before super().undo() pops them -+ entries = list(self.undo_stack[-depth]) -+ new_tabs = super().undo(depth) -+ -+ for entry, tab in zip(reversed(entries), new_tabs): -+ if not isinstance(entry, _TreeUndoEntry): -+ continue -+ root = self.widget.tree_root -+ uid = entry.uid -+ parent_uid = entry.parent_node_uid -+ parent_node = root.get_descendent_by_uid(parent_uid) -+ if not parent_node: -+ parent_node = root -+ -+ children = [] -+ for child_uid in entry.children_node_uids: -+ child_node = root.get_descendent_by_uid(child_uid) -+ children.append(child_node) -+ tab.node.parent = None # Remove the node from the tree -+ tab.node = notree.Node(tab, parent_node, -+ children, uid) -+ -+ # correctly reposition the tab -+ local_idx = entry.local_index -+ if tab.node.parent: # should always be true -+ new_siblings = list(tab.node.parent.children) -+ new_siblings.remove(tab.node) -+ new_siblings.insert(local_idx, tab.node) -+ tab.node.parent.children = new_siblings -+ -+ self.widget.tree_tab_update() -+ -+ @pyqtSlot('QUrl') -+ @pyqtSlot('QUrl', bool) -+ @pyqtSlot('QUrl', bool, bool) -+ def tabopen( -+ self, url: QUrl = None, -+ background: bool = None, -+ related: bool = True, -+ sibling: bool = False, -+ idx: int = None, -+ ) -> browsertab.AbstractTab: -+ """Open a new tab with a given url. -+ -+ Args: -+ related: Whether to set the tab as a child of the currently focused -+ tab. Follows `tabs.new_position.tree.related`. -+ sibling: Whether to set the tab as a sibling of the currently -+ focused tab. Follows `tabs.new_position.tree.sibling`. -+ -+ """ -+ # pylint: disable=arguments-differ -+ # we save this now because super.tabopen also resets the focus -+ cur_tab = self.widget.currentWidget() -+ tab = super().tabopen(url, background, related, idx) -+ -+ tab.node.parent = self.widget.tree_root -+ if cur_tab is None or tab is cur_tab: -+ self.widget.tree_tab_update() -+ return tab -+ -+ # get pos -+ if related: -+ pos = config.val.tabs.new_position.tree.new_child -+ parent = cur_tab.node -+ # pos can only be first, last -+ elif sibling: -+ pos = config.val.tabs.new_position.tree.new_sibling -+ parent = cur_tab.node.parent -+ # pos can be first, last, prev, next -+ else: -+ pos = config.val.tabs.new_position.tree.new_toplevel -+ parent = self.widget.tree_root -+ -+ self._position_tab(cur_tab, tab, pos, parent, sibling, related, background) -+ -+ return tab -+ -+ def _position_tab( -+ self, -+ cur_tab: browsertab.AbstractTab, -+ tab: browsertab.AbstractTab, -+ pos: str, -+ parent: notree.Node, -+ sibling: bool = False, -+ related: bool = True, -+ background: bool = None, -+ ) -> None: -+ toplevel = not sibling and not related -+ siblings = list(parent.children) -+ if tab.node in siblings: # true if parent is tree_root -+ # remove it and add it later in the right position -+ siblings.remove(tab.node) -+ -+ if pos == 'first': -+ rel_idx = 0 -+ if config.val.tabs.new_position.stacking and related: -+ rel_idx += self._tree_tab_child_rel_idx -+ self._tree_tab_child_rel_idx += 1 -+ siblings.insert(rel_idx, tab.node) -+ elif pos in ['prev', 'next'] and (sibling or toplevel): -+ # pivot is the tab relative to which 'prev' or 'next' apply -+ # it is always a member of 'siblings' -+ pivot = cur_tab.node if sibling else cur_tab.node.path[1] -+ direction = -1 if pos == 'prev' else 1 -+ rel_idx = 0 if pos == 'prev' else 1 -+ tgt_idx = siblings.index(pivot) + rel_idx -+ if config.val.tabs.new_position.stacking: -+ if sibling: -+ tgt_idx += self._tree_tab_sibling_rel_idx -+ self._tree_tab_sibling_rel_idx += direction -+ elif toplevel: -+ tgt_idx += self._tree_tab_toplevel_rel_idx -+ self._tree_tab_toplevel_rel_idx += direction -+ siblings.insert(tgt_idx, tab.node) -+ else: # position == 'last' -+ siblings.append(tab.node) -+ parent.children = siblings -+ self.widget.tree_tab_update() -+ if not background: -+ self._reset_stack_counters() -+ -+ def _reset_stack_counters(self): -+ self._tree_tab_child_rel_idx = 0 -+ self._tree_tab_sibling_rel_idx = 0 -+ self._tree_tab_toplevel_rel_idx = 0 -+ -+ @pyqtSlot(int) -+ def _on_current_changed(self, idx): -+ super()._on_current_changed(idx) -+ self._reset_stack_counters() -+ -+ def cycle_hide_tab(self, node): -+ """Utility function for tree_tab_cycle_hide command.""" -+ # height = node.height # height is always rel_height -+ if node.collapsed: -+ node.collapsed = False -+ for descendent in node.traverse(render_collapsed=True): -+ descendent.collapsed = False -+ return -+ -+ def rel_depth(n): -+ return n.depth - node.depth -+ -+ levels: Dict[int, list] = collections.defaultdict(list) -+ for d in node.traverse(render_collapsed=False): -+ r_depth = rel_depth(d) -+ levels[r_depth].append(d) -+ -+ # Remove highest level because it's leaves (or already collapsed) -+ del levels[max(levels.keys())] -+ -+ target = 0 -+ for level in sorted(levels, reverse=True): -+ nodes = levels[level] -+ if not all(n.collapsed or not n.children for n in nodes): -+ target = level -+ break -+ for n in levels[target]: -+ if not n.collapsed and n.children: -+ n.collapsed = True -diff --git a/qutebrowser/mainwindow/treetabwidget.py b/qutebrowser/mainwindow/treetabwidget.py -new file mode 100644 -index 00000000000..12de178c2ec ---- /dev/null -+++ b/qutebrowser/mainwindow/treetabwidget.py -@@ -0,0 +1,105 @@ -+# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: -+ -+# Copyright 2014-2018 Giuseppe Stelluto (pinusc) -+# -+# This file is part of qutebrowser. -+# -+# qutebrowser is free software: you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation, either version 3 of the License, or -+# (at your option) any later version. -+# -+# qutebrowser is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with qutebrowser. If not, see . -+ -+"""Extension of TabWidget for tree-tab functionality.""" -+ -+from qutebrowser.mainwindow.tabwidget import TabWidget -+from qutebrowser.misc.notree import Node -+from qutebrowser.utils import log -+ -+ -+class TreeTabWidget(TabWidget): -+ """Tab widget used in TabbedBrowser, with tree-functionality. -+ -+ Handles correct rendering of the tree as a tab field, and correct -+ positioning of tabs according to tree structure. -+ """ -+ -+ def __init__(self, win_id, parent=None): -+ # root of the tab tree, common for all tabs in the window -+ self.tree_root = Node(None) -+ super().__init__(win_id, parent) -+ self.tabBar().tabMoved.disconnect(self.update_tab_titles) -+ -+ def _init_config(self): -+ super()._init_config() -+ # For tree-tabs -+ self.update_tab_titles() # Must also be called when deactivating -+ self.tree_tab_update() -+ -+ def get_tab_fields(self, idx): -+ """Add tree field data to normal tab field data.""" -+ fields = super().get_tab_fields(idx) -+ -+ tab = self.widget(idx) -+ fields['collapsed'] = '[...] ' if tab.node.collapsed else '' -+ -+ # we remove the first two chars because every tab is child of tree -+ # root and that gets rendered as well -+ rendered_tree = self.tree_root.render() -+ try: -+ pre, _ = rendered_tree[idx+1] -+ tree_prefix = pre[2:] -+ except IndexError: # window or first tab are not initialized yet -+ tree_prefix = "" -+ log.misc.error("tree_prefix is empty!") -+ -+ fields['tree'] = tree_prefix -+ return fields -+ -+ def update_tree_tab_positions(self): -+ """Update tab positions according to the tree structure.""" -+ nodes = self.tree_root.traverse(render_collapsed=False) -+ for idx, node in enumerate(nodes): -+ if idx > 0: -+ cur_idx = self.indexOf(node.value) -+ self.tabBar().moveTab(cur_idx, idx-1) -+ -+ def update_tree_tab_visibility(self): -+ """Hide collapsed tabs and show uncollapsed ones. -+ -+ Sync the internal tree to the tabs the user can actually see. -+ """ -+ for node in self.tree_root.traverse(): -+ if node.value is None: -+ continue -+ if any(ancestor.collapsed for ancestor in node.path[:-1]): -+ if self.indexOf(node.value) != -1: -+ # node should be hidden but is shown -+ cur_tab = node.value -+ idx = self.indexOf(cur_tab) -+ if idx != -1: -+ self.removeTab(idx) -+ else: -+ if self.indexOf(node.value) == -1: -+ # node should be shown but is hidden -+ parent = node.parent -+ tab = node.value -+ name = tab.title() -+ icon = tab.icon() -+ if node.parent is not None: -+ parent_idx = self.indexOf(node.parent.value) -+ self.insertTab(parent_idx + 1, tab, icon, name) -+ tab.node.parent = parent # insertTab resets node -+ -+ def tree_tab_update(self): -+ """Update titles and positions.""" -+ self.update_tree_tab_visibility() -+ self.update_tree_tab_positions() -+ self.update_tab_titles() -diff --git a/qutebrowser/misc/notree.py b/qutebrowser/misc/notree.py -new file mode 100644 -index 00000000000..9d180ad4ce7 ---- /dev/null -+++ b/qutebrowser/misc/notree.py -@@ -0,0 +1,354 @@ -+# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: -+ -+# Copyright 2019 Giuseppe Stelluto (pinusc) -+# -+# This file is part of qutebrowser. -+# -+# qutebrowser is free software: you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation, either version 3 of the License, or -+# (at your option) any later version. -+# -+# qutebrowser is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with qutebrowser. If not, see . -+ -+"""Tree library for tree-tabs. -+ -+The fundamental unit is the Node class. -+ -+Create a tree with with Node(value, parent): -+root = Node('foo') -+child = Node('bar', root) -+child2 = Node('baz', root) -+child3 = Node('lorem', child) -+ -+You can also assign parent after instantiation, or even reassign it: -+child4 = Node('ipsum') -+child4.parent = root -+ -+Assign children: -+child.children = [] -+child2.children = [child4, child3] -+child3.parent -+> Node('foo/bar/baz') -+ -+Render a tree with render_tree(root_node): -+render_tree(root) -+ -+> ('', 'foo') -+> ('├─', 'bar') -+> ('│ ├─', 'lorem') -+> ('│ └─', 'ipsum') -+> ('└─', 'baz') -+""" -+import enum -+from typing import Optional, TypeVar, Sequence, List, Tuple, Iterable, Generic -+import itertools -+ -+# For Node.render -+CORNER = '└─' -+INTERSECTION = '├─' -+PIPE = '│' -+ -+ -+class TreeError(RuntimeError): -+ """Exception used for tree-related errors.""" -+ -+ -+class TraverseOrder(enum.Enum): -+ """To be used as argument to traverse(). -+ -+ Implemented orders are pre-order and post-order. -+ Attributes: -+ PRE: pre-order (parents before children). Same as in Node.render -+ POST: children of a node are always yield before their parent. -+ POST_R: Like POST, but children are yield in reverse order -+ """ -+ -+ PRE = 'pre-order' -+ POST = 'post-order' -+ POST_R = 'post-order-reverse' -+ -+ -+uid_gen = itertools.count(0) -+ -+# generic type of value held by Node -+T = TypeVar('T') # pylint: disable=invalid-name -+ -+ -+class Node(Generic[T]): -+ """Fundamental unit of notree library. -+ -+ Attributes: -+ value: The element (ususally a tab) the node represents -+ parent: Node's parent. -+ children: Node's children elements. -+ siblings: Children of parent node that are not self. -+ path: List of nodes from root of tree to self value, parent, and -+ children can all be set by user. Everything else will be updated -+ accordingly, so that if `node.parent = root_node`, then `node in -+ root_node.children` will be True. -+ """ -+ -+ sep: str = '/' -+ __parent: Optional['Node[T]'] = None -+ # this is a global 'static' class attribute -+ -+ def __init__(self, -+ value: T, -+ parent: Optional['Node[T]'] = None, -+ childs: Sequence['Node[T]'] = (), -+ uid: Optional[int] = None) -> None: -+ if uid is not None: -+ self.__uid = uid -+ else: -+ self.__uid = next(uid_gen) -+ -+ self.value = value -+ # set initial values so there's no need for AttributeError checks -+ self.__parent: Optional['Node[T]'] = None -+ self.__children: List['Node[T]'] = [] -+ -+ # For render memoization -+ self.__modified = False -+ self.__set_modified() # not the same as line above -+ self.__rendered: Optional[List[Tuple[str, 'Node[T]']]] = None -+ -+ if parent: -+ self.parent = parent # calls setter -+ if childs: -+ self.children = childs # this too -+ -+ self.__collapsed = False -+ -+ @property -+ def uid(self) -> int: -+ return self.__uid -+ -+ @property -+ def parent(self) -> Optional['Node[T]']: -+ return self.__parent -+ -+ @parent.setter -+ def parent(self, value: 'Node[T]') -> None: -+ """Set parent property. Also adds self to value.children.""" -+ # pylint: disable=protected-access -+ assert(value is None or isinstance(value, Node)) -+ if self.__parent: -+ self.__parent.__disown(self) -+ self.__parent = None -+ if value is not None: -+ value.__add_child(self) -+ self.__parent = value -+ self.__set_modified() -+ -+ @property -+ def children(self) -> Sequence['Node[T]']: -+ return tuple(self.__children) -+ -+ @children.setter -+ def children(self, value: Sequence['Node[T]']) -> None: -+ """Set children property, preserving order. -+ -+ Also sets n.parent = self for n in value. Does not allow duplicates. -+ """ -+ seen = set(value) -+ if len(seen) != len(value): -+ raise TreeError("A duplicate item is present in in %r" % value) -+ new_children = list(value) -+ for child in new_children: -+ if child.parent is not self: -+ child.parent = self -+ self.__children = new_children -+ self.__set_modified() -+ -+ @property -+ def path(self) -> List['Node[T]']: -+ """Get a list of all nodes from the root node to self.""" -+ if self.parent is None: -+ return [self] -+ else: -+ return self.parent.path + [self] -+ -+ @property -+ def depth(self) -> int: -+ """Get the number of nodes between self and the root node.""" -+ return len(self.path) - 1 -+ -+ @property -+ def index(self) -> int: -+ """Get self's position among its siblings (self.parent.children).""" -+ if self.parent is not None: -+ return self.parent.children.index(self) -+ else: -+ raise TreeError('Node has no parent.') -+ -+ @property -+ def collapsed(self) -> bool: -+ return self.__collapsed -+ -+ @collapsed.setter -+ def collapsed(self, val: bool) -> None: -+ self.__collapsed = val -+ self.__set_modified() -+ -+ def __set_modified(self) -> None: -+ """If self is modified, every ancestor is modified as well.""" -+ for node in self.path: -+ node.__modified = True # pylint: disable=protected-access -+ -+ def render(self) -> List[Tuple[str, 'Node[T]']]: -+ """Render a tree with ascii symbols. -+ -+ Tabs appear in the same order as in traverse() with TraverseOrder.PRE -+ Args: -+ node; the root of the tree to render -+ -+ Return: list of tuples where the first item is the symbol, -+ and the second is the node it refers to -+ """ -+ if not self.__modified and self.__rendered is not None: -+ return self.__rendered -+ -+ result = [('', self)] -+ for child in self.children: -+ if child.children: -+ subtree = child.render() -+ if child is not self.children[-1]: -+ subtree = [(PIPE + ' ' + c, n) for c, n in subtree] -+ char = INTERSECTION -+ else: -+ subtree = [(' ' + c, n) for c, n in subtree] -+ char = CORNER -+ subtree[0] = (char, subtree[0][1]) -+ if child.collapsed: -+ result += [subtree[0]] -+ else: -+ result += subtree -+ else: -+ if child is self.children[-1]: -+ result.append((CORNER, child)) -+ else: -+ result.append((INTERSECTION, child)) -+ self.__modified = False -+ self.__rendered = list(result) -+ return list(result) -+ -+ def traverse(self, order: TraverseOrder = TraverseOrder.PRE, -+ render_collapsed: bool = True) -> Iterable['Node']: -+ """Generator for all descendants of `self`. -+ -+ Args: -+ order: a TraverseOrder object. See TraverseOrder documentation. -+ render_collapsed: whether to yield children of collapsed nodes -+ Even if render_collapsed is False, collapsed nodes are be rendered. -+ It's their children that won't. -+ """ -+ if order == TraverseOrder.PRE: -+ yield self -+ -+ if self.collapsed and not render_collapsed: -+ if order != TraverseOrder.PRE: -+ yield self -+ return -+ -+ f = reversed if order is TraverseOrder.POST_R else lambda x: x -+ for child in f(self.children): -+ if render_collapsed or not child.collapsed: -+ yield from child.traverse(order, render_collapsed) -+ else: -+ yield child -+ if order in [TraverseOrder.POST, TraverseOrder.POST_R]: -+ yield self -+ -+ def __add_child(self, node: 'Node[T]') -> None: -+ if node not in self.__children: -+ self.__children.append(node) -+ -+ def __disown(self, value: 'Node[T]') -> None: -+ self.__set_modified() -+ if value in self.__children: -+ self.__children.remove(value) -+ -+ def get_descendent_by_uid(self, uid: int) -> Optional['Node[T]']: -+ """Return descendent identified by the provided uid. -+ -+ Returns None if there is no such descendent. -+ -+ Args: -+ uid: The uid of the node to return -+ """ -+ for descendent in self.traverse(): -+ if descendent.uid == uid: -+ return descendent -+ return None -+ -+ def promote(self, times: int = 1, to: str = 'first') -> None: -+ """Makes self a child of its grandparent, i.e. sibling of its parent. -+ -+ Args: -+ times: How many levels to promote the tab to. to: One of 'next', -+ 'prev', 'first', 'last'. Determines the position among siblings -+ after being promoted. 'next' and 'prev' are relative to the current -+ parent. -+ -+ """ -+ if to not in ['first', 'last', 'next', 'prev']: -+ raise Exception("Invalid value supplied for 'to': " + to) -+ position = {'first': 0, 'last': -1}.get(to, None) -+ diff = {'next': 1, 'prev': 0}.get(to, 1) -+ count = times -+ while count > 0: -+ if self.parent is None or self.parent.parent is None: -+ raise TreeError("Tab has no parent!") -+ grandparent = self.parent.parent -+ if position is not None: -+ idx = position -+ else: # diff is necessarily not none -+ idx = self.parent.index + diff -+ self.parent = None -+ -+ siblings = list(grandparent.children) -+ if idx != -1: -+ siblings.insert(idx, self) -+ else: -+ siblings.append(self) -+ grandparent.children = siblings -+ count -= 1 -+ -+ def demote(self, to: str = 'last') -> None: -+ """Demote a tab making it a child of its previous adjacent sibling.""" -+ if self.parent is None or self.parent.children is None: -+ raise TreeError("Tab has no siblings!") -+ siblings = list(self.parent.children) -+ -+ # we want previous node in the same subtree as current node -+ rel_idx = siblings.index(self) - 1 -+ -+ if rel_idx >= 0: -+ parent = siblings[rel_idx] -+ new_siblings = list(parent.children) -+ position = {'first': 0, 'last': -1}.get(to, -1) -+ if position == 0: -+ new_siblings.insert(0, self) -+ else: -+ new_siblings.append(self) -+ parent.children = new_siblings -+ else: -+ raise TreeError("Tab has no previous sibling!") -+ -+ def __repr__(self) -> str: -+ try: -+ value = str(self.value.url().url()) # type: ignore -+ except Exception: -+ value = str(self.value) -+ return "" % (self.__uid, value) -+ -+ def __str__(self) -> str: -+ # return "" % self.value -+ return str(self.value) -diff --git a/qutebrowser/misc/sessions.py b/qutebrowser/misc/sessions.py -index 3608568766c..c8445e4ad4d 100644 ---- a/qutebrowser/misc/sessions.py -+++ b/qutebrowser/misc/sessions.py -@@ -243,6 +243,9 @@ def _save_tab(self, tab, active, with_history=True): - active: Whether the tab is currently active. - with_history: Include the tab's history. - """ -+ # FIXME understand why this happens -+ if tab is None: -+ return {} - data: _JsonType = {'history': []} - if active: - data['active'] = True -@@ -287,13 +290,29 @@ def _save_all(self, *, only_window=None, with_private=False, with_history=True): - if getattr(active_window, 'win_id', None) == win_id: - win_data['active'] = True - win_data['geometry'] = bytes(main_window.saveGeometry()) -- win_data['tabs'] = [] - if tabbed_browser.is_private: - win_data['private'] = True -- for i, tab in enumerate(tabbed_browser.widgets()): -- active = i == tabbed_browser.widget.currentIndex() -- win_data['tabs'].append(self._save_tab(tab, active, -- with_history=with_history)) -+ -+ if tabbed_browser.is_treetabbedbrowser: -+ # a dict where keys are node UIDs, and values are dicts -+ # with tab data (the result of _save_tab) and a list of -+ # children UIDs -+ tree_data = {} -+ root_node = tabbed_browser.widget.tree_root -+ for i, node in enumerate(root_node.traverse(), -1): -+ node_data = {} -+ active = i == tabbed_browser.widget.currentIndex() -+ node_data['tab'] = self._save_tab(node.value, active) -+ node_data['children'] = [c.uid for c in node.children] -+ node_data['collapsed'] = node.collapsed -+ tree_data[node.uid] = node_data -+ win_data['tree'] = tree_data -+ else: -+ win_data['tabs'] = [] -+ for i, tab in enumerate(tabbed_browser.widgets()): -+ active = i == tabbed_browser.widget.currentIndex() -+ win_data['tabs'].append(self._save_tab(tab, active, -+ with_history=with_history)) - data['windows'].append(win_data) - return data - -@@ -461,6 +480,45 @@ def _load_tab(self, new_tab, data): # noqa: C901 - except ValueError as e: - raise SessionError(e) - -+ def _load_tree(self, tabbed_browser, tree_data): -+ tree_keys = list(tree_data.keys()) -+ if not tree_keys: -+ return None -+ -+ root_data = tree_data.get(tree_keys[0]) -+ if root_data is None: -+ return None -+ -+ root_node = tabbed_browser.widget.tree_root -+ tab_to_focus = None -+ index = -1 -+ -+ def recursive_load_node(uid): -+ nonlocal tab_to_focus -+ nonlocal index -+ index += 1 -+ node_data = tree_data[uid] -+ children_uids = node_data['children'] -+ -+ if tree_data[uid]['tab'].get('active'): -+ tab_to_focus = index -+ -+ tab_data = node_data['tab'] -+ new_tab = tabbed_browser.tabopen(background=False) -+ self._load_tab(new_tab, tab_data) -+ -+ new_tab.node.parent = root_node -+ children = [recursive_load_node(uid) for uid in children_uids] -+ new_tab.node.children = children -+ new_tab.node.collapsed = node_data['collapsed'] -+ return new_tab.node -+ -+ for child_uid in root_data['children']: -+ child = recursive_load_node(child_uid) -+ child.parent = root_node -+ -+ return tab_to_focus -+ - def _load_window(self, win): - """Turn yaml data into windows.""" - window = mainwindow.MainWindow(geometry=win['geometry'], -@@ -468,13 +526,29 @@ def _load_window(self, win): - tabbed_browser = objreg.get('tabbed-browser', scope='window', - window=window.win_id) - tab_to_focus = None -- for i, tab in enumerate(win['tabs']): -- new_tab = tabbed_browser.tabopen(background=False) -- self._load_tab(new_tab, tab) -- if tab.get('active', False): -- tab_to_focus = i -- if new_tab.data.pinned: -- new_tab.set_pinned(True) -+ -+ # plain_tabs is used in case the saved session contains a tree and -+ # tree-tabs is not enabled, or if the saved session contains normal -+ # tabs -+ plain_tabs = win.get('tabs', None) -+ if win.get('tree'): -+ if tabbed_browser.is_treetabbedbrowser: -+ tree_data = win.get('tree') -+ tab_to_focus = self._load_tree(tabbed_browser, tree_data) -+ tabbed_browser.widget.tree_tab_update() -+ else: -+ tree = win.get('tree') -+ plain_tabs = [tree[i]['tab'] for i in tree if -+ tree[i]['tab']] -+ if plain_tabs: -+ for i, tab in enumerate(plain_tabs): -+ new_tab = tabbed_browser.tabopen(background=False) -+ self._load_tab(new_tab, tab) -+ if tab.get('active', False): -+ tab_to_focus = i -+ if new_tab.data.pinned: -+ new_tab.set_pinned(True) -+ - if tab_to_focus is not None: - tabbed_browser.widget.setCurrentIndex(tab_to_focus) - -diff --git a/tests/end2end/features/conftest.py b/tests/end2end/features/conftest.py -index 8ce8ba699a1..75bddfa0f8f 100644 ---- a/tests/end2end/features/conftest.py -+++ b/tests/end2end/features/conftest.py -@@ -214,12 +214,15 @@ def open_path(quteproc, server, path): - path = path.replace('(port)', str(server.port)) - - new_tab = False -+ related_tab = False - new_bg_tab = False - new_window = False - private = False - as_url = False - wait = True - -+ related_tab_suffix = ' in a new related tab' -+ related_background_tab_suffix = ' in a new related background tab' - new_tab_suffix = ' in a new tab' - new_bg_tab_suffix = ' in a new background tab' - new_window_suffix = ' in a new window' -@@ -231,6 +234,14 @@ def open_path(quteproc, server, path): - if path.endswith(new_tab_suffix): - path = path[:-len(new_tab_suffix)] - new_tab = True -+ elif path.endswith(related_tab_suffix): -+ path = path[:-len(related_tab_suffix)] -+ new_tab = True -+ related_tab = True -+ elif path.endswith(related_background_tab_suffix): -+ path = path[:-len(related_background_tab_suffix)] -+ new_bg_tab = True -+ related_tab = True - elif path.endswith(new_bg_tab_suffix): - path = path[:-len(new_bg_tab_suffix)] - new_bg_tab = True -@@ -249,9 +260,9 @@ def open_path(quteproc, server, path): - else: - break - -- quteproc.open_path(path, new_tab=new_tab, new_bg_tab=new_bg_tab, -- new_window=new_window, private=private, as_url=as_url, -- wait=wait) -+ quteproc.open_path(path, related_tab=related_tab, new_tab=new_tab, -+ new_bg_tab=new_bg_tab, new_window=new_window, -+ private=private, as_url=as_url, wait=wait) - - - @bdd.when(bdd.parsers.parse("I set {opt} to {value}")) -diff --git a/tests/end2end/fixtures/quteprocess.py b/tests/end2end/fixtures/quteprocess.py -index c3194b8397e..a59a05ec222 100644 ---- a/tests/end2end/fixtures/quteprocess.py -+++ b/tests/end2end/fixtures/quteprocess.py -@@ -651,16 +651,17 @@ def temp_setting(self, opt, value): - self.set_setting(opt, old_value) - - def open_path(self, path, *, new_tab=False, new_bg_tab=False, -- new_window=False, private=False, as_url=False, port=None, -- https=False, wait=True): -+ related_tab=False, new_window=False, private=False, -+ as_url=False, port=None, https=False, wait=True): - """Open the given path on the local webserver in qutebrowser.""" - url = self.path_to_url(path, port=port, https=https) - self.open_url(url, new_tab=new_tab, new_bg_tab=new_bg_tab, -- new_window=new_window, private=private, as_url=as_url, -- wait=wait) -+ related_tab=related_tab, new_window=new_window, -+ private=private, as_url=as_url, wait=wait) - - def open_url(self, url, *, new_tab=False, new_bg_tab=False, -- new_window=False, private=False, as_url=False, wait=True): -+ related_tab=False, new_window=False, private=False, -+ as_url=False, wait=True): - """Open the given url in qutebrowser.""" - if sum(1 for opt in [new_tab, new_bg_tab, new_window, private, as_url] - if opt) > 1: -@@ -670,9 +671,15 @@ def open_url(self, url, *, new_tab=False, new_bg_tab=False, - self.send_cmd(url, invalid=True) - line = None - elif new_tab: -- line = self.send_cmd(':open -t ' + url) -+ if related_tab: -+ line = self.send_cmd(':open -t -r ' + url) -+ else: -+ line = self.send_cmd(':open -t ' + url) - elif new_bg_tab: -- line = self.send_cmd(':open -b ' + url) -+ if related_tab: -+ line = self.send_cmd(':open -b -r ' + url) -+ else: -+ line = self.send_cmd(':open -b ' + url) - elif new_window: - line = self.send_cmd(':open -w ' + url) - elif private: -diff --git a/tests/helpers/stubs.py b/tests/helpers/stubs.py -index 341d1de2a61..2dfb15916e9 100644 ---- a/tests/helpers/stubs.py -+++ b/tests/helpers/stubs.py -@@ -337,6 +337,7 @@ class FakeCommand: - hide: bool = False - debug: bool = False - deprecated: bool = False -+ tree_tab: bool = False - completion: Any = None - maxsplit: int = None - takes_count: Callable[[], bool] = lambda: False -diff --git a/tests/unit/misc/test_notree.py b/tests/unit/misc/test_notree.py -new file mode 100644 -index 00000000000..95f92f1a68f ---- /dev/null -+++ b/tests/unit/misc/test_notree.py -@@ -0,0 +1,308 @@ -+# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: -+ -+# Copyright 2019 Florian Bruhin (The-Compiler) -+# -+# This file is part of qutebrowser. -+# -+# qutebrowser is free software: you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation, either version 3 of the License, or -+# (at your option) any later version. -+# -+# qutebrowser is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with qutebrowser. If not, see . -+"""Tests for misc.notree library.""" -+import pytest -+ -+from qutebrowser.misc.notree import TreeError, Node, TraverseOrder -+ -+ -+@pytest.fixture -+def tree(): -+ """Return an example tree. -+ -+ n1 -+ ├─n2 -+ │ ├─n4 -+ │ └─n5 -+ └─n3 -+ ├─n6 -+ │ ├─n7 -+ │ ├─n8 -+ │ └─n9 -+ │ └─n10 -+ └─n11 -+ """ -+ # these are actually used because they appear in expected strings -+ n1 = Node('n1') -+ n2 = Node('n2', n1) -+ n4 = Node('n4', n2) -+ n5 = Node('n5', n2) -+ n3 = Node('n3', n1) -+ n6 = Node('n6', n3) -+ n7 = Node('n7', n6) -+ n8 = Node('n8', n6) -+ n9 = Node('n9', n6) -+ n10 = Node('n10', n9) -+ n11 = Node('n11', n3) -+ return n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11 -+ -+ -+@pytest.fixture -+def node(tree): -+ return tree[0] -+ -+ -+def test_creation(): -+ node = Node('foo') -+ assert node.value == 'foo' -+ -+ child = Node('bar', node) -+ assert child.parent == node -+ assert node.children == (child, ) -+ -+ -+def test_attach_parent(): -+ n1 = Node('n1', None, []) -+ print(n1.children) -+ n2 = Node('n2', n1) -+ n3 = Node('n3') -+ -+ n2.parent = n3 -+ assert n2.parent == n3 -+ assert n3.children == (n2, ) -+ assert n1.children == () -+ -+ -+def test_duplicate_child(): -+ p = Node('n1') -+ try: -+ c1 = Node('c1', p) -+ c2 = Node('c2', p) -+ p.children = [c1, c1, c2] -+ raise AssertionError("Can add duplicate child") -+ except TreeError: -+ pass -+ finally: -+ if len(p.children) == 3: -+ raise AssertionError("Can add duplicate child") -+ -+ -+def test_replace_parent(): -+ p1 = Node('foo') -+ p2 = Node('bar') -+ _ = Node('_', p2) -+ c = Node('baz', p1) -+ c.parent = p2 -+ assert c.parent is p2 -+ assert c not in p1.children -+ assert c in p2.children -+ -+ -+def test_replace_children(tree): -+ n2 = tree[1] -+ n3 = tree[2] -+ n6 = tree[5] -+ n11 = tree[10] -+ n3.children = [n11] -+ n2.children = (n6, ) + n2.children -+ assert n6.parent is n2 -+ assert n6 in n2.children -+ assert n11.parent is n3 -+ assert n11 in n3.children -+ assert n6 not in n3.children -+ assert len(n3.children) == 1 -+ -+ -+def test_promote_to_first(tree): -+ n1 = tree[0] -+ n3 = tree[2] -+ n6 = tree[5] -+ assert n6.parent is n3 -+ assert n3.parent is n1 -+ n6.promote(to='first') -+ assert n6.parent is n1 -+ assert n1.children[0] is n6 -+ -+ -+def test_promote_to_last(tree): -+ n1 = tree[0] -+ n3 = tree[2] -+ n6 = tree[5] -+ assert n6.parent is n3 -+ assert n3.parent is n1 -+ n6.promote(to='last') -+ assert n6.parent is n1 -+ assert n1.children[-1] is n6 -+ -+ -+def test_promote_to_prev(tree): -+ n1 = tree[0] -+ n3 = tree[2] -+ n6 = tree[5] -+ assert n6.parent is n3 -+ assert n3.parent is n1 -+ assert n1.children[1] is n3 -+ n6.promote(to='prev') -+ assert n6.parent is n1 -+ assert n1.children[1] is n6 -+ -+ -+def test_promote_to_next(tree): -+ n1 = tree[0] -+ n3 = tree[2] -+ n6 = tree[5] -+ assert n6.parent is n3 -+ assert n3.parent is n1 -+ assert n1.children[1] is n3 -+ n6.promote(to='next') -+ assert n6.parent is n1 -+ assert n1.children[2] is n6 -+ -+ -+def test_demote_to_first(tree): -+ n11 = tree[10] -+ n6 = tree[5] -+ assert n11.parent is n6.parent -+ parent = n11.parent -+ assert parent.children.index(n11) == parent.children.index(n6) + 1 -+ n11.demote(to='first') -+ assert n11.parent is n6 -+ assert n6.children[0] is n11 -+ -+ -+def test_demote_to_last(tree): -+ n11 = tree[10] -+ n6 = tree[5] -+ assert n11.parent is n6.parent -+ parent = n11.parent -+ assert parent.children.index(n11) == parent.children.index(n6) + 1 -+ n11.demote(to='last') -+ assert n11.parent is n6 -+ assert n6.children[-1] is n11 -+ -+ -+def test_traverse(node): -+ len_traverse = len(list(node.traverse())) -+ len_render = len(node.render()) -+ assert len_traverse == len_render -+ -+ -+def test_traverse_postorder(tree): -+ n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11 = tree -+ actual = list(n1.traverse(TraverseOrder.POST)) -+ print('\n'.join([str(n) for n in actual])) -+ assert actual == [n4, n5, n2, n7, n8, n10, n9, n6, n11, n3, n1] -+ -+ -+def test_traverse_postorder_r(tree): -+ n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11 = tree -+ actual = list(n1.traverse(TraverseOrder.POST_R)) -+ print('\n'.join([str(n) for n in actual])) -+ assert actual == [n11, n10, n9, n8, n7, n6, n3, n5, n4, n2, n1] -+ -+ -+def test_render_tree(node): -+ expected = [ -+ 'n1', -+ '├─n2', -+ '│ ├─n4', -+ '│ └─n5', -+ '└─n3', -+ ' ├─n6', -+ ' │ ├─n7', -+ ' │ ├─n8', -+ ' │ └─n9', -+ ' │ └─n10', -+ ' └─n11' -+ ] -+ result = [char + str(n) for char, n in node.render()] -+ print('\n'.join(result)) -+ assert expected == result -+ -+ -+def test_uid(node): -+ uids = set() -+ for n in node.traverse(): -+ assert n not in uids -+ uids.add(n.uid) -+ # pylint: disable=unused-variable -+ n1 = Node('n1') -+ n2 = Node('n2', n1) -+ n4 = Node('n4', n2) # noqa: F841 -+ n5 = Node('n5', n2) # noqa: F841 -+ n3 = Node('n3', n1) -+ n6 = Node('n6', n3) -+ n7 = Node('n7', n6) # noqa: F841 -+ n8 = Node('n8', n6) # noqa: F841 -+ n9 = Node('n9', n6) -+ n10 = Node('n10', n9) # noqa: F841 -+ n11 = Node('n11', n3) -+ # pylint: enable=unused-variable -+ for n in n1.traverse(): -+ assert n not in uids -+ uids.add(n.uid) -+ -+ n11_uid = n11.uid -+ assert n1.get_descendent_by_uid(n11_uid) is n11 -+ assert node.get_descendent_by_uid(n11_uid) is None -+ -+ -+def test_collapsed(node): -+ pre_collapsed_traverse = list(node.traverse()) -+ to_collapse = node.children[1] -+ -+ # collapse -+ to_collapse.collapsed = True -+ assert to_collapse.collapsed is True -+ for n in node.traverse(render_collapsed=False): -+ assert to_collapse not in n.path[:-1] -+ -+ assert list(to_collapse.traverse(render_collapsed=False)) == [to_collapse] -+ -+ assert list(node.traverse()) == pre_collapsed_traverse -+ -+ expected = [ -+ 'n1', -+ '├─n2', -+ '│ ├─n4', -+ '│ └─n5', -+ '└─n3' -+ ] -+ result = [char + str(n) for char, n in node.render()] -+ print('\n'.join(result)) -+ assert expected == result -+ -+ # uncollapse -+ to_collapse.collapsed = False -+ -+ assert any(n for n in node.traverse(render_collapsed=False) if to_collapse -+ in n.path[:-1]) -+ -+ -+def test_memoization(node): -+ assert node._Node__modified is True -+ node.render() -+ assert node._Node__modified is False -+ -+ node.children[0].parent = None -+ assert node._Node__modified is True -+ node.render() -+ assert node._Node__modified is False -+ -+ n2 = Node('ntest', parent=node) -+ assert node._Node__modified is True -+ assert n2._Node__modified is True -+ node.render() -+ assert node._Node__modified is False -+ -+ node.children[0].children[1].parent = None -+ assert node._Node__modified is True -+ assert node.children[0]._Node__modified is True -+ node.render() -+ assert node._Node__modified is False diff --git a/_/overlays/vim-numbertoggle-command-mode.patch b/_/overlays/vim-numbertoggle-command-mode.patch deleted file mode 100644 index 9e6601d..0000000 --- a/_/overlays/vim-numbertoggle-command-mode.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/plugin/number_toggle.vim b/plugin/number_toggle.vim -index d5dad54..80aa97e 100644 ---- a/plugin/number_toggle.vim -+++ b/plugin/number_toggle.vim -@@ -4,6 +4,6 @@ - - augroup numbertoggle - autocmd! -- autocmd BufEnter,FocusGained,InsertLeave,WinEnter * if &nu && mode() != "i" | set rnu | endif -- autocmd BufLeave,FocusLost,InsertEnter,WinLeave * if &nu | set nornu | endif -+ autocmd BufEnter,FocusGained,InsertLeave,WinEnter,CmdlineLeave * if &nu && mode() != "i" | set rnu | endif -+ autocmd BufLeave,FocusLost,InsertEnter,WinLeave,CmdlineEnter * if &nu | set nornu | redraw | endif - augroup END diff --git a/_/overlays/xdg-open-spawn-terminal.diff b/_/overlays/xdg-open-spawn-terminal.diff deleted file mode 100644 index d6c0844..0000000 --- a/_/overlays/xdg-open-spawn-terminal.diff +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/scripts/xdg-open.in b/scripts/xdg-open.in -index 50e31e6..6f698dc 100644 ---- a/scripts/xdg-open.in -+++ b/scripts/xdg-open.in -@@ -320,7 +320,14 @@ search_desktop_file() - args=$(( $args - 1 )) - done - [ $replaced -eq 1 ] || set -- "$@" "$target" -- env "$command" "$@" -+ if [ x"$(get_key "${file}" "Terminal")" = x"true" ] && ( [ ! -t 0 ] || [ ! -t 1 ] ); then -+ if [ -z "$TERMINAL" ]; then -+ TERMINAL="xterm -e" -+ fi -+ $TERMINAL env "$command" "$@" & -+ else -+ env "$command" "$@" -+ fi - - if [ $? -eq 0 ]; then - exit_success diff --git a/flake.lock b/flake.lock index 4baaf60..9d84551 100644 --- a/flake.lock +++ b/flake.lock @@ -10,11 +10,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1712079060, - "narHash": "sha256-/JdiT9t+zzjChc5qQiF+jhrVhRt8figYH29rZO7pFe4=", + "lastModified": 1714136352, + "narHash": "sha256-BtWQ2Th/jamO1SlD+2ASSW5Jaf7JhA/JLpQHk0Goqpg=", "owner": "ryantm", "repo": "agenix", - "rev": "1381a759b205dff7a6818733118d02253340fd5e", + "rev": "24a7ea390564ccd5b39b7884f597cfc8d7f6f44e", "type": "github" }, "original": { @@ -52,11 +52,11 @@ ] }, "locked": { - "lastModified": 1712947906, - "narHash": "sha256-T0eT2lMbcK7RLelkx0qx4SiFpOS/0dt0aSfLB+WsGV8=", + "lastModified": 1714405407, + "narHash": "sha256-h3pOvHCXkSdp1KOZqtkQmHgkR7VaOJXDhqhumk7sZLY=", "owner": "nix-community", "repo": "disko", - "rev": "8d4ae698eaac8bd717e23507da2ca8b345bec4b5", + "rev": "5eaf747af38dd272e1ab28a8ec4bd972424b07cf", "type": "github" }, "original": { @@ -74,11 +74,11 @@ }, "locked": { "dir": "pkgs/firefox-addons", - "lastModified": 1713078488, - "narHash": "sha256-EdCxHld1zzLdT7WteA7CULHslftZOePB9d8uDMT0tzA=", + "lastModified": 1714536206, + "narHash": "sha256-pnE2Px1VlcnWDc92TUmaILRgrWBbetKhpnMu5DfntbM=", "owner": "rycee", "repo": "nur-expressions", - "rev": "350bef505d552eb95271b216f1852bfe83f4a4ea", + "rev": "7772d48f5a728af51cd8ac85be5b124e2da0feac", "type": "gitlab" }, "original": { @@ -149,11 +149,11 @@ ] }, "locked": { - "lastModified": 1712386041, - "narHash": "sha256-dA82pOMQNnCJMAsPG7AXG35VmCSMZsJHTFlTHizpKWQ=", + "lastModified": 1714043624, + "narHash": "sha256-Xn2r0Jv95TswvPlvamCC46wwNo8ALjRCMBJbGykdhcM=", "owner": "nix-community", "repo": "home-manager", - "rev": "d6bb9f934f2870e5cbc5b94c79e9db22246141ff", + "rev": "86853e31dc1b62c6eeed11c667e8cdd0285d4411", "type": "github" }, "original": { @@ -185,11 +185,11 @@ ] }, "locked": { - "lastModified": 1712645404, - "narHash": "sha256-uEVd15WsX+Wti9PXW724puFcsFO72VTiJyBwW2WXT9M=", + "lastModified": 1714557650, + "narHash": "sha256-N1qTL5wIlbbX7DorBaKOMYfz+gYoyf8LREMWVlOXNYc=", "owner": "viperml", "repo": "nh", - "rev": "fe4a96a0b0b0662dba7c186b4a1746c70bbcad03", + "rev": "e4eb011975bee4c3f47199cc01d2d986e24851bd", "type": "github" }, "original": { @@ -207,11 +207,11 @@ "nmt": "nmt" }, "locked": { - "lastModified": 1709879831, - "narHash": "sha256-PZFXvKm929A3waipt2prRKYlNJvGQiBxWPDn/MIOKWo=", + "lastModified": 1713988078, + "narHash": "sha256-scRrzQQyJAT0iPAd8AZvolgiq7npatsfytwnduESndI=", "owner": "Gerschtli", "repo": "nix-formatter-pack", - "rev": "2499f41a01f1154c5a3b967aabe37d94e6b6d18b", + "rev": "08d0135dbe95992b5f8d54c351ce62be2177f0b4", "type": "github" }, "original": { @@ -222,11 +222,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1712909959, - "narHash": "sha256-7/5ubuwdEbQ7Z+Vqd4u0mM5L2VMNDsBh54visp27CtQ=", + "lastModified": 1714465198, + "narHash": "sha256-ySkEJvS0gPz2UhXm0H3P181T8fUxvDVcoUyGn0Kc5AI=", "owner": "nixos", "repo": "nixos-hardware", - "rev": "f58b25254be441cd2a9b4b444ed83f1e51244f1f", + "rev": "68d680c1b7c0e67a9b2144d6776583ee83664ef4", "type": "github" }, "original": { @@ -238,11 +238,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1712867921, - "narHash": "sha256-edTFV4KldkCMdViC/rmpJa7oLIU8SE/S35lh/ukC7bg=", + "lastModified": 1714531828, + "narHash": "sha256-ILsf3bdY/hNNI/Hu5bSt2/KbmHaAVhBbNUOdGztTHEg=", "owner": "nixos", "repo": "nixpkgs", - "rev": "51651a540816273b67bc4dedea2d37d116c5f7fe", + "rev": "0638fe2715d998fa81d173aad264eb671ce2ebc1", "type": "github" }, "original": { @@ -254,11 +254,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1712791164, - "narHash": "sha256-3sbWO1mbpWsLepZGbWaMovSO7ndZeFqDSdX0hZ9nVyw=", + "lastModified": 1714253743, + "narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=", "owner": "nixos", "repo": "nixpkgs", - "rev": "1042fd8b148a9105f3c0aca3a6177fd1d9360ba5", + "rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994", "type": "github" }, "original": { @@ -326,11 +326,11 @@ ] }, "locked": { - "lastModified": 1713066950, - "narHash": "sha256-ZaefFyvt5369XdjzSw43NhfbPM9MN5b9YXhzx4lFIRc=", + "lastModified": 1713892811, + "narHash": "sha256-uIGmA2xq41vVFETCF1WW4fFWFT2tqBln+aXnWrvjGRE=", "owner": "mic92", "repo": "sops-nix", - "rev": "226062b47fe0e2130ba3ee9f4f1c880dc815cf87", + "rev": "f1b0adc27265274e3b0c9b872a8f476a098679bd", "type": "github" }, "original": { @@ -377,11 +377,11 @@ ] }, "locked": { - "lastModified": 1709622318, - "narHash": "sha256-bTscF0366xtoIXgH7Zq+Mn0mpX3w4h/2xKpHiYMyLNc=", + "lastModified": 1713958148, + "narHash": "sha256-8PDNi/dgoI2kyM7uSiU4eoLBqUKoA+3TXuz+VWmuCOc=", "owner": "nix-community", "repo": "nixos-vscode-server", - "rev": "d0ed9b8cf1f0a71f110df9119489ab047e0726bd", + "rev": "fc900c16efc6a5ed972fb6be87df018bcf3035bc", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 6817052..ce048cc 100644 --- a/flake.nix +++ b/flake.nix @@ -57,9 +57,13 @@ homeConfigurations = { # .iso images # "gburd@iso-console" = libx.mkHome { hostname = "iso-console"; username = "nixos"; }; - # "gburd@iso-desktop" = libx.mkHome { hostname = "iso-desktop"; username = "nixos"; desktop = "pantheon"; }; + # "gburd@iso-desktop" = libx.mkHome { hostname = "iso-desktop"; username + # = "nixos"; desktop = "pantheon"; }; + # Workstations "gburd@floki" = libx.mkHome { hostname = "floki"; username = "gburd"; desktop = "pantheon"; }; + #"gburd@floki" = libx.mkHome { hostname = "floki"; username = "gburd"; desktop = "mate"; }; + # Servers }; @@ -68,6 +72,7 @@ # - nix build .#nixosConfigurations.{iso-console|iso-desktop}.config.system.build.isoImage # iso-console = libx.mkHost { hostname = "iso-console"; username = "nixos"; installer = nixpkgs + "/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix"; }; # iso-desktop = libx.mkHost { hostname = "iso-desktop"; username = "nixos"; installer = nixpkgs + "/nixos/modules/installer/cd-dvd/installation-cd-graphical-calamares.nix"; desktop = "pantheon"; }; + # Workstations # Lenovo Carbon X1 Extreme Gen 5 - x86_64 floki = libx.mkHost { hostname = "floki"; username = "gburd"; desktop = "pantheon"; }; diff --git a/home-manager/_mixins/cli/gh.nix b/home-manager/_mixins/cli/gh.nix index f6e7948..ae2a603 100644 --- a/home-manager/_mixins/cli/gh.nix +++ b/home-manager/_mixins/cli/gh.nix @@ -1,4 +1,4 @@ -{ pkgs, ... }: +{ pkgs, username, ... }: { programs.gh = { enable = true; @@ -9,6 +9,6 @@ }; }; home.persistence = { - "/persist/home/gburd".directories = [ ".config/gh" ]; + "/persist/home/${username}".directories = [ ".config/gh" ]; }; } diff --git a/home-manager/_mixins/cli/ssh.nix b/home-manager/_mixins/cli/ssh.nix index 26441f1..00d67e8 100644 --- a/home-manager/_mixins/cli/ssh.nix +++ b/home-manager/_mixins/cli/ssh.nix @@ -1,4 +1,4 @@ -{ outputs, lib, ... }: +{ outputs, lib, username, ... }: let hostnames = builtins.attrNames outputs.nixosConfigurations; in @@ -22,6 +22,6 @@ in }; home.persistence = { - "/persist/home/gburd".directories = [ ".ssh" ]; + "/persist/home/${username}".directories = [ ".ssh" ]; }; } diff --git a/home-manager/_mixins/console/default.nix b/home-manager/_mixins/console/default.nix index ab9092f..3088ee8 100644 --- a/home-manager/_mixins/console/default.nix +++ b/home-manager/_mixins/console/default.nix @@ -85,11 +85,11 @@ fish = { enable = true; shellAliases = { - cat = "bat --paging=never --style=plain"; + #cat = "bat --paging=never --style=plain"; htop = "btm --basic --tree --hide_table_gap --dot_marker --mem_as_value"; ip = "ip --color --brief"; - less = "bat --paging=always"; - more = "bat --paging=always"; + #less = "bat --paging=always"; + #more = "bat --paging=always"; top = "btm --basic --tree --hide_table_gap --dot_marker --mem_as_value"; tree = "exa --tree"; }; diff --git a/home-manager/_mixins/desktop/jetbrains-clion.nix b/home-manager/_mixins/desktop/jetbrains-clion.nix index 3f8a634..8291624 100644 --- a/home-manager/_mixins/desktop/jetbrains-clion.nix +++ b/home-manager/_mixins/desktop/jetbrains-clion.nix @@ -1,4 +1,4 @@ { pkgs, ... }: { - home.packages = [ pkgs.jetbrains.clion ]; + home.packages = [ pkgs.unstable.jetbrains.clion ]; } diff --git a/home-manager/_mixins/desktop/mate.nix b/home-manager/_mixins/desktop/mate.nix index 8e7500d..28988bf 100644 --- a/home-manager/_mixins/desktop/mate.nix +++ b/home-manager/_mixins/desktop/mate.nix @@ -10,8 +10,8 @@ with lib.hm.gvariant; cursor-theme = "Yaru"; document-font-name = "Work Sans 12"; font-name = "Work Sans 12"; - gtk-theme = "Yaru-magenta-dark"; - icon-theme = "Yaru-magenta-dark"; + gtk-theme = lib.mkForce "Yaru-magenta-dark"; + icon-theme = lib.mkForce "Yaru-magenta-dark"; monospace-font-name = "FiraCode Nerd Font Medium 13"; }; diff --git a/home-manager/_mixins/games/steam.nix b/home-manager/_mixins/games/steam.nix index b7e5cb2..076ec70 100644 --- a/home-manager/_mixins/games/steam.nix +++ b/home-manager/_mixins/games/steam.nix @@ -34,7 +34,7 @@ in protontricks ]; home.persistence = { - "/persist/home/gburd" = { + "/persist/home/${username}" = { allowOther = true; directories = [ ".factorio" diff --git a/home-manager/_mixins/pass/default.nix b/home-manager/_mixins/pass/default.nix index ff80ed8..98aef4b 100644 --- a/home-manager/_mixins/pass/default.nix +++ b/home-manager/_mixins/pass/default.nix @@ -1,4 +1,4 @@ -{ pkgs, config, ... }: { +{ pkgs, config, username, ... }: { programs.password-store = { enable = true; settings = { PASSWORD_STORE_DIR = "$HOME/.password-store"; }; @@ -12,6 +12,6 @@ }; home.persistence = { - "/persist/home/gburd".directories = [ ".password-store" ]; + "/persist/home/${username}".directories = [ ".password-store" ]; }; } diff --git a/home-manager/_mixins/productivity/mail.nix b/home-manager/_mixins/productivity/mail.nix index 195d6c0..fd2ba09 100644 --- a/home-manager/_mixins/productivity/mail.nix +++ b/home-manager/_mixins/productivity/mail.nix @@ -23,7 +23,7 @@ let in { home.persistence = { - "/persist/home/gburd".directories = [ "Mail" ]; + "/persist/home/${username}".directories = [ "Mail" ]; }; accounts.email = { diff --git a/home-manager/_mixins/productivity/vdirsyncer.nix b/home-manager/_mixins/productivity/vdirsyncer.nix index 672c6f8..7cd7930 100644 --- a/home-manager/_mixins/productivity/vdirsyncer.nix +++ b/home-manager/_mixins/productivity/vdirsyncer.nix @@ -6,7 +6,7 @@ in home.packages = with pkgs; [ vdirsyncer ]; home.persistence = { - "/persist/home/gburd".directories = + "/persist/home/${username}".directories = [ "Calendars" "Contacts" ".local/share/vdirsyncer" ]; }; @@ -29,7 +29,7 @@ in type = "carddav" url = "https://dav.burd.me" username = "greg@burd.me" - password.fetch = ["command", "${pass}", "mail.burd.m/greg@burd.me"] + password.fetch = ["command", "${pass}", "mail.burd.me/greg@burd.me"] [pair calendars] a = "calendars_local" diff --git a/home-manager/_mixins/users/_gburd/.gitconfig b/home-manager/_mixins/users/_gburd/.gitconfig new file mode 100644 index 0000000..ede4aed --- /dev/null +++ b/home-manager/_mixins/users/_gburd/.gitconfig @@ -0,0 +1,55 @@ +[format] + pretty=format:%C(yellow)%h%Creset | %C(green)%ad (%ar)%Creset | %C(blue)%an%Creset | %s + +[push] + default = simple + +[branch] + autosetuprebase = always + +[receive] + denyCurrentBranch = warn + +[filter "media"] + clean = git media clean %f + smudge = git media smudge %f + required = true + +# http://nicercode.github.io/blog/2013-04-30-excel-and-line-endings/ +[filter "cr"] + clean = LC_CTYPE=C awk '{printf(\"%s\\n\", $0)}' | LC_CTYPE=C tr '\\r' '\\n' + smudge = tr '\\n' '\\r' + +[diff] + tool = meld +[difftool] + prompt = false +[difftool "meld"] + cmd = meld "$LOCAL" "$REMOTE" + +[merge] + tool = meld +[mergetool "meld"] + # Choose one of these 2 lines (not both!) explained below. + cmd = meld "$LOCAL" "$MERGED" "$REMOTE" --output "$MERGED" + cmd = meld "$LOCAL" "$BASE" "$REMOTE" --output "$MERGED" + +[core] + editor = vim +# editor = emacs -nw -q + excludesfile = ~/.gitignore_global + pager = less -FMRiX + quotepath = false + +[filter "lfs"] + process = git-lfs filter-process + required = true + clean = git-lfs clean -- %f + smudge = git-lfs smudge -- %f + +[init] + templateDir = "$HOME/.git-template" + defaultBranch = main + +[commit] + gpgsign = true diff --git a/home-manager/_mixins/users/_gburd/alacritty.yml b/home-manager/_mixins/users/_gburd/alacritty.yml new file mode 100644 index 0000000..3dff021 --- /dev/null +++ b/home-manager/_mixins/users/_gburd/alacritty.yml @@ -0,0 +1,492 @@ +# Configuration for Alacritty, the GPU enhanced terminal emulator + +# Any items in the `env` entry below will be added as +# environment variables. Some entries may override variables +# set by alacritty it self. +# env: + # TERM env customization. + # + # If this property is not set, alacritty will set it to xterm-256color. + # + # Note that some xterm terminfo databases don't declare support for italics. + # You can verify this by checking for the presence of `smso` and `sitm` in + # `infocmp xterm-256color`. + # TERM: xterm-256color-italic + +window: + # Window dimensions (changes require restart) + # + # Specified in number of columns/lines, not pixels. If both are zero this + # setting is ignored. + dimensions: + columns: 100 + lines: 85 + + # Window padding (changes require restart) + # + # Blank space added around the window in pixels. This padding is not scaled by + # DPI and the specified value is always added at both opposing sides. + padding: + x: 0 + y: 0 + + # Spread additional padding evenly around the terminal content. + dynamic_padding: false + + # Window decorations + # + # Available values: + # - full: borders and title bar + # - none: neither borders nor title bar + # - transparent: title bar, transparent background and title bar buttons + # - buttonless: title bar, transparent background, but no title bar buttons + decorations: buttonless + + # Startup Mode (changes require restart) + # + # Values for `startup_mode`: + # - Windowed + # - Maximized + # - Fullscreen + # + # Values for `startup_mode` (macOS only): + # - SimpleFullscreen + startup_mode: Windowed + + # Background opacity + opacity: 1.0 + +scrolling: + # maximum number of lines in the scrollback buffer. Specifying '0' will + # disable scrolling. + history: 0 + + # Number of lines the viewport will move for every line scrolled when + # scrollback is enabled (history > 0). + multiplier: 3 + +# Font configuration (changes require restart) +font: + # The normal (roman) font face to use. + # Style can be specified to pick a specific face. + normal: + family: "FiraCode Nerd Font Mono" + style: Retina + + # The bold font face + bold: + family: "FiraCode Nerd Font Mono" + style: Bold + + # The italic font face + italic: + family: "FiraCode Nerd Font Mono" + style: Italic + + # Point size of the font + size: 14.0 + + # Offset is the extra space around each character. offset.y can be thought of + # as modifying the linespacing, and offset.x as modifying the letter spacing. + offset: + x: 0 + y: 0 + + # Glyph offset determines the locations of the glyphs within their cells with + # the default being at the bottom. Increase the x offset to move the glyph to + # the right, increase the y offset to move the glyph upward. + glyph_offset: + x: 0 + y: 0 + + # Thin stroke font rendering (macOS only) + # + # Thin strokes are suitable for retina displays, but for non-retina you + # probably want this set to false. + # + # macOS >= 10.14.x: + # + # If the font quality on non-retina display looks bad then set + # `use_thin_strokes` to `true` and enable font smoothing by running the + # following command: + # `defaults write -g CGFontRenderingFontSmoothingDisabled -bool NO` + # + # This is a global setting and will require a log out or restart to take + # effect. + use_thin_strokes: true + +# When true, bold text is drawn using the bright variant of colors. +draw_bold_text_with_bright_colors: false + +# Use custom cursor colors. If true, display the cursor in the cursor.foreground +# and cursor.background colors, otherwise invert the colors of the cursor. +custom_cursor_colors: true + +# Colors +colors: + + # Tomorrow (https://github.com/aarowill/base16-alacritty/blob/master/colors/base16-tomorrow.yml) + # Default colors + primary: + background: '0xffffff' + foreground: '0x4d4d4c' + # Colors the cursor will use if `custom_cursor_colors` is true + cursor: + text: '0xffffff' + cursor: '0x4d4d4c' + # Normal colors + normal: + black: '0xffffff' + red: '0xc82829' + green: '0x718c00' + yellow: '0xeab700' + blue: '0x4271ae' + magenta: '0x8959a8' + cyan: '0x3e999f' + white: '0x4d4d4c' + # Bright colors + bright: + black: '0x8e908c' + red: '0xf5871f' + green: '0xe0e0e0' + yellow: '0xd6d6d6' + blue: '0x969896' + magenta: '0x282a2e' + cyan: '0xa3685a' + white: '0x1d1f21' + + # # Tomorrow Night (https://github.com/aarowill/base16-alacritty/blob/master/colors/base16-tomorrow-night.yml) + # # Default colors + # primary: + # background: '0x1d1f21' + # foreground: '0xc5c8c6' + # # Colors the cursor will use if `custom_cursor_colors` is true + # cursor: + # text: '0x1d1f21' + # cursor: '0xc5c8c6' + # # Normal colors + # normal: + # black: '0x1d1f21' + # red: '0xcc6666' + # green: '0xb5bd68' + # yellow: '0xf0c674' + # blue: '0x81a2be' + # magenta: '0xb294bb' + # cyan: '0x8abeb7' + # white: '0xc5c8c6' + # # Bright colors + # bright: + # black: '0x969896' + # red: '0xde935f' + # green: '0x282a2e' + # yellow: '0x373b41' + # blue: '0xb4b7b4' + # magenta: '0xe0e0e0' + # cyan: '0xa3685a' + # white: '0xffffff' + + # Indexed Colors + # + # The indexed colors include all colors from 16 to 256. + # When these are not set, they're filled with sensible defaults. + # + # Example: + # `- { index: 16, color: '0xff00ff' }` + # + # indexed_colors: [] + +# Visual Bell +# +# Any time the BEL code is received, Alacritty "rings" the visual bell. Once +# rung, the terminal background will be set to white and transition back to the +# default background color. You can control the rate of this transition by +# setting the `duration` property (represented in milliseconds). You can also +# configure the transition function by setting the `animation` property. +# +# Possible values for `animation` +# `Ease` +# `EaseOut` +# `EaseOutSine` +# `EaseOutQuad` +# `EaseOutCubic` +# `EaseOutQuart` +# `EaseOutQuint` +# `EaseOutExpo` +# `EaseOutCirc` +# `Linear` +# +# To completely disable the visual bell, set its duration to 0. +# +bell: + animation: EaseOutExpo + color: '0xffffff' + duration: 0 + + +# Key bindings +# +# Key bindings are specified as a list of objects. Each binding will specify a +# key and modifiers required to trigger it, terminal modes where the binding is +# applicable, and what should be done when the key binding fires. It can either +# send a byte sequence to the running application (`chars`), execute a +# predefined action (`action`) or fork and execute a specified command plus +# arguments (`command`). +# +# Bindings are always filled by default, but will be replaced when a new binding +# with the same triggers is defined. To unset a default binding, it can be +# mapped to the `None` action. +# +# Example: +# `- { key: V, mods: Control|Shift, action: Paste }` +# +# Available fields: +# - key +# - mods (optional) +# - chars | action | command (exactly one required) +# - mode (optional) +# +# Values for `key`: +# - `A` -> `Z` +# - `F1` -> `F12` +# - `Key1` -> `Key0` +# +# A full list with available key codes can be found here: +# https://docs.rs/glutin/*/glutin/enum.VirtualKeyCode.html#variants +# +# Instead of using the name of the keys, the `key` field also supports using +# the scancode of the desired key. Scancodes have to be specified as a +# decimal number. +# This command will allow you to display the hex scancodes for certain keys: +# `showkey --scancodes` +# +# Values for `mods`: +# - Command +# - Control +# - Option +# - Super +# - Shift +# - Alt +# +# Multiple `mods` can be combined using `|` like this: `mods: Control|Shift`. +# Whitespace and capitalization is relevant and must match the example. +# +# Values for `chars`: +# The `chars` field writes the specified string to the terminal. This makes +# it possible to pass escape sequences. +# To find escape codes for bindings like `PageUp` ("\x1b[5~"), you can run +# the command `showkey -a` outside of tmux. +# Note that applications use terminfo to map escape sequences back to +# keys. It is therefore required to update the terminfo when +# changing an escape sequence. +# +# Values for `action`: +# - Paste +# - PasteSelection +# - Copy +# - IncreaseFontSize +# - DecreaseFontSize +# - ResetFontSize +# - ScrollPageUp +# - ScrollPageDown +# - ScrollLineUp +# - ScrollLineDown +# - ScrollToTop +# - ScrollToBottom +# - ClearHistory +# - Hide +# - Quit +# - ClearLogNotice +# - SpawnNewInstance +# - ToggleFullscreen +# - None +# +# Values for `action` (macOS only): +# - ToggleSimpleFullscreen: Enters fullscreen without occupying another space +# +# Values for `command`: +# The `command` field must be a map containing a `program` string and +# an `args` array of command line parameter strings. +# +# Example: +# `command: { program: "alacritty", args: ["-e", "vttest"] }` +# +# Values for `mode`: +# - ~AppCursor +# - AppCursor +# - ~AppKeypad +# - AppKeypad +# +key_bindings: + - { key: V, mods: Command, action: Paste} + - { key: C, mods: Command, action: Copy } + - { key: Q, mods: Command, action: Quit } + - { key: N, mods: Command, action: SpawnNewInstance } + - { key: Return, mods: Command, action: ToggleFullscreen } + + - { key: Home, chars: "\x1bOH", mode: AppCursor } + - { key: Home, chars: "\x1b[H", mode: ~AppCursor } + - { key: End, chars: "\x1bOF", mode: AppCursor } + - { key: End, chars: "\x1b[F", mode: ~AppCursor } + - { key: Equals, mods: Command, action: IncreaseFontSize } + - { key: Minus, mods: Command, action: DecreaseFontSize } + - { key: Minus, mods: Command|Shift, action: ResetFontSize } + - { key: PageUp, mods: Shift, chars: "\x1b[5;2~" } + - { key: PageUp, mods: Control, chars: "\x1b[5;5~" } + - { key: PageUp,chars: "\x1b[5~" } + - { key: PageDown, mods: Shift, chars: "\x1b[6;2~" } + - { key: PageDown, mods: Control, chars: "\x1b[6;5~" } + - { key: PageDown, chars: "\x1b[6~" } + - { key: Left, mods: Shift, chars: "\x1b[1;2D" } + - { key: Left, mods: Control, chars: "\x1b[1;5D" } + - { key: Left, mods: Alt, chars: "\x1b[1;3D" } + - { key: Left, chars: "\x1b[D", mode: ~AppCursor } + - { key: Left, chars: "\x1bOD", mode: AppCursor } + - { key: Right, mods: Shift, chars: "\x1b[1;2C" } + - { key: Right, mods: Control, chars: "\x1b[1;5C" } + - { key: Right, mods: Alt, chars: "\x1b[1;3C" } + - { key: Right, chars: "\x1b[C", mode: ~AppCursor } + - { key: Right, chars: "\x1bOC", mode: AppCursor } + - { key: Up, mods: Shift, chars: "\x1b[1;2A" } + - { key: Up, mods: Control, chars: "\x1b[1;5A" } + - { key: Up, mods: Alt, chars: "\x1b[1;3A" } + - { key: Up, chars: "\x1b[A", mode: ~AppCursor } + - { key: Up, chars: "\x1bOA", mode: AppCursor } + - { key: Down, mods: Shift, chars: "\x1b[1;2B" } + - { key: Down, mods: Control, chars: "\x1b[1;5B" } + - { key: Down, mods: Alt, chars: "\x1b[1;3B" } + - { key: Down, chars: "\x1b[B", mode: ~AppCursor } + - { key: Down, chars: "\x1bOB", mode: AppCursor } + - { key: Tab,mods: Shift, chars: "\x1b[Z" } + - { key: F1, chars: "\x1bOP" } + - { key: F2, chars: "\x1bOQ" } + - { key: F3, chars: "\x1bOR" } + - { key: F4, chars: "\x1bOS" } + - { key: F5, chars: "\x1b[15~" } + - { key: F6, chars: "\x1b[17~" } + - { key: F7, chars: "\x1b[18~" } + - { key: F8, chars: "\x1b[19~" } + - { key: F9, chars: "\x1b[20~" } + - { key: F10, chars: "\x1b[21~" } + - { key: F11, chars: "\x1b[23~" } + - { key: F12, chars: "\x1b[24~" } + - { key: Back, chars: "\x7f"} + - { key: Back, mods: Alt, chars: "\x1b\x7f" } + - { key: Insert,chars: "\x1b[2~" } + - { key: Delete,chars: "\x1b[3~" } + + # shortcuts for tmux. the leader key is control-b (0x02) + - { key: W, mods: Command, chars: "\x02&" } # close tab (kill) + - { key: T, mods: Command, chars: "\x02c" } # new tab + - { key: RBracket, mods: Command|Shift, chars: "\x02n" } # select next tab + - { key: LBracket, mods: Command|Shift, chars: "\x02p" } # select previous tab + - { key: RBracket, mods: Command, chars: "\x02o" } # select next pane + - { key: LBracket, mods: Command, chars: "\x02;" } # select last (previously used) pane + - { key: F, mods: Command, chars: "\x02/" } # search (upwards) (see tmux.conf) + +mouse: + # Click settings + # + # The `double_click` and `triple_click` settings control the time + # alacritty should wait for accepting multiple clicks as one double + # or triple click. + double_click: { threshold: 300 } + triple_click: { threshold: 300 } + + # If this is `true`, the cursor is temporarily hidden when typing. + hide_when_typing: true + + # URL launcher + # url: + # This program is executed when clicking on a text which is recognized as a URL. + # The URL is always added to the command as the last parameter. + # + # When set to `None`, URL launching will be disabled completely. + # + # Default: + # - (macOS) open + # - (Linux) xdg-open + # - (Windows) explorer + # launcher: + # program: xdg-open + # args: [] + + # These are the modifiers that need to be held down for opening URLs when clicking + # on them. The available modifiers are documented in the key binding section. + # modifiers: Control|Shift + +selection: + semantic_escape_chars: ",│`|:\"' ()[]{}<>" + + # When set to `true`, selected text will be copied to the primary clipboard. + save_to_clipboard: false + +# Mouse bindings +# +# Available fields: +# - mouse +# - action +# - mods (optional) +# +# Values for `mouse`: +# - Middle +# - Left +# - Right +# - Numeric identifier such as `5` +# +# All available `mods` and `action` values are documented in the key binding +# section. +mouse_bindings: + - { mouse: Middle, action: PasteSelection } + +cursor: + # Cursor style + # + # Values for 'style': + # - ▇ Block + # - _ Underline + # - | Beam + style: Block + + # If this is `true`, the cursor will be rendered as a hollow box when the + # window is not focused. + unfocused_hollow: true + +# dynamic_title: false + +# Live config reload (changes require restart) +live_config_reload: true + +debug: + # Should display the render timer + render_timer: false + + # Keep the log file after quitting Alacritty. + persistent_logging: false + + # Log level + # + # Values for `log_level`: + # - OFF + # - ERROR + # - WARN + # - INFO + # - DEBUG + # - TRACE + log_level: OFF + + # Print all received window events. + print_events: false + + # Record all characters and escape sequences as test data. + ref_test: false + +# Shell +# +# You can set shell.program to the path of your favorite shell, e.g. /bin/bash. +# Entries in shell.args are passed unmodified as arguments to the shell. +shell: + program: bash + args: + - --command=tmux + +# vim: nospell diff --git a/home-manager/_mixins/users/_gburd/default.nix b/home-manager/_mixins/users/_gburd/default.nix new file mode 100644 index 0000000..70ef391 --- /dev/null +++ b/home-manager/_mixins/users/_gburd/default.nix @@ -0,0 +1,144 @@ +{ inputs, config, pkgs, username, ... }: { + imports = [ + inputs.impermanence.nixosModules.home-manager.impermanence + ../../pass + ../../cli + ../../nvim + ]; + + home = { + + persistence = { + "/persist/home/gburd" = { + directories = [ + "Documents" + "Downloads" + "Pictures" + "Videos" + ".local/bin" + ".config" + ]; + allowOther = true; + }; + }; + + file.".face".source = ./face.png; + + file.".ssh/config".text = '' + Host burd.me *.burd.me *.ts.burd.me + ForwardAgent yes + Host floki + ForwardAgent yes + RemoteForward /%d/.gnupg-sockets/S.gpg-agent /%d/.gnupg-sockets/S.gpg-agent.extra + + Host * + ForwardAgent no + Compression no + ServerAliveInterval 0 + ServerAliveCountMax 3 + HashKnownHosts no + UserKnownHostsFile ~/.ssh/known_hosts + ControlMaster no + ControlPath ~/.ssh/master-%r@%n:%p + ControlPersist no + + Host github.com + HostName github.com + User git + ''; + + file.".inputrc".text = '' + "\C-v": "" + set enable-bracketed-paste off + ''; + + file.".config/direnv/direnv.toml".text = '' + [global] + load_dotenv = true + ''; + + file.".config/Code/User/settings.json".text = '' + { + "editor.inlineSuggest.enabled": true, + "editor.fontFamily": "'FiraCode Nerd Font Mono', 'Droid Sans Mono', 'monospace', monospace", + "editor.fontLigatures": true, + "cSpell.userWords": [ + "Burd", + "Wpedantic", + "Wvariadic" + ], + "files.watcherExclude": { + "**/.bloop": true, + "**/.metals": true, + "**/.ammonite": true + }, + "extensions.experimental.affinity": { + "asvetliakov.vscode-neovim": 1 + }, + "vscode-neovim.neovimExecutablePaths.linux": "/home/gburd/.nix-profile/bin/nvim", + } + ''; + + file.".config/alacritty/alacritty.yml".source = ./alacritty.yml; + + file.".config/Code/User/keybindings.json".text = '' + ''; + + file.".config/nvim/init.nvim".source = ./init.nvim + + # file.".config/sublime-text-2/Local/License.sublime_license".text = + # config.sops.secrets.sublime-licenses.text.path; + + # file.".config/sublime-merge/Local/License.sublime_license".text = + # config.sops.secrets.sublime-licenses.merge.path; + + # A Modern Unix experience, for the "kids" + # https://jvns.ca/blog/2022/04/12/a-list-of-new-ish--command-line-tools/ + packages = with pkgs; [ + asciinema # Terminal recorder + chafa # Terminal image viewer + chroma # Code syntax highlighter + clinfo # Terminal OpenCL info + dconf2nix # Nix code from Dconf files + httpie # Terminal HTTP client + iw # Terminal WiFi info + nixpkgs-review # Nix code review + ripgrep # Modern Unix `grep` + shellcheck # Code lint Shell + + _1password + _1password-gui + cfssl + dig + emacs + file + git-credential-1password + htop + openssl + plocate + ripgrep + tig + tree + lsof + unstable.flyctl + unstable.minio-client + unstable.element-desktop + ]; + sessionVariables = { + PAGER = "less"; + }; + + # http://rski.github.io/2021/09/05/nix-debugging.html + # https://github.com/nix-community/home-manager/commit/0056a5aea1a7b68bdacb7b829c325a1d4a3c4259 + enableDebugInfo = true; + }; + + programs = { + }; + + systemd.user.tmpfiles.rules = [ + "d ${config.home.homeDirectory}/ws 0755 ${username} users - -" + "d ${config.home.homeDirectory}/bin 0755 ${username} users - -" + ]; + +} diff --git a/home-manager/_mixins/users/_gburd/desktop.nix b/home-manager/_mixins/users/_gburd/desktop.nix new file mode 100644 index 0000000..d73ae91 --- /dev/null +++ b/home-manager/_mixins/users/_gburd/desktop.nix @@ -0,0 +1,20 @@ +{ config, lib, ... }: +with lib.hm.gvariant; +{ + imports = [ + ../../cli/signal.nix + ../../desktop/alacritty.nix + ../../desktop/dconf-editor.nix + ../../desktop/jetbrains-toolbox.nix + ../../desktop/meld.nix + ../../desktop/protonmail-bridge.nix + ../../desktop/sublime-merge.nix + ../../desktop/sublime.nix + ../../services/keybase.nix + ]; + + # Authrorize X11 access in Distrobox + home.file.".distroboxrc".text = '' + xhost +si:localuser:$USER + ''; +} diff --git a/home-manager/_mixins/users/_gburd/face.png b/home-manager/_mixins/users/_gburd/face.png new file mode 100644 index 0000000000000000000000000000000000000000..ef9da941c010fb0b619383d6a3d6d2fad6c100b5 GIT binary patch literal 33951 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.B&{f%75#t^Sy;S72!f<+0u|Llb*P(hg{>kEL#4F> zFD5h~z=8w{84(bOL6NI{6k`B214LF30F6cv??I8(N`Y;>2MV040g7CrSV;lSTh&r` zTdk~VP`w+3!+RT7*5^?e0*L*&QLTX7+y>FK6)>~XJsYEFtPQ5QPBeGxu(xy?Ewg|i zDrQy)-T(j)APE8~LWKe%s4N-+(WX&?Do{WmirKN!;Pgtoz{*MxHp>;G+0C`~U?uG? zM-f&9V3;_Q7z9C!6dD0V>_q@cUQP0MoOOooDCLS@O+^?=GK-{yEp5lVaL zdreJ>00D)_TZalk6ng+vgeZuF5TH0@BCWtx)?gTDBq9+&QqFm7Nn?Wq^Nwj6-C8ZQ zma23>Z9X5ijZX!;eO2-$?=4dlFOi6y4i#9C_uEksP?Taug_a}1)Ky>ztaqpYfe1hZ z2_=j|U)7+LcW$sYt4pnptOFf_U7rmhjj&E9r`c-Hj!6pJWNV$D0rGzVat9oVX{^XH P00000NkvXXu0mjfq$*xT literal 0 HcmV?d00001 diff --git a/home-manager/_mixins/users/_gburd/hosts/floki.nix b/home-manager/_mixins/users/_gburd/hosts/floki.nix new file mode 100644 index 0000000..a658311 --- /dev/null +++ b/home-manager/_mixins/users/_gburd/hosts/floki.nix @@ -0,0 +1,8 @@ +{ lib, ... }: +with lib.hm.gvariant; +{ + imports = [ + ../../../desktop/vorta.nix + ]; + dconf.settings = { }; +} diff --git a/home-manager/_mixins/users/_gburd/init.nvim b/home-manager/_mixins/users/_gburd/init.nvim new file mode 100644 index 0000000..7433ef9 --- /dev/null +++ b/home-manager/_mixins/users/_gburd/init.nvim @@ -0,0 +1,565 @@ +--[[ + +===================================================================== +==================== READ THIS BEFORE CONTINUING ==================== +===================================================================== + +Kickstart.nvim is *not* a distribution. + +Kickstart.nvim is a template for your own configuration. + The goal is that you can read every line of code, top-to-bottom, understand + what your configuration is doing, and modify it to suit your needs. + + Once you've done that, you should start exploring, configuring and tinkering to + explore Neovim! + + If you don't know anything about Lua, I recommend taking some time to read through + a guide. One possible example: + - https://learnxinyminutes.com/docs/lua/ + + + And then you can explore or search through `:help lua-guide` + - https://neovim.io/doc/user/lua-guide.html + + +Kickstart Guide: + +I have left several `:help X` comments throughout the init.lua +You should run that command and read that help section for more information. + +In addition, I have some `NOTE:` items throughout the file. +These are for you, the reader to help understand what is happening. Feel free to delete +them once you know what you're doing, but they should serve as a guide for when you +are first encountering a few different constructs in your nvim config. + +I hope you enjoy your Neovim journey, +- TJ + +P.S. You can delete this when you're done too. It's your config now :) +--]] +-- See `:help mapleader` +-- NOTE: Must happen before plugins are required (otherwise wrong leader will be used) +vim.g.mapleader = ',' +vim.g.maplocalleader = ',' + +-- Install package manager +-- https://github.com/folke/lazy.nvim +-- `:help lazy.nvim.txt` for more info +local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim' +if not vim.loop.fs_stat(lazypath) then + vim.fn.system { + 'git', + 'clone', + '--filter=blob:none', + 'https://github.com/folke/lazy.nvim.git', + '--branch=stable', -- latest stable release + lazypath, + } +end +vim.opt.rtp:prepend(lazypath) + +-- NOTE: Here is where you install your plugins. +-- You can configure plugins using the `config` key. +-- +-- You can also configure plugins after the setup call, +-- as they will be available in your neovim runtime. +require('lazy').setup({ + -- NOTE: First, some plugins that don't require any configuration + + -- Git related plugins + 'tpope/vim-fugitive', + 'tpope/vim-rhubarb', + + -- Detect tabstop and shiftwidth automatically + 'tpope/vim-sleuth', + + -- NOTE: This is where your plugins related to LSP can be installed. + -- The configuration is done below. Search for lspconfig to find it below. + { + -- LSP Configuration & Plugins + 'neovim/nvim-lspconfig', + dependencies = { + -- Automatically install LSPs to stdpath for neovim + { 'williamboman/mason.nvim', config = true }, + 'williamboman/mason-lspconfig.nvim', + + -- Useful status updates for LSP + -- NOTE: `opts = {}` is the same as calling `require('fidget').setup({})` + { 'j-hui/fidget.nvim', tag = 'legacy', opts = {} }, + + -- Additional lua configuration, makes nvim stuff amazing! + 'folke/neodev.nvim', + }, + }, + + { + "weilbith/nvim-code-action-menu", + cmd = "CodeActionMenu", + }, + + { + -- Autocompletion + 'hrsh7th/nvim-cmp', + dependencies = { + -- Snippet Engine & its associated nvim-cmp source + 'L3MON4D3/LuaSnip', + 'saadparwaiz1/cmp_luasnip', + + -- Adds LSP completion capabilities + 'hrsh7th/cmp-nvim-lsp', + + -- Adds a number of user-friendly snippets + 'rafamadriz/friendly-snippets', + }, + }, + + -- Useful plugin to show you pending keybinds. + { 'folke/which-key.nvim', opts = {} }, + { + -- Adds git related signs to the gutter, as well as utilities for managing changes + 'lewis6991/gitsigns.nvim', + opts = { + -- See `:help gitsigns.txt` + signs = { + add = { text = '+' }, + change = { text = '~' }, + delete = { text = '_' }, + topdelete = { text = '‾' }, + changedelete = { text = '~' }, + }, + on_attach = function(bufnr) + vim.keymap.set('n', 'gp', require('gitsigns').prev_hunk, + { buffer = bufnr, desc = '[G]o to [P]revious Hunk' }) + vim.keymap.set('n', 'gn', require('gitsigns').next_hunk, { buffer = bufnr, desc = '[G]o to [N]ext Hunk' }) + vim.keymap.set('n', 'ph', require('gitsigns').preview_hunk, { buffer = bufnr, desc = '[P]review [H]unk' }) + end, + }, + }, + + { + "ellisonleao/gruvbox.nvim", + priority = 1000, + config = function() + require('gruvbox').setup({ + contrast = "hard", + }) + vim.o.background = "dark" + vim.cmd.colorscheme 'gruvbox' + end, + }, + + { + -- Set lualine as statusline + 'nvim-lualine/lualine.nvim', + -- See `:help lualine.txt` + opts = { + options = { + icons_enabled = false, + theme = 'auto', + component_separators = '|', + section_separators = '', + }, + }, + }, + + { + -- Add indentation guides even on blank lines + 'lukas-reineke/indent-blankline.nvim', + -- Enable `lukas-reineke/indent-blankline.nvim` + -- See `:help indent_blankline.txt` + opts = { + char = '┊', + show_trailing_blankline_indent = false, + }, + }, + + -- "gc" to comment visual regions/lines + { 'numToStr/Comment.nvim', opts = {} }, + + -- Fuzzy Finder (files, lsp, etc) + { + 'nvim-telescope/telescope.nvim', + branch = '0.1.x', + dependencies = { + 'nvim-lua/plenary.nvim', + -- Fuzzy Finder Algorithm which requires local dependencies to be built. + -- Only load if `make` is available. Make sure you have the system + -- requirements installed. + { + 'nvim-telescope/telescope-fzf-native.nvim', + -- NOTE: If you are having trouble with this installation, + -- refer to the README for telescope-fzf-native for more instructions. + build = 'make', + cond = function() + return vim.fn.executable 'make' == 1 + end, + }, + }, + }, + + { + -- Highlight, edit, and navigate code + 'nvim-treesitter/nvim-treesitter', + dependencies = { + 'nvim-treesitter/nvim-treesitter-textobjects', + }, + build = ':TSUpdate', + }, + + -- NOTE: Next Step on Your Neovim Journey: Add/Configure additional "plugins" for kickstart + -- These are some example plugins that I've included in the kickstart repository. + -- Uncomment any of the lines below to enable them. + -- require 'kickstart.plugins.autoformat', + -- require 'kickstart.plugins.debug', + + -- NOTE: The import below can automatically add your own plugins, configuration, etc from `lua/custom/plugins/*.lua` + -- You can use this folder to prevent any conflicts with this init.lua if you're interested in keeping + -- up-to-date with whatever is in the kickstart repo. + -- Uncomment the following line and add your plugins to `lua/custom/plugins/*.lua` to get going. + -- + -- For additional information see: https://github.com/folke/lazy.nvim#-structuring-your-plugins + -- { import = 'custom.plugins' }, +}, {}) + +-- [[ Setting options ]] +-- See `:help vim.o` +-- NOTE: You can change these options as you wish! + +-- Set highlight on search +vim.o.hlsearch = false + +-- Make line numbers default +vim.wo.number = true + +-- Enable mouse mode +vim.o.mouse = 'a' + +-- Sync clipboard between OS and Neovim. +-- Remove this option if you want your OS clipboard to remain independent. +-- See `:help 'clipboard'` +vim.o.clipboard = 'unnamedplus' + +-- Enable break indent +vim.o.breakindent = true + +-- Save undo history +vim.o.undofile = true + +-- Case-insensitive searching UNLESS \C or capital in search +vim.o.ignorecase = true +vim.o.smartcase = true + +-- Keep signcolumn on by default +vim.wo.signcolumn = 'yes' + +-- Decrease update time +vim.o.updatetime = 250 +vim.o.timeoutlen = 300 + +-- Set completeopt to have a better completion experience +vim.o.completeopt = 'menuone,noselect' + +-- NOTE: You should make sure your terminal supports this +vim.o.termguicolors = true + +-- [[ Basic Keymaps ]] + +-- Keymaps for better default experience +-- See `:help vim.keymap.set()` +vim.keymap.set({ 'n', 'v' }, '', '', { silent = true }) + +-- Remap for dealing with word wrap +vim.keymap.set('n', 'k', "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true }) +vim.keymap.set('n', 'j', "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true }) + +-- [[ Highlight on yank ]] +-- See `:help vim.highlight.on_yank()` +local highlight_group = vim.api.nvim_create_augroup('YankHighlight', { clear = true }) +vim.api.nvim_create_autocmd('TextYankPost', { + callback = function() + vim.highlight.on_yank() + end, + group = highlight_group, + pattern = '*', +}) + +-- [[ Configure Telescope ]] +-- See `:help telescope` and `:help telescope.setup()` +require('telescope').setup { + defaults = { + mappings = { + i = { + [''] = false, + [''] = false, + }, + }, + }, +} + +-- Enable telescope fzf native, if installed +pcall(require('telescope').load_extension, 'fzf') + +-- See `:help telescope.builtin` +vim.keymap.set('n', '?', require('telescope.builtin').oldfiles, { desc = '[?] Find recently opened files' }) +vim.keymap.set('n', ';', require('telescope.builtin').buffers, { desc = '[;] Find existing buffers' }) +vim.keymap.set('n', '/', function() + -- You can pass additional configuration to telescope to change theme, layout, etc. + require('telescope.builtin').current_buffer_fuzzy_find(require('telescope.themes').get_dropdown { + winblend = 10, + previewer = false, + }) +end, { desc = '[/] Fuzzily search in current buffer' }) + +-- vim.keymap.set('n', 'sf', require('telescope.builtin').git_files, { desc = '[S]earch Git [f]iles' }) +vim.keymap.set('n', 't', require('telescope.builtin').git_files, { desc = '[S]earch Git [f]iles' }) + +vim.keymap.set('n', 'sa', require('telescope.builtin').find_files, { desc = '[S]earch [a]ll files' }) +vim.keymap.set('n', 'sh', require('telescope.builtin').help_tags, { desc = '[S]earch [H]elp' }) +vim.keymap.set('n', 'sw', require('telescope.builtin').grep_string, { desc = '[S]earch current [W]ord' }) +vim.keymap.set('n', 'sg', require('telescope.builtin').live_grep, { desc = '[S]earch by [G]rep' }) +vim.keymap.set('n', 'sd', require('telescope.builtin').diagnostics, { desc = '[S]earch [D]iagnostics' }) + +-- [[ Configure Treesitter ]] +-- See `:help nvim-treesitter` +require('nvim-treesitter.configs').setup { + -- Add languages to be installed here that you want installed for treesitter + ensure_installed = { 'html', 'c', 'cpp', 'go', 'lua', 'python', 'rust', 'tsx', 'javascript', 'typescript', 'vimdoc', 'vim' }, + + -- Autoinstall languages that are not installed. Defaults to false (but you can change for yourself!) + auto_install = false, + + highlight = { enable = true }, + indent = { enable = true }, + incremental_selection = { + enable = true, + keymaps = { + init_selection = '', + node_incremental = '', + scope_incremental = '', + node_decremental = '', + }, + }, + textobjects = { + select = { + enable = true, + lookahead = true, -- Automatically jump forward to textobj, similar to targets.vim + keymaps = { + -- You can use the capture groups defined in textobjects.scm + ['aa'] = '@parameter.outer', + ['ia'] = '@parameter.inner', + ['af'] = '@function.outer', + ['if'] = '@function.inner', + ['ac'] = '@class.outer', + ['ic'] = '@class.inner', + }, + }, + move = { + enable = true, + set_jumps = true, -- whether to set jumps in the jumplist + goto_next_start = { + [']m'] = '@function.outer', + [']]'] = '@class.outer', + }, + goto_next_end = { + [']M'] = '@function.outer', + [']['] = '@class.outer', + }, + goto_previous_start = { + ['[m'] = '@function.outer', + ['[['] = '@class.outer', + }, + goto_previous_end = { + ['[M'] = '@function.outer', + ['[]'] = '@class.outer', + }, + }, + swap = { + enable = true, + swap_next = { + ['a'] = '@parameter.inner', + }, + swap_previous = { + ['A'] = '@parameter.inner', + }, + }, + }, +} + +-- Diagnostic keymaps +vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, { desc = 'Go to previous diagnostic message' }) +vim.keymap.set('n', ']d', vim.diagnostic.goto_next, { desc = 'Go to next diagnostic message' }) +vim.keymap.set('n', 'e', vim.diagnostic.open_float, { desc = 'Open floating diagnostic message' }) +vim.keymap.set('n', 'q', vim.diagnostic.setloclist, { desc = 'Open diagnostics list' }) + +-- [[ Configure LSP ]] +-- This function gets run when an LSP connects to a particular buffer. +local on_attach = function(_, bufnr) + -- NOTE: Remember that lua is a real programming language, and as such it is possible + -- to define small helper and utility functions so you don't have to repeat yourself + -- many times. + -- + -- In this case, we create a function that lets us more easily define mappings specific + -- for LSP related items. It sets the mode, buffer and description for us each time. + local nmap = function(keys, func, desc) + if desc then + desc = 'LSP: ' .. desc + end + + vim.keymap.set('n', keys, func, { buffer = bufnr, desc = desc }) + end + + nmap('rn', vim.lsp.buf.rename, '[R]e[n]ame') + --nmap('ca', vim.lsp.buf.code_action, '[C]ode [A]ction') + nmap('ca', 'CodeActionMenu', '[C]ode [A]ction') + + --nmap('gd', vim.lsp.buf.definition, '[G]oto [D]efinition') + --nmap('gI', vim.lsp.buf.implementation, '[G]oto [I]mplementation') + --nmap('D', vim.lsp.buf.type_definition, 'Type [D]efinition') + nmap('gd', require('telescope.builtin').lsp_definitions, '[G]oto [D]efinition') + nmap('gr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences') + nmap('gI', require('telescope.builtin').lsp_implementations, '[G]oto [I]mplementation') + nmap('D', require('telescope.builtin').lsp_type_definitions, 'Type [D]efinition') + nmap('ds', require('telescope.builtin').lsp_document_symbols, '[D]ocument [S]ymbols') + nmap('ws', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[W]orkspace [S]ymbols') + nmap('gh', 'ClangdSwitchSourceHeader', '[G]oto [H]eader or source file') + + -- See `:help K` for why this keymap + nmap('K', vim.lsp.buf.hover, 'Hover Documentation') + nmap('', vim.lsp.buf.signature_help, 'Signature Documentation') + + -- Lesser used LSP functionality + nmap('gD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') + nmap('wa', vim.lsp.buf.add_workspace_folder, '[W]orkspace [A]dd Folder') + nmap('wr', vim.lsp.buf.remove_workspace_folder, '[W]orkspace [R]emove Folder') + nmap('wl', function() + print(vim.inspect(vim.lsp.buf.list_workspace_folders())) + end, '[W]orkspace [L]ist Folders') + + nmap('f', vim.lsp.buf.format, '[F]ormat buffer') +end + +-- Enable the following language servers +-- Feel free to add/remove any LSPs that you want here. They will automatically be installed. +-- +-- Add any additional override configuration in the following tables. They will be passed to +-- the `settings` field of the server config. You must look up that documentation yourself. +-- +-- If you want to override the default filetypes that your language server will attach to you can +-- define the property 'filetypes' to the map in question. +local servers = { + clangd = {}, + pyright = {}, + -- gopls = {}, + -- rust_analyzer = {}, + -- tsserver = {}, + html = { filetypes = { 'html', 'twig', 'hbs'} }, + + lua_ls = { + Lua = { + workspace = { checkThirdParty = false }, + telemetry = { enable = false }, + }, + }, +} + +-- Setup neovim lua configuration +require('neodev').setup() + +-- nvim-cmp supports additional completion capabilities, so broadcast that to servers +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities = require('cmp_nvim_lsp').default_capabilities(capabilities) + +-- Ensure the servers above are installed +local mason_lspconfig = require 'mason-lspconfig' + +mason_lspconfig.setup { + ensure_installed = vim.tbl_keys(servers), +} + +mason_lspconfig.setup_handlers { + function(server_name) + require('lspconfig')[server_name].setup { + capabilities = capabilities, + on_attach = on_attach, + settings = servers[server_name], + filetypes = (servers[server_name] or {}).filetypes, + } + end +} + +-- [[ Configure nvim-cmp ]] +-- See `:help cmp` +local cmp = require 'cmp' +local luasnip = require 'luasnip' +require('luasnip.loaders.from_vscode').lazy_load() +luasnip.config.setup {} + +cmp.setup { + snippet = { + expand = function(args) + luasnip.lsp_expand(args.body) + end, + }, + mapping = cmp.mapping.preset.insert { + [''] = cmp.mapping.select_next_item(), + [''] = cmp.mapping.select_prev_item(), + [''] = cmp.mapping.scroll_docs(-4), + [''] = cmp.mapping.scroll_docs(4), + [''] = cmp.mapping.complete {}, + [''] = cmp.mapping.confirm { + behavior = cmp.ConfirmBehavior.Replace, + select = true, + }, + [''] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_next_item() + elseif luasnip.expand_or_locally_jumpable() then + luasnip.expand_or_jump() + else + fallback() + end + end, { 'i', 's' }), + [''] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_prev_item() + elseif luasnip.locally_jumpable(-1) then + luasnip.jump(-1) + else + fallback() + end + end, { 'i', 's' }), + }, + sources = { + { name = 'nvim_lsp' }, + { name = 'luasnip' }, + }, +} + +-- +-- basic vim settings +-- +vim.o.hlsearch = false +vim.wo.number = true +vim.o.mouse = 'a' +vim.o.clipboard = 'unnamedplus' +vim.o.breakindent = true +vim.o.undofile = true +vim.o.ignorecase = true +vim.o.smartcase = true +vim.wo.signcolumn = 'yes' +vim.o.updatetime = 250 +vim.o.timeout = true +vim.o.timeoutlen = 300 +vim.o.completeopt = 'menuone,noselect' +vim.o.termguicolors = true +vim.o.textwidth = 80 +vim.o.tabstop = 4 +vim.o.softtabstop = 4 +vim.o.shiftwidth = 4 +vim.o.cinoptions = 'g1,h1' +vim.o.expandtab = true +vim.o.autoindent = true + + +-- The line beneath this is called `modeline`. See `:help modeline` +-- vim: ts=2 sts=2 sw=2 et diff --git a/home-manager/_mixins/users/_gburd/pgp.asc b/home-manager/_mixins/users/_gburd/pgp.asc new file mode 100644 index 0000000..79b63f0 --- /dev/null +++ b/home-manager/_mixins/users/_gburd/pgp.asc @@ -0,0 +1,63 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQINBFNe1PUBEACYwgGGxsjgU9iADTJrs9Fc8jtqDIqxlNIj49GGisGoKLxRkpwv +GmSA8Lf8ghN6Jq13Vf/QPjUqfUJMWe44k8KE0/knrMbXGLCWV/RCmgCoAd++naR+ +gqTCKDgBRuBG4vXRpYRkApxNweN2T31uhYWjLmdBK957xfcKCOmwzWI01zvBpuW3 +AJRq3+vs7TmnBJS9ryi+3UgfV2hTJkDVLt5DSCU8lBz7sO+vQXa/saV8qNT3lPY8 +6fistevl8Tiw+5Bp25T9rLIcEjnAM0ccfNzUGN3f2vJ82tfpHpM5k3O8NByN3QIj +s7vunlESlgcVkZK5AVmeaL+SyaYiobWV5Lx8CaEIAgPDSIi7cGIXl6MddV41F/Gc +RgvzIfwRWSjWKY2bXm5RIgXYjohhurYR7AEy6WBec/yemXoA4GN/CT/48jlleShs +OthUu8epPs3/e5DdLsXpWJIUwmtEkz/gOx642IQ9qo3CZwl7MtaC4u5fJm+rMmhD +ilVsb3LlSbzOC16o0J7s2aWZKEhsbUcB1lKRaCjArqHlc3/7HskcV86LPqb6JBfn +JwK/hRTQQP9PpM1v7UARgtabBd6UDVCYqDlj5tZthMO5FMNCplnUrzGyR7oWJ+d8 +iuo3/eJh4TldsIxRgamnGc+qnMArQIFI2NDDnHMng4nYDOrRgHe4zFJf7QARAQAB +tClrZXliYXNlLmlvL2dyZWdidXJkIDxncmVnYnVyZEBrZXliYXNlLmlvPokCPgQT +AQIAKAUCU17U9QIbLwUJEswDAAYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQ +IpMa94legt8RDA/+KIJLa3fBtOuVX7KMnxc1dqb3hQ8Sf8tkBPd7qeeL+MjeGyia +9dU0XTNlEA8LgGRB5LgUelWOmIsvaJr6WinAcu1wUeW7iZGl5zCbcsfwz0GDnFhh +OxmG9qhiVet+B+AEQ36AjgVzONmpKfBzTnMSOFVKFmTBCf5jbwk5uMHzQ90RBIZc +CPDYIH8EvI5vs7F51G+09f7fXXDOlBf10M+oDnmFa4JLp//+dKr0rl4D8PA1hhej +TSJ+s/ILpMjfRVCTkwN8iOFLXnjP6s6qj5ez716DS0REYnlu+LZfNjvOcDdVtdrS +BhCQCDCVFMTI1/Umv9+S1YAsHj08aeQ8uZu2Sku3gvMv9JjhLz0gh+sMc+oymFA7 +c4FWHA70oNPozpZkSf+ZozDRRCPj7D+eM37KFTN+EYos/Lvx1DC/pjgVNpCsEFZM +iGmQeGcCGhC0aes1utoLrC2Jazji04ATHQGQJieWrMes3mjknjQIM/gQAE5v2Sj/ +T2yM5XquLas0popQM0wc/QNjii66jnt+L8nBWFWphRW9BQ8TV9FDXt3RAr+Oy7Dn +RO2V4AZ8ALnPovk8KRVXKneozw5bXE6wigK1YqFTWXA0L/JoKGeie/67r3j7pjAC +YdRY8xJVkA4Sa3GxTSi+n9SDK1LflUcbU2jxkiO383HPgPrAuGKH5yt2H4+5Ag0E +U17U9QEQALFRDRB+s3RztFND3EdHpcn87AYAfWrvdOHDigdZwvE56h9Efrutj1rm +e9K8E/1ljGHydLqkl5zNKQtCusRRlDOM5/fAQkios5Qpk5pda92Smgmf1XgG3XH1 +I0F268OuMWHFg7JIRIEtM6vN+xKsXK0/d5ofXWbsojYqrfMrxxi8OBZWbqCdJGTs +Tk0LB8KBgN5mi1Wcl1qv65uxIaIltRhJdKghOM/mT+kmmYUQN+DfJlHw8R0sgfHU +J+c1+Gkm5GCW2kPWjBKxezvP4I3B3LRQT5rS1XV0loy5cn2bkCF2t8/54C4dOA7M +CIMlCj5oNEcZ6mxS4HEJmIZ/YeA9T95im7Cc/z7O3bJFA6nCPwaiXuzYj77vcbIJ +a33wh9fQtgaVztQDSj+gdB8hUqQ+oNZo0O/jZNwmucxztqqZ8r86irbhKbWuQIN7 +XCJZpmU3yj+8pDZPdGDYqsslJcpmPrPURf+WTT866IByvbPk0drY9pspUSUMpyVd +RQMNda5Ekg4wj+L2TW3KvklPs+DxjB8raTy11yWvOw9ha7HPOP1Ne5SA06AWcChX +NX/2HbG0Td1bjW6sVbxP1iEWJaXxOV6/k8YjaAr4oQp2jopdWVrF7pdKGM+3qg6b +PVPCdMMA5nOjF4jbf0pyrR6FIDYdf5Ohq8P6Fi6/+lPnce1Tdd4BABEBAAGJBEQE +GAECAA8FAlNe1PUCGy4FCRLMAwACKQkQIpMa94legt/BXSAEGQECAAYFAlNe1PUA +CgkQrvrMP8SVr4m7rw/+IptxuRbtRVirze4VaDYXp4njgQlLqMQWPa8xrx8TJ5Gj ++8GVZLTr/ZMFXobHYfDrz8o/+JRTshxdWp5PPq8e2qWNdGujTeSDz7fuXLZtR5Ax ++D9BvvfnmKGgPBuQY/aTCNKhWU2PwW8MhqYeKXnin7LJDfVLuno1oEotQ0WwfF8r +9QMlsiN6zZ65d3E8OQW4ezA3mcPNoOCWBQbyF2LDWtGbjGk7II51z7G51gq6/ahX +uir5glMewBXe/DY3197n37YbkYam+p7yXWZIlHkUr1LlQZoKKUxtx+ZtirX4ODP1 +LL73PMyTiewW0QKqvp5/znw5QIUk85TnZe6O6rJNkDF0jnhDL5ULb1pQbpOE4y1X +xIBxc3kcLeMhOUJoO2o+q8+wnK/bA5fLm/xlo72y5ioBZh1S/xRacOPsXvzDAfcQ +RLgU4VD1tihjBFs78f/Q9h9jdd4wJCiQboRJhaEIdIU0qKiPAZlxsfoYcFRiNgTy +I+1szCOk52FNIYytZV+JNb2LCEvw7TOyru3T2L3X55S+6sPQnBvXdls6bflERIwv +pS2qW9Ey7XbHnn9oMPgD5yzWDp6keD0TYBGbXS7AA85YqKMZ4ZumW/T65jOfgbBs +Y2QimzgslWGn+ER7lXh5R7mKfmLNXhie4mPilKB5WqzQtBvFwILjEOmKi/fv5ry+ +cw/+PPAujPBVt4jZM4PQP7GQr2/SRa5y9Rl3UaRyHrL7sroMtP0Ms5g1ngybX0ps +2043BUceA8oulk7Lig1EgFw0MaYexHF4iNKqvHVJZ6I9qpOH7oGFU2XiN/guAC7b +LAJkQek3B991MnYSXQEuB+I3ZZw2cVHcJIgz7OZAFwh5PKqM0Yk79KWFbkgchC7Q +DDBVnA4D+yiI93MyNN8sjbTIZ4BFjJeijNLPrwYTu3Gz95TSrQng8PIyx4nwqF3g +8XbA9mOL3v/5gf9bDuwTytebGTpimz8e77rLG3PQq9XnYwN4djDj+eGbC1zlVEE8 +dhL2x3n0xcHu9unnSnQ94SeAtV3OTRSHLdw3byCtaaiBpZ2oM9SxApmYz4HsEzhA +i/HJvCR8PFJb+IYzwmQiHLQQa2HdO5pRqJPLEqw2mGoHn9/mg9xlZq3TXMi2fcWy +TFu5ZpiN0+ys06HUFOsNC4f4GGwrsEP9kSdOUiNYzixagjThqWGBmMW/MkWfdGOg +5Tox/hDv9aWCr+8P2C3XyLF4w2i2ADDRCbF77Tag4/d1Ni/hz10X3lgZ/jzmhw4i +WcGEseGpMQEDbh098mUcdJJbOceXnozahIWA1XxP93gpVKpuXUyDYxJvbOMMYSQT +6x/O5FiZynjqsXMq4B+lmGmYoR7qzbfk7e0EugSj6dWrUVM= +=yrZE +-----END PGP PUBLIC KEY BLOCK----- diff --git a/home-manager/_mixins/users/_gburd/ssh.pub b/home-manager/_mixins/users/_gburd/ssh.pub new file mode 100644 index 0000000..7c07b31 --- /dev/null +++ b/home-manager/_mixins/users/_gburd/ssh.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGSNy/vMr2Zk9pvfjQnxiU9F8CGQJwCiXDxPecKG9/q+ Greg Burd - 2023-01-23 diff --git a/home-manager/_mixins/users/_gburd/symas-ssh.pub b/home-manager/_mixins/users/_gburd/symas-ssh.pub new file mode 100644 index 0000000..310ba2f --- /dev/null +++ b/home-manager/_mixins/users/_gburd/symas-ssh.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDPvS6pE5Y8Yc3YnKpKinjVKyziqnb7JZJGonDKnZi3I Greg Burd - 2023-08-03 diff --git a/home-manager/_mixins/users/gburd/default.nix b/home-manager/_mixins/users/gburd/default.nix index a9e788b..5e639d8 100644 --- a/home-manager/_mixins/users/gburd/default.nix +++ b/home-manager/_mixins/users/gburd/default.nix @@ -240,7 +240,6 @@ file git-credential-1password htop - vim openssl plocate ripgrep @@ -265,11 +264,13 @@ programs = { fish = { shellAliases = { - diff = "diffr"; - fast = "fast -u"; - glow = "glow --pager"; + #diff = "diffr"; + #fast = "fast -u"; + #glow = "glow --pager"; pubip = "curl -s ifconfig.me/ip"; # "curl -s https://api.ipify.org"; speedtest = "speedtest-go"; + vi = "nvim"; + vim = "nvim"; }; }; }; diff --git a/nixos/_mixins/desktop/vscode.nix b/nixos/_mixins/desktop/vscode.nix index 9aacff5..f7bda19 100644 --- a/nixos/_mixins/desktop/vscode.nix +++ b/nixos/_mixins/desktop/vscode.nix @@ -5,6 +5,7 @@ (vscode-with-extensions.override { inherit (unstable) vscode; vscodeExtensions = [ + unstable.vscode-extensions.asvetliakov.vscode-neovim unstable.vscode-extensions.coolbear.systemd-unit-file unstable.vscode-extensions.dotjoshjohnson.xml unstable.vscode-extensions.eamodio.gitlens @@ -21,6 +22,7 @@ unstable.vscode-extensions.ms-vscode.cmake-tools unstable.vscode-extensions.ms-vscode.cpptools unstable.vscode-extensions.ms-vscode.cpptools-extension-pack + unstable.vscode-extensions.ms-vscode.makefile-tools unstable.vscode-extensions.ms-vsliveshare.vsliveshare unstable.vscode-extensions.redhat.vscode-yaml unstable.vscode-extensions.ryu1kn.partial-diff diff --git a/nixos/_mixins/secrets.yaml b/nixos/_mixins/secrets.yaml index 70a60fd..1b01970 100644 --- a/nixos/_mixins/secrets.yaml +++ b/nixos/_mixins/secrets.yaml @@ -1,4 +1,5 @@ gburd-password: ENC[AES256_GCM,data:HFgg11lJrsrdHYBGOCWYDkFkE8aRPW++Q8Yhw6QeqbFmmFqx9NVo5WFQCa2dVT9uLDhCLN3uDbMgOrcwtRBxP58byOSQtCo895PqV4ICa/+s00ZrWXpD3oeMNNlqfIGtbw5Iq8CUkFBMDA==,iv:U/+fOgtpynPhyJN8F1pVljzzp/EcTlQVcdSaPeAp6Oc=,tag:8OeZ2C+UB1cF63Zx76RBMQ==,type:str] +greg-password: ENC[AES256_GCM,data:IJLXmo7hoetWIhf4X66RqXxy6V9o+Z+TaZQkniSzZ0OUk/DKMc1XEi+ykJHFXeUX+nkmCPeIPIHf9jfjOdNDl61C61c3A6OUw9ecmEpf0LJnOsDy3nSic3QNr/iwThMXFkfblZTDb/7ZmQ==,iv:p+VMxMS74n4Wp9AVaqZQOUXsTEjS4T0sahhAVZRvGJw=,tag:sAgxVG5y2pb2mG0rA3abyQ==,type:str] sublime-licenses: text: ENC[AES256_GCM,data:tjkf3PpbbnfvYi2fdsB6JX3gh5R1M1CIFto4QyYZzuXKr84XPQPPIvPQw+Uyzf+t++z7QG1FbvC15CTfuQWZzt5pU4EWMyiND9IPA2c39l2z+BZLyk3m+92/rhmPylU+jB90hZz7DhgzUXaXpMhHN9EF9z8wL9SFRDr6HGfFX1JR8x4XS4dk6b6kXKORtwHi0kJCsLwAjdKaVrlw6vGgDyYy7FTP5ZZa62JVzz+X08UmMkM98slivM691nJU6FvF9+UDlBE7U+2PGa9RF7y7qj0YO0pGrVf4pctfv/ssjPvByuTq39PXifvas6kRErHGTPgvQPz9uDYqzP6hw/S5fIiw+XDIBpExz1TKaeCEmmTDnVY2ViRGYqLFfoS3XdTlruiNtGkIruv8AGQCEsqt3FxXoO8kZ/dOWrJ4gqd7iqWPrIy9p14J8tMSCz86fU/PfCsemk0df2zCxgO3xiAZSHxx+hL5a+YEj5dyWouZC83Xht0GhIcUo1A8Q3q1BLbauQcJ2ZgNRDcF,iv:ut/h/DFDvFCKccEAGWyC9OfC/YOa8nNT/cBbxAPOzzs=,tag:KFyD5GjMbO4n3oPxgEdfng==,type:str] merge: ENC[AES256_GCM,data:Dz44UaqEcVAJtqJPXhT+q30FVfY43Ahsrspc+pz+XOjyxvFFgQF3e7HyeSrM8UVik0aYx5yT34IiduIYDq+KNVtq8Q+Jac0j6ielvQsOn4QVbDkJog8ydd45b+C9sV0kVF9eFcja8JsXvUxiNL/Z5ZvXAe5bhYp/kx+3C1O76WxjH5XWe+51orJq2cY4SLasNieJqnp2AoUCc4PC9y/aXSpJu8bU+LQibcvau/RHogsF5lw9cEM5oNqb/FPRpOIVIiqWBY8adRugSCtPvC062AHKcUu8tFCyzUwgO1uhBti7lkmXEoyHdjzpfuTN+JQLMlsQt4q5or3kz7DJ4K1SptcHxVnVPSb5yt2lPW/wrBusQR0gU9JzBjmuZMVwwca0U4o4oFAmWQz6fgHRLDhvx7cEPYqLI5w4W0jvZvAgtI2OXhqu1XKvyC4XkFMGf6c37kOc8iY2J+1x2FGMpKYy9Zwd/giSrSamNS7e1Bspx00MqLIbMzOFxqKxl8l3+gLETreeOJCTelpg,iv:pPtexa+/lhkmaDvscwhk6RKL6N41igNtftBNy8WNPIE=,tag:3MRH9LoF1vcNIr76cWu5KQ==,type:str] @@ -17,8 +18,8 @@ sops: SXIzUTBLQklXemM4anBNdnhhMGc5V2sKmIExI6uv2EgL2WTuBITlc98uAN4SQBDL kj6f8gQtJCXTyWFyZxcR1Z1f8q53R1ZmsKJv9a3oD4bx9riTjauC7w== -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-10-03T14:08:52Z" - mac: ENC[AES256_GCM,data:aara96dcSHaQbN1u+GdSEWApe0hWLxLa4TiqSkUk4Q5wft+1lcBXl8NNQNOY0p6nYZ4TdrBaRjakJocbCnQ4b2HSbRxY0w/wxO3ziaAdcghnEBBGsQ1KpP2GtDzP39rsGUjYgY7Lq0jgQ2yWH5/uOwCRcGdfA05VDcT7xSsrISU=,iv:ektoBdOSL9sSs+mI0HuCUvfegciELDAkPETIHDVky7c=,tag:MDXfa4Z3+BS5r5M7q5L9Hg==,type:str] + lastmodified: "2024-04-24T13:51:49Z" + mac: ENC[AES256_GCM,data:Z/djrG+I0tm91xusJdwqYQFSh76VOF5Fg4YUnVuXFPzvaO7UJ00qIIQ1BiigaBpAzRMg5iV4+z3/qJ259P28jyC9Bled4G7c8qlh81MDgKMg3BzaBeRW8th/Y9QYla4L8kgqOHE26HdCpdIPe3uILeQ+h7LxaUdtHgFiQL3rXOI=,iv:7MY1tiS4TzbAUopdqf1sGUYMGP0N46j8u/0gZAZv1so=,tag:KmvsFkmscIor30eC8sgEVA==,type:str] pgp: - created_at: "2023-09-22T14:23:05Z" enc: |- @@ -43,4 +44,4 @@ sops: -----END PGP MESSAGE----- fp: D4BB42BE729AEFBD2EFEBF8822931AF7895E82DF unencrypted_suffix: _unencrypted - version: 3.8.0 + version: 3.8.1 diff --git a/nixos/_mixins/users/_gburd/default.nix b/nixos/_mixins/users/_gburd/default.nix new file mode 100644 index 0000000..08b78b3 --- /dev/null +++ b/nixos/_mixins/users/_gburd/default.nix @@ -0,0 +1,69 @@ +{ config, desktop, hostname, inputs, lib, pkgs, ... }: +let + ifTheyExist = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups; +in +{ + imports = [ + inputs.vscode-server.nixosModules.default + ] ++ lib.optionals (desktop != null) [ + ../../desktop/chromium.nix + ../../desktop/chromium-extensions.nix + ../../desktop/vscode.nix + ../../desktop/${desktop}-apps.nix + ]; + + environment.systemPackages = with pkgs; [ + curl + ] ++ lib.optionals (desktop != null) [ + appimage-run + authy + chatterino2 + gimp-with-plugins + gnome.gnome-clocks + zoom-us + + # Fast moving apps use the unstable branch + unstable.discord + #unstable.google-chrome + ]; + + services = { + }; + + users.users.gburd = { + extraGroups = [ + "audio" + "input" + "networkmanager" + "users" + "video" + "wheel" + ] ++ ifTheyExist [ + "docker" + "git" + "i2c" + "libvirtd" + "network" + "podman" + "wireshark" + ]; + + homeMode = "0755"; + isNormalUser = true; + hashedPassword = "$6$RDOZHdTwt.BuOR4C$fYDkyb3yppbgX0ewPbsKabS2u9W.wyrRJONQPtugrO/gBJCzsWkfVIVYOAj07Qar1yqeYJBlBkYSFAgGe5ssw."; + # TODO: hashedPasswordFile = config.sops.secrets.gburd-password.path; + openssh.authorizedKeys.keys = [ + (builtins.readFile ../../../../home-manager/_mixins/users/gburd/ssh.pub) + (builtins.readFile ../../../../home-manager/_mixins/users/gburd/symas-ssh.pub) + ]; + packages = [ pkgs.home-manager ]; + shell = pkgs.fish; + }; + + sops.secrets.gburd-password = { + sopsFile = ../../secrets.yaml; + neededForUsers = true; + }; + + services.geoclue2.enable = true; +} diff --git a/nixos/default.nix b/nixos/default.nix index d3e20f2..8e38112 100644 --- a/nixos/default.nix +++ b/nixos/default.nix @@ -34,6 +34,8 @@ in kernel.sysctl = { "net.ipv4.ip_forward" = 1; "net.ipv6.conf.all.forwarding" = 1; + "/proc/sys/fs/aio-max-nr" = 220520; + "/proc/sys/kernel/perf_event_paranoid" = 1; }; };