Compare commits
No commits in common. "master" and "before-git" have entirely different histories.
master
...
before-git
452 changed files with 358 additions and 44668 deletions
|
@ -1,19 +0,0 @@
|
|||
name: Discord
|
||||
|
||||
on:
|
||||
- workflow_dispatch
|
||||
- push
|
||||
|
||||
jobs:
|
||||
discord_commits:
|
||||
runs-on: ubuntu-latest
|
||||
name: discord commits
|
||||
if: contains(github.event.head_commit.message, '(servers)')
|
||||
|
||||
steps:
|
||||
- name: Discommit
|
||||
uses: https://github.com/matt1432/discommit@v0.0.2
|
||||
with:
|
||||
discord_webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
api_url: 'https://git.nelim.org/api/v1/repos/$OWNER/$REPO/git/commits/$REF'
|
||||
title: 'New commit containing changes to server configs:'
|
22
.gitignore
vendored
22
.gitignore
vendored
|
@ -1,22 +0,0 @@
|
|||
# Python
|
||||
*.egg-info
|
||||
|
||||
# NPM
|
||||
*node_modules
|
||||
*build/
|
||||
|
||||
# Direnv
|
||||
*.direnv/
|
||||
|
||||
# Generated by nix
|
||||
result*
|
||||
.nixd.json
|
||||
|
||||
## AGS
|
||||
nixosModules/ags/config/ts/lockscreen/vars.ts
|
||||
**/config.js
|
||||
*icons
|
||||
**/types
|
||||
|
||||
# Other
|
||||
*.temp
|
16
LICENSE.md
16
LICENSE.md
|
@ -1,16 +0,0 @@
|
|||
MIT No Attribution
|
||||
|
||||
Copyright 2024 Mathis H.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
software and associated documentation files (the "Software"), to deal in the Software
|
||||
without restriction, including without limitation the rights to use, copy, modify,
|
||||
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
331
README.md
331
README.md
|
@ -1,111 +1,236 @@
|
|||
# My NixOS configs
|
||||
|
||||
## Ags
|
||||
|
||||
You might find it weird that most of my config is written in TypeScript.
|
||||
That's because all my desktops run
|
||||
[AGS](https://github.com/Aylur/ags)
|
||||
for UI. Click on
|
||||
[this](https://git.nelim.org/matt1432/nixos-configs/src/branch/master/nixosModules/ags)
|
||||
to see my configuration.
|
||||
|
||||
I'm also a victim of Stockholm syndrome at this point and make my scripts
|
||||
in TypeScript because it's the scripting language I am most comfortable with.
|
||||
|
||||
## About
|
||||
|
||||
### General
|
||||
|
||||
This repo is the complete configuration of machines I own,
|
||||
running NixOS or Nix. Its structure is based on a flake's
|
||||
[outputs](https://wiki.nixos.org/wiki/Flakes#Output_schema).
|
||||
|
||||
### Flake Location
|
||||
|
||||
This git repo will always be located at `$FLAKE` (`config.environment.variables.FLAKE`)
|
||||
and symlinked to `/etc/nixos` to have everything where NixOS tools
|
||||
expect things to be.
|
||||
|
||||
ie.
|
||||
|
||||
```bash
|
||||
sudo rm -r /etc/nixos
|
||||
|
||||
echo "$FLAKE" # /home/matt/.nix
|
||||
|
||||
sudo ln -sf /home/matt/.nix /etc/nixos
|
||||
# Archinstaller
|
||||
```
|
||||
loadkeys ca
|
||||
setfont ter-132b
|
||||
```
|
||||
|
||||
### Flake Outputs
|
||||
|
||||
| Output | Description |
|
||||
| ---------------------------------- | ----------- |
|
||||
| `nixosConfigurations` | [devices](https://git.nelim.org/matt1432/nixos-configs/src/branch/master/devices)' + ISO's configurations |
|
||||
| `nixOnDroidConfigurations.default` | [Nix-On-Droid](https://git.nelim.org/matt1432/nixos-configs/src/branch/master/devices/android)'s configuration |
|
||||
| `packages` | Some custom [packages](https://git.nelim.org/matt1432/nixos-configs/src/branch/master/packages) not available in nixpkgs or modified from it |
|
||||
| `legacyPackages` | Some custom [package scopes](https://git.nelim.org/matt1432/nixos-configs/src/branch/master/legacyPackages) not available in nixpkgs or modified from it |
|
||||
| `apps` | Scripts ran from the flake defined [here](https://git.nelim.org/matt1432/nixos-configs/src/branch/master/apps) |
|
||||
| `homeManagerModules` | [Modules](https://git.nelim.org/matt1432/nixos-configs/src/branch/master/homeManagerModules) made for home-manager |
|
||||
| `homeManagerModules` | [Modules](https://git.nelim.org/matt1432/nixos-configs/src/branch/master/nixosModules) made for NixOS systems |
|
||||
| `formatter` | I format nix code with [alejandra](https://github.com/kamadorueda/alejandra) |
|
||||
| `devShells.default` | A dev shell to build an ISO from the live-image nixosConfiguration |
|
||||
| `devShells.ags` | A dev shell to have a NodeJS env when I enter my AGS's config directory |
|
||||
|
||||
### Flake Inputs
|
||||
|
||||
To allow use of the full nix language for my inputs, I use [genflake](https://github.com/jorsn/flakegen).
|
||||
Therefore, the flake I edit is located at `./outputs.nix`.
|
||||
|
||||
I also prefer using a more descriptive format for my inputs like so:
|
||||
|
||||
```nix
|
||||
nixpkgs = {
|
||||
type = "github";
|
||||
owner = "NixOS";
|
||||
repo = "nixpkgs";
|
||||
|
||||
# Branch name
|
||||
ref = "nixos-unstable";
|
||||
|
||||
# Pin this input to a specific commit
|
||||
rev = "842d9d80cfd4560648c785f8a4e6f3b096790e19";
|
||||
};
|
||||
## Partionning with [cryptsetup](https://wiki.archlinux.org/title/Dm-crypt/Encrypting_an_entire_system#LUKS_on_a_partition)
|
||||
### Encrypting root partition
|
||||
```
|
||||
$ PART="encrypted partition number ie. 2"
|
||||
$ cryptsetup -y -v luksFormat --type luks1 /dev/nvme0n1p$PART
|
||||
$ cryptsetup open /dev/nvme0n1p$PART root
|
||||
$ mkfs.btrfs /dev/mapper/root
|
||||
$ mount /dev/mapper/root /mnt
|
||||
```
|
||||
### Mounting boot :
|
||||
```
|
||||
$ mount --mkdir /dev/nvme0n1p1 /mnt/boot
|
||||
```
|
||||
|
||||
to make it more clear what is what in the flake URI
|
||||
|
||||
### Secrets
|
||||
|
||||
All my secrets are in a private git repo that makes use of
|
||||
[sops-nix](https://github.com/Mic92/sops-nix).
|
||||
I generate `.sops.yaml` from `.sops.nix`:
|
||||
|
||||
```nix
|
||||
let
|
||||
wim = "somekey";
|
||||
binto = "somekey2";
|
||||
in {
|
||||
creation_rules = [
|
||||
{
|
||||
path_regex = "secrets/[^/]+\\.(yaml|json|env|ini)$";
|
||||
key_groups = [
|
||||
{
|
||||
age = [wim binto];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
### Installing packages on the device
|
||||
```
|
||||
$ pacstrap -K /mnt base linux-firmware linux amd-ucode patch dkms kmod btrfs-progs grub os-prober ntfs-3g efibootmgr efivar networkmanager iwd nano sudo texinfo man-db man-pages
|
||||
```
|
||||
|
||||
which is then converted to `.sops.yaml` using
|
||||
[remarshal](https://github.com/remarshal-project/remarshal)
|
||||
and this shell command:
|
||||
|
||||
```bash
|
||||
nix eval --json --file ./.sops.nix | remarshal --if json --of yaml > .sops.yaml
|
||||
## Preparing for chroot
|
||||
```
|
||||
$ genfstab -U /mnt >> /mnt/etc/fstab
|
||||
$ arch-chroot /mnt
|
||||
```
|
||||
|
||||
TLDR: I
|
||||
**[hate](https://ruudvanasseldonk.com/2023/01/11/the-yaml-document-from-hell)**
|
||||
YAML
|
||||
# Chroot in Installed Arch
|
||||
```
|
||||
$ ln -sf /usr/share/zoneinfo/America/Montreal /etc/localtime
|
||||
$ hwclock --systohc
|
||||
$ echo matt-laptop > /etc/hostname
|
||||
$ passwd
|
||||
```
|
||||
|
||||
## Localization
|
||||
Uncomment ca_FR.UTF-8 en_CA.UTF-8 en_US.UTF-8 fr_CA.UTF-8 and run
|
||||
```
|
||||
$ locale-gen
|
||||
$ echo LANG=en_CA.UTF-8 > /etc/locale.conf
|
||||
$ echo KEYMAP=ca > /etc/vconsole.conf
|
||||
```
|
||||
## Edit /etc/mkinitcpio.conf for LUKS
|
||||
```
|
||||
$ sed -i 's/BINARIES=.*/BINARIES=(btrfs)/' /etc/mkinitcpio.conf
|
||||
...
|
||||
$ sed -i 's/HOOKS=.*/HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block encrypt filesystems fsck)/' /etc/mkinitcpio.conf
|
||||
```
|
||||
then run ```mkinitpcio -P```
|
||||
|
||||
## Grub install
|
||||
```
|
||||
$ grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=wim --boot-directory=/boot/EFI/wim
|
||||
```
|
||||
|
||||
### Edit /etc/default/grub for LUKS
|
||||
```
|
||||
$ CRYPT="cryptdevice=$(blkid | sed -n 's/.*nvme0n1p'$PART': \(.*\) TYPE.*/\1/p'):root"
|
||||
$ sed -i 's#GRUB_CMDLINE_LINUX_DEFAULT.*#GRUB_CMDLINE_LINUX_DEFAULT="quiet loglevel 3 '$CRYPT' root=/dev/mapper/root"#' /etc/default/grub
|
||||
```
|
||||
make sure the UUID is the actual partition inside the LUKS container and run ```grub-mkconfig -o /boot/EFI/wim/grub/grub.cfg```
|
||||
|
||||
we can now reboot to the installed Arch
|
||||
<br/><br/>
|
||||
|
||||
# Inside installed Arch
|
||||
|
||||
## Configure [internet](https://wiki.archlinux.org/title/Iwd) access
|
||||
```
|
||||
$ systemctl enable --now NetworkManager systemd-networkd systemd-resolved systemd-timesyncd
|
||||
|
||||
$ cat << EOF >> /etc/NetworkManager/conf.d/wifi_backend.conf
|
||||
[device]
|
||||
wifi.backend=iwd
|
||||
EOF
|
||||
|
||||
$ cat << EOF >> /etc/iwd/main.conf
|
||||
[General]
|
||||
EnableNetworkConfiguration=true
|
||||
EOF
|
||||
|
||||
$ systemctl stop iwd
|
||||
$ systemctl restart NetworkManager
|
||||
$ iwctl device list # check if powered on
|
||||
$ iwctl station wlan0 scan
|
||||
$ iwctl station wlan0 get-networks
|
||||
$ iwctl station wlan0 connect $SSID
|
||||
```
|
||||
|
||||
### Configure systemd-resolved
|
||||
```
|
||||
$ ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
|
||||
$ sed -i 's/#DNS=.*/DNS=100.64.0.1/' /etc/systemd/resolved.conf
|
||||
$ sed -i 's/#FallbackDNS=.*/FallbackDNS=1.1.1.1/' /etc/systemd/resolved.conf
|
||||
$ sed -i 's/#DNSStubListener=.*/DNSStubListener=no/' /etc/systemd/resolved.conf
|
||||
```
|
||||
|
||||
### Configure reflector for mirror management of pacman
|
||||
```
|
||||
$ pacman -Sy reflector
|
||||
$ nano /etc/xdg/reflector/reflector.conf
|
||||
$ systemctl enable --now reflector.timer
|
||||
```
|
||||
|
||||
## User management
|
||||
```
|
||||
$ useradd -m matt -G wheel,input
|
||||
$ passwd matt
|
||||
$ env EDITOR=nano visudo # set wheel to allow sudo commands with pass
|
||||
```
|
||||
|
||||
## A lot of packages to install
|
||||
```
|
||||
$ pacman -Sy htop pkgfile mlocate rsync tmux mosh usbutils wget git curl devtools mesa lib32-mesa vulkan-radeon lib32-vulkan-radeon libva-mesa-driver lib32-libva-mesa-driver mesa-vdpau lib32-mesa-vdpau bash-completion fzf
|
||||
$ pkgfile --update
|
||||
```
|
||||
|
||||
## su matt
|
||||
|
||||
## Install paru
|
||||
```
|
||||
$ sudo pacman -S --needed git base-devel
|
||||
$ git clone https://aur.archlinux.org/paru-git.git
|
||||
$ cd paru-git
|
||||
$ makepkg -si
|
||||
|
||||
$ sed -i 's/#Color/Color/' /etc/pacman.conf
|
||||
$ sed -i 's/#IgnorePkg.*/IgnorePkg = linux-xanmod-anbox linux-xanmod-anbox-headers/' /etc/pacman.conf
|
||||
|
||||
$ cat << EOF >> /etc/paru.conf
|
||||
CombinedUpgrade
|
||||
BatchInstall
|
||||
BottomUp
|
||||
NoWarn = plymouth-theme-arch-elegant
|
||||
EOF
|
||||
```
|
||||
|
||||
## Audio
|
||||
### ALSA
|
||||
```
|
||||
$ yay -Sy alsa-utils alsa-firmware sof-firmware alsa-ucm-conf
|
||||
|
||||
#unmute speakers
|
||||
$ amixer sset Master unmute
|
||||
```
|
||||
|
||||
### Pipewire
|
||||
```
|
||||
$ yay -Sy pipewire-audio pipewire-alsa pipewire-pulse
|
||||
$ yay -R pulseaudio-alsa
|
||||
$ sudo systemctl stop pulseaudio.service
|
||||
$ systemctl --user enable --now pipewire-pulse.service
|
||||
```
|
||||
|
||||
## Fingerprint Sensor Hack
|
||||
```
|
||||
$ yay -Sy python pam-fprint-grosshack
|
||||
$ sudo systemctl enable --now fprintd
|
||||
$ fprintd-enroll
|
||||
```
|
||||
|
||||
### Use the reader
|
||||
add this to the top of every file in /etc/pam.d/ that you want ie. polkit-1, sudo uwu
|
||||
```
|
||||
auth sufficient pam_fprintd_grosshack.so
|
||||
auth sufficient pam_unix.so try_first_pass nullok
|
||||
```
|
||||
OR (for gtklock and check for sddm)
|
||||
```
|
||||
auth sufficient pam_fprintd.so
|
||||
```
|
||||
|
||||
## Plymouth and Silent Boot
|
||||
By following the wiki pages on [watchdogs](https://wiki.archlinux.org/title/Improving_performance#Watchdogs), [silent booting](https://wiki.archlinux.org/title/Silent_boot#top-page) and [Plymouth](https://wiki.archlinux.org/title/Plymouth), I edited my grub config and mkinitcpio, installed and setup Plymouth, to get a satisfying booting experience
|
||||
```
|
||||
$ yay -Sy plymouth-git
|
||||
```
|
||||
/etc/mkinitcpio.conf
|
||||
```
|
||||
$ sudo sed -i 's/MODULES=()/MODULES=(amdgpu)/' /etc/mkinitcpio.conf
|
||||
$ sudo sed -i 's/#COMPRESSION="lz4"/COMPRESSION="lz4"/' /etc/mkinitcpio.conf
|
||||
$ sudo sed -i 's/HOOKS=(.* /HOOKS=(base udev plymouth encrypt autodetect modconf kms keyboard keymap consolefont block filesystems fsck)/' /etc/mkinitcpio.conf
|
||||
COMPRESSION="lz4"
|
||||
```
|
||||
/etc/default/grub
|
||||
```
|
||||
sudo sed -i 's/quiet loglevel 3/quiet splash loglevel=3 systemd.show_status=auto rd.udev.log_level=3 splash nowatchdog psi=1/' /etc/default/grub
|
||||
```
|
||||
Mute watchdog
|
||||
```
|
||||
$ echo blacklist sp5100_tco | sudo tee /etc/modprobe.d/disable-sp5100-watchdog.conf
|
||||
```
|
||||
Apply changes [Theme](https://github.com/murkl/plymouth-theme-arch-elegant)
|
||||
```
|
||||
$ git clone https://github.com/murkl/plymouth-theme-arch-elegant.git
|
||||
$ cd plymouth-theme-arch-elegant/aur
|
||||
$ makepkg -si
|
||||
$ sudo plymouth-set-default-theme -R arch-elegant
|
||||
$ sudo grub-mkconfig -o /boot/grub/grub.cfg
|
||||
$ sudo sed -i 's/echo/#ech~o/g' /boot/grub/grub.cfg
|
||||
```
|
||||
|
||||
## Here are some random changes and tweaks
|
||||
|
||||
### Firefox touchscreen [tweak](https://wiki.archlinux.org/title/Firefox/Tweaks#Enable_touchscreen_gestures)
|
||||
```
|
||||
$ echo MOZ_USE_XINPUT2 DEFAULT=1 | sudo tee -a /etc/security/pam_env.conf
|
||||
```
|
||||
then logout
|
||||
|
||||
### More Packages that are most likely needed
|
||||
```
|
||||
run toinstall.sh script
|
||||
$ sudo reboot
|
||||
```
|
||||
|
||||
### Flatpak
|
||||
```
|
||||
$ flatpak install com.github.iwalton3.jellyfin-media-player com.github.tchx84.Flatseal xournalpp stemlink
|
||||
$ sudo flatpak override --filesystem=xdg-config/gtk-3.0
|
||||
```
|
||||
|
||||
## Finally, install dotfiles
|
||||
### get access to repo first
|
||||
```
|
||||
$ mkdir ~/git && cd ~/git
|
||||
$ git clone git@git.nelim.org:matt1432/dotfiles.git
|
||||
$ cd dotfiles
|
||||
$ bash getenv.sh
|
||||
$ sudo bash setup.sh
|
||||
$ sudo bash fzf.sh /usr/share/fzf
|
||||
```
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
inputs,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (pkgs.lib) getExe;
|
||||
|
||||
mkApp = file: {
|
||||
program = getExe (pkgs.callPackage file ({} // inputs));
|
||||
type = "app";
|
||||
};
|
||||
in {
|
||||
updateFlake = mkApp ./update;
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
use flake $FLAKE#node
|
|
@ -1,33 +0,0 @@
|
|||
{
|
||||
lib,
|
||||
buildNpmPackage,
|
||||
callPackage,
|
||||
makeWrapper,
|
||||
nodejs_latest,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) concatMapStringsSep getBin;
|
||||
inherit (builtins) readFile fromJSON;
|
||||
|
||||
packageJSON = fromJSON (readFile ./package.json);
|
||||
in
|
||||
buildNpmPackage rec {
|
||||
pname = packageJSON.name;
|
||||
inherit (packageJSON) version;
|
||||
|
||||
src = ./.;
|
||||
npmDepsHash = "sha256-nYdr7jbe5wW9Rg0G4l5jbZg8G0o8DioeSGpx+8e0VZI=";
|
||||
|
||||
runtimeInputs = [
|
||||
(callPackage ../../nixosModules/docker/updateImage.nix {})
|
||||
];
|
||||
nativeBuildInputs = [makeWrapper];
|
||||
|
||||
postInstall = ''
|
||||
wrapProgram $out/bin/${pname} \
|
||||
--prefix PATH : ${concatMapStringsSep ":" (p: getBin p) runtimeInputs}
|
||||
'';
|
||||
|
||||
nodejs = nodejs_latest;
|
||||
meta.mainProgram = pname;
|
||||
}
|
|
@ -1,451 +0,0 @@
|
|||
import eslint from '@eslint/js';
|
||||
import jsdoc from 'eslint-plugin-jsdoc';
|
||||
import stylistic from '@stylistic/eslint-plugin';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
|
||||
export default tseslint.config({
|
||||
files: ['**/*.js', '**/*.ts'],
|
||||
ignores: ['node_modules/**', 'types/**'],
|
||||
|
||||
extends: [
|
||||
eslint.configs.recommended,
|
||||
jsdoc.configs['flat/recommended-typescript'],
|
||||
stylistic.configs['recommended-flat'],
|
||||
...tseslint.configs.recommended,
|
||||
...tseslint.configs.stylistic,
|
||||
],
|
||||
|
||||
rules: {
|
||||
// JSDoc settings
|
||||
'jsdoc/tag-lines': ['warn', 'any', { startLines: 1 }],
|
||||
'jsdoc/check-line-alignment': ['warn', 'always', {
|
||||
tags: ['param', 'arg', 'argument', 'property', 'prop'],
|
||||
}],
|
||||
'jsdoc/no-types': 'off',
|
||||
|
||||
// Newer settings
|
||||
'@typescript-eslint/no-extraneous-class': ['off'],
|
||||
'@typescript-eslint/no-implied-eval': ['off'],
|
||||
'class-methods-use-this': 'off',
|
||||
'@stylistic/no-multiple-empty-lines': 'off',
|
||||
|
||||
// Pre-flat config
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
args: 'all',
|
||||
argsIgnorePattern: '^_',
|
||||
caughtErrors: 'all',
|
||||
caughtErrorsIgnorePattern: '^_',
|
||||
destructuredArrayIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
ignoreRestSiblings: true,
|
||||
},
|
||||
],
|
||||
|
||||
'array-callback-return': [
|
||||
'error',
|
||||
{
|
||||
allowImplicit: true,
|
||||
checkForEach: true,
|
||||
},
|
||||
],
|
||||
'no-constructor-return': [
|
||||
'error',
|
||||
],
|
||||
'no-unreachable-loop': [
|
||||
'error',
|
||||
{
|
||||
ignore: [
|
||||
'ForInStatement',
|
||||
'ForOfStatement',
|
||||
],
|
||||
},
|
||||
],
|
||||
'no-use-before-define': [
|
||||
'error',
|
||||
{
|
||||
functions: false,
|
||||
},
|
||||
],
|
||||
'block-scoped-var': [
|
||||
'error',
|
||||
],
|
||||
'curly': [
|
||||
'warn',
|
||||
],
|
||||
'default-case-last': [
|
||||
'warn',
|
||||
],
|
||||
'default-param-last': [
|
||||
'error',
|
||||
],
|
||||
'eqeqeq': [
|
||||
'error',
|
||||
'smart',
|
||||
],
|
||||
'func-names': [
|
||||
'warn',
|
||||
'never',
|
||||
],
|
||||
'func-style': [
|
||||
'warn',
|
||||
'expression',
|
||||
],
|
||||
'logical-assignment-operators': [
|
||||
'warn',
|
||||
'always',
|
||||
],
|
||||
'no-array-constructor': [
|
||||
'error',
|
||||
],
|
||||
'no-empty-function': [
|
||||
'warn',
|
||||
],
|
||||
'no-empty-static-block': [
|
||||
'warn',
|
||||
],
|
||||
'no-extend-native': [
|
||||
'error',
|
||||
],
|
||||
'no-extra-bind': [
|
||||
'warn',
|
||||
],
|
||||
'no-implicit-coercion': [
|
||||
'warn',
|
||||
],
|
||||
'no-iterator': [
|
||||
'error',
|
||||
],
|
||||
'no-labels': [
|
||||
'error',
|
||||
],
|
||||
'no-lone-blocks': [
|
||||
'error',
|
||||
],
|
||||
'no-lonely-if': [
|
||||
'error',
|
||||
],
|
||||
'no-loop-func': [
|
||||
'error',
|
||||
],
|
||||
'no-magic-numbers': [
|
||||
'error',
|
||||
{
|
||||
ignore: [
|
||||
-1,
|
||||
0.1,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
10,
|
||||
12,
|
||||
33,
|
||||
66,
|
||||
100,
|
||||
255,
|
||||
360,
|
||||
450,
|
||||
500,
|
||||
1000,
|
||||
],
|
||||
ignoreDefaultValues: true,
|
||||
ignoreClassFieldInitialValues: true,
|
||||
},
|
||||
],
|
||||
'no-multi-assign': [
|
||||
'error',
|
||||
],
|
||||
'no-new-wrappers': [
|
||||
'error',
|
||||
],
|
||||
'no-object-constructor': [
|
||||
'error',
|
||||
],
|
||||
'no-proto': [
|
||||
'error',
|
||||
],
|
||||
'no-return-assign': [
|
||||
'error',
|
||||
],
|
||||
'no-sequences': [
|
||||
'error',
|
||||
],
|
||||
'no-shadow': [
|
||||
'error',
|
||||
{
|
||||
builtinGlobals: true,
|
||||
allow: [
|
||||
'Window',
|
||||
],
|
||||
},
|
||||
],
|
||||
'no-undef-init': [
|
||||
'warn',
|
||||
],
|
||||
'no-undefined': [
|
||||
'error',
|
||||
],
|
||||
'no-useless-constructor': [
|
||||
'warn',
|
||||
],
|
||||
'no-useless-escape': [
|
||||
'off',
|
||||
],
|
||||
'no-useless-return': [
|
||||
'error',
|
||||
],
|
||||
'no-var': [
|
||||
'error',
|
||||
],
|
||||
'no-void': [
|
||||
'off',
|
||||
],
|
||||
'no-with': [
|
||||
'error',
|
||||
],
|
||||
'object-shorthand': [
|
||||
'error',
|
||||
'always',
|
||||
],
|
||||
'one-var': [
|
||||
'error',
|
||||
'never',
|
||||
],
|
||||
'operator-assignment': [
|
||||
'warn',
|
||||
'always',
|
||||
],
|
||||
'prefer-arrow-callback': [
|
||||
'error',
|
||||
],
|
||||
'prefer-const': [
|
||||
'error',
|
||||
],
|
||||
'prefer-object-has-own': [
|
||||
'error',
|
||||
],
|
||||
'prefer-regex-literals': [
|
||||
'error',
|
||||
],
|
||||
'prefer-template': [
|
||||
'warn',
|
||||
],
|
||||
'no-prototype-builtins': 'off',
|
||||
'@typescript-eslint/no-var-requires': [
|
||||
'off',
|
||||
],
|
||||
'@stylistic/array-bracket-newline': [
|
||||
'warn',
|
||||
'consistent',
|
||||
],
|
||||
'@stylistic/array-bracket-spacing': [
|
||||
'warn',
|
||||
'never',
|
||||
],
|
||||
'@stylistic/arrow-parens': [
|
||||
'warn',
|
||||
'always',
|
||||
],
|
||||
'@stylistic/brace-style': [
|
||||
'warn',
|
||||
'stroustrup',
|
||||
],
|
||||
'@stylistic/comma-dangle': [
|
||||
'warn',
|
||||
'always-multiline',
|
||||
],
|
||||
'@stylistic/comma-spacing': [
|
||||
'warn',
|
||||
{
|
||||
before: false,
|
||||
after: true,
|
||||
},
|
||||
],
|
||||
'@stylistic/comma-style': [
|
||||
'error',
|
||||
'last',
|
||||
],
|
||||
'@stylistic/dot-location': [
|
||||
'error',
|
||||
'property',
|
||||
],
|
||||
'@stylistic/function-call-argument-newline': [
|
||||
'warn',
|
||||
'consistent',
|
||||
],
|
||||
'@stylistic/function-paren-newline': [
|
||||
'warn',
|
||||
'consistent',
|
||||
],
|
||||
'@stylistic/indent': [
|
||||
'warn',
|
||||
4,
|
||||
{
|
||||
SwitchCase: 1,
|
||||
ignoreComments: true,
|
||||
ignoredNodes: ['TemplateLiteral > *'],
|
||||
},
|
||||
],
|
||||
'@stylistic/key-spacing': [
|
||||
'warn',
|
||||
{
|
||||
beforeColon: false,
|
||||
afterColon: true,
|
||||
},
|
||||
],
|
||||
'@stylistic/keyword-spacing': [
|
||||
'warn',
|
||||
{
|
||||
before: true,
|
||||
},
|
||||
],
|
||||
'@stylistic/linebreak-style': [
|
||||
'error',
|
||||
'unix',
|
||||
],
|
||||
'@stylistic/lines-between-class-members': [
|
||||
'warn',
|
||||
'always',
|
||||
{
|
||||
exceptAfterSingleLine: true,
|
||||
},
|
||||
],
|
||||
'@stylistic/max-len': [
|
||||
'warn',
|
||||
{
|
||||
code: 105,
|
||||
ignoreComments: true,
|
||||
ignoreTrailingComments: true,
|
||||
ignoreUrls: true,
|
||||
},
|
||||
],
|
||||
'@stylistic/multiline-ternary': [
|
||||
'warn',
|
||||
'always-multiline',
|
||||
],
|
||||
'@stylistic/new-parens': [
|
||||
'error',
|
||||
],
|
||||
'@stylistic/no-mixed-operators': [
|
||||
'warn',
|
||||
],
|
||||
'@stylistic/no-mixed-spaces-and-tabs': [
|
||||
'error',
|
||||
],
|
||||
'@stylistic/no-multi-spaces': [
|
||||
'error',
|
||||
],
|
||||
'@stylistic/no-tabs': [
|
||||
'error',
|
||||
],
|
||||
'@stylistic/no-trailing-spaces': [
|
||||
'error',
|
||||
],
|
||||
'@stylistic/no-whitespace-before-property': [
|
||||
'warn',
|
||||
],
|
||||
'@stylistic/nonblock-statement-body-position': [
|
||||
'error',
|
||||
'below',
|
||||
],
|
||||
'@stylistic/object-curly-newline': [
|
||||
'warn',
|
||||
{
|
||||
consistent: true,
|
||||
},
|
||||
],
|
||||
'@stylistic/object-curly-spacing': [
|
||||
'warn',
|
||||
'always',
|
||||
],
|
||||
'@stylistic/operator-linebreak': [
|
||||
'warn',
|
||||
'after',
|
||||
],
|
||||
'@stylistic/padded-blocks': [
|
||||
'error',
|
||||
'never',
|
||||
],
|
||||
'@stylistic/padding-line-between-statements': [
|
||||
'warn',
|
||||
{
|
||||
blankLine: 'always',
|
||||
prev: '*',
|
||||
next: 'return',
|
||||
},
|
||||
{
|
||||
blankLine: 'always',
|
||||
prev: [
|
||||
'const',
|
||||
'let',
|
||||
'var',
|
||||
],
|
||||
next: '*',
|
||||
},
|
||||
{
|
||||
blankLine: 'any',
|
||||
prev: [
|
||||
'const',
|
||||
'let',
|
||||
'var',
|
||||
],
|
||||
next: [
|
||||
'const',
|
||||
'let',
|
||||
'var',
|
||||
],
|
||||
},
|
||||
{
|
||||
blankLine: 'always',
|
||||
prev: [
|
||||
'case',
|
||||
'default',
|
||||
],
|
||||
next: '*',
|
||||
},
|
||||
],
|
||||
'@stylistic/quote-props': [
|
||||
'error',
|
||||
'consistent-as-needed',
|
||||
],
|
||||
'@stylistic/quotes': [
|
||||
'error',
|
||||
'single',
|
||||
{
|
||||
avoidEscape: true,
|
||||
},
|
||||
],
|
||||
'@stylistic/semi': [
|
||||
'error',
|
||||
'always',
|
||||
],
|
||||
'@stylistic/semi-spacing': [
|
||||
'warn',
|
||||
],
|
||||
'@stylistic/space-before-blocks': [
|
||||
'warn',
|
||||
],
|
||||
'@stylistic/space-before-function-paren': [
|
||||
'warn',
|
||||
'never',
|
||||
],
|
||||
'@stylistic/space-infix-ops': [
|
||||
'warn',
|
||||
],
|
||||
'@stylistic/spaced-comment': [
|
||||
'warn',
|
||||
'always',
|
||||
],
|
||||
'@stylistic/switch-colon-spacing': [
|
||||
'warn',
|
||||
],
|
||||
'@stylistic/wrap-regex': [
|
||||
'warn',
|
||||
],
|
||||
},
|
||||
});
|
2172
apps/update/package-lock.json
generated
2172
apps/update/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"name": "update-flake",
|
||||
"version": "0.0.0",
|
||||
"bin": "out/bin/app.cjs",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "node_ver=$(node -v); esbuild src/app.ts --bundle --platform=node --target=\"node${node_ver:1:2}\" --outfile=out/bin/app.cjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@eslint/js": "9.11.1",
|
||||
"@stylistic/eslint-plugin": "2.8.0",
|
||||
"@types/eslint__js": "8.42.3",
|
||||
"@types/node": "22.6.0",
|
||||
"esbuild": "0.24.0",
|
||||
"eslint": "9.11.1",
|
||||
"eslint-plugin-jsdoc": "50.2.4",
|
||||
"jiti": "1.21.6",
|
||||
"typescript": "5.6.2",
|
||||
"typescript-eslint": "8.7.0"
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
import { spawnSync } from 'node:child_process';
|
||||
import { writeFileSync } from 'node:fs';
|
||||
|
||||
import { parseArgs } from './lib.ts';
|
||||
import { updateFirefoxAddons } from '././firefox.ts';
|
||||
import { updateDocker, updateFlakeInputs, updateVuetorrent } from './misc.ts';
|
||||
|
||||
|
||||
/* Constants */
|
||||
const FLAKE = process.env.FLAKE;
|
||||
|
||||
if (!FLAKE) {
|
||||
console.error('Env var FLAKE not found');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const args = parseArgs();
|
||||
|
||||
if (args['d'] || args['docker']) {
|
||||
console.log(updateDocker());
|
||||
}
|
||||
|
||||
if (args['i'] || args['inputs']) {
|
||||
console.log(updateFlakeInputs());
|
||||
}
|
||||
|
||||
if (args['f'] || args['firefox']) {
|
||||
console.log(updateFirefoxAddons());
|
||||
}
|
||||
|
||||
if (args['v'] || args['vuetorrent']) {
|
||||
console.log(updateVuetorrent());
|
||||
}
|
||||
|
||||
if (args['a'] || args['all']) {
|
||||
// Update this first because of nix run cmd
|
||||
const firefoxOutput = updateFirefoxAddons();
|
||||
|
||||
console.log(firefoxOutput);
|
||||
|
||||
|
||||
const flakeOutput = updateFlakeInputs();
|
||||
|
||||
console.log(flakeOutput);
|
||||
|
||||
|
||||
const dockerOutput = updateDocker();
|
||||
|
||||
console.log(dockerOutput);
|
||||
|
||||
|
||||
const vuetorrentOutput = updateVuetorrent();
|
||||
|
||||
console.log(vuetorrentOutput);
|
||||
|
||||
|
||||
spawnSync('nix-fast-build', ['-f', `${FLAKE}#nixFastChecks`], {
|
||||
shell: true,
|
||||
stdio: [process.stdin, process.stdout, process.stderr],
|
||||
});
|
||||
|
||||
const output = [
|
||||
'chore: update flake.lock',
|
||||
`Flake Inputs:\n${flakeOutput}`,
|
||||
`Docker Images:\n${dockerOutput}`,
|
||||
`Firefox Addons:\n${firefoxOutput}`,
|
||||
`Misc Sources:\n${vuetorrentOutput}`,
|
||||
].join('\n\n');
|
||||
|
||||
if (args['f']) {
|
||||
writeFileSync(args['f'] as string, output);
|
||||
}
|
||||
else {
|
||||
console.log(output);
|
||||
}
|
||||
}
|
||||
|
||||
spawnSync('alejandra', ['-q', FLAKE], { shell: true });
|
|
@ -1,76 +0,0 @@
|
|||
import { spawnSync } from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
import { parseFetchurl } from './lib.ts';
|
||||
|
||||
/* Constants */
|
||||
const FLAKE = process.env.FLAKE;
|
||||
|
||||
|
||||
const updateFFZ = () => {
|
||||
const FILE = `${FLAKE}/legacyPackages/firefox-addons/default.nix`;
|
||||
const URL = 'https://cdn.frankerfacez.com/script/frankerfacez-4.0-an+fx.xpi';
|
||||
|
||||
const HASH = parseFetchurl(URL);
|
||||
|
||||
spawnSync('sed', ['-i', `'s,url = .*,url = \"${URL}\";,'`, FILE], { shell: true });
|
||||
spawnSync('sed', ['-i', `'s,sha256 = .*,sha256 = \"${HASH}\";,'`, FILE], { shell: true });
|
||||
};
|
||||
|
||||
export const updateFirefoxAddons = () => {
|
||||
console.log('Updating FFZ addon');
|
||||
updateFFZ();
|
||||
|
||||
console.log('Updating firefox addons using mozilla-addons-to-nix');
|
||||
|
||||
const DIR = `${FLAKE}/legacyPackages/firefox-addons`;
|
||||
const GENERATED_FILE = `${DIR}/generated-firefox-addons.nix`;
|
||||
const SLUGS = `${DIR}/addons.json`;
|
||||
|
||||
const nameMap = Object.fromEntries([...JSON.parse(readFileSync(SLUGS, 'utf-8'))]
|
||||
.map((addon) => [addon.slug, addon.pname || addon.slug]));
|
||||
|
||||
const nixExpr = `'
|
||||
x: let
|
||||
inherit (builtins) attrValues filter hasAttr isAttrs map;
|
||||
in
|
||||
map (d: d.name) (filter (y:
|
||||
isAttrs y &&
|
||||
hasAttr "type" y &&
|
||||
y.type == "derivation") (attrValues x))
|
||||
'`;
|
||||
|
||||
const OLD_VERS = Object.fromEntries([...JSON.parse(spawnSync('nix', [
|
||||
'eval',
|
||||
'.#legacyPackages.x86_64-linux.firefoxAddons',
|
||||
'--apply',
|
||||
nixExpr,
|
||||
'--json',
|
||||
], { shell: true }).stdout.toString())]
|
||||
.map((p) => {
|
||||
const pname = p.replace(/-[0-9].*$/, '');
|
||||
|
||||
return [pname, p.replace(`${pname}-`, '')];
|
||||
})
|
||||
.filter((pinfo) => pinfo[0] !== 'frankerfacez'));
|
||||
|
||||
const NEW_VERS = Object.fromEntries(spawnSync(
|
||||
'nix',
|
||||
['run', 'sourcehut:~rycee/mozilla-addons-to-nix',
|
||||
SLUGS, GENERATED_FILE],
|
||||
{ shell: true },
|
||||
).stdout
|
||||
.toString()
|
||||
.split('\n')
|
||||
.map((p) => {
|
||||
const pinfo = p.replace('Fetched ', '').split(' ');
|
||||
|
||||
return [nameMap[pinfo[0]], pinfo[2]];
|
||||
}));
|
||||
|
||||
return Object.keys(OLD_VERS)
|
||||
.sort()
|
||||
.filter((pname) => OLD_VERS[pname] !== NEW_VERS[pname])
|
||||
.map((pname) => `${pname}: ${OLD_VERS[pname]} -> ${NEW_VERS[pname]}`)
|
||||
.join('\n');
|
||||
};
|
|
@ -1,30 +0,0 @@
|
|||
import { spawnSync } from 'node:child_process';
|
||||
|
||||
|
||||
export const parseArgs = () => {
|
||||
const args = {} as Record<string, unknown>;
|
||||
let lastFlag: string | null = null;
|
||||
|
||||
for (let i = 2; i < process.argv.length; ++i) {
|
||||
const arg = process.argv[i];
|
||||
|
||||
if (arg.toString().startsWith('-')) {
|
||||
lastFlag = arg.toString().replace(/^-{1,2}/, '');
|
||||
args[lastFlag] = true;
|
||||
}
|
||||
else if (lastFlag) {
|
||||
args[lastFlag] = arg;
|
||||
lastFlag = null;
|
||||
}
|
||||
else {
|
||||
console.error(`Could not parse args: ${arg.toString()}`);
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
};
|
||||
|
||||
export const parseFetchurl = (url: string) => JSON.parse(spawnSync(
|
||||
'nix', ['store', 'prefetch-file', '--refresh', '--json',
|
||||
'--hash-type', 'sha256', url, '--name', '"escaped"'], { shell: true },
|
||||
).stdout.toString()).hash;
|
|
@ -1,75 +0,0 @@
|
|||
import { readdirSync, writeFileSync } from 'node:fs';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
|
||||
import { parseFetchurl } from './lib.ts';
|
||||
|
||||
|
||||
/* Constants */
|
||||
const FLAKE = process.env.FLAKE;
|
||||
|
||||
export const updateFlakeInputs = () => {
|
||||
const output = spawnSync(
|
||||
`git restore flake.lock &> /dev/null; nix flake update --flake ${FLAKE}` +
|
||||
' |& grep -v "warning: updating lock file"',
|
||||
[],
|
||||
{ shell: true },
|
||||
).stdout
|
||||
.toString()
|
||||
// Add an extra blank line between inputs
|
||||
.split('\n•')
|
||||
.join('\n\n•')
|
||||
// Shorten git revs to help readability
|
||||
.split('\n')
|
||||
.map((l) => l
|
||||
.replace(/.{33}\?narHash=sha256[^']*/, '')
|
||||
.replace(/&rev=(.{7})[^'&]*/, (_, backref) => `&rev=${backref}`))
|
||||
.join('\n');
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
export const updateDocker = () => {
|
||||
let updates = '';
|
||||
|
||||
const FILE = `${FLAKE}/devices/nos/modules/docker`;
|
||||
|
||||
readdirSync(FILE, { withFileTypes: true, recursive: true }).forEach((path) => {
|
||||
if (path.name === 'compose.nix') {
|
||||
console.log(`Updating ${path.parentPath.split('/').at(-1)} images`);
|
||||
updates += spawnSync('updateImages', [path.parentPath], { shell: true })
|
||||
.stdout.toString();
|
||||
}
|
||||
});
|
||||
|
||||
return updates;
|
||||
};
|
||||
|
||||
const genVueText = (version: string, hash: string, url: string) =>
|
||||
`# This file was autogenerated. DO NOT EDIT!
|
||||
{
|
||||
version = "${version}";
|
||||
url = "${url}";
|
||||
hash = "${hash}";
|
||||
}
|
||||
`;
|
||||
|
||||
export const updateVuetorrent = () => {
|
||||
const FILE = `${FLAKE}/devices/nos/modules/qbittorrent/vuetorrent.nix`;
|
||||
|
||||
const OLD_VERSION = JSON.parse(spawnSync('nix',
|
||||
['eval', '-f', FILE, '--json'],
|
||||
{ shell: true }).stdout.toString()).version;
|
||||
|
||||
const VERSION = JSON.parse(spawnSync('curl',
|
||||
['-s', 'https://api.github.com/repos/VueTorrent/VueTorrent/releases/latest'],
|
||||
{ shell: true }).stdout.toString()).tag_name.replace('v', '');
|
||||
|
||||
const URL = `https://github.com/VueTorrent/VueTorrent/releases/download/v${VERSION}/vuetorrent.zip`;
|
||||
const HASH = parseFetchurl(URL);
|
||||
|
||||
const fileText = genVueText(VERSION, HASH, URL);
|
||||
|
||||
writeFileSync(FILE, fileText);
|
||||
|
||||
return OLD_VERSION !== VERSION ? `Vuetorrent: ${OLD_VERSION} -> ${VERSION}` : '';
|
||||
};
|
|
@ -1,31 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
// Env
|
||||
"target": "ESNext",
|
||||
"lib": ["ESNext"],
|
||||
// Module
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext",
|
||||
"allowImportingTsExtensions": true,
|
||||
"baseUrl": ".",
|
||||
// Emit
|
||||
"noEmit": true,
|
||||
"newLine": "LF",
|
||||
// Interop
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"isolatedModules": true,
|
||||
// Type Checking
|
||||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"allowJs": true,
|
||||
"checkJs": true
|
||||
},
|
||||
"includes": [
|
||||
"*.ts",
|
||||
"**/*.ts",
|
||||
"*.js",
|
||||
"**/*.js"
|
||||
]
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
pkgs,
|
||||
self,
|
||||
}: let
|
||||
nixosMachines = import ./machines.nix {inherit pkgs self;};
|
||||
in
|
||||
nixosMachines
|
|
@ -1,10 +0,0 @@
|
|||
# CI: https://github.com/Mic92/dotfiles/blob/c2f538934d67417941f83d8bb65b8263c43d32ca/flake.nix#L168
|
||||
{
|
||||
pkgs,
|
||||
self,
|
||||
}: let
|
||||
inherit (pkgs.lib) filterAttrs mapAttrs' nameValuePair;
|
||||
in
|
||||
mapAttrs'
|
||||
(name: config: nameValuePair "nixos-${name}" config.config.system.build.toplevel)
|
||||
((filterAttrs (_: config: config.pkgs.system == pkgs.system)) self.nixosConfigurations)
|
|
@ -1,131 +0,0 @@
|
|||
{
|
||||
config,
|
||||
home-manager,
|
||||
lib,
|
||||
nh,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
./vars
|
||||
|
||||
./modules
|
||||
./packages.nix
|
||||
self.nixosModules.borgbackup
|
||||
|
||||
home-manager.nixosModules.home-manager
|
||||
];
|
||||
|
||||
boot.tmp.useTmpfs = true;
|
||||
|
||||
systemd.services.nix-daemon = {
|
||||
environment.TMPDIR = "/home/nix-cache";
|
||||
preStart = ''
|
||||
mkdir -p ${config.systemd.services.nix-daemon.environment.TMPDIR}
|
||||
'';
|
||||
};
|
||||
|
||||
nix = {
|
||||
package = pkgs.nixVersions.nix_2_24;
|
||||
|
||||
# Edit nix.conf
|
||||
settings = {
|
||||
# Store
|
||||
keep-outputs = true;
|
||||
keep-derivations = true;
|
||||
auto-optimise-store = true;
|
||||
|
||||
# Commands
|
||||
experimental-features = ["nix-command" "flakes"];
|
||||
http-connections = 0; # unlimited for local cache
|
||||
warn-dirty = false;
|
||||
show-trace = true;
|
||||
allow-import-from-derivation = true;
|
||||
|
||||
# remote building
|
||||
trusted-users = ["matt" "nixremote"];
|
||||
};
|
||||
};
|
||||
|
||||
programs.nh = {
|
||||
enable = true;
|
||||
package = nh.packages.${pkgs.system}.default;
|
||||
|
||||
# weekly cleanup
|
||||
clean = {
|
||||
enable = true;
|
||||
extraArgs = "--keep-since 30d";
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
fwupd.enable = true;
|
||||
|
||||
xserver.xkb = {
|
||||
layout = "ca";
|
||||
variant = "multix";
|
||||
};
|
||||
};
|
||||
|
||||
boot.supportedFilesystems = ["ext4" "xfs" "btrfs" "vfat" "ntfs"];
|
||||
system.fsPackages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
btrfs-progs
|
||||
nfs-utils
|
||||
ntfs3g
|
||||
xfsprogs
|
||||
;
|
||||
};
|
||||
|
||||
environment.variables.NPM_CONFIG_GLOBALCONFIG = "/etc/npmrc";
|
||||
environment.etc.npmrc.text = ''
|
||||
fund = false
|
||||
update-notifier = false
|
||||
'';
|
||||
|
||||
environment.systemPackages = builtins.attrValues {
|
||||
# Peripherals
|
||||
inherit
|
||||
(pkgs)
|
||||
hdparm
|
||||
pciutils
|
||||
usbutils
|
||||
rar
|
||||
;
|
||||
};
|
||||
|
||||
home-manager.users = let
|
||||
inherit (lib) mkIf mkOption types;
|
||||
inherit (config.vars) mainUser;
|
||||
|
||||
default = {
|
||||
imports = [
|
||||
# Make the vars be the same on Nix and HM
|
||||
{
|
||||
options.vars = mkOption {
|
||||
type = types.attrs;
|
||||
readOnly = true;
|
||||
default = config.vars;
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
programs.bash.sessionVariables = {
|
||||
FLAKE = config.environment.variables.FLAKE;
|
||||
};
|
||||
}
|
||||
|
||||
./home
|
||||
./home/trash-d
|
||||
];
|
||||
|
||||
home.stateVersion = config.system.stateVersion;
|
||||
};
|
||||
in {
|
||||
root = default;
|
||||
greeter = mkIf (config.services.greetd.enable) default;
|
||||
${mainUser} = default;
|
||||
};
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
# Check git status of nix configs
|
||||
fetchNix() {(
|
||||
cd "$FLAKE" || exit 1
|
||||
git fetch --all --quiet
|
||||
GIT=$(git -c color.status=always status |
|
||||
grep -v -e "On branch" \
|
||||
-e "up to date" \
|
||||
-e 'use "git' \
|
||||
-e "nothing to commit")
|
||||
|
||||
CHECK=$(echo "$GIT" | sed '/^$/d')
|
||||
|
||||
if [ "$CHECK" != "" ]; then
|
||||
echo "$GIT"
|
||||
echo
|
||||
fi
|
||||
)}
|
||||
|
||||
# Check for internet
|
||||
if wget -q --spider https://git.nelim.org; then
|
||||
fetchNix
|
||||
else
|
||||
echo "Offline"
|
||||
fi
|
||||
|
||||
# Pokemon Sprite
|
||||
pokemon-colorscripts -r 1-5
|
|
@ -1,31 +0,0 @@
|
|||
function colorgrid() {
|
||||
iter=16
|
||||
while [ $iter -lt 52 ]
|
||||
do
|
||||
second=$[$iter+36]
|
||||
third=$[$second+36]
|
||||
four=$[$third+36]
|
||||
five=$[$four+36]
|
||||
six=$[$five+36]
|
||||
seven=$[$six+36]
|
||||
if [ $seven -gt 250 ];then seven=$[$seven-251]; fi
|
||||
|
||||
echo -en "\033[38;5;$(echo $iter)m█ "
|
||||
printf "%03d" $iter
|
||||
echo -en " \033[38;5;$(echo $second)m█ "
|
||||
printf "%03d" $second
|
||||
echo -en " \033[38;5;$(echo $third)m█ "
|
||||
printf "%03d" $third
|
||||
echo -en " \033[38;5;$(echo $four)m█ "
|
||||
printf "%03d" $four
|
||||
echo -en " \033[38;5;$(echo $five)m█ "
|
||||
printf "%03d" $five
|
||||
echo -en " \033[38;5;$(echo $six)m█ "
|
||||
printf "%03d" $six
|
||||
echo -en " \033[38;5;$(echo $seven)m█ "
|
||||
printf "%03d" $seven
|
||||
|
||||
iter=$[$iter+1]
|
||||
printf '\r\n'
|
||||
done
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
# Modified from https://github.com/dracula/fzf
|
||||
|
||||
export FZF_DEFAULT_OPTS='--color=fg:#f8f8f2,hl:#bd93f9 --color=fg+:#f8f8f2,hl+:#bd93f9 --color=info:#ffb86c,prompt:#50fa7b,pointer:#ff79c6 --color=marker:#ff79c6,spinner:#ffb86c,header:#6272a4'
|
|
@ -1,10 +0,0 @@
|
|||
# Modified from https://github.com/dracula/man-pages
|
||||
|
||||
#man-page colors
|
||||
export LESS_TERMCAP_mb=$'\e[1;31m' # begin bold
|
||||
export LESS_TERMCAP_md=$'\e[1;34m' # begin blink
|
||||
export LESS_TERMCAP_so=$'\e[01;45;37m' # begin reverse video
|
||||
export LESS_TERMCAP_us=$'\e[01;36m' # begin underline
|
||||
export LESS_TERMCAP_me=$'\e[0m' # reset bold/blink
|
||||
export LESS_TERMCAP_se=$'\e[0m' # reset reverse video
|
||||
export LESS_TERMCAP_ue=$'\e[0m' # reset underline
|
|
@ -1,143 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) concatStrings fileContents;
|
||||
inherit (config.vars) promptColors;
|
||||
in {
|
||||
imports = [./programs.nix];
|
||||
|
||||
programs = {
|
||||
starship = {
|
||||
enable = true;
|
||||
enableBashIntegration = true;
|
||||
|
||||
settings = {
|
||||
format = concatStrings [
|
||||
"╭╴"
|
||||
"[](fg:${promptColors.firstColor})"
|
||||
"[ ](bg:${promptColors.firstColor} fg:#090c0c)"
|
||||
"[](bg:${promptColors.secondColor} fg:${promptColors.firstColor})"
|
||||
"$username$hostname"
|
||||
"[](fg:${promptColors.secondColor} bg:${promptColors.thirdColor})"
|
||||
"$directory"
|
||||
"[](fg:${promptColors.thirdColor} bg:${promptColors.fourthColor})"
|
||||
"$git_branch"
|
||||
"[](fg:${promptColors.fourthColor})$shlvl$nix_shell"
|
||||
"\n╰╴$character"
|
||||
];
|
||||
|
||||
username = {
|
||||
show_always = true;
|
||||
style_user = "fg:${promptColors.textColor} bg:${promptColors.secondColor}";
|
||||
style_root = "fg:red bg:${promptColors.secondColor} blink";
|
||||
format = "[ $user]($style)";
|
||||
};
|
||||
|
||||
hostname = {
|
||||
ssh_only = false;
|
||||
style = "fg:${promptColors.textColor} bg:${promptColors.secondColor}";
|
||||
format = "[@$hostname ]($style)";
|
||||
};
|
||||
|
||||
directory = {
|
||||
style = "fg:${promptColors.firstColor} bg:${promptColors.thirdColor}";
|
||||
format = "[ $path ]($style)";
|
||||
truncate_to_repo = false;
|
||||
truncation_length = 0;
|
||||
|
||||
substitutions = {
|
||||
"Documents" = " ";
|
||||
"Downloads" = " ";
|
||||
"Music" = " ";
|
||||
"Pictures" = " ";
|
||||
};
|
||||
};
|
||||
|
||||
git_branch = {
|
||||
style = "fg:${promptColors.secondColor} bg:${promptColors.fourthColor}";
|
||||
symbol = "";
|
||||
format = "[ $symbol $branch ]($style)";
|
||||
};
|
||||
|
||||
shlvl = {
|
||||
disabled = false;
|
||||
repeat = true;
|
||||
symbol = " ";
|
||||
format = "[ $symbol]($style)";
|
||||
threshold = 1;
|
||||
};
|
||||
|
||||
nix_shell = {
|
||||
symbol = "❄️ ";
|
||||
format = "[ $symbol]($style)";
|
||||
};
|
||||
|
||||
character = {
|
||||
success_symbol = "[\\$](bold green)";
|
||||
error_symbol = "[\\$](bold red)";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
bash = {
|
||||
enable = true;
|
||||
enableCompletion = true;
|
||||
|
||||
historyFile = "\$HOME/.cache/.bash_history";
|
||||
historyFileSize = 100000; # default
|
||||
historySize = 10000; # default
|
||||
historyControl = [
|
||||
"erasedups"
|
||||
"ignorespace"
|
||||
];
|
||||
historyIgnore = [
|
||||
"ls"
|
||||
"exit"
|
||||
"logout"
|
||||
];
|
||||
|
||||
shellOptions = [
|
||||
"histappend"
|
||||
"checkwinsize"
|
||||
"extglob"
|
||||
"globstar"
|
||||
"checkjobs"
|
||||
"autocd"
|
||||
"cdspell"
|
||||
"dirspell"
|
||||
"dotglob"
|
||||
];
|
||||
|
||||
shellAliases = {
|
||||
# Add whitespace after, to allow
|
||||
# sudo to inherit all other aliases
|
||||
sudo = "sudo ";
|
||||
|
||||
ls = "ls -lah --color=auto";
|
||||
tree = "tree -a -I node_modules";
|
||||
cp = "cp -r";
|
||||
};
|
||||
|
||||
#profileExtra = ''
|
||||
#'';
|
||||
bashrcExtra =
|
||||
# bash
|
||||
''
|
||||
# Check if shell is interactive
|
||||
[[ $- == *i* ]] || return 0
|
||||
|
||||
${fileContents ./config/dracula/less.sh}
|
||||
${fileContents ./config/dracula/fzf.sh}
|
||||
|
||||
${fileContents ./config/colorgrid.sh}
|
||||
${fileContents ./config/bashrc}
|
||||
'';
|
||||
#initExtra = ''
|
||||
#'';
|
||||
#logoutExtra = ''
|
||||
#'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
{
|
||||
pkgs,
|
||||
config,
|
||||
self,
|
||||
...
|
||||
}: {
|
||||
programs = {
|
||||
fzf = {
|
||||
enable = true;
|
||||
enableBashIntegration = true;
|
||||
};
|
||||
|
||||
bash = {
|
||||
sessionVariables = {
|
||||
inherit (config.home.sessionVariables) RIPGREP_CONFIG_PATH;
|
||||
};
|
||||
|
||||
shellAliases = {
|
||||
rg = "rga";
|
||||
cat = "bat ";
|
||||
man = "BAT_THEME='default' batman ";
|
||||
};
|
||||
};
|
||||
|
||||
ripgrep = {
|
||||
enable = true;
|
||||
package = pkgs.ripgrep-all;
|
||||
|
||||
arguments = [
|
||||
"--max-columns=150"
|
||||
"--max-columns-preview"
|
||||
"--hidden"
|
||||
"--glob=!.git/*"
|
||||
"--smart-case"
|
||||
"--sort"
|
||||
"path"
|
||||
];
|
||||
};
|
||||
|
||||
jq.enable = true;
|
||||
htop.enable = true;
|
||||
|
||||
bat = {
|
||||
enable = true;
|
||||
|
||||
config.theme = "dracula-bat";
|
||||
themes.dracula-bat.src = self.legacyPackages.${pkgs.system}.dracula.bat;
|
||||
|
||||
extraPackages = builtins.attrValues {
|
||||
inherit (pkgs.bat-extras) batman;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
{...}: {
|
||||
imports = [
|
||||
./bash
|
||||
./direnv
|
||||
./git
|
||||
./neovim
|
||||
./nix-index
|
||||
./tmux
|
||||
];
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
{pkgs, ...}: {
|
||||
programs.direnv = {
|
||||
enable = true;
|
||||
enableBashIntegration = true;
|
||||
|
||||
nix-direnv = {
|
||||
enable = true;
|
||||
package = pkgs.nix-direnv;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
{
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
mkRemoteConf = remote: email: name: {
|
||||
condition = "hasconfig:remote.*.url:${remote}:*/**";
|
||||
contents.user = {inherit email name;};
|
||||
};
|
||||
mkDefaultRemote = remote: mkRemoteConf remote "matt@nelim.org" "matt1432";
|
||||
in {
|
||||
programs = {
|
||||
git = {
|
||||
enable = true;
|
||||
package = pkgs.gitFull;
|
||||
|
||||
lfs.enable = true;
|
||||
|
||||
includes = [
|
||||
{path = toString self.legacyPackages.${pkgs.system}.dracula.git;}
|
||||
|
||||
(mkDefaultRemote "https://github.com")
|
||||
(mkDefaultRemote "git@github.com")
|
||||
(mkDefaultRemote "git@git.nelim.org")
|
||||
|
||||
(mkRemoteConf "git@gitlab.info.uqam.ca" "gj591944@ens.uqam.ca" "Mathis Hurtubise")
|
||||
];
|
||||
|
||||
delta = {
|
||||
enable = true;
|
||||
options = {
|
||||
side-by-side = true;
|
||||
line-numbers-zero-style = "#E6EDF3";
|
||||
};
|
||||
};
|
||||
|
||||
extraConfig = {
|
||||
diff.sopsdiffer.textconv = "sops --config /dev/null -d";
|
||||
|
||||
# https://github.com/dandavison/delta/issues/630#issuecomment-860046929
|
||||
pager = let
|
||||
cmd = "LESS='LRc --mouse' ${pkgs.delta}/bin/delta";
|
||||
in {
|
||||
diff = cmd;
|
||||
show = cmd;
|
||||
stash = cmd;
|
||||
log = cmd;
|
||||
reflog = cmd;
|
||||
};
|
||||
|
||||
sendemail = {
|
||||
smtpserver = "127.0.0.1";
|
||||
smtpuser = "matt@nelim.org";
|
||||
smtpencryption = "tls";
|
||||
smtpserverport = 1025;
|
||||
smtpsslcertpath = "";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
home.packages = [
|
||||
(pkgs.writeShellApplication {
|
||||
name = "chore";
|
||||
runtimeInputs = [pkgs.git];
|
||||
|
||||
text = ''
|
||||
DIR=''${1:-"$FLAKE"}
|
||||
|
||||
cd "$DIR" || exit 1
|
||||
|
||||
git add flake.lock
|
||||
git commit -m 'chore: update flake.lock'
|
||||
git push
|
||||
'';
|
||||
})
|
||||
];
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
# see https://github.com/CppCXY/EmmyLuaCodeStyle
|
||||
[*.lua]
|
||||
# [basic]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
quote_style = single
|
||||
|
||||
max_line_length = 120
|
||||
end_of_line = lf
|
||||
|
||||
table_separator_style = comma
|
||||
trailing_table_separator = smart
|
||||
|
||||
call_arg_parentheses = keep
|
||||
|
||||
# [space]
|
||||
space_around_table_field_list = true
|
||||
space_before_attribute = true
|
||||
space_before_function_open_parenthesis = false
|
||||
space_before_function_call_open_parenthesis = false
|
||||
space_before_closure_open_parenthesis = false
|
||||
space_before_function_call_single_arg = false
|
||||
space_before_open_square_bracket = false
|
||||
space_inside_function_call_parentheses = false
|
||||
space_inside_function_param_list_parentheses = false
|
||||
space_inside_square_brackets = false
|
||||
|
||||
# like t[#t+1] = 1
|
||||
space_around_table_append_operator = false
|
||||
ignore_spaces_inside_function_call = false
|
||||
|
||||
# detail number or 'keep'
|
||||
space_before_inline_comment = 1
|
||||
|
||||
# convert '---' to '--- ' or '--' to '-- '
|
||||
space_after_comment_dash = false
|
||||
|
||||
# [operator space]
|
||||
space_around_math_operator = true
|
||||
space_around_math_operator.exponent = false
|
||||
space_around_concat_operator = true
|
||||
space_around_logical_operator = true
|
||||
space_around_assign_operator = true
|
||||
|
||||
space_after_comma = true
|
||||
space_after_comma_in_for_statement = true
|
||||
|
||||
# [align]
|
||||
align_call_args = false
|
||||
align_function_params = true
|
||||
align_continuous_assign_statement = true
|
||||
align_continuous_rect_table_field = true
|
||||
align_continuous_line_space = 2
|
||||
align_if_branch = false
|
||||
|
||||
# option none / always / contain_curly/
|
||||
align_array_table = true
|
||||
|
||||
align_continuous_similar_call_args = false
|
||||
|
||||
align_continuous_inline_comment = true
|
||||
# option none / always / only_call_stmt
|
||||
align_chain_expr = none
|
||||
|
||||
# [indent]
|
||||
never_indent_before_if_condition = false
|
||||
never_indent_comment_on_if_branch = false
|
||||
keep_indents_on_empty_lines = false
|
||||
allow_non_indented_comments = false
|
||||
|
||||
# [line space]
|
||||
|
||||
# The following configuration supports four expressions
|
||||
# keep
|
||||
# fixed(n)
|
||||
# min(n)
|
||||
# max(n)
|
||||
# for eg. min(2)
|
||||
|
||||
line_space_after_if_statement = keep
|
||||
|
||||
line_space_after_do_statement = keep
|
||||
|
||||
line_space_after_while_statement = keep
|
||||
|
||||
line_space_after_repeat_statement = keep
|
||||
|
||||
line_space_after_for_statement = keep
|
||||
|
||||
line_space_after_local_or_assign_statement = keep
|
||||
|
||||
line_space_after_function_statement = fixed(2)
|
||||
|
||||
line_space_after_expression_statement = keep
|
||||
|
||||
line_space_after_comment = keep
|
||||
|
||||
line_space_around_block = fixed(1)
|
||||
|
||||
# [line break]
|
||||
break_all_list_when_line_exceed = false
|
||||
auto_collapse_lines = false
|
||||
break_before_braces = false
|
||||
|
||||
# [preference]
|
||||
ignore_space_after_colon = false
|
||||
end_statement_with_semicolon = always
|
|
@ -1,116 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
./git.nix
|
||||
./langs
|
||||
./theme.nix
|
||||
./treesitter.nix
|
||||
];
|
||||
|
||||
programs = {
|
||||
neovim = {
|
||||
enable = true;
|
||||
|
||||
extraLuaConfig =
|
||||
# lua
|
||||
''
|
||||
-- by default, the indent is 2 spaces.
|
||||
vim.opt.smartindent = true;
|
||||
vim.opt.expandtab = true;
|
||||
vim.opt.shiftwidth = 2;
|
||||
vim.opt.softtabstop = 2;
|
||||
vim.opt.tabstop = 2;
|
||||
|
||||
vim.opt.number = true;
|
||||
vim.opt.relativenumber = true;
|
||||
|
||||
vim.opt.undofile = true;
|
||||
vim.opt.undodir = '${config.xdg.cacheHome}/nvim/';
|
||||
|
||||
-- Always show the signcolumn, otherwise it would shift
|
||||
-- the text each time diagnostics appear/become resolved
|
||||
vim.opt.signcolumn = 'yes';
|
||||
|
||||
-- remove highlight on words
|
||||
vim.keymap.set('n', '<esc>', ':noh<cr><esc>', {
|
||||
noremap = true,
|
||||
silent = true,
|
||||
});
|
||||
|
||||
-- Get rid of deprecated messages
|
||||
vim.tbl_add_reverse_lookup = function(tbl)
|
||||
for k, v in pairs(tbl) do
|
||||
tbl[v] = k;
|
||||
end
|
||||
end;
|
||||
vim.tbl_islist = function(tbl)
|
||||
return vim.islist(tbl);
|
||||
end;
|
||||
vim.diagnostic.is_disabled = function()
|
||||
return not vim.diagnostic.is_enabled();
|
||||
end;
|
||||
vim.lsp.buf_get_clients = function()
|
||||
return vim.lsp.get_clients();
|
||||
end;
|
||||
vim.lsp.get_active_clients = function()
|
||||
return vim.lsp.get_clients();
|
||||
end;
|
||||
'';
|
||||
|
||||
plugins = [
|
||||
pkgs.vimPlugins.fzfWrapper
|
||||
pkgs.vimPlugins.fzf-vim
|
||||
|
||||
{
|
||||
plugin = pkgs.vimPlugins.todo-comments-nvim;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
require('todo-comments').setup();
|
||||
'';
|
||||
}
|
||||
{
|
||||
plugin = pkgs.vimPlugins.mini-nvim;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
-- TODO: see how this works
|
||||
local ts_input = require('mini.surround').gen_spec.input.treesitter;
|
||||
|
||||
require('mini.surround').setup({
|
||||
custom_surroundings = {
|
||||
-- Use tree-sitter to search for function call
|
||||
f = {
|
||||
input = ts_input({
|
||||
outer = '@call.outer',
|
||||
inner = '@call.inner',
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
plugin = pkgs.vimPlugins.nvim-config-local;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
require('config-local').setup({
|
||||
config_files = { '.nvim.lua', '.nvimrc', '.exrc' },
|
||||
|
||||
-- Where the plugin keeps files data
|
||||
hashfile = '${config.xdg.cacheHome}/nvim/config-local',
|
||||
});
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
{pkgs, ...}: {
|
||||
programs = {
|
||||
neovim = {
|
||||
plugins = [
|
||||
pkgs.vimPlugins.fugitive
|
||||
|
||||
{
|
||||
plugin = pkgs.vimPlugins.gitsigns-nvim;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
local gitsigns = require("gitsigns");
|
||||
|
||||
local function visual_stage()
|
||||
local first_line = vim.fn.line('v');
|
||||
local last_line = vim.fn.getpos('.')[2];
|
||||
gitsigns.stage_hunk({ first_line, last_line });
|
||||
end
|
||||
|
||||
vim.keymap.set("v", "gs", function()
|
||||
visual_stage()
|
||||
end);
|
||||
|
||||
gitsigns.setup();
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) getExe mkIf;
|
||||
inherit (config.vars) neovimIde;
|
||||
in {
|
||||
programs = {
|
||||
# I love doing typos
|
||||
bash.shellAliases = {
|
||||
nivm = "nvim";
|
||||
nivim = "nvim";
|
||||
};
|
||||
|
||||
neovim = {
|
||||
defaultEditor = true;
|
||||
viAlias = true;
|
||||
vimAlias = true;
|
||||
|
||||
extraPackages = mkIf neovimIde [
|
||||
pkgs.nodePackages.bash-language-server
|
||||
pkgs.shellcheck
|
||||
];
|
||||
|
||||
extraLuaConfig =
|
||||
mkIf neovimIde
|
||||
# lua
|
||||
''
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
pattern = 'sh',
|
||||
command = 'setlocal ts=4 sw=4 sts=0 expandtab',
|
||||
});
|
||||
|
||||
require('lspconfig').bashls.setup({
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
|
||||
settings = {
|
||||
bashIde = {
|
||||
shellcheckPath = '${getExe pkgs.shellcheck}',
|
||||
},
|
||||
},
|
||||
});
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
inherit (config.vars) neovimIde;
|
||||
in
|
||||
mkIf neovimIde {
|
||||
programs = {
|
||||
neovim = {
|
||||
extraPackages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
gcc
|
||||
clang-tools
|
||||
cmake-language-server
|
||||
;
|
||||
};
|
||||
|
||||
extraLuaConfig =
|
||||
# lua
|
||||
''
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
pattern = { 'cpp' , 'c'},
|
||||
command = 'setlocal ts=4 sw=4 sts=0 expandtab',
|
||||
});
|
||||
|
||||
local lsp = require('lspconfig');
|
||||
|
||||
lsp.cmake.setup({
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
});
|
||||
|
||||
lsp.clangd.setup({
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
|
||||
handlers = require('lsp-status').extensions.clangd.setup(),
|
||||
on_attach = function(_, bufnr)
|
||||
require("clangd_extensions.inlay_hints").setup_autocmd()
|
||||
require("clangd_extensions.inlay_hints").set_inlay_hints()
|
||||
end,
|
||||
});
|
||||
'';
|
||||
|
||||
plugins = builtins.attrValues {
|
||||
inherit (pkgs.vimPlugins) clangd_extensions-nvim;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) fileContents mkBefore mkIf;
|
||||
inherit (config.vars) neovimIde;
|
||||
in {
|
||||
imports = [
|
||||
./bash.nix
|
||||
./clang.nix
|
||||
./hyprlang.nix
|
||||
./java.nix
|
||||
./json.nix
|
||||
./lua.nix
|
||||
./markdown.nix
|
||||
./nix.nix
|
||||
./python.nix
|
||||
./rust.nix
|
||||
./web.nix
|
||||
];
|
||||
|
||||
programs = mkIf neovimIde {
|
||||
neovim = {
|
||||
extraLuaConfig =
|
||||
mkBefore
|
||||
# lua
|
||||
''
|
||||
-- Start completion / snippet stuff
|
||||
vim.g.coq_settings = {
|
||||
auto_start = 'shut-up',
|
||||
keymap = {
|
||||
recommended = false,
|
||||
},
|
||||
-- https://github.com/NixOS/nixpkgs/issues/168928#issuecomment-1109581739
|
||||
xdg = true,
|
||||
};
|
||||
|
||||
-- Add formatting cmd
|
||||
vim.api.nvim_create_user_command(
|
||||
'Format',
|
||||
function()
|
||||
vim.lsp.buf.format({ async = true });
|
||||
end,
|
||||
{}
|
||||
);
|
||||
|
||||
-- LSP-Status setup
|
||||
local lsp_status = require('lsp-status');
|
||||
lsp_status.register_progress();
|
||||
|
||||
-- Remove LSP highlighting to use Treesitter
|
||||
vim.api.nvim_create_autocmd('LspAttach', {
|
||||
callback = function(args)
|
||||
local client = vim.lsp.get_client_by_id(args.data.client_id);
|
||||
client.server_capabilities.semanticTokensProvider = nil;
|
||||
lsp_status.on_attach(client);
|
||||
end,
|
||||
});
|
||||
|
||||
-- Disable virtual_text since it's redundant due to lsp_lines.
|
||||
vim.diagnostic.config({
|
||||
virtual_text = false,
|
||||
});
|
||||
|
||||
require('lsp_lines').setup();
|
||||
'';
|
||||
|
||||
plugins =
|
||||
(builtins.attrValues {
|
||||
inherit
|
||||
(pkgs.vimPlugins)
|
||||
nvim-lspconfig
|
||||
lsp-status-nvim
|
||||
lsp_lines-nvim
|
||||
cmp-buffer
|
||||
cmp-nvim-lsp
|
||||
cmp-path
|
||||
cmp-spell
|
||||
vim-vsnip
|
||||
;
|
||||
})
|
||||
++ [
|
||||
{
|
||||
plugin = pkgs.vimPlugins.nvim-cmp;
|
||||
type = "lua";
|
||||
config = fileContents ../plugins/cmp.lua;
|
||||
}
|
||||
|
||||
{
|
||||
plugin = pkgs.vimPlugins.nvim-autopairs;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
require('nvim-autopairs').setup({});
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
inherit (config.vars) neovimIde;
|
||||
in
|
||||
mkIf neovimIde {
|
||||
programs = {
|
||||
neovim = {
|
||||
extraLuaConfig =
|
||||
# lua
|
||||
''
|
||||
vim.filetype.add({
|
||||
pattern = { ['.*/hypr/.*%.conf'] = 'hyprlang' },
|
||||
});
|
||||
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
pattern = 'hyprlang',
|
||||
command = 'setlocal ts=4 sw=4 sts=0 expandtab',
|
||||
});
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) getExe mkIf;
|
||||
inherit (config.vars) neovimIde;
|
||||
|
||||
javaSdk = pkgs.temurin-bin-17;
|
||||
javaPkgs = builtins.attrValues {inherit (pkgs) gradle maven;};
|
||||
in
|
||||
mkIf neovimIde {
|
||||
home.packages = javaPkgs;
|
||||
|
||||
xdg.dataFile.".gradle/gradle.properties".text = ''
|
||||
org.gradle.java.home = ${javaSdk}
|
||||
'';
|
||||
|
||||
programs = {
|
||||
java = {
|
||||
enable = true;
|
||||
package = javaSdk;
|
||||
};
|
||||
|
||||
neovim = {
|
||||
extraPackages = javaPkgs;
|
||||
|
||||
extraLuaConfig =
|
||||
# lua
|
||||
''
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
pattern = 'java',
|
||||
command = 'setlocal ts=4 sw=4 sts=0 expandtab',
|
||||
});
|
||||
'';
|
||||
|
||||
plugins = [
|
||||
{
|
||||
# TOOD: setup debugger https://github.com/mfussenegger/nvim-jdtls#debugger-via-nvim-dap
|
||||
plugin = pkgs.vimPlugins.nvim-jdtls;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
--
|
||||
local startJdtls = function()
|
||||
local config = {
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
|
||||
cmd = { '${getExe pkgs.jdt-language-server}' },
|
||||
root_dir = vim.fs.dirname(vim.fs.find(
|
||||
{ 'gradlew', '.git', 'mvnw', 'pom.xml' },
|
||||
{ upward = true }
|
||||
)[1]),
|
||||
|
||||
settings = {
|
||||
java = {
|
||||
configuration = {
|
||||
runtimes = {
|
||||
{
|
||||
name = 'JavaSE-17',
|
||||
path = '${javaSdk}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
require('jdtls').start_or_attach(config);
|
||||
end
|
||||
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
pattern = 'java',
|
||||
callback = startJdtls,
|
||||
});
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
inherit (config.vars) neovimIde;
|
||||
in
|
||||
mkIf neovimIde {
|
||||
programs = {
|
||||
neovim = {
|
||||
extraPackages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
vscode-langservers-extracted
|
||||
yaml-language-server
|
||||
;
|
||||
};
|
||||
|
||||
extraLuaConfig =
|
||||
# lua
|
||||
''
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
pattern = 'yaml',
|
||||
command = 'setlocal ts=4 sw=4 sts=0 expandtab',
|
||||
});
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
pattern = 'json',
|
||||
command = 'setlocal ts=4 sw=4 sts=0 expandtab',
|
||||
});
|
||||
|
||||
local lsp = require('lspconfig');
|
||||
|
||||
lsp.jsonls.setup({
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
});
|
||||
|
||||
lsp.yamlls.setup({
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
|
||||
settings = {
|
||||
yaml = {
|
||||
schemas = {
|
||||
[
|
||||
"https://json.schemastore.org/github-workflow.json"
|
||||
] = "/.github/workflows/*",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
inherit (config.vars) neovimIde;
|
||||
|
||||
flakeEnv = config.programs.bash.sessionVariables.FLAKE;
|
||||
in
|
||||
mkIf neovimIde {
|
||||
programs = {
|
||||
neovim = {
|
||||
extraPackages = builtins.attrValues {
|
||||
inherit (pkgs) lua-language-server;
|
||||
};
|
||||
|
||||
plugins = [
|
||||
{
|
||||
plugin = pkgs.vimPlugins.neodev-nvim;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
pattern = 'lua',
|
||||
command = 'setlocal ts=4 sw=4 sts=0 expandtab',
|
||||
});
|
||||
|
||||
-- IMPORTANT: make sure to setup neodev BEFORE lspconfig
|
||||
require("neodev").setup({
|
||||
override = function(root_dir, library)
|
||||
if root_dir:find('${flakeEnv}', 1, true) == 1 then
|
||||
library.enabled = true
|
||||
library.plugins = true
|
||||
end
|
||||
end,
|
||||
});
|
||||
|
||||
require('lspconfig').lua_ls.setup({
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
});
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
self,
|
||||
vimplugin-easytables-src,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
inherit (config.vars) neovimIde;
|
||||
|
||||
inherit (import "${self}/lib" {inherit pkgs;}) buildPlugin;
|
||||
in
|
||||
mkIf neovimIde {
|
||||
programs = {
|
||||
neovim = {
|
||||
extraPackages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
pandoc
|
||||
texlab
|
||||
texliveFull
|
||||
rubber
|
||||
;
|
||||
};
|
||||
|
||||
extraLuaConfig =
|
||||
# lua
|
||||
''
|
||||
local lsp = require('lspconfig');
|
||||
|
||||
lsp.texlab.setup({
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
|
||||
settings = {
|
||||
texlab = {
|
||||
formatterLineLength = 100,
|
||||
latexFormatter = 'latexindent',
|
||||
latexindent = {
|
||||
modifyLineBreaks = false,
|
||||
["local"] = '.indentconfig.yaml';
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
'';
|
||||
|
||||
plugins = [
|
||||
{
|
||||
plugin = buildPlugin "easytables-nvim" vimplugin-easytables-src;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
require('easytables').setup();
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
plugin = pkgs.vimPlugins.knap;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
--
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
pattern = 'tex',
|
||||
command = 'setlocal ts=4 sw=4 sts=0 expandtab',
|
||||
});
|
||||
|
||||
vim.g.knap_settings = {
|
||||
-- HTML
|
||||
htmloutputext = 'html',
|
||||
htmltohtml = 'none',
|
||||
htmltohtmlviewerlaunch = "",
|
||||
htmltohtmlviewerrefresh = 'none',
|
||||
|
||||
-- Markdown
|
||||
mdoutputext = 'html',
|
||||
markdownoutputext = 'html',
|
||||
|
||||
-- Markdown to PDF
|
||||
mdtopdf = 'pandoc %docroot% -o /tmp/%outputfile%',
|
||||
markdowntopdf = 'pandoc %docroot% -o /tmp/%outputfile%',
|
||||
mdtopdfviewerlaunch = 'sioyek /tmp/%outputfile%',
|
||||
markdowntopdfviewerlaunch = 'sioyek /tmp/%outputfile%',
|
||||
mdtopdfviewerrefresh = 'none',
|
||||
markdowntopdfviewerrefresh = "none",
|
||||
|
||||
-- Markdown to HTML
|
||||
mdtohtml = 'pandoc --standalone %docroot% -o /tmp/%outputfile%',
|
||||
markdowntohtml = 'pandoc --standalone %docroot% -o /tmp/%outputfile%',
|
||||
mdtohtmlviewerlaunch = 'firefox -new-window /tmp/%outputfile%',
|
||||
markdowntohtmlviewerlaunch = 'firefox -new-window /tmp/%outputfile%',
|
||||
mdtohtmlviewerrefresh = 'none',
|
||||
markdowntohtmlviewerrefresh = 'none',
|
||||
|
||||
-- LaTeX
|
||||
-- TODO: stop from polluting workspace
|
||||
};
|
||||
|
||||
-- F4 processes the document once, and refreshes the view
|
||||
vim.keymap.set({ 'n', 'v', 'i' }, '<F4>', function()
|
||||
require('knap').process_once();
|
||||
end);
|
||||
|
||||
-- F5 closes the viewer application, and
|
||||
-- allows settings to be reset
|
||||
vim.keymap.set({ 'n', 'v', 'i' }, '<F5>', function()
|
||||
require('knap').close_viewer();
|
||||
end);
|
||||
|
||||
-- F6 toggles the auto-processing on and off
|
||||
vim.keymap.set({ 'n', 'v', 'i' }, '<F6>', function()
|
||||
require('knap').toggle_autopreviewing();
|
||||
end);
|
||||
|
||||
-- F7 invokes a SyncTeX forward search, or similar,
|
||||
-- where appropriate
|
||||
vim.keymap.set({ 'n', 'v', 'i' }, '<F7>', function()
|
||||
require('knap').forward_jump();
|
||||
end);
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
nixd,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) getExe hasPrefix mkIf removePrefix;
|
||||
inherit (config.vars) hostName mainUser neovimIde;
|
||||
|
||||
defaultFormatter = self.formatter.${pkgs.system};
|
||||
|
||||
nixdPkg = nixd.packages.${pkgs.system}.default;
|
||||
|
||||
flakeEnv = config.programs.bash.sessionVariables.FLAKE;
|
||||
flakeDir = "${removePrefix "/home/${mainUser}/" flakeEnv}";
|
||||
in
|
||||
mkIf neovimIde {
|
||||
assertions = [
|
||||
{
|
||||
assertion =
|
||||
neovimIde
|
||||
&& hasPrefix "/home/${mainUser}/" flakeEnv
|
||||
|| !neovimIde;
|
||||
message = ''
|
||||
Your $FLAKE environment variable needs to point to a directory in
|
||||
the main users' home to use the neovim module.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = [
|
||||
defaultFormatter
|
||||
nixdPkg
|
||||
];
|
||||
|
||||
# nixd by default kinda spams LspLog
|
||||
home.sessionVariables.NIXD_FLAGS = "-log=error";
|
||||
|
||||
xdg.dataFile."${flakeDir}/.nixd.json".text = builtins.toJSON {
|
||||
nixpkgs = {
|
||||
expr = "import (builtins.getFlake \"${flakeDir}\").inputs.nixpkgs {}";
|
||||
};
|
||||
options.nixos = {
|
||||
expr = "(builtins.getFlake \"${flakeDir}\").nixosConfigurations.${hostName}.options";
|
||||
};
|
||||
};
|
||||
|
||||
programs = {
|
||||
neovim = {
|
||||
extraPackages = [
|
||||
nixdPkg
|
||||
];
|
||||
|
||||
extraLuaConfig =
|
||||
# lua
|
||||
''
|
||||
require('lspconfig').nixd.setup({
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
|
||||
filetypes = { 'nix', 'in.nix' },
|
||||
settings = {
|
||||
nixd = {
|
||||
formatting = {
|
||||
-- TODO: Try to find <flake>.formatter
|
||||
command = { '${getExe defaultFormatter}' },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
inherit (config.vars) neovimIde;
|
||||
in
|
||||
mkIf neovimIde {
|
||||
programs = {
|
||||
neovim = {
|
||||
withPython3 = true;
|
||||
|
||||
extraPackages = [
|
||||
pkgs.basedpyright
|
||||
];
|
||||
|
||||
extraLuaConfig =
|
||||
# lua
|
||||
''
|
||||
require('lspconfig').basedpyright.setup({
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
});
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
inherit (config.vars) neovimIde;
|
||||
in
|
||||
mkIf neovimIde {
|
||||
programs = {
|
||||
neovim = {
|
||||
extraPackages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
cargo
|
||||
rustc
|
||||
rust-analyzer
|
||||
rustfmt
|
||||
;
|
||||
};
|
||||
|
||||
extraLuaConfig =
|
||||
# lua
|
||||
''
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
pattern = { 'rust' },
|
||||
command = 'setlocal ts=4 sw=4 sts=0 expandtab',
|
||||
});
|
||||
|
||||
require('lspconfig').rust_analyzer.setup({
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
});
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
self,
|
||||
vimplugin-ts-error-translator-src,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
inherit (config.vars) neovimIde;
|
||||
|
||||
inherit (import "${self}/lib" {inherit pkgs;}) buildPlugin;
|
||||
in
|
||||
mkIf neovimIde {
|
||||
programs = {
|
||||
neovim = {
|
||||
withNodeJs = true;
|
||||
|
||||
extraPackages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
nodejs_latest
|
||||
vscode-langservers-extracted
|
||||
;
|
||||
|
||||
inherit
|
||||
(pkgs.nodePackages)
|
||||
npm
|
||||
neovim
|
||||
;
|
||||
};
|
||||
|
||||
extraLuaConfig =
|
||||
# lua
|
||||
''
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
pattern = { 'javascript', 'javascriptreact', 'javascript.jsx', 'typescript', 'typescriptreact', 'typescript.tsx', 'css', 'scss' },
|
||||
command = 'setlocal ts=4 sw=4 sts=0 expandtab',
|
||||
});
|
||||
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
pattern = 'html',
|
||||
command = 'setlocal ts=2 sw=2 expandtab',
|
||||
});
|
||||
|
||||
vim.api.nvim_create_autocmd('FileType', {
|
||||
pattern = 'scss',
|
||||
command = 'setlocal iskeyword+=@-@',
|
||||
});
|
||||
|
||||
local lsp = require('lspconfig');
|
||||
local tsserver = require('typescript-tools');
|
||||
|
||||
tsserver.setup({
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
|
||||
handlers = {
|
||||
-- format error code with better error message
|
||||
['textDocument/publishDiagnostics'] = function(err, result, ctx, config)
|
||||
require('ts-error-translator').translate_diagnostics(err, result, ctx, config)
|
||||
vim.lsp.diagnostic.on_publish_diagnostics(err, result, ctx, config)
|
||||
end,
|
||||
},
|
||||
});
|
||||
|
||||
lsp.eslint.setup({
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
|
||||
-- auto-save
|
||||
on_attach = function(client, bufnr)
|
||||
vim.api.nvim_create_autocmd('BufWritePre', {
|
||||
buffer = bufnr,
|
||||
command = 'EslintFixAll',
|
||||
});
|
||||
end,
|
||||
|
||||
settings = {
|
||||
validate = 'on',
|
||||
packageManager = 'npm',
|
||||
useESLintClass = true,
|
||||
useFlatConfig = true,
|
||||
experimental = {
|
||||
useFlatConfig = true,
|
||||
},
|
||||
codeAction = {
|
||||
disableRuleComment = {
|
||||
enable = true,
|
||||
location = 'separateLine'
|
||||
},
|
||||
showDocumentation = {
|
||||
enable = true,
|
||||
},
|
||||
},
|
||||
codeActionOnSave = {
|
||||
mode = 'all',
|
||||
rules = {},
|
||||
},
|
||||
format = true,
|
||||
quiet = false,
|
||||
onIgnoredFiles = 'off',
|
||||
rulesCustomizations = {},
|
||||
run = 'onType',
|
||||
problems = {
|
||||
shortenToSingleLine = false,
|
||||
},
|
||||
nodePath = "",
|
||||
workingDirectory = {
|
||||
mode = 'location',
|
||||
},
|
||||
options = {
|
||||
flags = {'unstable_ts_config'},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
lsp.cssls.setup({
|
||||
capabilities = require('cmp_nvim_lsp').default_capabilities(),
|
||||
|
||||
settings = {
|
||||
css = {
|
||||
validate = false,
|
||||
},
|
||||
less = {
|
||||
validate = false,
|
||||
},
|
||||
scss = {
|
||||
validate = false,
|
||||
},
|
||||
},
|
||||
});
|
||||
'';
|
||||
|
||||
plugins = [
|
||||
pkgs.vimPlugins.typescript-tools-nvim
|
||||
(buildPlugin "ts-error-translator" vimplugin-ts-error-translator-src)
|
||||
|
||||
{
|
||||
plugin = pkgs.vimPlugins.package-info-nvim;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
local packageInfo = require('package-info');
|
||||
packageInfo.setup({
|
||||
hide_up_to_date = true,
|
||||
package_manager = 'npm',
|
||||
});
|
||||
|
||||
vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile' }, {
|
||||
pattern = { 'package.json' },
|
||||
callback = function()
|
||||
packageInfo.show({ force = true });
|
||||
end,
|
||||
});
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
local cmp = require('cmp');
|
||||
local cmp_autopairs = require('nvim-autopairs.completion.cmp');
|
||||
|
||||
cmp.event:on(
|
||||
'confirm_done',
|
||||
cmp_autopairs.on_confirm_done()
|
||||
);
|
||||
|
||||
cmp.setup({
|
||||
sources = {
|
||||
{ name = 'nvim_lsp' },
|
||||
{ name = 'buffer' },
|
||||
{ name = 'path' },
|
||||
},
|
||||
|
||||
snippet = {
|
||||
expand = function(args)
|
||||
vim.fn['vsnip#anonymous'](args.body);
|
||||
end,
|
||||
},
|
||||
|
||||
mapping = {
|
||||
-- Confirm selection
|
||||
['<Right>'] = cmp.mapping.confirm({ select = true }),
|
||||
|
||||
-- Next selection
|
||||
['<Down>'] = cmp.mapping(function(fallback)
|
||||
if cmp.visible() then
|
||||
cmp.select_next_item();
|
||||
else
|
||||
fallback();
|
||||
end;
|
||||
end, {
|
||||
'i',
|
||||
's',
|
||||
}),
|
||||
|
||||
-- Previous selection
|
||||
['<Up>'] = cmp.mapping(function(fallback)
|
||||
if cmp.visible() then
|
||||
cmp.select_prev_item();
|
||||
else
|
||||
fallback();
|
||||
end;
|
||||
end, {
|
||||
'i',
|
||||
's',
|
||||
}),
|
||||
},
|
||||
});
|
|
@ -1,443 +0,0 @@
|
|||
-- Modified from https://github.com/lauranaujokat/nvim/blob/4102c789d05667f636107e3dae4ac589053ee88d/lua/setups/heirline.lua#L4
|
||||
|
||||
local conditions = require('heirline.conditions');
|
||||
local utils = require('heirline.utils');
|
||||
|
||||
---@class Palette
|
||||
---@field [string] any
|
||||
local dracula = require('dracula').colors();
|
||||
|
||||
local colors = {
|
||||
bright_bg = dracula.selection,
|
||||
dark_bg = dracula.menu,
|
||||
bright_fg = dracula.fg,
|
||||
red = dracula.red,
|
||||
dark_red = utils.get_highlight('DiffDelete').bg,
|
||||
green = dracula.green,
|
||||
blue = dracula.blue,
|
||||
gray = utils.get_highlight('NonText').fg,
|
||||
orange = utils.get_highlight('Constant').fg,
|
||||
purple = utils.get_highlight('Statement').fg,
|
||||
cyan = dracula.cyan,
|
||||
diag_warn = utils.get_highlight('DiagnosticWarn').fg,
|
||||
diag_error = utils.get_highlight('DiagnosticError').fg,
|
||||
diag_hint = utils.get_highlight('DiagnosticHint').fg,
|
||||
diag_info = utils.get_highlight('DiagnosticInfo').fg,
|
||||
git_del = utils.get_highlight('GitSignsDelete').fg,
|
||||
git_add = utils.get_highlight('GitSignsAdd').fg,
|
||||
git_change = utils.get_highlight('GitSignsChange').fg,
|
||||
};
|
||||
|
||||
require('heirline').load_colors(colors);
|
||||
|
||||
local ViMode = {
|
||||
-- get vim current mode, this information will be required by the provider
|
||||
-- and the highlight functions, so we compute it only once per component
|
||||
-- evaluation and store it as a component attribute
|
||||
init = function(self)
|
||||
self.mode = vim.fn.mode(1);
|
||||
|
||||
-- execute this only once, this is required if you want the ViMode
|
||||
-- component to be updated on operator pending mode
|
||||
if not self.once then
|
||||
vim.api.nvim_create_autocmd('ModeChanged', {
|
||||
pattern = '*:*o',
|
||||
command = 'redrawstatus',
|
||||
});
|
||||
self.once = true;
|
||||
end;
|
||||
end,
|
||||
|
||||
static = {
|
||||
mode_names = {
|
||||
n = 'N',
|
||||
no = 'N?',
|
||||
nov = 'N?',
|
||||
noV = 'N?',
|
||||
['no\22'] = 'N?',
|
||||
niI = 'Ni',
|
||||
niR = 'Nr',
|
||||
niV = 'Nv',
|
||||
nt = 'Nt',
|
||||
v = 'V',
|
||||
vs = 'Vs',
|
||||
V = 'V_',
|
||||
Vs = 'Vs',
|
||||
['\22'] = '^V',
|
||||
['\22s'] = '^V',
|
||||
s = 'S',
|
||||
S = 'S_',
|
||||
['\19'] = '^S',
|
||||
i = 'I',
|
||||
ic = 'Ic',
|
||||
ix = 'Ix',
|
||||
R = 'R',
|
||||
Rc = 'Rc',
|
||||
Rx = 'Rx',
|
||||
Rv = 'Rv',
|
||||
Rvc = 'Rv',
|
||||
Rvx = 'Rv',
|
||||
c = 'C',
|
||||
cv = 'Ex',
|
||||
r = '...',
|
||||
rm = 'M',
|
||||
['r?'] = '?',
|
||||
['!'] = '!',
|
||||
t = 'T',
|
||||
},
|
||||
|
||||
mode_colors = {
|
||||
n = 'red',
|
||||
i = 'green',
|
||||
v = 'cyan',
|
||||
V = 'cyan',
|
||||
['\22'] = 'cyan',
|
||||
c = 'orange',
|
||||
s = 'purple',
|
||||
S = 'purple',
|
||||
['\19'] = 'purple',
|
||||
R = 'orange',
|
||||
r = 'orange',
|
||||
['!'] = 'red',
|
||||
t = 'red',
|
||||
},
|
||||
},
|
||||
|
||||
-- To be extra meticulous, we can also add some vim statusline syntax to
|
||||
-- control the padding and make sure our string is always at least 2
|
||||
-- characters long. Plus a nice Icon.
|
||||
provider = function(self)
|
||||
return ' ' .. self.mode_names[self.mode] .. '%)';
|
||||
end,
|
||||
|
||||
-- Same goes for the highlight. Now the foreground will change according to the current mode.
|
||||
hl = function(self)
|
||||
local mode = self.mode:sub(1, 1); -- get only the first mode character
|
||||
return { fg = self.mode_colors[mode], bold = true };
|
||||
end,
|
||||
|
||||
-- Re-evaluate the component only on ModeChanged event
|
||||
update = {
|
||||
'ModeChanged',
|
||||
},
|
||||
};
|
||||
|
||||
local FileNameBlock = {
|
||||
init = function(self)
|
||||
self.filename = vim.api.nvim_buf_get_name(0);
|
||||
end,
|
||||
};
|
||||
|
||||
-- FileNameBlock children
|
||||
local FileIcon = {
|
||||
init = function(self)
|
||||
local filename = self.filename;
|
||||
local extension = vim.fn.fnamemodify(filename, ':e');
|
||||
self.icon, self.icon_color =
|
||||
require('nvim-web-devicons').get_icon_color(filename, extension, { default = true });
|
||||
end,
|
||||
|
||||
provider = function(self)
|
||||
return self.icon and (self.icon .. ' ');
|
||||
end,
|
||||
|
||||
hl = function(self)
|
||||
return { fg = self.icon_color };
|
||||
end,
|
||||
};
|
||||
|
||||
local FileName = {
|
||||
provider = function(self)
|
||||
-- first, trim the pattern relative to the current directory. For other
|
||||
-- options, see :h filename-modifers
|
||||
local filename = vim.fn.fnamemodify(self.filename, ':.');
|
||||
if filename == '' then
|
||||
return '[No Name]';
|
||||
end;
|
||||
-- now, if the filename would occupy more than 1/4th of the available
|
||||
-- space, we trim the file path to its initials
|
||||
-- See Flexible Components section below for dynamic truncation
|
||||
if not conditions.width_percent_below(#filename, 0.25) then
|
||||
filename = vim.fn.pathshorten(filename);
|
||||
end;
|
||||
return filename;
|
||||
end,
|
||||
|
||||
hl = { fg = utils.get_highlight('Directory').fg },
|
||||
};
|
||||
|
||||
local FileFlags = {
|
||||
{
|
||||
condition = function()
|
||||
return vim.bo.modified;
|
||||
end,
|
||||
provider = '[+]',
|
||||
hl = { fg = 'green' },
|
||||
},
|
||||
{
|
||||
condition = function()
|
||||
return not vim.bo.modifiable or vim.bo.readonly;
|
||||
end,
|
||||
provider = '',
|
||||
hl = { fg = 'orange' },
|
||||
},
|
||||
};
|
||||
|
||||
local FileNameModifer = {
|
||||
hl = function()
|
||||
if vim.bo.modified then
|
||||
-- use `force` because we need to override the child's hl foreground
|
||||
return { fg = 'cyan', bold = true, force = true };
|
||||
end;
|
||||
end,
|
||||
};
|
||||
|
||||
-- let's add the children to our FileNameBlock component
|
||||
FileNameBlock = utils.insert(
|
||||
FileNameBlock,
|
||||
FileIcon,
|
||||
utils.insert(FileNameModifer, FileName), -- a new table where FileName is a child of FileNameModifier
|
||||
unpack(FileFlags), -- A small optimisation, since their parent does nothing
|
||||
{ provider = '%<' } -- this means that the statusline is cut here when there's not enough space
|
||||
);
|
||||
|
||||
local Ruler = {
|
||||
provider = ' line: %l col: %c',
|
||||
hl = { fg = 'green', bold = false },
|
||||
};
|
||||
|
||||
local ScrollRuler = {
|
||||
-- %l = current line number
|
||||
-- %L = number of lines in the buffer
|
||||
-- %c = column number
|
||||
-- %P = percentage through file of displayed window
|
||||
provider = '%P',
|
||||
};
|
||||
|
||||
local ScrollBar = {
|
||||
static = {
|
||||
sbar = { '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█' },
|
||||
-- sbar = { '🭶', '🭷', '🭸', '🭹', '🭺', '🭻' }
|
||||
},
|
||||
|
||||
provider = function(self)
|
||||
local curr_line = vim.api.nvim_win_get_cursor(0)[1];
|
||||
local lines = vim.api.nvim_buf_line_count(0);
|
||||
local i = math.floor((curr_line - 1) / lines * #self.sbar) + 1;
|
||||
return string.rep(self.sbar[i], 2);
|
||||
end,
|
||||
|
||||
hl = { fg = 'cyan', bg = 'bright_bg' },
|
||||
};
|
||||
|
||||
local LSPActive = {
|
||||
condition = conditions.lsp_attached,
|
||||
update = { 'LspAttach', 'LspDetach' },
|
||||
|
||||
provider = function()
|
||||
local names = {};
|
||||
for _, server in pairs(vim.lsp.get_clients()) do
|
||||
table.insert(names, server.name);
|
||||
end;
|
||||
return ' [' .. table.concat(names, ' ') .. '] ';
|
||||
end,
|
||||
|
||||
hl = { fg = 'green', bold = false },
|
||||
};
|
||||
|
||||
local spinner_frames = { '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏' };
|
||||
|
||||
-- From https://github.com/mhartington/dotfiles/blob/5961460e3a492f7815259a692fca5ca2a1df924a/config/nvim/lua/mh/statusline/lsp_status.lua#L4
|
||||
local function get_lsp_progress()
|
||||
local messages = require('lsp-status/messaging').messages;
|
||||
local buf_messages = messages();
|
||||
local msgs = {};
|
||||
|
||||
for _, msg in ipairs(buf_messages) do
|
||||
local contents;
|
||||
|
||||
if msg.progress then
|
||||
contents = msg.title;
|
||||
|
||||
if msg.spinner then
|
||||
contents = spinner_frames[(msg.spinner % #spinner_frames) + 1] .. ' ' .. contents;
|
||||
end;
|
||||
elseif msg.status then
|
||||
contents = msg.content;
|
||||
|
||||
if msg.uri then
|
||||
local space = math.min(60, math.floor(0.6 * vim.fn.winwidth(0)));
|
||||
local filename = vim.uri_to_fname(msg.uri);
|
||||
|
||||
filename = vim.fn.fnamemodify(filename, ':~:.');
|
||||
|
||||
if #filename > space then
|
||||
filename = vim.fn.pathshorten(filename);
|
||||
end;
|
||||
|
||||
contents = '(' .. filename .. ') ' .. contents;
|
||||
end;
|
||||
else
|
||||
contents = msg.content;
|
||||
end;
|
||||
|
||||
table.insert(msgs, contents);
|
||||
end;
|
||||
|
||||
return table.concat(msgs, ' ');
|
||||
end;
|
||||
|
||||
local LSPMessages = {
|
||||
provider = function()
|
||||
local progress = get_lsp_progress();
|
||||
|
||||
if progress == '' then
|
||||
return '';
|
||||
else
|
||||
return ' ' .. progress;
|
||||
end;
|
||||
end,
|
||||
hl = { fg = 'purple' },
|
||||
};
|
||||
|
||||
local Diagnostics = {
|
||||
condition = conditions.has_diagnostics,
|
||||
|
||||
static = {
|
||||
error_icon = ' ',
|
||||
warn_icon = ' ',
|
||||
info_icon = ' ',
|
||||
hint_icon = ' ',
|
||||
},
|
||||
|
||||
init = function(self)
|
||||
self.errors = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.ERROR });
|
||||
self.warnings = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.WARN });
|
||||
self.hints = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.HINT });
|
||||
self.info = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.INFO });
|
||||
end,
|
||||
|
||||
update = { 'DiagnosticChanged', 'BufEnter' },
|
||||
|
||||
{
|
||||
provider = function(self)
|
||||
-- 0 is just another output, we can decide to print it or not!
|
||||
return self.errors > 0 and (self.error_icon .. self.errors);
|
||||
end,
|
||||
hl = { fg = 'diag_error' },
|
||||
},
|
||||
{
|
||||
provider = function(self)
|
||||
return self.warnings > 0 and (self.warn_icon .. self.warnings);
|
||||
end,
|
||||
hl = { fg = 'diag_warn' },
|
||||
},
|
||||
{
|
||||
provider = function(self)
|
||||
return self.info > 0 and (self.info_icon .. self.info);
|
||||
end,
|
||||
hl = { fg = 'diag_info' },
|
||||
},
|
||||
{
|
||||
provider = function(self)
|
||||
return self.hints > 0 and (self.hint_icon .. self.hints);
|
||||
end,
|
||||
hl = { fg = 'diag_hint' },
|
||||
},
|
||||
};
|
||||
|
||||
local Git = {
|
||||
condition = conditions.is_git_repo,
|
||||
|
||||
init = function(self)
|
||||
self.status_dict = vim.b.gitsigns_status_dict;
|
||||
self.has_changes = self.status_dict.added ~= 0 or
|
||||
self.status_dict.removed ~= 0 or
|
||||
self.status_dict.changed ~= 0;
|
||||
end,
|
||||
|
||||
hl = { fg = 'orange' },
|
||||
|
||||
{ -- git branch name
|
||||
provider = function(self)
|
||||
return ' ' .. self.status_dict.head;
|
||||
end,
|
||||
hl = { bold = true },
|
||||
},
|
||||
-- You could handle delimiters, icons and counts similar to Diagnostics
|
||||
{
|
||||
condition = function(self)
|
||||
return self.has_changes;
|
||||
end,
|
||||
provider = '(',
|
||||
},
|
||||
{
|
||||
provider = function(self)
|
||||
local count = self.status_dict.added or 0;
|
||||
return count > 0 and ('+' .. count);
|
||||
end,
|
||||
hl = { fg = 'git_add' },
|
||||
},
|
||||
{
|
||||
provider = function(self)
|
||||
local count = self.status_dict.removed or 0;
|
||||
return count > 0 and ('-' .. count);
|
||||
end,
|
||||
hl = { fg = 'git_del' },
|
||||
},
|
||||
{
|
||||
provider = function(self)
|
||||
local count = self.status_dict.changed or 0;
|
||||
return count > 0 and ('~' .. count);
|
||||
end,
|
||||
hl = { fg = 'git_change' },
|
||||
},
|
||||
{
|
||||
condition = function(self)
|
||||
return self.has_changes;
|
||||
end,
|
||||
provider = ')',
|
||||
},
|
||||
};
|
||||
|
||||
local Align = { provider = '%=' };
|
||||
local Space = { provider = ' ' };
|
||||
|
||||
Left = utils.surround({ '', '' }, 'bright_bg', { ViMode, Diagnostics, LSPMessages });
|
||||
Middle = utils.surround({ '', '' }, 'bright_bg', { LSPActive, FileNameBlock, Ruler });
|
||||
Right = utils.surround({ '', '' }, 'bright_bg', { Git, Space, ScrollRuler, Space, ScrollBar });
|
||||
|
||||
local DefaultStatusline = {
|
||||
hl = { bg = 'dark_bg' },
|
||||
condition = function()
|
||||
return true;
|
||||
end,
|
||||
Left,
|
||||
Align,
|
||||
Middle,
|
||||
Align,
|
||||
Right,
|
||||
};
|
||||
|
||||
local StatusLines = {
|
||||
hl = function()
|
||||
if conditions.is_active() then
|
||||
return 'StatusLine';
|
||||
else
|
||||
return 'StatusLineNC';
|
||||
end;
|
||||
end,
|
||||
|
||||
-- the first statusline with no condition, or which condition returns true is used.
|
||||
-- think of it as a switch case with breaks to stop fallthrough.
|
||||
fallthrough = false,
|
||||
|
||||
DefaultStatusline,
|
||||
};
|
||||
|
||||
-- Make it global
|
||||
vim.opt.laststatus = 3;
|
||||
|
||||
require('heirline').setup({
|
||||
statusline = StatusLines,
|
||||
});
|
|
@ -1,63 +0,0 @@
|
|||
-- Override netrw
|
||||
vim.g.loaded_netrw = 0;
|
||||
vim.g.loaded_netrwPlugin = 0;
|
||||
|
||||
require('neo-tree').setup({
|
||||
close_if_last_window = true,
|
||||
enable_refresh_on_write = true,
|
||||
|
||||
window = {
|
||||
width = 22,
|
||||
},
|
||||
|
||||
filesystem = {
|
||||
use_libuv_file_watcher = true,
|
||||
group_empty_dirs = true,
|
||||
|
||||
filtered_items = {
|
||||
visible = false,
|
||||
hide_dotfiles = false,
|
||||
hide_gitignored = false,
|
||||
hide_by_name = {},
|
||||
hide_by_pattern = {},
|
||||
always_show = {},
|
||||
never_show = {},
|
||||
never_show_by_pattern = {},
|
||||
},
|
||||
},
|
||||
|
||||
source_selector = {
|
||||
winbar = true,
|
||||
statusline = false,
|
||||
},
|
||||
|
||||
follow_current_file = {
|
||||
enabled = true,
|
||||
leave_dirs_open = true,
|
||||
},
|
||||
});
|
||||
|
||||
local function is_neotree_open()
|
||||
local manager = require('neo-tree.sources.manager');
|
||||
local renderer = require('neo-tree.ui.renderer');
|
||||
local state = manager.get_state('filesystem');
|
||||
return renderer.window_exists(state);
|
||||
end;
|
||||
|
||||
-- Auto open Neo-Tree on big enough window
|
||||
vim.api.nvim_create_autocmd({ 'VimEnter', 'VimResized' }, {
|
||||
pattern = '*',
|
||||
callback = function()
|
||||
if vim.api.nvim_eval([[&columns]]) > 100 then
|
||||
if is_neotree_open() == false then
|
||||
vim.cmd[[Neotree show]];
|
||||
vim.cmd[[Neotree close]];
|
||||
vim.cmd[[Neotree show]];
|
||||
end;
|
||||
else
|
||||
if is_neotree_open() then
|
||||
vim.cmd[[Neotree close]];
|
||||
end;
|
||||
end;
|
||||
end,
|
||||
});
|
|
@ -1,179 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
nvim-theme-src,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) fileContents optionals;
|
||||
inherit (config.vars) neovimIde;
|
||||
in {
|
||||
programs = {
|
||||
neovim = {
|
||||
extraPackages = builtins.attrValues {
|
||||
inherit (pkgs) bat;
|
||||
};
|
||||
|
||||
plugins =
|
||||
[
|
||||
{
|
||||
plugin = pkgs.vimPlugins.dracula-nvim.overrideAttrs {
|
||||
src = nvim-theme-src;
|
||||
};
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
-- set dot icon in place of trailing whitespaces
|
||||
vim.opt.listchars = {
|
||||
tab = '→ ',
|
||||
trail = '•',
|
||||
extends = '⟩',
|
||||
precedes = '⟨',
|
||||
nbsp = '␣',
|
||||
};
|
||||
vim.opt.list = true;
|
||||
|
||||
-- Add visual indicator for trailing whitespaces
|
||||
vim.opt.fillchars = { eob = " " };
|
||||
vim.fn.matchadd('errorMsg', [[\s\+$]]);
|
||||
|
||||
vim.cmd.colorscheme('dracula');
|
||||
'';
|
||||
}
|
||||
{
|
||||
plugin = pkgs.vimPlugins.indent-blankline-nvim;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
--
|
||||
local highlight = {
|
||||
"RainbowRed",
|
||||
"RainbowYellow",
|
||||
"RainbowBlue",
|
||||
"RainbowOrange",
|
||||
"RainbowGreen",
|
||||
"RainbowViolet",
|
||||
"RainbowCyan",
|
||||
};
|
||||
|
||||
local hooks = require('ibl.hooks');
|
||||
hooks.register(hooks.type.HIGHLIGHT_SETUP, function()
|
||||
vim.api.nvim_set_hl(0, "RainbowRed", { fg = "#E06C75" });
|
||||
vim.api.nvim_set_hl(0, "RainbowYellow", { fg = "#E5C07B" });
|
||||
vim.api.nvim_set_hl(0, "RainbowBlue", { fg = "#61AFEF" });
|
||||
vim.api.nvim_set_hl(0, "RainbowOrange", { fg = "#D19A66" });
|
||||
vim.api.nvim_set_hl(0, "RainbowGreen", { fg = "#98C379" });
|
||||
vim.api.nvim_set_hl(0, "RainbowViolet", { fg = "#C678DD" });
|
||||
vim.api.nvim_set_hl(0, "RainbowCyan", { fg = "#56B6C2" });
|
||||
end);
|
||||
|
||||
require('ibl').setup({
|
||||
indent = {
|
||||
highlight = highlight,
|
||||
char = "▏",
|
||||
},
|
||||
});
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
plugin = pkgs.vimPlugins.nvim-highlight-colors;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
-- Ensure termguicolors is enabled if not already
|
||||
vim.opt.termguicolors = true;
|
||||
|
||||
require('nvim-highlight-colors').setup({});
|
||||
'';
|
||||
}
|
||||
|
||||
# Deps of heirline config
|
||||
pkgs.vimPlugins.nvim-web-devicons
|
||||
{
|
||||
plugin = pkgs.vimPlugins.heirline-nvim;
|
||||
type = "lua";
|
||||
config = fileContents ./plugins/heirline.lua;
|
||||
}
|
||||
]
|
||||
++ optionals neovimIde [
|
||||
{
|
||||
plugin = pkgs.vimPlugins.neo-tree-nvim;
|
||||
type = "lua";
|
||||
config = fileContents ./plugins/neotree.lua;
|
||||
}
|
||||
{
|
||||
plugin = pkgs.vimPlugins.codewindow-nvim;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
--
|
||||
local codewindow = require('codewindow');
|
||||
|
||||
codewindow.setup({
|
||||
auto_enable = false,
|
||||
minimap_width = 8,
|
||||
relative = 'editor',
|
||||
window_border = 'none',
|
||||
exclude_filetypes = { 'help' },
|
||||
});
|
||||
|
||||
vim.api.nvim_create_autocmd({ 'VimEnter', 'VimResized' }, {
|
||||
pattern = '*',
|
||||
callback = function()
|
||||
if vim.api.nvim_win_get_width(0) < 88 then
|
||||
codewindow.close_minimap();
|
||||
else
|
||||
codewindow.open_minimap();
|
||||
end
|
||||
end,
|
||||
});
|
||||
'';
|
||||
}
|
||||
{
|
||||
plugin = pkgs.vimPlugins.transparent-nvim;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
require('transparent').setup({
|
||||
groups = {
|
||||
'Normal',
|
||||
'NormalNC',
|
||||
'Comment',
|
||||
'Constant',
|
||||
'Special',
|
||||
'Identifier',
|
||||
'Statement',
|
||||
'PreProc',
|
||||
'Type',
|
||||
'Underlined',
|
||||
'Todo',
|
||||
'String',
|
||||
'Function',
|
||||
'Conditional',
|
||||
'Repeat',
|
||||
'Operator',
|
||||
'Structure',
|
||||
'LineNr',
|
||||
'NonText',
|
||||
'SignColumn',
|
||||
'CursorLine',
|
||||
'CursorLineNr',
|
||||
'StatusLine',
|
||||
'StatusLineNC',
|
||||
'EndOfBuffer',
|
||||
},
|
||||
extra_groups = {},
|
||||
exclude_groups = {},
|
||||
});
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
{pkgs, ...}: {
|
||||
programs.neovim.plugins = [
|
||||
{
|
||||
plugin = pkgs.vimPlugins.nvim-treesitter-context;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
require('treesitter-context').setup({
|
||||
enable = true,
|
||||
max_lines = 3,
|
||||
min_window_height = 20,
|
||||
});
|
||||
|
||||
vim.cmd.hi('TreesitterContextBottom', 'gui=underline guisp=Grey');
|
||||
'';
|
||||
}
|
||||
|
||||
pkgs.vimPlugins.nvim-treesitter-textobjects
|
||||
|
||||
{
|
||||
plugin = pkgs.vimPlugins.nvim-treesitter.withAllGrammars;
|
||||
type = "lua";
|
||||
config =
|
||||
# lua
|
||||
''
|
||||
require('nvim-treesitter.configs').setup({
|
||||
highlight = { enable = true },
|
||||
indent = { enable = true },
|
||||
});
|
||||
'';
|
||||
}
|
||||
];
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
{nix-index-db, ...}: {
|
||||
imports = [nix-index-db.hmModules.nix-index];
|
||||
|
||||
programs = {
|
||||
nix-index-database.comma.enable = true;
|
||||
nix-index = {
|
||||
enable = true;
|
||||
enableBashIntegration = true;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
{pkgs, ...}: {
|
||||
programs = {
|
||||
# Make sure we have color support
|
||||
bash.shellAliases.tmux = "tmux -2";
|
||||
|
||||
tmux = {
|
||||
enable = true;
|
||||
mouse = true;
|
||||
keyMode = "vi";
|
||||
terminal = "tmux-256color";
|
||||
newSession = true;
|
||||
historyLimit = 30000;
|
||||
|
||||
plugins = builtins.attrValues {
|
||||
inherit (pkgs.tmuxPlugins) dracula;
|
||||
};
|
||||
|
||||
extraConfig =
|
||||
# bash
|
||||
''
|
||||
bind-key -n Home send Escape "OH"
|
||||
bind-key -n End send Escape "OF"
|
||||
bind -T root WheelUpPane if-shell -F -t = "#{alternate_on}" "send-keys -M" "select-pane -t =; copy-mode -e; send-keys -M"
|
||||
bind -T root WheelDownPane if-shell -F -t = "#{alternate_on}" "send-keys -M" "select-pane -t =; send-keys -M"
|
||||
|
||||
set -ga terminal-overrides ',xterm*:smcup@:rmcup@'
|
||||
set -ga terminal-overrides ",*256col*:Tc"
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: {
|
||||
home.packages = [self.packages.${pkgs.system}.trash-d];
|
||||
|
||||
programs.bash.shellAliases.rm = "trash";
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) foldl isList mergeAttrsWithFunc optionals unique;
|
||||
|
||||
mergeAttrsList = list:
|
||||
foldl (mergeAttrsWithFunc (a: b:
|
||||
if isList a && isList b
|
||||
then unique (a ++ b)
|
||||
else b)) {}
|
||||
list;
|
||||
in {
|
||||
environment.systemPackages = [
|
||||
(pkgs.writeShellApplication {
|
||||
name = "rebuild-no-cache";
|
||||
runtimeInputs = [config.programs.nh.package];
|
||||
text = ''
|
||||
nh os switch -- --option binary-caches "https://cache.nixos.org" "$@"
|
||||
'';
|
||||
})
|
||||
];
|
||||
|
||||
nix = {
|
||||
settings = let
|
||||
mkSubstituterConf = url: key: {
|
||||
substituters = [url];
|
||||
trusted-public-keys = optionals (key != null) [key];
|
||||
};
|
||||
in
|
||||
mergeAttrsList ([
|
||||
(mkSubstituterConf "https://cache.nixos.org" "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=")
|
||||
(mkSubstituterConf "https://hyprland.cachix.org" "hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc=")
|
||||
(mkSubstituterConf "https://nix-gaming.cachix.org" "nix-gaming.cachix.org-1:nbjlureqMbRAxR1gJ/f3hxemL9svXaZF/Ees8vCUUs4=")
|
||||
(mkSubstituterConf "https://nixpkgs-wayland.cachix.org" "nixpkgs-wayland.cachix.org-1:3lwxaILxMRkVhehr5StQprHdEo4IrE8sRho9R9HOLYA=")
|
||||
(mkSubstituterConf "https://nix-community.cachix.org" "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=")
|
||||
(mkSubstituterConf "https://viperml.cachix.org" "viperml.cachix.org-1:qZhKBMTfmcLL+OG6fj/hzsMEedgKvZVFRRAhq7j8Vh8=")
|
||||
(mkSubstituterConf "https://cuda-maintainers.cachix.org" "cuda-maintainers.cachix.org-1:0dq3bujKpuEPMCX6U4WylrUDZ9JyUG0VpVZa7CNfq5E=")
|
||||
]
|
||||
++ optionals (!config.services.nix-serve.enable) [
|
||||
(mkSubstituterConf "https://cache.nelim.org" "cache.nelim.org:JmFqkUdH11EA9EZOFAGVHuRYp7EbsdJDHvTQzG2pPyY=")
|
||||
]);
|
||||
};
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
{...}: {
|
||||
imports = [
|
||||
./cachix.nix
|
||||
./locale.nix
|
||||
./locate.nix
|
||||
./global.nix
|
||||
];
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
nixpkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (config.sops.secrets) access-token;
|
||||
inherit (lib) hasAttr optionalString;
|
||||
in {
|
||||
# Minimize dowloads of indirect nixpkgs flakes
|
||||
nix = {
|
||||
registry.nixpkgs.flake = nixpkgs;
|
||||
nixPath = ["nixpkgs=${nixpkgs}"];
|
||||
|
||||
extraOptions =
|
||||
optionalString (hasAttr "sops" config)
|
||||
"!include ${access-token.path}";
|
||||
};
|
||||
|
||||
# Global hm settings
|
||||
home-manager.useGlobalPkgs = true;
|
||||
home-manager.useUserPackages = true;
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
{pkgs, ...}: {
|
||||
fonts = {
|
||||
fontconfig = {
|
||||
enable = true;
|
||||
defaultFonts = {
|
||||
emoji = ["Noto Color Emoji"];
|
||||
monospace = ["JetBrainsMono Nerd Font"];
|
||||
sansSerif = ["Noto Nerd Font"];
|
||||
serif = ["Noto Nerd Font"];
|
||||
};
|
||||
};
|
||||
|
||||
packages =
|
||||
[
|
||||
(pkgs.nerdfonts.override {
|
||||
fonts = [
|
||||
"JetBrainsMono"
|
||||
"Go-Mono"
|
||||
"Iosevka"
|
||||
"NerdFontsSymbolsOnly"
|
||||
"SpaceMono"
|
||||
"Ubuntu"
|
||||
"Noto"
|
||||
];
|
||||
})
|
||||
]
|
||||
++ (builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
noto-fonts
|
||||
noto-fonts-cjk
|
||||
noto-fonts-emoji
|
||||
liberation_ttf
|
||||
font-awesome
|
||||
meslo-lgs-nf
|
||||
jetbrains-mono
|
||||
ubuntu_font_family
|
||||
;
|
||||
});
|
||||
};
|
||||
|
||||
# Select internationalisation properties.
|
||||
i18n.defaultLocale = "en_CA.UTF-8";
|
||||
console.useXkbConfig = true;
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (config.vars) mainUser;
|
||||
cfg = config.services.locate;
|
||||
|
||||
locateGroup = lib.getName cfg.package.name;
|
||||
|
||||
locate = "${cfg.package}/bin/locate";
|
||||
updatedb = "${cfg.package}/bin/updatedb";
|
||||
|
||||
database = "/var/lib/locate/locatedb";
|
||||
pruneFS = builtins.concatStringsSep " " cfg.pruneFS;
|
||||
pruneNames = builtins.concatStringsSep " " cfg.pruneNames;
|
||||
prunePaths = builtins.concatStringsSep " " cfg.prunePaths;
|
||||
|
||||
updatedbBin = ''
|
||||
${updatedb} -o ${database} --prunefs "${pruneFS}" \
|
||||
--prunepaths "${prunePaths}" --prunenames "${pruneNames}"
|
||||
'';
|
||||
in {
|
||||
users.users.${mainUser}.extraGroups = [
|
||||
locateGroup
|
||||
];
|
||||
|
||||
# TODO: add timer
|
||||
systemd.services.locate = {
|
||||
wantedBy = ["default.target"];
|
||||
serviceConfig = {
|
||||
User = mainUser;
|
||||
Group = locateGroup;
|
||||
StateDirectory = "locate";
|
||||
StateDirectoryMode = "0770";
|
||||
ExecStart = updatedbBin;
|
||||
};
|
||||
};
|
||||
|
||||
home-manager.users.${mainUser}.programs.bash.shellAliases = {
|
||||
locate = "${pkgs.writeShellScriptBin "lct" ''
|
||||
exec ${locate} -d ${database} "$@" 2> >(grep -v "/var/cache/locatedb")
|
||||
''}/bin/lct";
|
||||
|
||||
updatedb = updatedbBin;
|
||||
};
|
||||
|
||||
services.locate = {
|
||||
enable = true;
|
||||
package = pkgs.mlocate;
|
||||
localuser = null;
|
||||
interval = "never";
|
||||
|
||||
prunePaths = [
|
||||
"/var/lib/flatpak"
|
||||
|
||||
# Defaults
|
||||
"/tmp"
|
||||
"/var/tmp"
|
||||
"/var/cache"
|
||||
"/var/lock"
|
||||
"/var/run"
|
||||
"/var/spool"
|
||||
"/nix/var/log/nix"
|
||||
];
|
||||
|
||||
pruneNames = [
|
||||
"node_modules"
|
||||
|
||||
# Defaults
|
||||
".bzr"
|
||||
".cache"
|
||||
".git"
|
||||
".hg"
|
||||
".svn"
|
||||
];
|
||||
};
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
./vars
|
||||
./modules/global.nix
|
||||
./packages.nix
|
||||
];
|
||||
|
||||
nix = {
|
||||
# Edit nix.conf
|
||||
extraOptions = ''
|
||||
experimental-features = nix-command flakes
|
||||
keep-outputs = true
|
||||
keep-derivations = true
|
||||
warn-dirty = false
|
||||
'';
|
||||
|
||||
substituters = [
|
||||
# Nix-community
|
||||
"https://nix-community.cachix.org"
|
||||
];
|
||||
trustedPublicKeys = [
|
||||
# Nix-community
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
];
|
||||
};
|
||||
|
||||
# Global hm settings
|
||||
home-manager.config = {
|
||||
imports = [
|
||||
# Make the vars be the same on Nix and HM
|
||||
{
|
||||
options.vars = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
readOnly = true;
|
||||
default = config.vars;
|
||||
};
|
||||
}
|
||||
|
||||
./home
|
||||
|
||||
{
|
||||
programs.bash.sessionVariables = {
|
||||
FLAKE = config.environment.variables.FLAKE;
|
||||
};
|
||||
|
||||
programs.bash.shellAliases = {
|
||||
# Make ping work on nix-on-droid
|
||||
# https://github.com/nix-community/nix-on-droid/issues/185#issuecomment-1659294700
|
||||
ping = "/android/system/bin/linker64 /android/system/bin/ping";
|
||||
|
||||
# SSH
|
||||
# Desktop
|
||||
pc = "ssh -t matt@100.64.0.6 'tmux -2u new -At phone'";
|
||||
|
||||
# NAS
|
||||
nos = "ssh -t matt@100.64.0.4 'tmux -2u new -At phone'";
|
||||
|
||||
# Experimenting server
|
||||
servivi = "ssh -t matt@100.64.0.7 'tmux -2u new -At phone'";
|
||||
|
||||
# Home-assistant
|
||||
homie = "ssh -t matt@100.64.0.10 'tmux -2u new -At phone'";
|
||||
|
||||
# Cluster nodes
|
||||
thingone = "ssh -t matt@100.64.0.8 'tmux -2u new -At phone'";
|
||||
thingtwo = "ssh -t matt@100.64.0.9 'tmux -2u new -At phone'";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
home.stateVersion = "23.05";
|
||||
};
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
inputs @ {
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: {
|
||||
nixpkgs.overlays =
|
||||
(map (i: inputs.${i}.overlays.default) [
|
||||
"discord-overlay"
|
||||
"grim-hyprland"
|
||||
"nixpkgs-wayland"
|
||||
])
|
||||
++ (builtins.attrValues {
|
||||
inherit
|
||||
(self.overlays)
|
||||
xdg-desktop-portal-kde
|
||||
;
|
||||
});
|
||||
|
||||
environment.systemPackages =
|
||||
(builtins.attrValues {
|
||||
inherit
|
||||
(self.packages.${pkgs.system})
|
||||
pokemon-colorscripts
|
||||
repl
|
||||
;
|
||||
|
||||
inherit
|
||||
(pkgs.nodePackages)
|
||||
undollar
|
||||
;
|
||||
|
||||
inherit (pkgs) alejandra;
|
||||
|
||||
# Archiving
|
||||
inherit
|
||||
(pkgs)
|
||||
zip
|
||||
unzip
|
||||
p7zip
|
||||
bzip2
|
||||
gzip
|
||||
gnutar
|
||||
xz
|
||||
;
|
||||
|
||||
# File management
|
||||
inherit
|
||||
(pkgs)
|
||||
findutils
|
||||
diffutils
|
||||
utillinux
|
||||
which
|
||||
imagemagick
|
||||
;
|
||||
|
||||
# Networking
|
||||
inherit (pkgs.dig) dnsutils;
|
||||
inherit
|
||||
(pkgs)
|
||||
arp-scan
|
||||
openssh
|
||||
rsync
|
||||
wget
|
||||
gnupg
|
||||
;
|
||||
|
||||
# Misc CLI stuff
|
||||
inherit
|
||||
(pkgs)
|
||||
killall
|
||||
nix-output-monitor
|
||||
progress
|
||||
tree
|
||||
gnugrep
|
||||
gnused
|
||||
;
|
||||
|
||||
# Expected Stuff
|
||||
inherit
|
||||
(pkgs)
|
||||
hostname
|
||||
man
|
||||
perl
|
||||
tzdata
|
||||
;
|
||||
})
|
||||
++ [
|
||||
# This could help as well: nix derivation show -r /run/current-system
|
||||
(pkgs.writeShellApplication {
|
||||
name = "listDerivs";
|
||||
text = ''
|
||||
nix-store --query --requisites /run/current-system | cut -d- -f2- | sort -u
|
||||
'';
|
||||
})
|
||||
|
||||
(pkgs.writeShellApplication {
|
||||
name = "from";
|
||||
|
||||
runtimeInputs = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
coreutils
|
||||
which
|
||||
;
|
||||
};
|
||||
|
||||
text = ''
|
||||
for var do
|
||||
realpath "$(which "$var")"
|
||||
done
|
||||
'';
|
||||
})
|
||||
];
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkDefault mkOption types;
|
||||
flakeDir = config.environment.variables.FLAKE;
|
||||
cfg = config.vars;
|
||||
in {
|
||||
options.vars = {
|
||||
mainUser = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Username that was defined at the initial setup process
|
||||
'';
|
||||
};
|
||||
|
||||
hostName = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Hostname that was defined at the initial setup process
|
||||
'';
|
||||
};
|
||||
|
||||
promptMainColor = mkOption {
|
||||
type = types.enum (import ./prompt-schemes.nix {});
|
||||
default = "purple";
|
||||
};
|
||||
|
||||
promptColors = mkOption {
|
||||
description = ''
|
||||
Colors used in starship prompt
|
||||
'';
|
||||
|
||||
default = import ./prompt-schemes.nix {color = cfg.promptMainColor;};
|
||||
|
||||
readOnly = true;
|
||||
type = types.submodule {
|
||||
options = let
|
||||
inherit (types) str;
|
||||
in {
|
||||
textColor = mkOption {type = str;};
|
||||
firstColor = mkOption {type = str;};
|
||||
secondColor = mkOption {type = str;};
|
||||
thirdColor = mkOption {type = str;};
|
||||
fourthColor = mkOption {type = str;};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
configDir = mkOption {
|
||||
type = types.str;
|
||||
default = "${flakeDir}/devices/${cfg.hostName}/config";
|
||||
description = ''
|
||||
The path to where most of the devices' configs are in the .nix folder
|
||||
'';
|
||||
};
|
||||
|
||||
neovimIde = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
environment.variables.FLAKE = mkDefault "/home/${cfg.mainUser}/.nix";
|
||||
};
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
{color ? null}: let
|
||||
inherit (builtins) attrNames removeAttrs;
|
||||
|
||||
schemes = {
|
||||
"purple" = {
|
||||
textColor = "#090c0c";
|
||||
firstColor = "#bd93f9";
|
||||
secondColor = "#715895";
|
||||
thirdColor = "#382c4a";
|
||||
fourthColor = "#120e18";
|
||||
};
|
||||
|
||||
"green" = {
|
||||
textColor = "#090c0c";
|
||||
firstColor = "#78ae66";
|
||||
secondColor = "#567c49";
|
||||
thirdColor = "#334a2c";
|
||||
fourthColor = "#11180e";
|
||||
};
|
||||
|
||||
"red" = {
|
||||
textColor = "#090c0c";
|
||||
firstColor = "#e04242";
|
||||
secondColor = "#9c2e2e";
|
||||
thirdColor = "#591a1a";
|
||||
fourthColor = "#160606";
|
||||
};
|
||||
|
||||
"blue" = {
|
||||
textColor = "#090c0c";
|
||||
firstColor = "#6684ee";
|
||||
secondColor = "#475ca6";
|
||||
thirdColor = "#28345f";
|
||||
fourthColor = "#010617";
|
||||
};
|
||||
|
||||
"orange" = {
|
||||
textColor = "#090c0c";
|
||||
firstColor = "#ff9c42";
|
||||
secondColor = "#c66b00";
|
||||
thirdColor = "#874500";
|
||||
fourthColor = "#3a1c00";
|
||||
};
|
||||
|
||||
"yellow" = {
|
||||
textColor = "#090c0c";
|
||||
firstColor = "#ffea42";
|
||||
secondColor = "#d4c300";
|
||||
thirdColor = "#8f8b00";
|
||||
fourthColor = "#3e3c00";
|
||||
};
|
||||
|
||||
"cyan" = {
|
||||
textColor = "#090c0c";
|
||||
firstColor = "#42eaff";
|
||||
secondColor = "#00a2b8";
|
||||
thirdColor = "#005768";
|
||||
fourthColor = "#001f26";
|
||||
};
|
||||
|
||||
"pink" = {
|
||||
textColor = "#090c0c";
|
||||
firstColor = "#ff42cb";
|
||||
secondColor = "#b80073";
|
||||
thirdColor = "#6b003f";
|
||||
fourthColor = "#2d0017";
|
||||
};
|
||||
|
||||
# Template
|
||||
"color" = {
|
||||
textColor = "#090c0c";
|
||||
firstColor = "";
|
||||
secondColor = "";
|
||||
thirdColor = "";
|
||||
fourthColor = "";
|
||||
};
|
||||
};
|
||||
in
|
||||
if ! isNull color
|
||||
then schemes.${color}
|
||||
else attrNames (removeAttrs schemes ["color"])
|
129
conf/pkgs.log
Normal file
129
conf/pkgs.log
Normal file
|
@ -0,0 +1,129 @@
|
|||
acpi
|
||||
alacritty
|
||||
asp
|
||||
bat
|
||||
blueman
|
||||
bluez
|
||||
bluez-plugins
|
||||
bluez-tools
|
||||
bluez-utils
|
||||
brightnessctl
|
||||
cliphist
|
||||
cpio
|
||||
cups
|
||||
discord
|
||||
doctest
|
||||
dolphin
|
||||
dosfstools
|
||||
exfatprogs
|
||||
f2fs-tools
|
||||
ffmpeg-compat-57
|
||||
ffmpegthumbs
|
||||
firefox
|
||||
flatery-icon-theme-git
|
||||
fwupd
|
||||
galaxybudsclient-bin
|
||||
gimp
|
||||
git-lfs
|
||||
gnome-bluetooth-3.0
|
||||
gnome-calculator
|
||||
gnome-keyring
|
||||
gnome-themes-extra
|
||||
gparted
|
||||
grim
|
||||
grub-customizer
|
||||
gtklock
|
||||
gtklock-playerctl-module
|
||||
gtklock-powerbar-module
|
||||
gtklock-userinfo-module
|
||||
hplip
|
||||
hyprpaper-git
|
||||
iio-sensor-proxy-git
|
||||
jdk-temurin
|
||||
kde-cli-tools
|
||||
kdegraphics-thumbnailers
|
||||
kimageformats
|
||||
kio-admin
|
||||
kvantum
|
||||
libinput-gestures-git
|
||||
libreoffice-fresh
|
||||
light
|
||||
lostfiles
|
||||
nano
|
||||
neofetch
|
||||
neovim-git
|
||||
network-manager-applet
|
||||
nextcloud-client
|
||||
nilfs-utils
|
||||
nm-connection-editor
|
||||
nwg-look-bin
|
||||
otf-font-awesome
|
||||
pavucontrol
|
||||
photoqt
|
||||
pkgfile
|
||||
pokemon-colorscripts-git
|
||||
polkit-kde-agent
|
||||
progress
|
||||
python-evdev
|
||||
python-libevdev
|
||||
python-pyclip
|
||||
python-pyqt5
|
||||
python-pyqt5-3d
|
||||
python-pyqt5-chart
|
||||
python-pyqt5-datavisualization
|
||||
python-pyqt5-networkauth
|
||||
python-pyqt5-purchasing
|
||||
python-pyqt5-webengine
|
||||
python-pyqt6
|
||||
python-pyqt6-3d
|
||||
python-pyqt6-charts
|
||||
python-pyqt6-datavisualization
|
||||
python-pyqt6-networkauth
|
||||
python-pyqt6-webengine
|
||||
python-uinput
|
||||
qt5-charts
|
||||
qt5-imageformats
|
||||
qt5ct
|
||||
reiserfsprogs
|
||||
ripgrep
|
||||
rofi-lbonn-wayland-only-git
|
||||
rustup
|
||||
sddm-git
|
||||
seahorse
|
||||
slurp
|
||||
spicetify-cli-git
|
||||
spicetify-themes-git
|
||||
spotify-snapstore
|
||||
spotifywm-git
|
||||
squeekboard-git
|
||||
swappy-git
|
||||
swayidle
|
||||
swaync-git
|
||||
swayosd-git
|
||||
tablet-mode
|
||||
tlp
|
||||
ttf-font-awesome
|
||||
ttf-go-nerd
|
||||
ttf-jetbrains-mono
|
||||
ttf-jetbrains-mono-nerd
|
||||
ttf-meslo-nerd-font-powerlevel10k
|
||||
ttf-ms-win11-auto
|
||||
ttf-nerd-fonts-symbols
|
||||
ttf-nerd-fonts-symbols-common
|
||||
ttf-space-mono-nerd
|
||||
ttf-ubuntu-font-family
|
||||
ttf-ubuntu-nerd
|
||||
tutanota-desktop-bin
|
||||
waybar-hyprland-git
|
||||
waydroid-git
|
||||
wev
|
||||
wine-staging
|
||||
winetricks
|
||||
wl-clip-persist-git
|
||||
wl-color-picker
|
||||
xclip
|
||||
xdg-desktop-portal-hyprland-git
|
||||
xdg-utils
|
||||
xorg-xwayland
|
||||
zathura-pdf-mupdf
|
||||
zenity
|
1
conf/toinstall.sh
Executable file
1
conf/toinstall.sh
Executable file
|
@ -0,0 +1 @@
|
|||
yay -Sy acpi alacritty asp bat blueman bluez bluez-plugins bluez-tools bluez-utils brightnessctl cliphist cpio cups discord doctest dolphin dosfstools exfatprogs f2fs-tools ffmpeg-compat-57 ffmpegthumbs firefox flatery-icon-theme-git fwupd galaxybudsclient-bin gimp git-lfs gnome-bluetooth-3.0 gnome-calculator gnome-keyring gnome-themes-extra gparted grim grub-customizer gtklock gtklock-playerctl-module gtklock-powerbar-module gtklock-userinfo-module hplip hyprpaper-git iio-sensor-proxy-git jdk-temurin kde-cli-tools kdegraphics-thumbnailers kimageformats kio-admin kvantum libinput-gestures-git libreoffice-fresh light lostfiles nano neofetch neovim-git network-manager-applet nextcloud-client nilfs-utils nm-connection-editor nwg-look-bin otf-font-awesome pavucontrol photoqt pkgfile pokemon-colorscripts-git polkit-kde-agent progress python-evdev python-libevdev python-pyclip python-pyqt5 python-pyqt5-3d python-pyqt5-chart python-pyqt5-datavisualization python-pyqt5-networkauth python-pyqt5-purchasing python-pyqt5-webengine python-pyqt6 python-pyqt6-3d python-pyqt6-charts python-pyqt6-datavisualization python-pyqt6-networkauth python-pyqt6-webengine python-uinput qt5-charts qt5-imageformats qt5ct reiserfsprogs ripgrep rofi-lbonn-wayland-only-git rustup sddm-git seahorse slurp spicetify-cli-git spicetify-themes-git spotify-snapstore spotifywm-git squeekboard-git swappy-git swayidle swaync-git swayosd-git tablet-mode tlp ttf-font-awesome ttf-go-nerd ttf-jetbrains-mono ttf-jetbrains-mono-nerd ttf-meslo-nerd-font-powerlevel10k ttf-ms-win11-auto ttf-nerd-fonts-symbols ttf-nerd-fonts-symbols-common ttf-space-mono-nerd ttf-ubuntu-font-family ttf-ubuntu-nerd tutanota-desktop-bin waybar-hyprland-git waydroid-git wev wine-staging winetricks wl-clip-persist-git wl-color-picker xclip xdg-desktop-portal-hyprland-git xdg-utils xorg-xwayland zathura-pdf-mupdf zenity
|
|
@ -1,40 +0,0 @@
|
|||
# Devices
|
||||
|
||||
This directory encompasses every device's main configuration file.
|
||||
|
||||
## List of my Devices
|
||||
|
||||
| Name | Description |
|
||||
| ----------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| `android` | My [Nix-On-Droid](https://github.com/nix-community/nix-on-droid) configuration for my OnePlus 9 Pro |
|
||||
| `bbsteamie` | My wife's SteamDeck that has a pink case |
|
||||
| `binto` | My desktop PC with a multi-monitor setup and an NVIDIA (cringe) 3070 |
|
||||
| `cluster` | Two Lenovo mini PCs that make use of [NixOS-pcsd](https://github.com/matt1432/nixos-pcsd) to form a cluster |
|
||||
| `homie` | My Lenovo mini PC that will serve as a Home-assistant server |
|
||||
| `nos` | My custom built NAS |
|
||||
| `servivi` | A gaming PC in a previous life, it is now used as a build farm and hosts game servers |
|
||||
| `wim` | My 2-1 Lenovo Laptop that I use for uni |
|
||||
|
||||
## Global Vars
|
||||
|
||||
In every device's `default.nix`, you'll find these [settings](https://git.nelim.org/matt1432/nixos-configs/src/branch/master/common/vars.nix)
|
||||
|
||||
```nix
|
||||
# $FLAKE/devices/<name>/default.nix
|
||||
|
||||
vars = {
|
||||
mainUser = "matt";
|
||||
hostName = "wim";
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
from these declared settings, I get access to global variables
|
||||
that are different on each host using a 'let in' block:
|
||||
|
||||
```nix
|
||||
let
|
||||
inherit (config.vars) mainUser ...;
|
||||
in {
|
||||
...
|
||||
```
|
|
@ -1,58 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
vars = {
|
||||
mainUser = "nix-on-droid";
|
||||
hostName = "localhost";
|
||||
neovimIde = false;
|
||||
};
|
||||
|
||||
environment.variables.FLAKE = "/data/data/com.termux.nix/files/home/.nix";
|
||||
|
||||
terminal.font = "${(pkgs.nerdfonts.override {
|
||||
fonts = [
|
||||
"JetBrainsMono"
|
||||
];
|
||||
})}/share/fonts/truetype/NerdFonts/JetBrainsMonoNerdFontMono-Regular.ttf";
|
||||
|
||||
environment.packages = [
|
||||
(pkgs.writeShellApplication {
|
||||
name = "switch";
|
||||
runtimeInputs = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
coreutils
|
||||
nix-output-monitor
|
||||
nvd
|
||||
;
|
||||
};
|
||||
text = ''
|
||||
oldProfile=$(realpath /nix/var/nix/profiles/per-user/nix-on-droid/profile)
|
||||
|
||||
nix-on-droid ${lib.concatStringsSep " " [
|
||||
"switch"
|
||||
"--flake ${config.environment.variables.FLAKE}"
|
||||
"--builders ssh-ng://matt@100.64.0.7"
|
||||
''"$@"''
|
||||
"|&"
|
||||
"nom"
|
||||
]} &&
|
||||
|
||||
nvd diff "$oldProfile" "$(realpath /nix/var/nix/profiles/per-user/nix-on-droid/profile)"
|
||||
'';
|
||||
})
|
||||
];
|
||||
|
||||
environment.etcBackupExtension = ".bak";
|
||||
environment.motd = null;
|
||||
home-manager.backupFileExtension = "hm-bak";
|
||||
|
||||
# Set your time zone.
|
||||
time.timeZone = "America/Montreal";
|
||||
|
||||
# No touchy
|
||||
system.stateVersion = "23.05";
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
{
|
||||
config,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
inherit (config.vars) mainUser hostName;
|
||||
in {
|
||||
# ------------------------------------------------
|
||||
# Imports
|
||||
# ------------------------------------------------
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
|
||||
./modules
|
||||
|
||||
self.nixosModules.kmscon
|
||||
self.nixosModules.plymouth
|
||||
self.nixosModules.server
|
||||
];
|
||||
|
||||
# State Version: DO NOT CHANGE
|
||||
system.stateVersion = "24.11";
|
||||
|
||||
# ------------------------------------------------
|
||||
# User Settings
|
||||
# ------------------------------------------------
|
||||
vars = {
|
||||
mainUser = "mariah";
|
||||
hostName = "bbsteamie";
|
||||
promptMainColor = "pink";
|
||||
};
|
||||
|
||||
users.users.${mainUser} = {
|
||||
isNormalUser = true;
|
||||
extraGroups = [
|
||||
"wheel"
|
||||
"adm"
|
||||
];
|
||||
};
|
||||
|
||||
networking = {
|
||||
inherit hostName;
|
||||
networkmanager.enable = true;
|
||||
};
|
||||
|
||||
time.timeZone = "America/Montreal";
|
||||
|
||||
# ------------------------------------------------
|
||||
# `Self` Modules configuration
|
||||
# ------------------------------------------------
|
||||
roles.server = {
|
||||
user = mainUser;
|
||||
sshd.enable = true;
|
||||
};
|
||||
|
||||
boot.plymouth = {
|
||||
enable = true;
|
||||
theme = "bgrt";
|
||||
};
|
||||
|
||||
services.kmscon.enable = true;
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
{
|
||||
config,
|
||||
jovian,
|
||||
modulesPath,
|
||||
...
|
||||
}: {
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
nixpkgs.overlays = [jovian.overlays.default];
|
||||
imports = [
|
||||
(modulesPath + "/installer/scan/not-detected.nix")
|
||||
jovian.nixosModules.default
|
||||
];
|
||||
|
||||
jovian = {
|
||||
steamos.useSteamOSConfig = true;
|
||||
|
||||
devices.steamdeck = {
|
||||
enable = true;
|
||||
enableGyroDsuService = true;
|
||||
};
|
||||
hardware.has.amd.gpu = true;
|
||||
};
|
||||
|
||||
boot = {
|
||||
kernelModules = ["kvm-amd"];
|
||||
initrd.availableKernelModules = ["nvme" "xhci_pci" "usbhid" "sdhci_pci"];
|
||||
|
||||
loader = {
|
||||
efi.canTouchEfiVariables = true;
|
||||
|
||||
systemd-boot = {
|
||||
enable = true;
|
||||
configurationLimit = 30;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
virtualisation.waydroid.enable = true;
|
||||
|
||||
fileSystems = {
|
||||
"/" = {
|
||||
device = "/dev/disk/by-label/NIXROOT";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
"/boot" = {
|
||||
device = "/dev/disk/by-label/NIXBOOT";
|
||||
fsType = "vfat";
|
||||
options = ["fmask=0022" "dmask=0022"];
|
||||
};
|
||||
|
||||
"/run/media/mariah/SDCARD" = {
|
||||
device = "/dev/disk/by-label/SDCARD";
|
||||
fsType = "ext4";
|
||||
};
|
||||
};
|
||||
|
||||
swapDevices = [
|
||||
{
|
||||
device = "/.swapfile";
|
||||
size = 16 * 1024; # 16GB
|
||||
}
|
||||
];
|
||||
|
||||
hardware.cpu.amd.updateMicrocode = config.hardware.enableRedistributableFirmware;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
{...}: {
|
||||
imports = [
|
||||
./desktop
|
||||
];
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
{pkgs, ...}: let
|
||||
defaultSession = "plasma";
|
||||
in {
|
||||
imports = [
|
||||
(import ./session-switching.nix defaultSession)
|
||||
(import ./steam.nix defaultSession)
|
||||
];
|
||||
|
||||
services.desktopManager.plasma6.enable = true;
|
||||
|
||||
programs = {
|
||||
kdeconnect.enable = true;
|
||||
xwayland.enable = true;
|
||||
};
|
||||
|
||||
# Flatpak support for Discover
|
||||
services.flatpak.enable = true;
|
||||
services.packagekit.enable = true;
|
||||
|
||||
# Wayland env vars
|
||||
environment.variables = {
|
||||
NIXOS_OZONE_WL = "1";
|
||||
ELECTRON_OZONE_PLATFORM_HINT = "auto";
|
||||
};
|
||||
|
||||
environment.systemPackages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
firefox
|
||||
wl-clipboard
|
||||
xclip
|
||||
;
|
||||
|
||||
inherit
|
||||
(pkgs.kdePackages)
|
||||
discover
|
||||
krfb
|
||||
;
|
||||
};
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
# How to install Palia Map and Overwolf on Linux
|
||||
|
||||
Dependencies:
|
||||
- latest GE-Proton: https://github.com/GloriousEggroll/proton-ge-custom
|
||||
- protontricks: https://github.com/Matoking/protontricks
|
||||
- protonhax: https://github.com/jcnils/protonhax
|
||||
|
||||
|
||||
## First Step: Install and run Palia at least once
|
||||
|
||||
|
||||
## Second Step: Setup Palia WINEPREFIX with latest GE-Proton
|
||||
|
||||
1. Delete prefix at /home/"$USER"/.steam/steam/steamapps/compatdata/2707930/pfx
|
||||
|
||||
```bash
|
||||
rm -r /home/"$USER"/.steam/steam/steamapps/compatdata/2707930/pfx
|
||||
```
|
||||
|
||||
2. Launch Palia with GE-Proton by going to game properties -> Compatibility -> Force the use ... -> Select GE-Proton...
|
||||
|
||||
3. Install dotnet48 and other Windows deps to allow for Overwolf installation
|
||||
|
||||
```bash
|
||||
# Force proton version of protontricks
|
||||
export PROTON_VERSION="GE-Proton9-10"
|
||||
protontricks 2707930 dotnet48
|
||||
|
||||
# If VC is needed
|
||||
protontricks 2707930 vcrun2010
|
||||
protontricks 2707930 vcrun2012
|
||||
protontricks 2707930 vcrun2013
|
||||
```
|
||||
|
||||
|
||||
## Third Step: Install Overwolf
|
||||
|
||||
1. Get this older version that worked for me here: https://overwolf.en.uptodown.com/windows/download/4714215
|
||||
|
||||
2. Install it with protontricks. Follow the GUI installer as if you were on Windows
|
||||
|
||||
```bash
|
||||
export PROTON_VERSION="GE-Proton9-10"
|
||||
protontricks-launch --appid 2707930 Downloads/overwolf-0-195-0-18.exe
|
||||
```
|
||||
|
||||
|
||||
## Fourth Step: Install Palia Map
|
||||
|
||||
1. Get the installer from here: https://www.overwolf.com/app/Leon_Machens-Palia_Map
|
||||
|
||||
2. Install it with protontricks.
|
||||
|
||||
```bash
|
||||
export PROTON_VERSION="GE-Proton9-10"
|
||||
protontricks-launch --appid 2707930 Downloads/Palia\ Map\ -\ Installer.exe
|
||||
```
|
||||
|
||||
3. An error should popup saying `Installation failed` or something along those lines.
|
||||
Close it and wait. You should see the Overwolf overlay on the left side of your screen
|
||||
with the Palia Map icon saying `Installing` and then when it's done: `Palia Map`.
|
||||
|
||||
If nothing happens, try rebooting your PC and retrying the above shell commands until it works.
|
||||
|
||||
|
||||
## Final Step: Setting it up in Steam
|
||||
|
||||
1. Add this line to Palia launch options
|
||||
```bash
|
||||
protonhax init %command%
|
||||
```
|
||||
|
||||
2. Add random non-steam game to your library and then edit its properties:
|
||||
|
||||
Change the name to `Palia Map` or anything you like
|
||||
|
||||
Change the target to this command:
|
||||
|
||||
```bash
|
||||
protonhax run 2707930 "/home/$USER/.local/share/Steam/steamapps/compatdata/2707930/pfx/drive_c/users/steamuser/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Overwolf/Palia Map.lnk"
|
||||
```
|
|
@ -1,115 +0,0 @@
|
|||
defaultSession: {
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
config = let
|
||||
inherit (lib) findFirst getExe mkForce;
|
||||
|
||||
inherit (config.vars) mainUser;
|
||||
|
||||
switch-session = pkgs.writeShellApplication {
|
||||
name = "switch-session";
|
||||
|
||||
text = ''
|
||||
mkdir -p /etc/sddm.conf.d
|
||||
|
||||
cat <<EOF | tee /etc/sddm.conf.d/autologin.conf
|
||||
[Autologin]
|
||||
User=${mainUser}
|
||||
Session=$1
|
||||
Relogin=true
|
||||
EOF
|
||||
'';
|
||||
};
|
||||
|
||||
gaming-mode = pkgs.writeShellScriptBin "gaming-mode" ''
|
||||
sudo ${pkgs.systemd}/bin/systemctl start to-gaming-mode.service
|
||||
'';
|
||||
in {
|
||||
services.displayManager.sddm = {
|
||||
enable = true;
|
||||
autoLogin.relogin = true;
|
||||
|
||||
wayland = {
|
||||
enable = true;
|
||||
compositorCommand = "kwin";
|
||||
};
|
||||
};
|
||||
|
||||
# Sets the default session at launch
|
||||
systemd.services."set-session" = {
|
||||
wantedBy = ["multi-user.target"];
|
||||
before = ["display-manager.service"];
|
||||
|
||||
path = [switch-session];
|
||||
|
||||
script = ''
|
||||
switch-session "${defaultSession}"
|
||||
'';
|
||||
};
|
||||
|
||||
# Allows switching to gaming mode
|
||||
systemd.services."to-gaming-mode" = {
|
||||
wantedBy = mkForce [];
|
||||
|
||||
path = [switch-session];
|
||||
|
||||
script = ''
|
||||
switch-session "gamescope-wayland"
|
||||
systemctl restart display-manager
|
||||
sleep 10
|
||||
switch-session "${defaultSession}"
|
||||
'';
|
||||
};
|
||||
|
||||
# Make it so we don't need root to switch to gaming mode
|
||||
security.sudo.extraRules = [
|
||||
{
|
||||
users = [mainUser];
|
||||
groups = [100];
|
||||
commands = [
|
||||
{
|
||||
command = "${pkgs.systemd}/bin/systemctl start to-gaming-mode.service";
|
||||
options = ["SETENV" "NOPASSWD"];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
home-manager.users.${mainUser} = {
|
||||
# Add desktop entry to make it GUI friendly
|
||||
xdg.desktopEntries."Gaming Mode" = {
|
||||
name = "Gaming Mode";
|
||||
exec = getExe gaming-mode;
|
||||
icon = "steam";
|
||||
terminal = false;
|
||||
type = "Application";
|
||||
};
|
||||
|
||||
home.file."Desktop/Gaming Mode.desktop".source =
|
||||
(
|
||||
findFirst
|
||||
(x: x.meta.name == "Gaming Mode.desktop") {}
|
||||
config.home-manager.users.mariah.home.packages
|
||||
)
|
||||
+ "/share/applications/Gaming Mode.desktop";
|
||||
|
||||
# Fix remote control prompt showing up everytime
|
||||
xdg.configFile = let
|
||||
mkAutostart = name: flags: {
|
||||
"autostart/${name}.desktop".text = "[Desktop Entry]\nType=Application\nExec=${name} ${flags}";
|
||||
};
|
||||
in (
|
||||
# Needs xdg-desktop-portal-kde patch provided by `self.overlays.xdg-desktop-portal-kde`
|
||||
{"plasmaremotedesktoprc".text = "[Sharing]\nUnattended=true";}
|
||||
// (mkAutostart "krfb" "--nodialog %c")
|
||||
// (mkAutostart "steam" "-silent %U")
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
# For accurate stack trace
|
||||
_file = ./session-switching.nix;
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
defaultSession: {
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: {
|
||||
config = let
|
||||
inherit (config.vars) mainUser;
|
||||
|
||||
cfg = config.programs.steam;
|
||||
in {
|
||||
# Normal Steam Stuff
|
||||
programs.steam = {
|
||||
enable = true;
|
||||
protontricks.enable = true;
|
||||
|
||||
remotePlay.openFirewall = true;
|
||||
extraCompatPackages = [
|
||||
self.packages.${pkgs.system}.proton-ge-latest
|
||||
];
|
||||
};
|
||||
|
||||
# Jovian Steam settings
|
||||
jovian.steam = {
|
||||
# Steam > Settings > System > Enable Developer Mode
|
||||
# Steam > Developer > CEF Remote Debugging
|
||||
enable = true;
|
||||
user = mainUser;
|
||||
|
||||
environment = {
|
||||
STEAM_EXTRA_COMPAT_TOOLS_PATHS =
|
||||
lib.makeSearchPathOutput
|
||||
"steamcompattool"
|
||||
""
|
||||
cfg.extraCompatPackages;
|
||||
};
|
||||
|
||||
desktopSession = defaultSession;
|
||||
};
|
||||
|
||||
# Decky settings
|
||||
jovian.decky-loader = {
|
||||
enable = true;
|
||||
user = mainUser;
|
||||
stateDir = "/home/${mainUser}/.local/share/decky"; # Keep scoped to user
|
||||
# https://github.com/Jovian-Experiments/Jovian-NixOS/blob/1171169117f63f1de9ef2ea36efd8dcf377c6d5a/modules/decky-loader.nix#L80-L84
|
||||
|
||||
extraPackages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
curl
|
||||
unzip
|
||||
util-linux
|
||||
gnugrep
|
||||
readline
|
||||
procps
|
||||
pciutils
|
||||
libpulseaudio
|
||||
;
|
||||
};
|
||||
};
|
||||
|
||||
# Misc Packages
|
||||
environment.systemPackages = [
|
||||
pkgs.steam-rom-manager
|
||||
pkgs.r2modman
|
||||
|
||||
self.packages.${pkgs.system}.protonhax
|
||||
|
||||
# Ryujinx ACNH crashes on Vulkan
|
||||
pkgs.ryujinx
|
||||
];
|
||||
};
|
||||
|
||||
# For accurate stack trace
|
||||
_file = ./steam.nix;
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
# Cosmetic
|
||||
general {
|
||||
gaps_in = 10
|
||||
gaps_out = 20
|
||||
border_size = 0
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
{
|
||||
config,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
inherit (config.vars) mainUser hostName;
|
||||
in {
|
||||
# ------------------------------------------------
|
||||
# Imports
|
||||
# ------------------------------------------------
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
|
||||
./modules
|
||||
|
||||
self.nixosModules.adb
|
||||
self.nixosModules.desktop
|
||||
self.nixosModules.kmscon
|
||||
self.nixosModules.server
|
||||
];
|
||||
|
||||
home-manager.users.${mainUser}.imports = [
|
||||
self.homeManagerModules.firefox
|
||||
];
|
||||
|
||||
# State Version: DO NOT CHANGE
|
||||
system.stateVersion = "23.11";
|
||||
|
||||
# ------------------------------------------------
|
||||
# User Settings
|
||||
# ------------------------------------------------
|
||||
vars = {
|
||||
mainUser = "matt";
|
||||
hostName = "binto";
|
||||
promptMainColor = "purple";
|
||||
};
|
||||
|
||||
users.users.${mainUser} = {
|
||||
isNormalUser = true;
|
||||
extraGroups = [
|
||||
"wheel"
|
||||
"input"
|
||||
"uinput"
|
||||
"adm"
|
||||
"video"
|
||||
"libvirtd"
|
||||
];
|
||||
};
|
||||
|
||||
networking = {
|
||||
inherit hostName;
|
||||
networkmanager.enable = true;
|
||||
firewall.enable = false;
|
||||
};
|
||||
|
||||
time.timeZone = "America/Montreal";
|
||||
|
||||
# ------------------------------------------------
|
||||
# `Self` Modules configuration
|
||||
# ------------------------------------------------
|
||||
roles.desktop = {
|
||||
user = mainUser;
|
||||
|
||||
ags.enable = true;
|
||||
mainMonitor = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. G27QC 0x00000B1D";
|
||||
displayManager.duplicateScreen = false;
|
||||
|
||||
fontSize = 12.5;
|
||||
};
|
||||
|
||||
roles.server = {
|
||||
user = mainUser;
|
||||
tailscale.enable = true;
|
||||
sshd.enable = true;
|
||||
};
|
||||
|
||||
programs.adb = {
|
||||
enable = true;
|
||||
user = mainUser;
|
||||
};
|
||||
|
||||
services.kmscon.enable = true;
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
{
|
||||
config,
|
||||
modulesPath,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
imports = [(modulesPath + "/installer/scan/not-detected.nix")];
|
||||
|
||||
boot = {
|
||||
kernelPackages = pkgs.linuxPackages_zen;
|
||||
|
||||
kernelParams = ["amd_pstate=active"];
|
||||
kernelModules = ["kvm-amd"];
|
||||
|
||||
# Zenpower for ryzen cpu monitoring
|
||||
extraModulePackages = builtins.attrValues {
|
||||
inherit
|
||||
(config.boot.kernelPackages)
|
||||
v4l2loopback
|
||||
zenpower
|
||||
;
|
||||
};
|
||||
blacklistedKernelModules = ["k10temp"];
|
||||
|
||||
supportedFilesystems = ["ntfs"];
|
||||
|
||||
consoleLogLevel = 0;
|
||||
|
||||
initrd = {
|
||||
verbose = false;
|
||||
systemd.enable = true;
|
||||
availableKernelModules = ["nvme" "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod"];
|
||||
};
|
||||
|
||||
loader = {
|
||||
efi.canTouchEfiVariables = true;
|
||||
timeout = 2;
|
||||
|
||||
systemd-boot = {
|
||||
enable = true;
|
||||
consoleMode = "max";
|
||||
configurationLimit = 30;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fileSystems = {
|
||||
"/" = {
|
||||
device = "/dev/disk/by-label/NIXROOT";
|
||||
fsType = "btrfs";
|
||||
};
|
||||
|
||||
# sudo btrfs subvolume create /@swap
|
||||
"/swap" = {
|
||||
device = "/dev/disk/by-label/NIXROOT";
|
||||
fsType = "btrfs";
|
||||
# Idk why this is the subvol
|
||||
options = ["subvol=@/@swap"];
|
||||
};
|
||||
|
||||
"/boot" = {
|
||||
device = "/dev/disk/by-label/NIXBOOT";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
"/run/media/matt/Games" = {
|
||||
device = "/dev/disk/by-uuid/da62f4ee-d4a6-4fdd-ab12-9c5e131c6f30";
|
||||
fsType = "ext4";
|
||||
};
|
||||
};
|
||||
|
||||
swapDevices = [
|
||||
{
|
||||
device = "/swap/swapfile";
|
||||
size = 16 * 1024;
|
||||
}
|
||||
];
|
||||
|
||||
zramSwap.enable = true;
|
||||
|
||||
hardware = {
|
||||
cpu.amd.updateMicrocode = config.hardware.enableRedistributableFirmware;
|
||||
uinput.enable = true;
|
||||
};
|
||||
|
||||
virtualisation = {
|
||||
libvirtd.enable = true;
|
||||
spiceUSBRedirection.enable = true;
|
||||
};
|
||||
environment.systemPackages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
qemu
|
||||
virtiofsd
|
||||
;
|
||||
};
|
||||
|
||||
nvidia = {
|
||||
enable = true;
|
||||
enableNvidiaSettings = true;
|
||||
enableWayland = true;
|
||||
enableCUDA = true;
|
||||
};
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{...}: {
|
||||
imports = [
|
||||
./gpu-replay.nix
|
||||
./nix-gaming.nix
|
||||
];
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) concatStringsSep removePrefix;
|
||||
|
||||
inherit (config.vars) mainUser;
|
||||
|
||||
cfgDesktop = config.roles.desktop;
|
||||
|
||||
gsr = self.packages.${pkgs.system}.gpu-screen-recorder;
|
||||
hyprPkgs = config.home-manager.users.${mainUser}.wayland.windowManager.hyprland.finalPackage;
|
||||
in {
|
||||
security.wrappers = {
|
||||
gpu-screen-recorder = {
|
||||
owner = "root";
|
||||
group = "video";
|
||||
capabilities = "cap_sys_nice+ep";
|
||||
source = "${gsr}/bin/gpu-screen-recorder";
|
||||
};
|
||||
|
||||
gsr-kms-server = {
|
||||
owner = "root";
|
||||
group = "video";
|
||||
capabilities = "cap_sys_admin+ep";
|
||||
source = "${gsr}/bin/gsr-kms-server";
|
||||
};
|
||||
};
|
||||
|
||||
home-manager.users.${mainUser} = {
|
||||
home.packages = [
|
||||
gsr
|
||||
|
||||
(pkgs.writeShellApplication {
|
||||
name = "gpu-save-replay";
|
||||
runtimeInputs = [pkgs.procps];
|
||||
text = ''
|
||||
pkill --signal SIGUSR1 -f gpu-screen-recorder
|
||||
'';
|
||||
})
|
||||
|
||||
(pkgs.writeShellApplication {
|
||||
name = "gsr-start";
|
||||
runtimeInputs = [pkgs.pulseaudio hyprPkgs pkgs.xorg.xrandr];
|
||||
text = ''
|
||||
main="${removePrefix "desc:" cfgDesktop.mainMonitor}"
|
||||
WINDOW=$(hyprctl -j monitors | jq '.[] |= (.description |= gsub(","; ""))' | jq -r ".[] | select(.description | test(\"$main\")) | .name")
|
||||
|
||||
# Fix fullscreen game resolution
|
||||
xrandr --output "$WINDOW" --primary
|
||||
|
||||
gpu-screen-recorder ${concatStringsSep " " [
|
||||
''-v no''
|
||||
''-r 1200''
|
||||
''-mf yes''
|
||||
''-o /home/matt/Videos/Replay''
|
||||
# Audio settings
|
||||
''-ac aac''
|
||||
''-a "$(pactl get-default-sink).monitor"''
|
||||
''-a "$(pactl get-default-source)"''
|
||||
# Video settings
|
||||
''-w "$WINDOW"''
|
||||
''-f 60''
|
||||
''-c mkv''
|
||||
''-k hevc''
|
||||
''-q very_high''
|
||||
]}
|
||||
'';
|
||||
})
|
||||
];
|
||||
|
||||
wayland.windowManager.hyprland.settings = {
|
||||
bind = [",F8, exec, ags -r 'GSR.saveReplay()'"];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
{
|
||||
nix-gaming,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
nix-gaming.nixosModules.platformOptimizations
|
||||
];
|
||||
|
||||
programs = {
|
||||
steam = {
|
||||
enable = true;
|
||||
remotePlay.openFirewall = true;
|
||||
|
||||
extraCompatPackages = [
|
||||
self.packages.${pkgs.system}.proton-ge-latest
|
||||
];
|
||||
|
||||
platformOptimizations.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = [
|
||||
(pkgs.lutris.override {
|
||||
extraLibraries = pkgs: [
|
||||
# List library dependencies here
|
||||
];
|
||||
extraPkgs = pkgs: [
|
||||
# List extra packages available to lutris here
|
||||
];
|
||||
})
|
||||
|
||||
pkgs.r2modman
|
||||
pkgs.ryujinx
|
||||
];
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
deviceName: {
|
||||
config,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
inherit (config.vars) mainUser hostName;
|
||||
|
||||
clusterIP = config.services.pcsd.virtualIps.caddy-vip.ip;
|
||||
in {
|
||||
# ------------------------------------------------
|
||||
# Imports
|
||||
# ------------------------------------------------
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
|
||||
./modules
|
||||
|
||||
self.nixosModules.kmscon
|
||||
self.nixosModules.server
|
||||
];
|
||||
|
||||
# State Version: DO NOT CHANGE
|
||||
system.stateVersion = "24.05";
|
||||
|
||||
# ------------------------------------------------
|
||||
# User Settings
|
||||
# ------------------------------------------------
|
||||
vars = {
|
||||
mainUser = "matt";
|
||||
hostName = deviceName;
|
||||
promptMainColor =
|
||||
if deviceName == "thingone"
|
||||
then "green"
|
||||
else if deviceName == "thingtwo"
|
||||
then "red"
|
||||
else "purple";
|
||||
};
|
||||
|
||||
users.users.${mainUser} = {
|
||||
isNormalUser = true;
|
||||
extraGroups = [
|
||||
"wheel"
|
||||
"adm"
|
||||
];
|
||||
};
|
||||
|
||||
networking = {
|
||||
inherit hostName;
|
||||
resolvconf.enable = true;
|
||||
nameservers = [
|
||||
clusterIP
|
||||
"1.0.0.1"
|
||||
];
|
||||
extraHosts = ''
|
||||
10.0.0.244 thingone
|
||||
10.0.0.159 thingtwo
|
||||
'';
|
||||
firewall.enable = false;
|
||||
};
|
||||
|
||||
time.timeZone = "America/Montreal";
|
||||
|
||||
# ------------------------------------------------
|
||||
# `Self` Modules configuration
|
||||
# ------------------------------------------------
|
||||
roles.server = {
|
||||
user = mainUser;
|
||||
tailscale.enable = true;
|
||||
sshd.enable = true;
|
||||
};
|
||||
|
||||
services.kmscon.enable = true;
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
{
|
||||
config,
|
||||
modulesPath,
|
||||
...
|
||||
}: {
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
imports = [(modulesPath + "/installer/scan/not-detected.nix")];
|
||||
|
||||
boot = {
|
||||
loader = {
|
||||
efi.canTouchEfiVariables = true;
|
||||
timeout = 2;
|
||||
|
||||
systemd-boot = {
|
||||
enable = true;
|
||||
consoleMode = "max";
|
||||
configurationLimit = 30;
|
||||
};
|
||||
};
|
||||
|
||||
initrd.availableKernelModules = [
|
||||
"xhci_pci"
|
||||
"ahci"
|
||||
"usbhid"
|
||||
"usb_storage"
|
||||
"sd_mod"
|
||||
];
|
||||
};
|
||||
|
||||
fileSystems = {
|
||||
"/" = {
|
||||
device = "/dev/disk/by-label/NIXROOT";
|
||||
fsType = "btrfs";
|
||||
};
|
||||
|
||||
# sudo btrfs subvolume create /@swap
|
||||
"/swap" = {
|
||||
device = "/dev/disk/by-label/NIXROOT";
|
||||
fsType = "btrfs";
|
||||
options = ["subvol=@swap"];
|
||||
};
|
||||
|
||||
"/boot" = {
|
||||
device = "/dev/disk/by-label/NIXBOOT";
|
||||
fsType = "vfat";
|
||||
};
|
||||
};
|
||||
|
||||
swapDevices = [
|
||||
{
|
||||
device = "/swap/swapfile";
|
||||
size = 16 * 1024;
|
||||
}
|
||||
];
|
||||
|
||||
zramSwap.enable = true;
|
||||
|
||||
hardware.cpu.intel.updateMicrocode = config.hardware.enableRedistributableFirmware;
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
{...}: {
|
||||
services = {
|
||||
blocky = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
upstream = {
|
||||
default = [
|
||||
"127.0.0.1:5335"
|
||||
"127.0.0.1:5335"
|
||||
];
|
||||
};
|
||||
|
||||
blocking = {
|
||||
blackLists = {
|
||||
ads = [
|
||||
"https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
{
|
||||
caddy-plugins,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
inherit (config.vars) hostName mainUser;
|
||||
inherit (config.sops) secrets;
|
||||
|
||||
caddy = caddy-plugins.packages.${pkgs.system}.default;
|
||||
in {
|
||||
imports = [caddy-plugins.nixosModules.default];
|
||||
|
||||
# User stuff
|
||||
environment.systemPackages = [caddy];
|
||||
users.users.${mainUser}.extraGroups = ["caddy"];
|
||||
|
||||
boot.kernel.sysctl."net.ipv4.ip_nonlocal_bind" = 1;
|
||||
|
||||
systemd.services.caddy.serviceConfig = {
|
||||
EnvironmentFile = secrets.caddy-cloudflare.path;
|
||||
|
||||
# For some reason the service
|
||||
# doesn't shutdown normally
|
||||
KillSignal = "SIGKILL";
|
||||
RestartKillSignal = "SIGKILL";
|
||||
};
|
||||
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
enableReload = false;
|
||||
package = caddy;
|
||||
|
||||
virtualHosts = let
|
||||
clusterIP = config.services.pcsd.virtualIps.caddy-vip.ip;
|
||||
nosIP = "10.0.0.121";
|
||||
serviviIP = "10.0.0.249";
|
||||
homieIP = "100.64.0.10";
|
||||
|
||||
tlsConf = ''
|
||||
tls {
|
||||
dns cloudflare {$CLOUDFLARE_API_TOKEN}
|
||||
resolvers 1.0.0.1
|
||||
}
|
||||
'';
|
||||
|
||||
mkPublicReverseProxy = subdomain: ip: extraConf:
|
||||
{
|
||||
hostName = "${subdomain}.nelim.org";
|
||||
reverseProxy = ip;
|
||||
listenAddresses = [clusterIP];
|
||||
extraConfig = tlsConf + (extraConf.extraConfig or "");
|
||||
}
|
||||
// (builtins.removeAttrs extraConf ["extraConfig"]);
|
||||
in {
|
||||
# Public
|
||||
"Home-Assistant" = mkPublicReverseProxy "homie" "${homieIP}:8123" {};
|
||||
"Vaultwarden" = mkPublicReverseProxy "vault" "${nosIP}:8781" {};
|
||||
"Hauk" = mkPublicReverseProxy "hauk" "${nosIP}:3003" {};
|
||||
"Headscale" = mkPublicReverseProxy "headscale" "${clusterIP}:8085" {};
|
||||
|
||||
"Jellyfin" = mkPublicReverseProxy "jelly" "${nosIP}:8096" {
|
||||
subDirectories.jfa-go = {
|
||||
subDirName = "accounts";
|
||||
reverseProxy = "${nosIP}:8056";
|
||||
};
|
||||
};
|
||||
|
||||
"Jellyseer" = mkPublicReverseProxy "seerr" "${nosIP}:5055" {};
|
||||
|
||||
"Gameyfin" = mkPublicReverseProxy "games" "${nosIP}:8074" {};
|
||||
|
||||
"Forgejo" = mkPublicReverseProxy "git" "${nosIP}:3000" {};
|
||||
|
||||
"Nextcloud" = mkPublicReverseProxy "cloud" "${nosIP}:8042" {
|
||||
extraConfig = ''
|
||||
redir /.well-known/carddav /remote.php/dav 301
|
||||
redir /.well-known/caldav /remote.php/dav 301
|
||||
redir /.well-known/webfinger /index.php/.well-known/webfinger 301
|
||||
redir /.well-known/nodeinfo /index.php/.well-known/nodeinfo 301
|
||||
'';
|
||||
};
|
||||
"OnlyOffice" = mkPublicReverseProxy "office" "http://${nosIP}:8055" {};
|
||||
|
||||
"Immich" = mkPublicReverseProxy "photos" "${nosIP}:2283" {};
|
||||
|
||||
"Binary Cache" = mkPublicReverseProxy "cache" "${serviviIP}:5000" {};
|
||||
|
||||
# Private
|
||||
"nelim.org" = {
|
||||
serverAliases = ["*.nelim.org"];
|
||||
extraConfig = tlsConf;
|
||||
listenAddresses = [
|
||||
(
|
||||
if hostName == "thingone"
|
||||
then "100.64.0.8"
|
||||
else "100.64.0.9"
|
||||
)
|
||||
];
|
||||
|
||||
subDomains = {
|
||||
esphome.reverseProxy = "${homieIP}:6052";
|
||||
pr-tracker.reverseProxy = "${serviviIP}:3000";
|
||||
|
||||
pcsd = {
|
||||
extraConfig = ''
|
||||
reverse_proxy https://${clusterIP}:2224 {
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
# Resume builder
|
||||
resume.reverseProxy = "${nosIP}:3060";
|
||||
resauth.reverseProxy = "${nosIP}:3100";
|
||||
|
||||
# FreshRSS & Co
|
||||
bridge.reverseProxy = "${nosIP}:3006";
|
||||
drss.reverseProxy = "${nosIP}:3007";
|
||||
freshrss = {
|
||||
subDomainName = "rss";
|
||||
reverseProxy = "${nosIP}:2800";
|
||||
};
|
||||
|
||||
wgui.reverseProxy = "${nosIP}:51821";
|
||||
|
||||
lan = {
|
||||
reverseProxy = "${nosIP}:3020";
|
||||
extraConfig = ''
|
||||
redir /index.html /
|
||||
'';
|
||||
|
||||
subDirectories = {
|
||||
bazarr.reverseProxy = "${nosIP}:6767";
|
||||
prowlarr.reverseProxy = "${nosIP}:9696";
|
||||
radarr.reverseProxy = "${nosIP}:7878";
|
||||
sabnzbd.reverseProxy = "${nosIP}:8382";
|
||||
sonarr.reverseProxy = "${nosIP}:8989";
|
||||
|
||||
qbittorent = {
|
||||
subDirName = "qbt";
|
||||
experimental = true;
|
||||
reverseProxy = "${nosIP}:8080";
|
||||
};
|
||||
|
||||
vaultwarden = {
|
||||
subDirName = "vault";
|
||||
experimental = true;
|
||||
reverseProxy = "${nosIP}:8780";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Top secret Business
|
||||
joal.extraConfig = ''
|
||||
route {
|
||||
rewrite * /joal/ui{uri}
|
||||
reverse_proxy * ${nosIP}:5656
|
||||
}
|
||||
'';
|
||||
joalws.extraConfig = ''
|
||||
route {
|
||||
reverse_proxy ${nosIP}:5656
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
{...}: {
|
||||
imports = [
|
||||
./blocky.nix
|
||||
./caddy.nix
|
||||
./headscale
|
||||
./nfs-client.nix
|
||||
./pcsd.nix
|
||||
./unbound.nix
|
||||
];
|
||||
}
|
|
@ -1,338 +0,0 @@
|
|||
# bash completion V2 for headscale -*- shell-script -*-
|
||||
|
||||
__headscale_debug()
|
||||
{
|
||||
if [[ -n ${BASH_COMP_DEBUG_FILE-} ]]; then
|
||||
echo "$*" >> "${BASH_COMP_DEBUG_FILE}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Macs have bash3 for which the bash-completion package doesn't include
|
||||
# _init_completion. This is a minimal version of that function.
|
||||
__headscale_init_completion()
|
||||
{
|
||||
COMPREPLY=()
|
||||
_get_comp_words_by_ref "$@" cur prev words cword
|
||||
}
|
||||
|
||||
# This function calls the headscale program to obtain the completion
|
||||
# results and the directive. It fills the 'out' and 'directive' vars.
|
||||
__headscale_get_completion_results() {
|
||||
local requestComp lastParam lastChar args
|
||||
|
||||
# Prepare the command to request completions for the program.
|
||||
# Calling ${words[0]} instead of directly headscale allows handling aliases
|
||||
args=("${words[@]:1}")
|
||||
requestComp="${words[0]} __complete ${args[*]}"
|
||||
|
||||
lastParam=${words[$((${#words[@]}-1))]}
|
||||
lastChar=${lastParam:$((${#lastParam}-1)):1}
|
||||
__headscale_debug "lastParam ${lastParam}, lastChar ${lastChar}"
|
||||
|
||||
if [[ -z ${cur} && ${lastChar} != = ]]; then
|
||||
# If the last parameter is complete (there is a space following it)
|
||||
# We add an extra empty parameter so we can indicate this to the go method.
|
||||
__headscale_debug "Adding extra empty parameter"
|
||||
requestComp="${requestComp} ''"
|
||||
fi
|
||||
|
||||
# When completing a flag with an = (e.g., headscale -n=<TAB>)
|
||||
# bash focuses on the part after the =, so we need to remove
|
||||
# the flag part from $cur
|
||||
if [[ ${cur} == -*=* ]]; then
|
||||
cur="${cur#*=}"
|
||||
fi
|
||||
|
||||
__headscale_debug "Calling ${requestComp}"
|
||||
# Use eval to handle any environment variables and such
|
||||
out=$(eval "${requestComp}" 2>/dev/null)
|
||||
|
||||
# Extract the directive integer at the very end of the output following a colon (:)
|
||||
directive=${out##*:}
|
||||
# Remove the directive
|
||||
out=${out%:*}
|
||||
if [[ ${directive} == "${out}" ]]; then
|
||||
# There is not directive specified
|
||||
directive=0
|
||||
fi
|
||||
__headscale_debug "The completion directive is: ${directive}"
|
||||
__headscale_debug "The completions are: ${out}"
|
||||
}
|
||||
|
||||
__headscale_process_completion_results() {
|
||||
local shellCompDirectiveError=1
|
||||
local shellCompDirectiveNoSpace=2
|
||||
local shellCompDirectiveNoFileComp=4
|
||||
local shellCompDirectiveFilterFileExt=8
|
||||
local shellCompDirectiveFilterDirs=16
|
||||
local shellCompDirectiveKeepOrder=32
|
||||
|
||||
if (((directive & shellCompDirectiveError) != 0)); then
|
||||
# Error code. No completion.
|
||||
__headscale_debug "Received error from custom completion go code"
|
||||
return
|
||||
else
|
||||
if (((directive & shellCompDirectiveNoSpace) != 0)); then
|
||||
if [[ $(type -t compopt) == builtin ]]; then
|
||||
__headscale_debug "Activating no space"
|
||||
compopt -o nospace
|
||||
else
|
||||
__headscale_debug "No space directive not supported in this version of bash"
|
||||
fi
|
||||
fi
|
||||
if (((directive & shellCompDirectiveKeepOrder) != 0)); then
|
||||
if [[ $(type -t compopt) == builtin ]]; then
|
||||
# no sort isn't supported for bash less than < 4.4
|
||||
if [[ ${BASH_VERSINFO[0]} -lt 4 || ( ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -lt 4 ) ]]; then
|
||||
__headscale_debug "No sort directive not supported in this version of bash"
|
||||
else
|
||||
__headscale_debug "Activating keep order"
|
||||
compopt -o nosort
|
||||
fi
|
||||
else
|
||||
__headscale_debug "No sort directive not supported in this version of bash"
|
||||
fi
|
||||
fi
|
||||
if (((directive & shellCompDirectiveNoFileComp) != 0)); then
|
||||
if [[ $(type -t compopt) == builtin ]]; then
|
||||
__headscale_debug "Activating no file completion"
|
||||
compopt +o default
|
||||
else
|
||||
__headscale_debug "No file completion directive not supported in this version of bash"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Separate activeHelp from normal completions
|
||||
local completions=()
|
||||
local activeHelp=()
|
||||
__headscale_extract_activeHelp
|
||||
|
||||
if (((directive & shellCompDirectiveFilterFileExt) != 0)); then
|
||||
# File extension filtering
|
||||
local fullFilter filter filteringCmd
|
||||
|
||||
# Do not use quotes around the $completions variable or else newline
|
||||
# characters will be kept.
|
||||
for filter in ${completions[*]}; do
|
||||
fullFilter+="$filter|"
|
||||
done
|
||||
|
||||
filteringCmd="_filedir $fullFilter"
|
||||
__headscale_debug "File filtering command: $filteringCmd"
|
||||
$filteringCmd
|
||||
elif (((directive & shellCompDirectiveFilterDirs) != 0)); then
|
||||
# File completion for directories only
|
||||
|
||||
local subdir
|
||||
subdir=${completions[0]}
|
||||
if [[ -n $subdir ]]; then
|
||||
__headscale_debug "Listing directories in $subdir"
|
||||
pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return
|
||||
else
|
||||
__headscale_debug "Listing directories in ."
|
||||
_filedir -d
|
||||
fi
|
||||
else
|
||||
__headscale_handle_completion_types
|
||||
fi
|
||||
|
||||
__headscale_handle_special_char "$cur" :
|
||||
__headscale_handle_special_char "$cur" =
|
||||
|
||||
# Print the activeHelp statements before we finish
|
||||
if ((${#activeHelp[*]} != 0)); then
|
||||
printf "\n";
|
||||
printf "%s\n" "${activeHelp[@]}"
|
||||
printf "\n"
|
||||
|
||||
# The prompt format is only available from bash 4.4.
|
||||
# We test if it is available before using it.
|
||||
if (x=${PS1@P}) 2> /dev/null; then
|
||||
printf "%s" "${PS1@P}${COMP_LINE[@]}"
|
||||
else
|
||||
# Can't print the prompt. Just print the
|
||||
# text the user had typed, it is workable enough.
|
||||
printf "%s" "${COMP_LINE[@]}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Separate activeHelp lines from real completions.
|
||||
# Fills the $activeHelp and $completions arrays.
|
||||
__headscale_extract_activeHelp() {
|
||||
local activeHelpMarker="_activeHelp_ "
|
||||
local endIndex=${#activeHelpMarker}
|
||||
|
||||
while IFS='' read -r comp; do
|
||||
if [[ ${comp:0:endIndex} == $activeHelpMarker ]]; then
|
||||
comp=${comp:endIndex}
|
||||
__headscale_debug "ActiveHelp found: $comp"
|
||||
if [[ -n $comp ]]; then
|
||||
activeHelp+=("$comp")
|
||||
fi
|
||||
else
|
||||
# Not an activeHelp line but a normal completion
|
||||
completions+=("$comp")
|
||||
fi
|
||||
done <<<"${out}"
|
||||
}
|
||||
|
||||
__headscale_handle_completion_types() {
|
||||
__headscale_debug "__headscale_handle_completion_types: COMP_TYPE is $COMP_TYPE"
|
||||
|
||||
case $COMP_TYPE in
|
||||
37|42)
|
||||
# Type: menu-complete/menu-complete-backward and insert-completions
|
||||
# If the user requested inserting one completion at a time, or all
|
||||
# completions at once on the command-line we must remove the descriptions.
|
||||
# https://github.com/spf13/cobra/issues/1508
|
||||
local tab=$'\t' comp
|
||||
while IFS='' read -r comp; do
|
||||
[[ -z $comp ]] && continue
|
||||
# Strip any description
|
||||
comp=${comp%%$tab*}
|
||||
# Only consider the completions that match
|
||||
if [[ $comp == "$cur"* ]]; then
|
||||
COMPREPLY+=("$comp")
|
||||
fi
|
||||
done < <(printf "%s\n" "${completions[@]}")
|
||||
;;
|
||||
|
||||
*)
|
||||
# Type: complete (normal completion)
|
||||
__headscale_handle_standard_completion_case
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
__headscale_handle_standard_completion_case() {
|
||||
local tab=$'\t' comp
|
||||
|
||||
# Short circuit to optimize if we don't have descriptions
|
||||
if [[ "${completions[*]}" != *$tab* ]]; then
|
||||
IFS=$'\n' read -ra COMPREPLY -d '' < <(compgen -W "${completions[*]}" -- "$cur")
|
||||
return 0
|
||||
fi
|
||||
|
||||
local longest=0
|
||||
local compline
|
||||
# Look for the longest completion so that we can format things nicely
|
||||
while IFS='' read -r compline; do
|
||||
[[ -z $compline ]] && continue
|
||||
# Strip any description before checking the length
|
||||
comp=${compline%%$tab*}
|
||||
# Only consider the completions that match
|
||||
[[ $comp == "$cur"* ]] || continue
|
||||
COMPREPLY+=("$compline")
|
||||
if ((${#comp}>longest)); then
|
||||
longest=${#comp}
|
||||
fi
|
||||
done < <(printf "%s\n" "${completions[@]}")
|
||||
|
||||
# If there is a single completion left, remove the description text
|
||||
if ((${#COMPREPLY[*]} == 1)); then
|
||||
__headscale_debug "COMPREPLY[0]: ${COMPREPLY[0]}"
|
||||
comp="${COMPREPLY[0]%%$tab*}"
|
||||
__headscale_debug "Removed description from single completion, which is now: ${comp}"
|
||||
COMPREPLY[0]=$comp
|
||||
else # Format the descriptions
|
||||
__headscale_format_comp_descriptions $longest
|
||||
fi
|
||||
}
|
||||
|
||||
__headscale_handle_special_char()
|
||||
{
|
||||
local comp="$1"
|
||||
local char=$2
|
||||
if [[ "$comp" == *${char}* && "$COMP_WORDBREAKS" == *${char}* ]]; then
|
||||
local word=${comp%"${comp##*${char}}"}
|
||||
local idx=${#COMPREPLY[*]}
|
||||
while ((--idx >= 0)); do
|
||||
COMPREPLY[idx]=${COMPREPLY[idx]#"$word"}
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
__headscale_format_comp_descriptions()
|
||||
{
|
||||
local tab=$'\t'
|
||||
local comp desc maxdesclength
|
||||
local longest=$1
|
||||
|
||||
local i ci
|
||||
for ci in ${!COMPREPLY[*]}; do
|
||||
comp=${COMPREPLY[ci]}
|
||||
# Properly format the description string which follows a tab character if there is one
|
||||
if [[ "$comp" == *$tab* ]]; then
|
||||
__headscale_debug "Original comp: $comp"
|
||||
desc=${comp#*$tab}
|
||||
comp=${comp%%$tab*}
|
||||
|
||||
# $COLUMNS stores the current shell width.
|
||||
# Remove an extra 4 because we add 2 spaces and 2 parentheses.
|
||||
maxdesclength=$(( COLUMNS - longest - 4 ))
|
||||
|
||||
# Make sure we can fit a description of at least 8 characters
|
||||
# if we are to align the descriptions.
|
||||
if ((maxdesclength > 8)); then
|
||||
# Add the proper number of spaces to align the descriptions
|
||||
for ((i = ${#comp} ; i < longest ; i++)); do
|
||||
comp+=" "
|
||||
done
|
||||
else
|
||||
# Don't pad the descriptions so we can fit more text after the completion
|
||||
maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
|
||||
fi
|
||||
|
||||
# If there is enough space for any description text,
|
||||
# truncate the descriptions that are too long for the shell width
|
||||
if ((maxdesclength > 0)); then
|
||||
if ((${#desc} > maxdesclength)); then
|
||||
desc=${desc:0:$(( maxdesclength - 1 ))}
|
||||
desc+="…"
|
||||
fi
|
||||
comp+=" ($desc)"
|
||||
fi
|
||||
COMPREPLY[ci]=$comp
|
||||
__headscale_debug "Final comp: $comp"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
__start_headscale()
|
||||
{
|
||||
local cur prev words cword split
|
||||
|
||||
COMPREPLY=()
|
||||
|
||||
# Call _init_completion from the bash-completion package
|
||||
# to prepare the arguments properly
|
||||
if declare -F _init_completion >/dev/null 2>&1; then
|
||||
_init_completion -n =: || return
|
||||
else
|
||||
__headscale_init_completion -n =: || return
|
||||
fi
|
||||
|
||||
__headscale_debug
|
||||
__headscale_debug "========= starting completion logic =========="
|
||||
__headscale_debug "cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}, cword is $cword"
|
||||
|
||||
# The user could have moved the cursor backwards on the command-line.
|
||||
# We need to trigger completion from the $cword location, so we need
|
||||
# to truncate the command-line ($words) up to the $cword location.
|
||||
words=("${words[@]:0:$cword+1}")
|
||||
__headscale_debug "Truncated words[*]: ${words[*]},"
|
||||
|
||||
local out directive
|
||||
__headscale_get_completion_results
|
||||
__headscale_process_completion_results
|
||||
}
|
||||
|
||||
if [[ $(type -t compopt) = "builtin" ]]; then
|
||||
complete -o default -F __start_headscale headscale
|
||||
else
|
||||
complete -o default -o nospace -F __start_headscale headscale
|
||||
fi
|
||||
|
||||
# ex: ts=4 sw=4 et filetype=sh
|
|
@ -1,87 +0,0 @@
|
|||
{
|
||||
config,
|
||||
headscale,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (builtins) readFile;
|
||||
inherit (lib) mkAfter mkForce;
|
||||
inherit (pkgs.writers) writeYAML;
|
||||
|
||||
inherit (config.vars) mainUser hostName;
|
||||
headscale-flake = headscale.packages.${pkgs.system}.headscale;
|
||||
|
||||
clusterIP = config.services.pcsd.virtualIps.caddy-vip.ip;
|
||||
in {
|
||||
environment.systemPackages = [headscale-flake];
|
||||
users.users.${mainUser}.extraGroups = ["headscale"];
|
||||
|
||||
home-manager.users.${mainUser}
|
||||
.programs.bash.bashrcExtra = mkAfter (readFile ./completion.bash);
|
||||
|
||||
services.headscale = {
|
||||
enable = true;
|
||||
package = headscale-flake;
|
||||
};
|
||||
|
||||
# Takes way too long to shutdown
|
||||
systemd.services."headscale".serviceConfig.TimeoutStopSec = "5";
|
||||
|
||||
environment.etc."headscale/config.yaml".source = mkForce (
|
||||
writeYAML "headscale.yaml" {
|
||||
server_url = "https://headscale.nelim.org";
|
||||
listen_addr = "${clusterIP}:8085";
|
||||
prefixes = {
|
||||
v4 = "100.64.0.0/10";
|
||||
v6 = "fd7a:115c:a1e0::/48";
|
||||
};
|
||||
metrics_listen_addr = "127.0.0.1:9090";
|
||||
grpc_listen_addr = "0.0.0.0:50443";
|
||||
grpc_allow_insecure = false;
|
||||
disable_check_updates = true;
|
||||
ephemeral_node_inactivity_timeout = "30m";
|
||||
unix_socket = "/run/headscale/headscale.sock";
|
||||
unix_socket_permission = "0770";
|
||||
|
||||
database = {
|
||||
type = "sqlite";
|
||||
sqlite.path = "/var/lib/headscale/db.sqlite";
|
||||
};
|
||||
|
||||
private_key_path = "/var/lib/headscale/private.key";
|
||||
noise.private_key_path = "/var/lib/headscale/noise_private.key";
|
||||
|
||||
dns = let
|
||||
caddyIp =
|
||||
if hostName == "thingone"
|
||||
then "100.64.0.8"
|
||||
else "100.64.0.9";
|
||||
in {
|
||||
magic_dns = false;
|
||||
override_local_dns = true;
|
||||
nameservers.global = [caddyIp];
|
||||
};
|
||||
|
||||
log = {
|
||||
format = "text";
|
||||
level = "info";
|
||||
};
|
||||
|
||||
derp = {
|
||||
auto_update_enable = true;
|
||||
update_frequency = "24h";
|
||||
|
||||
server = {
|
||||
enabled = true;
|
||||
stun_listen_addr = "${clusterIP}:3479";
|
||||
private_key_path = "/var/lib/headscale/derp_server_private.key";
|
||||
|
||||
region_id = 995;
|
||||
region_code = "mon";
|
||||
region_name = "montreal";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
{pkgs, ...}: {
|
||||
# NFS client setup
|
||||
services.rpcbind.enable = true;
|
||||
boot.supportedFilesystems = ["nfs"];
|
||||
environment.systemPackages = builtins.attrValues {
|
||||
inherit (pkgs) nfs-utils;
|
||||
};
|
||||
|
||||
systemd.mounts = let
|
||||
host = "10.0.0.249";
|
||||
in [
|
||||
{
|
||||
type = "nfs";
|
||||
mountConfig = {
|
||||
Options = "noatime";
|
||||
};
|
||||
what = "${host}:/caddy";
|
||||
where = "/var/lib/caddy";
|
||||
requiredBy = ["caddy.service"];
|
||||
}
|
||||
|
||||
{
|
||||
type = "nfs";
|
||||
mountConfig = {
|
||||
Options = "noatime";
|
||||
};
|
||||
what = "${host}:/headscale";
|
||||
where = "/var/lib/headscale";
|
||||
requiredBy = ["headscale.service"];
|
||||
}
|
||||
];
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pcsd,
|
||||
...
|
||||
}: let
|
||||
inherit (config.sops) secrets;
|
||||
in {
|
||||
imports = [pcsd.nixosModules.default];
|
||||
|
||||
services.pcsd = {
|
||||
enable = true;
|
||||
enableBinaryCache = true;
|
||||
enableWebUI = true;
|
||||
|
||||
clusterName = "thingies";
|
||||
|
||||
corosyncKeyFile = secrets.corosync.path;
|
||||
clusterUserPasswordFile = secrets.pcs-pass.path;
|
||||
|
||||
virtualIps = {
|
||||
"caddy-vip" = {
|
||||
ip = "10.0.0.130";
|
||||
interface = "eno1";
|
||||
group = "caddy-grp";
|
||||
};
|
||||
};
|
||||
|
||||
systemdResources = {
|
||||
"unbound" = {
|
||||
enable = true;
|
||||
group = "caddy-grp";
|
||||
startAfter = ["caddy-vip"];
|
||||
};
|
||||
|
||||
"blocky" = {
|
||||
enable = true;
|
||||
group = "caddy-grp";
|
||||
startAfter = ["unbound"];
|
||||
};
|
||||
|
||||
"headscale" = {
|
||||
enable = true;
|
||||
group = "caddy-grp";
|
||||
startAfter = ["blocky"];
|
||||
};
|
||||
|
||||
"caddy" = {
|
||||
enable = true;
|
||||
group = "caddy-grp";
|
||||
startAfter = ["headscale"];
|
||||
};
|
||||
};
|
||||
|
||||
nodes = [
|
||||
{
|
||||
name = "thingone";
|
||||
nodeid = 1;
|
||||
ring_addrs = ["10.0.0.244"];
|
||||
}
|
||||
{
|
||||
name = "thingtwo";
|
||||
nodeid = 2;
|
||||
ring_addrs = ["10.0.0.159"];
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) foldl isList mapAttrsToList mergeAttrsWithFunc remove unique;
|
||||
mergeAttrsList = list:
|
||||
foldl (mergeAttrsWithFunc (a: b:
|
||||
if isList a && isList b
|
||||
then unique (a ++ b)
|
||||
else b)) {}
|
||||
list;
|
||||
|
||||
inherit (config.vars) mainUser hostName;
|
||||
|
||||
serviviIP = "100.64.0.7";
|
||||
caddyIp =
|
||||
if hostName == "thingone"
|
||||
then "100.64.0.8"
|
||||
else "100.64.0.9";
|
||||
in {
|
||||
# https://github.com/MatthewVance/unbound-docker-rpi/issues/4#issuecomment-1001879602
|
||||
boot.kernel.sysctl."net.core.rmem_max" = 1048576;
|
||||
|
||||
users.users.${mainUser}.extraGroups = ["unbound"];
|
||||
|
||||
services.unbound = {
|
||||
enable = true;
|
||||
enableRootTrustAnchor = true;
|
||||
resolveLocalQueries = false;
|
||||
|
||||
settings = {
|
||||
server = let
|
||||
mkLocalEntry = domain: ip: {
|
||||
local-zone = ["${domain} redirect"];
|
||||
local-data = ["\"${domain} IN A ${ip}\""];
|
||||
};
|
||||
|
||||
mkMinecraftEntry = domain: port: {
|
||||
local-zone = ["${domain} transparent"];
|
||||
local-data = [
|
||||
"\"${domain} IN A ${serviviIP}\""
|
||||
"\"_minecraft._tcp.${domain}. 180 IN SRV 0 0 ${toString port} ${domain}.\""
|
||||
];
|
||||
};
|
||||
|
||||
forceResolveEntry = domain: {
|
||||
local-zone = ["${domain} always_transparent"];
|
||||
};
|
||||
|
||||
publicApps = remove "nelim.org" (mapAttrsToList (n: v: v.hostName) config.services.caddy.virtualHosts);
|
||||
in
|
||||
mergeAttrsList (
|
||||
(map forceResolveEntry publicApps)
|
||||
++ [
|
||||
(mkMinecraftEntry "mc.nelim.org" 25569)
|
||||
(mkMinecraftEntry "mc2.nelim.org" 25560)
|
||||
(mkMinecraftEntry "cv.nelim.org" 25566)
|
||||
|
||||
(mkLocalEntry "nelim.org" caddyIp)
|
||||
|
||||
{
|
||||
interface = ["127.0.0.1"];
|
||||
port = 5335;
|
||||
|
||||
do-ip4 = true;
|
||||
do-ip6 = false;
|
||||
prefer-ip6 = false;
|
||||
do-udp = true;
|
||||
do-tcp = true;
|
||||
|
||||
# Performance
|
||||
prefetch = true;
|
||||
num-threads = 1;
|
||||
|
||||
private-address = [
|
||||
"172.16.0.0/12"
|
||||
"10.0.0.0/8"
|
||||
"100.64.0.0/8"
|
||||
"fd00::/8"
|
||||
"fe80::/10"
|
||||
];
|
||||
|
||||
# Default stuff
|
||||
harden-glue = true;
|
||||
harden-dnssec-stripped = true;
|
||||
use-caps-for-id = false;
|
||||
edns-buffer-size = 1232;
|
||||
so-rcvbuf = "1m";
|
||||
}
|
||||
]
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
{
|
||||
config,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
inherit (config.vars) mainUser hostName;
|
||||
in {
|
||||
# ------------------------------------------------
|
||||
# Imports
|
||||
# ------------------------------------------------
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
|
||||
./modules
|
||||
|
||||
self.nixosModules.docker
|
||||
self.nixosModules.kmscon
|
||||
self.nixosModules.server
|
||||
];
|
||||
|
||||
# State Version: DO NOT CHANGE
|
||||
system.stateVersion = "24.11";
|
||||
|
||||
# ------------------------------------------------
|
||||
# User Settings
|
||||
# ------------------------------------------------
|
||||
vars = {
|
||||
mainUser = "matt";
|
||||
hostName = "homie";
|
||||
promptMainColor = "yellow";
|
||||
};
|
||||
|
||||
users.users.${mainUser} = {
|
||||
isNormalUser = true;
|
||||
extraGroups = [
|
||||
"wheel"
|
||||
"adm"
|
||||
];
|
||||
};
|
||||
|
||||
networking = {
|
||||
inherit hostName;
|
||||
resolvconf.enable = true;
|
||||
firewall.enable = false;
|
||||
};
|
||||
|
||||
time.timeZone = "America/Montreal";
|
||||
|
||||
# ------------------------------------------------
|
||||
# `Self` Modules configuration
|
||||
# ------------------------------------------------
|
||||
roles.server = {
|
||||
user = mainUser;
|
||||
tailscale.enable = true;
|
||||
sshd.enable = true;
|
||||
};
|
||||
|
||||
services.kmscon.enable = true;
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
{
|
||||
config,
|
||||
modulesPath,
|
||||
...
|
||||
}: {
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
imports = [(modulesPath + "/installer/scan/not-detected.nix")];
|
||||
|
||||
boot = {
|
||||
loader = {
|
||||
efi.canTouchEfiVariables = true;
|
||||
timeout = 2;
|
||||
|
||||
systemd-boot = {
|
||||
enable = true;
|
||||
consoleMode = "max";
|
||||
configurationLimit = 30;
|
||||
};
|
||||
};
|
||||
|
||||
initrd.availableKernelModules = [
|
||||
"xhci_pci"
|
||||
"ahci"
|
||||
"nvme"
|
||||
"usbhid"
|
||||
"usb_storage"
|
||||
"sd_mod"
|
||||
];
|
||||
};
|
||||
|
||||
fileSystems = {
|
||||
"/" = {
|
||||
device = "/dev/disk/by-label/NIXROOT";
|
||||
fsType = "btrfs";
|
||||
};
|
||||
|
||||
# sudo btrfs subvolume create /@swap
|
||||
"/swap" = {
|
||||
device = "/dev/disk/by-label/NIXROOT";
|
||||
fsType = "btrfs";
|
||||
options = ["subvol=@swap"];
|
||||
};
|
||||
|
||||
"/boot" = {
|
||||
device = "/dev/disk/by-label/NIXBOOT";
|
||||
fsType = "vfat";
|
||||
options = ["fmask=0022" "dmask=0022"];
|
||||
};
|
||||
};
|
||||
|
||||
swapDevices = [
|
||||
{
|
||||
device = "/swap/swapfile";
|
||||
size = 16 * 1024;
|
||||
}
|
||||
];
|
||||
|
||||
zramSwap.enable = true;
|
||||
|
||||
hardware.cpu.intel.updateMicrocode = config.hardware.enableRedistributableFirmware;
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
# Unfortunately I had some hardware issues but this does work
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkForce getExe;
|
||||
|
||||
connectControllers = getExe (pkgs.writeShellApplication {
|
||||
name = "connectControllers";
|
||||
runtimeInputs = with pkgs; [gnugrep usbutils];
|
||||
text = ''
|
||||
set +o errexit
|
||||
|
||||
for dev in /sys/bus/usb/devices/*; do
|
||||
vendor="$(cat "$dev/idVendor" 2>/dev/null)"
|
||||
prod="$(cat "$dev/idProduct" 2>/dev/null)"
|
||||
|
||||
if [[ "$vendor" != "" && "$prod" != "" ]]; then
|
||||
if [[ "$(lsusb -d "$vendor:$prod" | grep "Microsoft Corp. Xbox Controller")" != "" ]]; then
|
||||
echo 0 > "$dev/authorized"
|
||||
echo 1 > "$dev/authorized"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
'';
|
||||
});
|
||||
|
||||
hyprConf = pkgs.writeText "greetd-hypr-config" ''
|
||||
cursor {
|
||||
inactive_timeout = 1
|
||||
}
|
||||
|
||||
misc {
|
||||
disable_hyprland_logo = true
|
||||
disable_splash_rendering = true
|
||||
}
|
||||
|
||||
decoration {
|
||||
blur {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
animations {
|
||||
enabled = false
|
||||
first_launch_animation = false
|
||||
}
|
||||
|
||||
bind = SUPER, Q, exec, kitty
|
||||
|
||||
windowrule = fullscreen, ^(.*)$
|
||||
exec-once = waydroid show-full-ui
|
||||
exec-once = sleep 10; sudo ${connectControllers}
|
||||
'';
|
||||
|
||||
user = "matt";
|
||||
command = "Hyprland --config ${hyprConf}";
|
||||
|
||||
session = {inherit command user;};
|
||||
in {
|
||||
# Make it so we don't need root to connect controllers
|
||||
security.sudo.extraRules = [
|
||||
{
|
||||
users = [user];
|
||||
groups = [user];
|
||||
commands = [
|
||||
{
|
||||
command = connectControllers;
|
||||
options = ["SETENV" "NOPASSWD"];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
# TODO: make the following declarative and also make the image declarative
|
||||
# Add this to /var/lib/waydroid/waydroid.cfg for controller support
|
||||
# persist.waydroid.udev = true
|
||||
# persist.waydroid.uevent = true
|
||||
virtualisation.waydroid.enable = true;
|
||||
|
||||
users.users."greeter" = {
|
||||
home = "/var/lib/greeter";
|
||||
};
|
||||
|
||||
programs.hyprland.enable = true;
|
||||
|
||||
services = {
|
||||
greetd = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
default_session = session;
|
||||
initial_session = session;
|
||||
};
|
||||
};
|
||||
|
||||
pipewire.enable = mkForce false;
|
||||
};
|
||||
|
||||
environment.systemPackages = [pkgs.kitty];
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{...}: {
|
||||
imports = [
|
||||
./home-assistant
|
||||
./music
|
||||
];
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
{
|
||||
pkgs,
|
||||
self,
|
||||
wakewords-src,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
self.nixosModules.esphome-plus
|
||||
self.nixosModules.wyoming-plus
|
||||
];
|
||||
|
||||
services = {
|
||||
home-assistant = {
|
||||
customComponents = builtins.attrValues {
|
||||
inherit
|
||||
(self.legacyPackages.${pkgs.system}.hass-components)
|
||||
extended-ollama-conversation
|
||||
tuya-local
|
||||
;
|
||||
};
|
||||
|
||||
extraComponents = [
|
||||
"esphome"
|
||||
"ollama"
|
||||
"wyoming"
|
||||
"scrape"
|
||||
];
|
||||
|
||||
config = {
|
||||
assist_pipeline = {};
|
||||
conversation = {};
|
||||
media_source = {};
|
||||
};
|
||||
};
|
||||
|
||||
wyoming = {
|
||||
piper.servers."en" = {
|
||||
enable = true;
|
||||
uri = "tcp://127.0.0.1:10200";
|
||||
|
||||
# see https://github.com/rhasspy/rhasspy3/blob/master/programs/tts/piper/script/download.py
|
||||
voice = "en-us-ryan-low"; # using `hfc male (medium)` in GUI
|
||||
speaker = 0;
|
||||
};
|
||||
|
||||
openwakeword = {
|
||||
enable = true;
|
||||
uri = "tcp://127.0.0.1:10400";
|
||||
|
||||
customModelsDirectories = ["${wakewords-src}/en/yo_homie"];
|
||||
};
|
||||
};
|
||||
|
||||
esphome = {
|
||||
enable = true;
|
||||
address = "100.64.0.10";
|
||||
port = 6052;
|
||||
};
|
||||
};
|
||||
|
||||
# In case tailscale is down
|
||||
boot.kernel.sysctl."net.ipv4.ip_nonlocal_bind" = 1;
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) getExe;
|
||||
|
||||
turnOnUE = pkgs.writeShellApplication {
|
||||
name = "turnOnUE";
|
||||
|
||||
runtimeInputs = [config.hardware.bluetooth.package];
|
||||
|
||||
text = ''
|
||||
cmd=0x0003
|
||||
bt_device_addr=88:C6:26:93:4B:77
|
||||
|
||||
# This is the MAC address on the first line of `bluetootctl show`
|
||||
# without the `:` and with `01` added at the end
|
||||
bt_controller_addr=E848B8C8200001
|
||||
|
||||
exec gatttool -b $bt_device_addr --char-write-req --handle=$cmd --value=$bt_controller_addr
|
||||
'';
|
||||
};
|
||||
in {
|
||||
environment.systemPackages = [turnOnUE];
|
||||
|
||||
services.home-assistant = {
|
||||
extraComponents = [
|
||||
"mpd"
|
||||
|
||||
# BT components
|
||||
"ibeacon"
|
||||
"led_ble"
|
||||
"kegtron"
|
||||
"xiaomi_ble"
|
||||
];
|
||||
|
||||
# Turn On the speaker automatically when openwakeword is used
|
||||
config = {
|
||||
shell_command.turn_on_ue = getExe turnOnUE;
|
||||
script.turn_on_ue = {
|
||||
alias = "Music - TurnOnUE";
|
||||
description = "Script for turning on the UE Boom 2 speaker.";
|
||||
icon = "mdi:music";
|
||||
mode = "single";
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "Run shell command";
|
||||
service = "shell_command.turn_on_ue";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
automation = [
|
||||
{
|
||||
alias = "Turn On UE";
|
||||
mode = "single";
|
||||
trigger = [
|
||||
{
|
||||
platform = "state";
|
||||
entity_id = "wake_word.openwakeword";
|
||||
}
|
||||
];
|
||||
condition = [];
|
||||
action = [
|
||||
{
|
||||
action = "shell_command.turn_on_ue";
|
||||
metadata = {};
|
||||
data = {};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
{pkgs, ...}: {
|
||||
imports = [
|
||||
./assist.nix
|
||||
./bluetooth.nix
|
||||
./firmware.nix
|
||||
./frontend.nix
|
||||
./spotify.nix
|
||||
./timer.nix
|
||||
];
|
||||
|
||||
environment.systemPackages = [
|
||||
(pkgs.writeShellApplication {
|
||||
name = "yaml2nix";
|
||||
runtimeInputs = with pkgs; [yj];
|
||||
text = ''
|
||||
input="$(yj < "$1")"
|
||||
output="''${2:-""}"
|
||||
|
||||
nixCode="$(nix eval --expr "builtins.fromJSON '''$input'''" --impure | alejandra -q | sed 's/ = null;/ = {};/g')"
|
||||
|
||||
if [[ "$output" != "" ]]; then
|
||||
echo "$nixCode" > "$output"
|
||||
else
|
||||
echo "$nixCode"
|
||||
fi
|
||||
'';
|
||||
})
|
||||
|
||||
(pkgs.writeShellApplication {
|
||||
name = "nix2yaml";
|
||||
runtimeInputs = with pkgs; [remarshal];
|
||||
text = ''
|
||||
input="$1"
|
||||
output="''${2:-""}"
|
||||
|
||||
yamlCode="$(nix eval --json --file "$input" | remarshal --if json --of yaml)"
|
||||
|
||||
if [[ "$output" != "" ]]; then
|
||||
echo "$yamlCode" > "$output"
|
||||
else
|
||||
echo "$yamlCode"
|
||||
fi
|
||||
'';
|
||||
})
|
||||
];
|
||||
|
||||
# TODO: some components / integrations / addons require manual interaction in the GUI, find way to make it all declarative
|
||||
services.home-assistant = {
|
||||
enable = true;
|
||||
|
||||
extraComponents = [
|
||||
"androidtv_remote"
|
||||
"caldav"
|
||||
"cast"
|
||||
"holiday"
|
||||
"isal"
|
||||
"met"
|
||||
"switchbot"
|
||||
"upnp"
|
||||
"yamaha_musiccast"
|
||||
];
|
||||
|
||||
config = {
|
||||
homeassistant = {
|
||||
name = "Home";
|
||||
unit_system = "metric";
|
||||
currency = "CAD";
|
||||
country = "CA";
|
||||
time_zone = "America/Montreal";
|
||||
external_url = "https://homie.nelim.org";
|
||||
};
|
||||
|
||||
# Proxy settings
|
||||
http = {
|
||||
server_host = "0.0.0.0";
|
||||
trusted_proxies = ["100.64.0.8" "100.64.0.9"];
|
||||
use_x_forwarded_for = true;
|
||||
};
|
||||
|
||||
# `default_config` enables too much stuff. this is what I want from it
|
||||
config = {};
|
||||
dhcp = {};
|
||||
history = {};
|
||||
image_upload = {};
|
||||
logbook = {};
|
||||
mobile_app = {};
|
||||
my = {};
|
||||
sun = {};
|
||||
zeroconf = {};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,308 +0,0 @@
|
|||
# I use nix2yaml from ../default.nix to convert this to YAML and place it in the functions of extended_ollama_conversation
|
||||
let
|
||||
inherit (import ../../../../../lib {}) lib;
|
||||
inherit (lib) concatStrings concatStringsSep splitString;
|
||||
in [
|
||||
{
|
||||
spec = {
|
||||
name = "get_attributes";
|
||||
description = "Get attributes of any home assistant entity";
|
||||
parameters = {
|
||||
type = "object";
|
||||
|
||||
properties = {
|
||||
entity_id = {
|
||||
type = "string";
|
||||
description = "entity_id";
|
||||
};
|
||||
};
|
||||
|
||||
required = ["entity_id"];
|
||||
};
|
||||
};
|
||||
|
||||
function = {
|
||||
type = "template";
|
||||
value_template = "{{ states[entity_id] }}";
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
spec = {
|
||||
name = "timer_start";
|
||||
description = "Use this function to start a timer in Home Assistant whose ID defaults to 1.";
|
||||
|
||||
parameters = {
|
||||
type = "object";
|
||||
|
||||
properties = {
|
||||
hours = {
|
||||
type = "string";
|
||||
description = "The amount of hours the timer should run for.";
|
||||
};
|
||||
|
||||
minutes = {
|
||||
type = "string";
|
||||
description = "The amount of minutes the timer should run for.";
|
||||
};
|
||||
|
||||
seconds = {
|
||||
type = "string";
|
||||
description = "The amount of seconds the timer should run for.";
|
||||
};
|
||||
};
|
||||
|
||||
required = [];
|
||||
};
|
||||
};
|
||||
|
||||
function = {
|
||||
type = "script";
|
||||
|
||||
sequence = [
|
||||
{
|
||||
service = "script.assist_timerstart";
|
||||
|
||||
# dummy ID that won't be used by the script
|
||||
target.entity_id = "timer.assist_timer1";
|
||||
|
||||
data = {
|
||||
duration = concatStrings [
|
||||
''{% if not hours %} {% set hours = "0" %} {% endif %}''
|
||||
''{% if not minutes %} {% set minutes = "0" %} {% endif %}''
|
||||
''{% if not seconds %} {% set seconds = "0" %} {% endif %}''
|
||||
|
||||
''{{ hours | int(default=0) }}:{{ minutes | int(default=0) }}:{{ seconds | int(default=0) }}''
|
||||
];
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
spec = {
|
||||
name = "timer_stop";
|
||||
description = "Use this function to stop a timer in Home Assistant.";
|
||||
|
||||
parameters = {
|
||||
type = "object";
|
||||
|
||||
properties = {
|
||||
timer_number = {
|
||||
type = "string";
|
||||
description = "The number of the timer";
|
||||
enum = ["1" "2" "3"];
|
||||
};
|
||||
};
|
||||
|
||||
required = ["timer_number"];
|
||||
};
|
||||
};
|
||||
|
||||
function = {
|
||||
type = "script";
|
||||
|
||||
sequence = [
|
||||
{
|
||||
service = "script.assist_timerstop";
|
||||
target.entity_id = ''{{ "timer.assist_timer" ~ timer_number }}'';
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
spec = {
|
||||
name = "timer_pause";
|
||||
description = "Use this function to pause a timer in Home Assistant.";
|
||||
|
||||
parameters = {
|
||||
type = "object";
|
||||
|
||||
properties = {
|
||||
timer_number = {
|
||||
type = "string";
|
||||
description = "The number of the timer";
|
||||
enum = ["1" "2" "3"];
|
||||
};
|
||||
};
|
||||
|
||||
required = ["timer_number"];
|
||||
};
|
||||
};
|
||||
|
||||
function = {
|
||||
type = "script";
|
||||
|
||||
sequence = [
|
||||
{
|
||||
service = "script.assist_timerpause";
|
||||
|
||||
target.entity_id = ''{{ "timer.assist_timer" ~ timer_number }}'';
|
||||
|
||||
data = {
|
||||
timer_action = "pause";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
spec = {
|
||||
name = "timer_unpause";
|
||||
description = "Use this function to unpause or resume a timer in Home Assistant.";
|
||||
|
||||
parameters = {
|
||||
type = "object";
|
||||
|
||||
properties = {
|
||||
timer_number = {
|
||||
type = "string";
|
||||
description = "The number of the timer";
|
||||
enum = ["1" "2" "3"];
|
||||
};
|
||||
};
|
||||
|
||||
required = ["timer_number"];
|
||||
};
|
||||
};
|
||||
|
||||
function = {
|
||||
type = "script";
|
||||
|
||||
sequence = [
|
||||
{
|
||||
service = "script.assist_timerpause";
|
||||
|
||||
target.entity_id = ''{{ "timer.assist_timer" ~ timer_number }}'';
|
||||
|
||||
data = {
|
||||
timer_action = "resume";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
spec = {
|
||||
name = "timer_duration";
|
||||
description = "Use this function to get the remaining duration of a timer in Home Assistant.";
|
||||
|
||||
parameters = {
|
||||
type = "object";
|
||||
|
||||
properties = {
|
||||
timer_number = {
|
||||
type = "string";
|
||||
description = "The number of the timer";
|
||||
enum = ["1" "2" "3"];
|
||||
};
|
||||
};
|
||||
|
||||
required = ["timer_number"];
|
||||
};
|
||||
};
|
||||
|
||||
function = {
|
||||
type = "template";
|
||||
|
||||
value_template = concatStringsSep " " (splitString "\n" ''
|
||||
{%- set entity_id = "timer.assist_timer" ~ timer_number %}
|
||||
|
||||
{%- set timer_amount = states.timer
|
||||
| selectattr("state","eq","active")
|
||||
| selectattr("entity_id","match","timer.assist_timer*")
|
||||
| map(attribute="entity_id")
|
||||
| list
|
||||
| length -%}
|
||||
|
||||
{% if timer_amount == 0 %}
|
||||
There are no timers active.
|
||||
|
||||
{% else %}
|
||||
{%- if entity_id != "all" and entity_id != "null" %}
|
||||
{%- set active_timers = states.timer
|
||||
| selectattr("state","eq","active")
|
||||
| selectattr("entity_id","match",entity_id)
|
||||
| list -%}
|
||||
|
||||
{%- else%}
|
||||
{%- set active_timers = states.timer
|
||||
| selectattr("state","eq","active")
|
||||
| selectattr("entity_id","match","timer.assist_timer*")
|
||||
| list -%}
|
||||
{%- endif %}
|
||||
|
||||
{% if active_timers|length == 0 %}
|
||||
{%- if entity_id != "all" and entity_id != "null" %}
|
||||
This timer is not active.
|
||||
|
||||
{%- else %}
|
||||
There are no timers active.
|
||||
{%- endif %}
|
||||
|
||||
{% elif active_timers | length > 1 %}
|
||||
There are {{active_timers|length }} timers active.
|
||||
{% endif %}
|
||||
|
||||
{% for timer in active_timers %}
|
||||
{% set timer_id = timer.entity_id %}
|
||||
{% set timer_finishes_at = state_attr(timer_id, "finishes_at") %}
|
||||
{% set time_remaining = as_datetime(timer_finishes_at) - now() %}
|
||||
{% set hours_remaining = time_remaining.total_seconds() // 3600 %}
|
||||
{% set minutes_remaining = (time_remaining.total_seconds() % 3600) // 60 %}
|
||||
{% set seconds_remaining = time_remaining.total_seconds() % 60 %}
|
||||
|
||||
{% if timer.state == "active" or timer.state == "paused" %}
|
||||
{% if entity_id != timer_id %}
|
||||
{{ state_attr(timer_id, "friendly_name")[9:] }} {% if timer.state == "paused" %} is paused and {% endif %} has
|
||||
|
||||
{% else %}
|
||||
There are
|
||||
{% endif %}
|
||||
|
||||
{% if hours_remaining > 0 %}{{ hours_remaining | round }} hours {% endif %}
|
||||
{% if minutes_remaining == 1 %}1 minute {% endif %}
|
||||
{% if minutes_remaining > 1 %}{{ minutes_remaining | round }} minutes {% endif %}
|
||||
{% if seconds_remaining == 1 and hours_remaining == 0%}1 seconde {% endif %}
|
||||
{% if seconds_remaining > 1 and hours_remaining == 0 %}{{ seconds_remaining | round }} seconds {% endif %}remaining.
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
'');
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
spec = {
|
||||
name = "play_artist";
|
||||
description = "Use this function to play music from an artist";
|
||||
|
||||
parameters = {
|
||||
type = "object";
|
||||
|
||||
properties.query = {
|
||||
type = "string";
|
||||
description = "The query";
|
||||
};
|
||||
|
||||
required = ["query"];
|
||||
};
|
||||
};
|
||||
|
||||
function = {
|
||||
type = "script";
|
||||
sequence = [
|
||||
{
|
||||
service = "script.play_artist";
|
||||
data = {
|
||||
criteria = "{{ query }}";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
]
|
|
@ -1,52 +0,0 @@
|
|||
{%- set customize_glob_exposed_attributes = {
|
||||
".*": {
|
||||
"friendly_name": true,
|
||||
"temperature": true,
|
||||
"current_temperature": true,
|
||||
"temperature_unit": true,
|
||||
"brightness": true,
|
||||
"humidity": true,
|
||||
"unit_of_measurement": true,
|
||||
"device_class": true,
|
||||
"current_position": true,
|
||||
"percentage": true,
|
||||
"volume_level": true,
|
||||
"media_title": true,
|
||||
"media_artist": true,
|
||||
"media_album_name": true,
|
||||
},
|
||||
} %}
|
||||
|
||||
{%- macro get_exposed_attributes(entity_id) -%}
|
||||
{%- set ns = namespace(exposed_attributes = {}, result = {}) %}
|
||||
{%- for pattern, attributes in customize_glob_exposed_attributes.items() -%}
|
||||
{%- if entity_id | regex_match(pattern) -%}
|
||||
{%- set ns.exposed_attributes = dict(ns.exposed_attributes, **attributes) -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- for attribute_key, should_include in ns.exposed_attributes.items() -%}
|
||||
{%- if should_include and state_attr(entity_id, attribute_key) != None -%}
|
||||
{%- set temp = {attribute_key: state_attr(entity_id, attribute_key)} if should_include is boolean else {attribute_key: should_include} -%}
|
||||
{%- set ns.result = dict(ns.result, **temp) -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- set result = ns.result | to_json if ns.result!={} else None -%}
|
||||
{{"'" + result + "'" if result != None else ''}}
|
||||
{%- endmacro -%}
|
||||
|
||||
I want you to act as smart home manager of Home Assistant.
|
||||
I will provide information of smart home along with a question, you will truthfully make correction or answer using information provided in one sentence in everyday language.
|
||||
|
||||
Current Time: {{now()}}
|
||||
|
||||
Available Devices:
|
||||
```csv
|
||||
entity_id,name,state,aliases,attributes
|
||||
{% for entity in exposed_entities -%}
|
||||
{{ entity.entity_id }},{{ entity.name }},{{ entity.state }},{{entity.aliases | join('/')}},{{get_exposed_attributes(entity.entity_id)}}
|
||||
{% endfor -%}
|
||||
```
|
||||
|
||||
The current state of devices is provided in available devices.
|
||||
Do not ask for confirmation to execute a service.
|
||||
Do not restate or appreciate what user says, rather make a quick inquiry.
|
|
@ -1,383 +0,0 @@
|
|||
{config, ...}: {
|
||||
services.esphome = {
|
||||
secretsFile = config.sops.secrets.esphome.path;
|
||||
|
||||
firmwareConfigs = {
|
||||
# -------------------------------------------------------------
|
||||
"AtomEcho" = {
|
||||
# Device specific settings
|
||||
api.encryption.key = "!secret api_key";
|
||||
|
||||
ota = [
|
||||
{
|
||||
platform = "esphome";
|
||||
password = "!secret ota_pass";
|
||||
}
|
||||
];
|
||||
|
||||
wifi = {
|
||||
ssid = "!secret wifi_ssid";
|
||||
password = "!secret wifi_password";
|
||||
|
||||
manual_ip = {
|
||||
static_ip = "192.168.0.92";
|
||||
gateway = "192.168.0.1";
|
||||
subnet = "255.255.255.0";
|
||||
};
|
||||
|
||||
ap = {
|
||||
ssid = "Esp1 Fallback Hotspot";
|
||||
password = "!secret ap_fallback";
|
||||
};
|
||||
};
|
||||
|
||||
# Hardware Declaration
|
||||
esphome = {
|
||||
friendly_name = "M5Stack Atom Echo";
|
||||
min_version = "2024.6.0";
|
||||
name = "m5stack-atom-echo";
|
||||
name_add_mac_suffix = true;
|
||||
};
|
||||
|
||||
esp32 = {
|
||||
board = "m5stack-atom";
|
||||
framework.type = "esp-idf";
|
||||
};
|
||||
|
||||
esp_adf = {};
|
||||
|
||||
button = [
|
||||
{
|
||||
id = "button_safe_mode";
|
||||
name = "Safe Mode Boot";
|
||||
platform = "safe_mode";
|
||||
}
|
||||
{
|
||||
id = "factory_reset_btn";
|
||||
name = "Factory reset";
|
||||
platform = "factory_reset";
|
||||
}
|
||||
];
|
||||
|
||||
microphone = [
|
||||
{
|
||||
adc_type = "external";
|
||||
i2s_din_pin = "GPIO23";
|
||||
id = "echo_microphone";
|
||||
pdm = true;
|
||||
platform = "i2s_audio";
|
||||
}
|
||||
];
|
||||
|
||||
speaker = [
|
||||
{
|
||||
dac_type = "external";
|
||||
i2s_dout_pin = "GPIO21"; # "GPIO22"; turn off speaker
|
||||
id = "echo_speaker";
|
||||
mode = "mono";
|
||||
platform = "i2s_audio";
|
||||
}
|
||||
];
|
||||
|
||||
i2s_audio = [
|
||||
{
|
||||
id = "i2s_audio_bus";
|
||||
i2s_bclk_pin = "GPIO19";
|
||||
i2s_lrclk_pin = "GPIO33";
|
||||
}
|
||||
];
|
||||
|
||||
light = [
|
||||
{
|
||||
id = "led";
|
||||
name = "None";
|
||||
entity_category = "config";
|
||||
|
||||
chipset = "SK6812";
|
||||
pin = "GPIO27";
|
||||
platform = "esp32_rmt_led_strip";
|
||||
|
||||
default_transition_length = "0s";
|
||||
disabled_by_default = false;
|
||||
num_leds = 1;
|
||||
rgb_order = "grb";
|
||||
rmt_channel = 0;
|
||||
|
||||
effects = [
|
||||
{
|
||||
pulse = {
|
||||
name = "Slow Pulse";
|
||||
|
||||
max_brightness = "100%";
|
||||
min_brightness = "50%";
|
||||
transition_length = "250ms";
|
||||
update_interval = "250ms";
|
||||
};
|
||||
}
|
||||
{
|
||||
pulse = {
|
||||
name = "Fast Pulse";
|
||||
|
||||
max_brightness = "100%";
|
||||
min_brightness = "50%";
|
||||
transition_length = "100ms";
|
||||
update_interval = "100ms";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
# Home-assistant buttons
|
||||
switch = [
|
||||
{
|
||||
id = "use_wake_word";
|
||||
name = "Use wake word";
|
||||
entity_category = "config";
|
||||
|
||||
optimistic = true;
|
||||
platform = "template";
|
||||
restore_mode = "RESTORE_DEFAULT_ON";
|
||||
|
||||
on_turn_on = [
|
||||
{lambda = "id(va).set_use_wake_word(true);";}
|
||||
{
|
||||
"if" = {
|
||||
condition.not = ["voice_assistant.is_running"];
|
||||
"then" = ["voice_assistant.start_continuous"];
|
||||
};
|
||||
}
|
||||
{"script.execute" = "reset_led";}
|
||||
];
|
||||
|
||||
on_turn_off = [
|
||||
"voice_assistant.stop"
|
||||
{lambda = "id(va).set_use_wake_word(false);";}
|
||||
{"script.execute" = "reset_led";}
|
||||
];
|
||||
}
|
||||
|
||||
{
|
||||
id = "use_listen_light";
|
||||
name = "Use listen light";
|
||||
entity_category = "config";
|
||||
|
||||
optimistic = true;
|
||||
platform = "template";
|
||||
restore_mode = "RESTORE_DEFAULT_ON";
|
||||
|
||||
on_turn_on = [{"script.execute" = "reset_led";}];
|
||||
on_turn_off = [{"script.execute" = "reset_led";}];
|
||||
}
|
||||
];
|
||||
|
||||
binary_sensor = [
|
||||
{
|
||||
id = "echo_button";
|
||||
name = "Button";
|
||||
entity_category = "diagnostic";
|
||||
|
||||
disabled_by_default = false;
|
||||
|
||||
platform = "gpio";
|
||||
pin = {
|
||||
inverted = true;
|
||||
number = "GPIO39";
|
||||
};
|
||||
|
||||
on_multi_click = [
|
||||
{
|
||||
timing = ["ON for at least 50ms" "OFF for at least 50ms"];
|
||||
"then" = [
|
||||
{
|
||||
"if" = {
|
||||
condition = {"switch.is_off" = "use_wake_word";};
|
||||
"then" = [
|
||||
{
|
||||
"if" = {
|
||||
condition = "voice_assistant.is_running";
|
||||
"then" = [
|
||||
{"voice_assistant.stop" = {};}
|
||||
{"script.execute" = "reset_led";}
|
||||
];
|
||||
"else" = [{"voice_assistant.start" = {};}];
|
||||
};
|
||||
}
|
||||
];
|
||||
"else" = [
|
||||
"voice_assistant.stop"
|
||||
{delay = "1s";}
|
||||
{"script.execute" = "reset_led";}
|
||||
{"script.wait" = "reset_led";}
|
||||
{"voice_assistant.start_continuous" = {};}
|
||||
];
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
timing = ["ON for at least 10s"];
|
||||
"then" = [{"button.press" = "factory_reset_btn";}];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
# Misc
|
||||
logger = {};
|
||||
|
||||
external_components = [
|
||||
{
|
||||
source = "github://pr#5230";
|
||||
components = ["esp_adf"];
|
||||
refresh = "0s";
|
||||
}
|
||||
];
|
||||
|
||||
# Configs
|
||||
script = [
|
||||
{
|
||||
id = "reset_led";
|
||||
"then" = [
|
||||
{
|
||||
"if" = {
|
||||
condition = [
|
||||
{"switch.is_on" = "use_wake_word";}
|
||||
{"switch.is_on" = "use_listen_light";}
|
||||
];
|
||||
"then" = [
|
||||
{
|
||||
"light.turn_on" = {
|
||||
id = "led";
|
||||
brightness = "60%";
|
||||
effect = "none";
|
||||
|
||||
red = "100%";
|
||||
green = "89%";
|
||||
blue = "71%";
|
||||
};
|
||||
}
|
||||
];
|
||||
"else" = [{"light.turn_off" = "led";}];
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
voice_assistant = {
|
||||
id = "va";
|
||||
speaker = "echo_speaker";
|
||||
microphone = "echo_microphone";
|
||||
auto_gain = "31dBFS";
|
||||
|
||||
noise_suppression_level = 2;
|
||||
vad_threshold = 3;
|
||||
volume_multiplier = 2;
|
||||
|
||||
on_listening = [
|
||||
{
|
||||
"light.turn_on" = {
|
||||
id = "led";
|
||||
effect = "Slow Pulse";
|
||||
|
||||
green = "0%";
|
||||
red = "0%";
|
||||
blue = "100%";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
on_stt_vad_end = [
|
||||
{
|
||||
"light.turn_on" = {
|
||||
id = "led";
|
||||
effect = "Fast Pulse";
|
||||
|
||||
red = "0%";
|
||||
green = "0%";
|
||||
blue = "100%";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
on_tts_start = [
|
||||
{
|
||||
"light.turn_on" = {
|
||||
id = "led";
|
||||
brightness = "100%";
|
||||
effect = "none";
|
||||
|
||||
red = "0%";
|
||||
green = "0%";
|
||||
blue = "100%";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
# Play audio from bluetooth speaker
|
||||
on_tts_end = [
|
||||
{
|
||||
"homeassistant.service" = {
|
||||
service = "media_player.play_media";
|
||||
data = {
|
||||
entity_id = "media_player.music_player_daemon";
|
||||
media_content_id = "!lambda \"return x;\"";
|
||||
media_content_type = "music";
|
||||
announce = "\"true\"";
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
on_end = [
|
||||
{delay = "100ms";}
|
||||
{wait_until.not."speaker.is_playing" = {};}
|
||||
{"script.execute" = "reset_led";}
|
||||
];
|
||||
|
||||
on_error = [
|
||||
{
|
||||
"light.turn_on" = {
|
||||
id = "led";
|
||||
brightness = "100%";
|
||||
effect = "none";
|
||||
|
||||
red = "100%";
|
||||
green = "0%";
|
||||
blue = "0%";
|
||||
};
|
||||
}
|
||||
{delay = "1s";}
|
||||
{"script.execute" = "reset_led";}
|
||||
];
|
||||
|
||||
on_client_connected = [
|
||||
{
|
||||
"if" = {
|
||||
condition = {"switch.is_on" = "use_wake_word";};
|
||||
"then" = [
|
||||
{"voice_assistant.start_continuous" = {};}
|
||||
{"script.execute" = "reset_led";}
|
||||
];
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
on_client_disconnected = [
|
||||
{
|
||||
"if" = {
|
||||
condition = {"switch.is_on" = "use_wake_word";};
|
||||
"then" = [
|
||||
{"voice_assistant.stop" = {};}
|
||||
{"light.turn_off" = "led";}
|
||||
];
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
# -------------------------------------------------------------
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
{dracul-ha-src, ...}: {
|
||||
services.home-assistant = {
|
||||
config = {
|
||||
# GUI
|
||||
frontend = {
|
||||
themes = "!include ${dracul-ha-src}/themes/dracul-ha.yaml";
|
||||
};
|
||||
lovelace = {
|
||||
mode = "yaml";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) getExe;
|
||||
in {
|
||||
systemd.services.home-assistant.preStart = let
|
||||
WorkingDirectory = "/var/lib/hass";
|
||||
creds = config.sops.secrets.spotifyd.path;
|
||||
in
|
||||
getExe (pkgs.writeShellApplication {
|
||||
name = "spotify-plus-creds";
|
||||
text = ''
|
||||
cp -f ${creds} ${WorkingDirectory}/.storage/SpotifyWebApiPython_librespot_credentials.json
|
||||
'';
|
||||
});
|
||||
|
||||
services.home-assistant = {
|
||||
# Needed for spotifyplus
|
||||
package = pkgs.home-assistant.override {
|
||||
packageOverrides = _: super: {
|
||||
inherit (self.packages.${pkgs.system}) urllib3;
|
||||
};
|
||||
};
|
||||
|
||||
customComponents = builtins.attrValues {
|
||||
inherit
|
||||
(self.legacyPackages.${pkgs.system}.hass-components)
|
||||
spotifyplus
|
||||
;
|
||||
};
|
||||
|
||||
extraComponents = [
|
||||
"spotify"
|
||||
];
|
||||
|
||||
config = {
|
||||
script.play_artist = {
|
||||
alias = "Spotify - Play Artist";
|
||||
sequence = [
|
||||
{
|
||||
sequence = [
|
||||
{
|
||||
action = "spotifyplus.search_artists";
|
||||
data = {
|
||||
entity_id = "media_player.spotifyplus";
|
||||
criteria = ''{{ criteria }}'';
|
||||
limit = 1;
|
||||
};
|
||||
response_variable = "sp_results";
|
||||
}
|
||||
{
|
||||
action = "spotifyplus.player_media_play_context";
|
||||
data = {
|
||||
entity_id = "media_player.spotifyplus";
|
||||
context_uri = ''
|
||||
{% for item in sp_results.result | dictsort %}
|
||||
{% if item[0] == 'items' %}
|
||||
{{ item[1][0].uri }}
|
||||
{% break %}
|
||||
{% endif %}
|
||||
{%- endfor %}
|
||||
'';
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,859 +0,0 @@
|
|||
# From https://github.com/don86nl/ha_intents/blob/main/config/packages/assist_timers.yaml
|
||||
{lib, ...}: let
|
||||
inherit (lib) concatStrings concatStringsSep;
|
||||
|
||||
mkTimer = id: {
|
||||
"assist_timer${toString id}" = {
|
||||
icon = "mdi:assistant";
|
||||
name = "Assist - Timer ${toString id}";
|
||||
restore = true;
|
||||
};
|
||||
};
|
||||
|
||||
mkLocation = id: {
|
||||
"assist_timer${toString id}_location" = {
|
||||
icon = "mdi:assistant";
|
||||
name = "Assist - Timer ${toString id} Location";
|
||||
max = 255;
|
||||
};
|
||||
};
|
||||
|
||||
entityIdList = concatStringsSep " " [
|
||||
''{{ states.timer ''
|
||||
''| rejectattr('state','eq','idle')''
|
||||
''| selectattr('entity_id','match','timer.assist_timer*')''
|
||||
''| map(attribute='entity_id')''
|
||||
];
|
||||
|
||||
settings = rec {
|
||||
timer_target = timer_target_default;
|
||||
timer_target_default = "media_player.music_player_daemon";
|
||||
|
||||
timer_tts = true;
|
||||
timer_tts_service = "tts.speak";
|
||||
timer_tts_target = "tts.piper";
|
||||
timer_volume = 0.4;
|
||||
timer_tts_message = "A set timer has finished.";
|
||||
|
||||
timer_media_location = "/path/to/file.mp3";
|
||||
};
|
||||
in {
|
||||
services.home-assistant = {
|
||||
config = {
|
||||
homeassistant.customize."script.assist_timerstart" = {inherit settings;};
|
||||
|
||||
# Make timers
|
||||
timer = (mkTimer 1) // (mkTimer 2) // (mkTimer 3);
|
||||
|
||||
# Makes location of a timer customizable from the UI
|
||||
input_text = (mkLocation 1) // (mkLocation 2) // (mkLocation 3);
|
||||
|
||||
# Automate some logic
|
||||
automation = [
|
||||
{
|
||||
alias = "Assist - TimerReached";
|
||||
description = "Assist automation when set timer time is reached.";
|
||||
id = "assist_timerreached";
|
||||
mode = "single";
|
||||
|
||||
condition = [
|
||||
{
|
||||
alias = "Finished timer is an assist timer";
|
||||
condition = "template";
|
||||
value_template = ''{{ trigger.event.data.entity_id[:18] == 'timer.assist_timer' }}'';
|
||||
}
|
||||
];
|
||||
|
||||
trigger = [
|
||||
{
|
||||
alias = "Any timer reached";
|
||||
id = "timer_finished";
|
||||
event_type = "timer.finished";
|
||||
platform = "event";
|
||||
}
|
||||
];
|
||||
|
||||
variables = {inherit settings;};
|
||||
|
||||
action = [
|
||||
{
|
||||
alias = "Get generic variables from script";
|
||||
|
||||
variables = {
|
||||
timer_target = concatStrings [
|
||||
''{%- if settings.get('timer_target')[:13] == "" %}''
|
||||
''{{- settings.get('timer_target_default') }}''
|
||||
|
||||
''{%- elif settings.get('timer_target')[:13] == "media_player." %}''
|
||||
''{{- settings.get('timer_target') }}''
|
||||
|
||||
''{%- elif (${concatStringsSep " " [
|
||||
''settings.get('timer_target')[:7] == "sensor."''
|
||||
''or''
|
||||
''settings.get('timer_target')[:11] == "input_text.")''
|
||||
''and''
|
||||
''(states(settings.get('timer_target'))[:13] == "media_player.")''
|
||||
]}%}''
|
||||
''{{- states(settings.get('timer_target')) }}''
|
||||
|
||||
''{%- elif (${concatStringsSep " " [
|
||||
''settings.get('timer_target')[:7] == "sensor."''
|
||||
''or''
|
||||
''settings.get('timer_target')[:11] == "input_text.")''
|
||||
''and''
|
||||
''(states(settings.get('timer_target')) == "")''
|
||||
]}%}''
|
||||
''{{- settings.get('timer_target_default') }}''
|
||||
|
||||
''{%- else %}''
|
||||
''{%- set media_player_list = states.media_player | map(attribute='entity_id') | list %}''
|
||||
|
||||
''{%- if "sensor." in settings.get('timer_target') or "input_text." in target_area %}''
|
||||
''{%- set target_area = states(settings.get('timer_target')) %}''
|
||||
|
||||
''{%- else %}''
|
||||
''{%- set target_area = settings.get('timer_target') %}''
|
||||
''{%- endif %}''
|
||||
|
||||
''{%- for entity_id in media_player_list %}''
|
||||
''{%- if area_name(entity_id) | lower == target_area | lower %}''
|
||||
''{{ entity_id }}''
|
||||
''{%- endif %}''
|
||||
''{%- endfor %}''
|
||||
''{%- endif %} ''
|
||||
];
|
||||
|
||||
timer_tts = ''{{ settings.get('timer_tts') }}'';
|
||||
timer_tts_service = ''{{ settings.get('timer_tts_service') }}'';
|
||||
timer_tts_target = ''{{ settings.get('timer_tts_target') }}'';
|
||||
timer_volume = ''{{ settings.get('timer_volume') }}'';
|
||||
timer_tts_message = ''{{ settings.get('timer_tts_message') }}'';
|
||||
|
||||
timer_media_location = ''{{ settings.get('timer_media_location') }}'';
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
alias = "Store current device volume";
|
||||
|
||||
variables = {
|
||||
device_volume = ''{{ state_attr(timer_target, 'volume_level') }}'';
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
alias = "Media file or TTS";
|
||||
|
||||
choose = [
|
||||
{
|
||||
alias = "Media file";
|
||||
|
||||
conditions = [
|
||||
{
|
||||
alias = "Timer is a media file";
|
||||
condition = "template";
|
||||
value_template = ''{{ timer_tts == false }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "Play media";
|
||||
service = "media_player.play_media";
|
||||
target.entity_id = ''{{ timer_target }}'';
|
||||
enabled = true;
|
||||
|
||||
data = {
|
||||
announce = true;
|
||||
media_content_id = ''{{ timer_media_location }}'';
|
||||
media_content_type = "music";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
default = [
|
||||
{delay.seconds = 1;}
|
||||
{
|
||||
alias = "Choose TTS service";
|
||||
choose = [
|
||||
{
|
||||
conditions = [
|
||||
{
|
||||
alias = "tts.cloud_say";
|
||||
condition = "template";
|
||||
value_template = ''{{ timer_tts_service != 'tts.speak' }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{
|
||||
service = ''{{ timer_tts_service }}'';
|
||||
|
||||
data = {
|
||||
cache = true;
|
||||
entity_id = ''{{ timer_target }}'';
|
||||
message = concatStrings [
|
||||
''{% if timer_tts_message[:7] == "sensor." or timer_tts_message[:11] == "input_text." %}''
|
||||
''{{ states(timer_tts_message) }}''
|
||||
''{% else %}''
|
||||
''{{ timer_tts_message }}''
|
||||
''{% endif %}''
|
||||
];
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
default = [
|
||||
{
|
||||
service = "tts.speak";
|
||||
|
||||
target.entity_id = ''{{ timer_tts_target }}'';
|
||||
|
||||
data = {
|
||||
cache = true;
|
||||
media_player_entity_id = ''{{ timer_target }}'';
|
||||
message = concatStrings [
|
||||
''{% if timer_tts_message[:7] == "sensor." or timer_tts_message[:11] == "input_text." %}''
|
||||
''{{ states(timer_tts_message) }}''
|
||||
''{% else %}''
|
||||
''{{ timer_tts_message }}''
|
||||
''{% endif %}''
|
||||
];
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
{
|
||||
alias = "Restore device previous volume";
|
||||
service = "media_player.volume_set";
|
||||
|
||||
target.entity_id = ''{{ timer_target }}'';
|
||||
|
||||
data = {
|
||||
volume_level = ''{{ device_volume }}'';
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
{
|
||||
alias = "Assist - TimerFinished";
|
||||
id = "assist_timerfinished";
|
||||
description = "Assist automation when set timer time is finished.";
|
||||
mode = "parallel";
|
||||
|
||||
condition = [
|
||||
{
|
||||
alias = "Timer was active or paused";
|
||||
condition = "template";
|
||||
value_template = ''{{ trigger.from_state != trigger.to_state }}'';
|
||||
}
|
||||
];
|
||||
|
||||
trigger = [
|
||||
{
|
||||
alias = "Assist timer finished or cancelled";
|
||||
entity_id = ["timer.assist_timer1" "timer.assist_timer2" "timer.assist_timer3"];
|
||||
platform = "state";
|
||||
to = "idle";
|
||||
}
|
||||
];
|
||||
|
||||
action = [
|
||||
{
|
||||
alias = "Delay for Timer Reached automation";
|
||||
delay.seconds = 3;
|
||||
}
|
||||
|
||||
{
|
||||
alias = "Reset timer location";
|
||||
service = "input_text.set_value";
|
||||
|
||||
target.entity_id = ''{{ 'input_text.' + trigger.entity_id[6:] + '_location' }}'';
|
||||
|
||||
data = {
|
||||
value = "";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
# Scripts to start, pause and stop timers
|
||||
script = let
|
||||
entity_id = ''{% if entity_id is set or entity_id != "" %} {{ entity_id }} {% else %} null {% endif %}'';
|
||||
in {
|
||||
assist_timerpause = {
|
||||
alias = "Assist - TimerPause";
|
||||
description = "Script for pausing a timer using HA Assist.";
|
||||
icon = "mdi:assistant";
|
||||
mode = "single";
|
||||
|
||||
variables = {
|
||||
inherit entity_id;
|
||||
timer_action = ''{% if timer_action is set or timer_action != "" %} {{ timer_action }} {% else %} resume {% endif %}'';
|
||||
};
|
||||
|
||||
sequence = [
|
||||
{
|
||||
choose = [
|
||||
{
|
||||
conditions = [
|
||||
{
|
||||
alias = "Single Timer";
|
||||
condition = "template";
|
||||
value_template = ''{{ entity_id[0][:18] == 'timer.assist_timer' }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "Single timer: Idle or active";
|
||||
|
||||
choose = [
|
||||
{
|
||||
conditions = [
|
||||
{
|
||||
alias = "Timer not active";
|
||||
condition = "template";
|
||||
value_template = ''{{ states(entity_id) == 'idle' }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{stop = "Timer is not active";}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
default = [
|
||||
{
|
||||
alias = "Pause or resume";
|
||||
|
||||
choose = [
|
||||
{
|
||||
alias = "Pause";
|
||||
|
||||
conditions = [
|
||||
{
|
||||
alias = "Action = pause";
|
||||
condition = "template";
|
||||
value_template = ''{{ timer_action == 'pause' }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "Pause timer";
|
||||
service = "timer.pause";
|
||||
|
||||
target.entity_id = ''{{ entity_id }}'';
|
||||
}
|
||||
{stop = "Pause timer";}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
default = [
|
||||
{
|
||||
alias = "Resume timer";
|
||||
service = "timer.start";
|
||||
|
||||
target.entity_id = ''{{ entity_id }}'';
|
||||
}
|
||||
{stop = "Resume timer";}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
{
|
||||
alias = "No specific timer";
|
||||
|
||||
conditions = [
|
||||
{
|
||||
alias = "No specific Timer";
|
||||
condition = "template";
|
||||
value_template = ''{{ entity_id == 'null' or entity_id | list | length == 0 }}'';
|
||||
}
|
||||
|
||||
{
|
||||
alias = "Timer(s) are active";
|
||||
condition = "template";
|
||||
value_template = ''${entityIdList} | list | length > 0 }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "No specific timer: # active?";
|
||||
|
||||
choose = [
|
||||
{
|
||||
conditions = [
|
||||
{
|
||||
alias = "No specific timer asked";
|
||||
condition = "template";
|
||||
value_template = ''{{ entity_id == 'null' or entity_id | list | length == 0 }}'';
|
||||
}
|
||||
|
||||
{
|
||||
alias = "Multiple timers active";
|
||||
condition = "template";
|
||||
value_template = ''${entityIdList} | list | length > 1 }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{stop = "Multiple timers active, none specified";}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
default = [
|
||||
{
|
||||
alias = "Pause or resume";
|
||||
|
||||
choose = [
|
||||
{
|
||||
alias = "Pause";
|
||||
|
||||
conditions = [
|
||||
{
|
||||
alias = "Action = pause";
|
||||
condition = "template";
|
||||
value_template = ''{{ timer_action == 'pause' }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "Pause timer";
|
||||
service = "timer.pause";
|
||||
|
||||
target.entity_id = ''${entityIdList} | join(', ') }}'';
|
||||
}
|
||||
{stop = "Pause timer";}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
default = [
|
||||
{
|
||||
alias = "Resume timer";
|
||||
service = "timer.start";
|
||||
|
||||
target.entity_id = ''${entityIdList} | join(', ') }}'';
|
||||
}
|
||||
{stop = "Resume timer";}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
{
|
||||
alias = "All timers";
|
||||
|
||||
conditions = [
|
||||
{
|
||||
alias = "All timers";
|
||||
condition = "template";
|
||||
value_template = ''{{ entity_id[0] == 'all' }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "Timers active?";
|
||||
|
||||
choose = [
|
||||
{
|
||||
alias = "No timers active";
|
||||
|
||||
conditions = [
|
||||
{
|
||||
alias = "No timers active";
|
||||
condition = "template";
|
||||
value_template = ''${entityIdList} | list | length == 0 }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{stop = "No timers active";}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
default = [
|
||||
{
|
||||
alias = "Pause or resume";
|
||||
|
||||
choose = [
|
||||
{
|
||||
alias = "Pause";
|
||||
|
||||
conditions = [
|
||||
{
|
||||
alias = "Action = pause";
|
||||
condition = "template";
|
||||
value_template = ''{{ timer_action == 'pause' }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "Pause timer";
|
||||
service = "timer.pause";
|
||||
target.entity_id = ''${entityIdList} | join(', ') }}'';
|
||||
}
|
||||
{stop = "Pause timer";}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
default = [
|
||||
{
|
||||
alias = "Resume timer";
|
||||
service = "timer.start";
|
||||
|
||||
target.entity_id = ''${entityIdList} | join(', ') }}'';
|
||||
}
|
||||
{stop = "Resume timer";}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
assist_timerstart = {
|
||||
alias = "Assist - TimerStart";
|
||||
description = "Script for starting a timer using HA Assist.";
|
||||
icon = "mdi:assistant";
|
||||
mode = "single";
|
||||
|
||||
variables = {inherit settings;};
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "Set variables";
|
||||
|
||||
variables = {
|
||||
timer_location = concatStrings [
|
||||
''{%- if settings.get('timer_target')[:13] == "media_player." %}''
|
||||
''{{ area_name(settings.get('timer_target')) | lower }}''
|
||||
|
||||
''{% elif (settings.get('timer_target')[:7] == "sensor." or settings.get('timer_target')[:11] == "input_text.") and states(settings.get('timer_target'))[:13] == "media_player." %}''
|
||||
''{{- states(settings.get('timer_target')) }}''
|
||||
|
||||
''{%- elif settings.get('timer_target')[:13] != "media_player." and settings.get('timer_target')[:7] != "sensor." and settings.get('timer_target')[:11] != "input_text." %}''
|
||||
''{{- settings.get('timer_target') }}''
|
||||
|
||||
''{%- elif (settings.get('timer_target')[:7] == "sensor." or settings.get('timer_target')[:11] == "input_text.") and (states(settings.get('timer_target')) != "") and (states(settings.get('timer_target'))[:13] == "media_player.") %}''
|
||||
''{{ area_name(settings.get('timer_target_default')) }} ''
|
||||
|
||||
''{%- elif (settings.get('timer_target')[:7] == "sensor." or settings.get('timer_target')[:11] == "input_text.") %}''
|
||||
''{% if states(settings.get('timer_target')) != "" and states(settings.get('timer_target')) != "not_home" and states(settings.get('timer_target')) != 0 %}''
|
||||
''{{ states(settings.get('timer_target')) }}''
|
||||
|
||||
''{% else %}''
|
||||
''{{- area_name(settings.get('timer_target_default')) | lower }}''
|
||||
''{%- endif %}''
|
||||
|
||||
''{%- else %}''
|
||||
''{{- area_name(settings.get('timer_target')) | lower }}''
|
||||
''{%- endif %}''
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
alias = "Set timer location";
|
||||
service = "input_text.set_value";
|
||||
|
||||
target.entity_id = concatStrings [
|
||||
''{% if states('timer.assist_timer1') != 'active' and states('timer.assist_timer1') != 'paused' %}''
|
||||
''input_text.assist_timer1_location''
|
||||
|
||||
''{% elif states('timer.assist_timer2') != 'active' and states('timer.assist_timer2') != 'paused' %}''
|
||||
''input_text.assist_timer2_location''
|
||||
|
||||
''{% else %}''
|
||||
''input_text.assist_timer3_location''
|
||||
''{% endif%}''
|
||||
];
|
||||
|
||||
data = {
|
||||
value = ''{{ timer_location }}'';
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
alias = "Start timer";
|
||||
service = "timer.start";
|
||||
|
||||
target.entity_id = concatStrings [
|
||||
''{% if states('timer.assist_timer1') != 'active' and states('timer.assist_timer1') != 'paused' %}''
|
||||
''timer.assist_timer1''
|
||||
|
||||
''{% elif states('timer.assist_timer2') != 'active' and states('timer.assist_timer2') != 'paused' %}''
|
||||
''timer.assist_timer2''
|
||||
|
||||
''{% else %}''
|
||||
''timer.assist_timer3''
|
||||
''{% endif%}''
|
||||
];
|
||||
|
||||
data_template = {
|
||||
duration = ''{{ duration }}'';
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
assist_timerstop = {
|
||||
alias = "Assist - TimerStop";
|
||||
description = "Script for stopping a timer using HA Assist.";
|
||||
icon = "mdi:assistant";
|
||||
mode = "single";
|
||||
|
||||
variables = {inherit entity_id;};
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "Set variables";
|
||||
variables = {inherit entity_id;};
|
||||
}
|
||||
|
||||
{
|
||||
choose = [
|
||||
{
|
||||
alias = "Stop Timer music";
|
||||
|
||||
conditions = [
|
||||
{
|
||||
alias = "Timer is a media file";
|
||||
condition = "template";
|
||||
value_template = ''{{ timer_tts == false }}'';
|
||||
}
|
||||
|
||||
{
|
||||
condition = "template";
|
||||
value_template = ''
|
||||
{% set mediaplayer = namespace(entity=[]) %}
|
||||
{% for player in states.media_player %}
|
||||
{%- if ((state_attr(player.entity_id, 'media_content_id') |lower != 'none' and state_attr(player.entity_id, 'media_content_id')[:47][38:] == 'timer.mp3') or state_attr(player.entity_id, 'media_title') | lower == 'timer') and states(player.entity_id) == 'playing' -%}
|
||||
{%- set mediaplayer.entity = player.entity_id -%}
|
||||
{% endif -%}
|
||||
{% endfor %}
|
||||
{{ mediaplayer.entity[:12] == 'media_player' }}
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "Stop timer music";
|
||||
service = "media_player.media_stop";
|
||||
|
||||
target.entity_id = ''
|
||||
{% set mediaplayer = namespace(entity=[]) %}
|
||||
{% for player in states.media_player %}
|
||||
{% if ((state_attr(player.entity_id, 'media_content_id') |lower != 'none' and state_attr(player.entity_id, 'media_content_id')[:47][38:] == 'timer.mp3') or state_attr(player.entity_id, 'media_title') | lower == 'timer') and states(player.entity_id) == 'playing' %}
|
||||
{% set mediaplayer.entity = player.entity_id %}
|
||||
{% endif %}
|
||||
{% endfor %} {{ mediaplayer.entity }}'';
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
{
|
||||
conditions = [
|
||||
{
|
||||
alias = "Single Timer";
|
||||
condition = "template";
|
||||
value_template = ''{{ entity_id[0][:18] == 'timer.assist_timer' }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "Single timer: Idle or active";
|
||||
|
||||
choose = [
|
||||
{
|
||||
conditions = [
|
||||
{
|
||||
alias = "Timer not active";
|
||||
condition = "template";
|
||||
value_template = ''{{ states(entity_id) == 'idle' }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{stop = "Timer is not active";}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
default = [
|
||||
{
|
||||
alias = "Reset timer location value";
|
||||
service = "input_text.set_value";
|
||||
|
||||
target.entity_id = ''${entityIdList} | join('_location, ') | replace('timer.', 'input_text.') }}'';
|
||||
|
||||
data = {
|
||||
value = "0";
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
alias = "Cancel single timer";
|
||||
service = "timer.cancel";
|
||||
|
||||
target.entity_id = ''{{ entity_id }}'';
|
||||
}
|
||||
|
||||
{stop = "Timer cancelled";}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
{
|
||||
alias = "No specific timer";
|
||||
|
||||
conditions = [
|
||||
{
|
||||
alias = "No specific Timer";
|
||||
condition = "template";
|
||||
value_template = ''{{ entity_id == 'null' or entity_id | list | length == 0 }}'';
|
||||
}
|
||||
|
||||
{
|
||||
alias = "Timer(s) are active";
|
||||
condition = "template";
|
||||
value_template = ''${entityIdList} | list | length > 0 }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "No specific timer: # active?";
|
||||
|
||||
choose = [
|
||||
{
|
||||
conditions = [
|
||||
{
|
||||
alias = "No specific timer asked";
|
||||
condition = "template";
|
||||
value_template = ''{{ entity_id == 'null' or entity_id | list | length == 0 }}'';
|
||||
}
|
||||
|
||||
{
|
||||
alias = "Multiple timers active";
|
||||
condition = "template";
|
||||
value_template = ''${entityIdList} | list | length > 1 }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{stop = "Multiple timers active, none specified";}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
default = [
|
||||
{
|
||||
alias = "Cancel single timer";
|
||||
service = "timer.cancel";
|
||||
|
||||
target.entity_id = ''${entityIdList} | join(', ') }}'';
|
||||
}
|
||||
|
||||
{
|
||||
alias = "Reset timer location value";
|
||||
service = "input_text.set_value";
|
||||
metadata = {};
|
||||
|
||||
target.entity_id = ''${entityIdList} | join('_location, ') | replace('timer.', 'input_text.') }}'';
|
||||
|
||||
data = {value = "0";};
|
||||
}
|
||||
|
||||
{stop = "Timer cancelled";}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
{
|
||||
alias = "All timers";
|
||||
|
||||
conditions = [
|
||||
{
|
||||
alias = "All timers";
|
||||
condition = "template";
|
||||
value_template = ''{{ entity_id[0] == 'all' }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{
|
||||
alias = "Timers active?";
|
||||
|
||||
choose = [
|
||||
{
|
||||
alias = "No timers active";
|
||||
|
||||
conditions = [
|
||||
{
|
||||
alias = "No timers active";
|
||||
condition = "template";
|
||||
value_template = ''${entityIdList} | list | length == 0 }}'';
|
||||
}
|
||||
];
|
||||
|
||||
sequence = [
|
||||
{stop = "No timers active";}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
default = [
|
||||
{
|
||||
alias = "Cancel all timers";
|
||||
service = "timer.cancel";
|
||||
|
||||
target.entity_id = ''${entityIdList} | join(', ') }}'';
|
||||
}
|
||||
|
||||
{stop = "Cancel all timers";}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (config.vars) mainUser;
|
||||
in {
|
||||
hardware.bluetooth = {
|
||||
enable = true;
|
||||
powerOnBoot = true;
|
||||
|
||||
settings = {
|
||||
General = {
|
||||
DiscoverableTimeout = 0;
|
||||
Experimental = true;
|
||||
KernelExperimental = true;
|
||||
};
|
||||
|
||||
Policy.AutoEnable = "true";
|
||||
};
|
||||
};
|
||||
|
||||
# Have pulseaudio and spotifyd start at boot but after bluetooth
|
||||
# so bluetooth accepts sound connections from the start.
|
||||
users.users.${mainUser}.linger = true;
|
||||
systemd.user.services = {
|
||||
pulseaudio.after = ["bluetooth.service"];
|
||||
spotifyd.after = ["pulseaudio.service"];
|
||||
};
|
||||
systemd.user.targets.default.wants = [
|
||||
"pulseaudio.service"
|
||||
"spotifyd.service"
|
||||
];
|
||||
|
||||
# Allow pulseaudio to be managed by MPD
|
||||
hardware.pulseaudio = {
|
||||
enable = true;
|
||||
|
||||
zeroconf = {
|
||||
discovery.enable = true;
|
||||
publish.enable = true;
|
||||
};
|
||||
|
||||
extraConfig = ''
|
||||
load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1
|
||||
'';
|
||||
};
|
||||
|
||||
services = {
|
||||
upower.enable = true;
|
||||
|
||||
mpd = {
|
||||
enable = true;
|
||||
|
||||
network = {
|
||||
listenAddress = "127.0.0.1";
|
||||
port = 6600;
|
||||
};
|
||||
|
||||
extraConfig = ''
|
||||
audio_output {
|
||||
type "pulse"
|
||||
name "UE Boom 2"
|
||||
sink "bluez_sink.88_C6_26_93_4B_77.a2dp_sink"
|
||||
server "127.0.0.1"
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
home-manager.users.${mainUser}.services.spotifyd = {
|
||||
enable = true;
|
||||
|
||||
package = pkgs.spotifyd.override {
|
||||
withMpris = false;
|
||||
withKeyring = false;
|
||||
};
|
||||
|
||||
settings.global = {
|
||||
device_name = config.networking.hostName + " connect";
|
||||
device_type = "speaker";
|
||||
|
||||
zeroconf_port = 33798;
|
||||
|
||||
autoplay = false;
|
||||
backend = "pulseaudio";
|
||||
bitrate = 320;
|
||||
no_audio_cache = true;
|
||||
volume_normalisation = false;
|
||||
};
|
||||
};
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue