diff --git a/colors.nix b/colors.nix index e7b6bce..84cca5d 100644 --- a/colors.nix +++ b/colors.nix @@ -109,9 +109,11 @@ let inherit (builtins) mapAttrs map; in rec { }; hex = mapAttrs (name: value: - if name != "grayscales" - then mapAttrs (n: v: "#" + v) value - else map (v: "#" + v) value + if name == "grayscales" + then map (v: "#" + v) value + else if name == "hex" + then value + else mapAttrs (n: v: "#" + v) value ) (dark); }; diff --git a/machines/thor/configuration.nix b/machines/thor/configuration.nix index b23db53..b843b96 100644 --- a/machines/thor/configuration.nix +++ b/machines/thor/configuration.nix @@ -5,7 +5,7 @@ ./hardware-configuration.nix ../../modules ]; - + riley = { ide = true; gui = true; @@ -15,4 +15,39 @@ hostName = "thor"; interfaces.enp9s0.useDHCP = true; }; + + devices = { + + # Audio devices + audio = { + + # Outputs + speakers = "alsa_output.pci-0000_0c_00.4.analog-stereo"; + external = "alsa_output.pci-0000_0a_00.1.hdmi-stereo"; + headset = null; # Thor doesn't have bluetooth support (yet) + + # Inputs + main-mic = "alsa_input.usb-046d_C922_Pro_Stream_Webcam_CC9E75BF-02.analog-stereo"; + + }; + + # Displays + video.displays = { + + # Connected to the ultrawide output + "HDMI-1" = { + primary = true; + position = [ 0 0 ]; + }; + + # Vertical output to the right of HDMI-1 + "DP-2" = { + rotate = "left"; + position = [ 2560 ((1080 - 1920) / 2) ]; + }; + + }; + + }; + } diff --git a/machines/thor/hardware-configuration.nix b/machines/thor/hardware-configuration.nix index 0c46e4d..8dea2d2 100644 --- a/machines/thor/hardware-configuration.nix +++ b/machines/thor/hardware-configuration.nix @@ -4,31 +4,32 @@ { config, lib, pkgs, modulesPath, ... }: { - imports = - [ (modulesPath + "/installer/scan/not-detected.nix") + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") ]; - boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-amd" ]; - boot.extraModulePackages = [ ]; + boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-amd" ]; + boot.extraModulePackages = [ ]; - fileSystems."/" = - { device = "/dev/disk/by-uuid/f3cdd2ab-62ba-4d72-8a28-b3adc0ec3997"; - fsType = "ext4"; + fileSystems."/" = { + device = "/dev/disk/by-uuid/f3cdd2ab-62ba-4d72-8a28-b3adc0ec3997"; + fsType = "ext4"; }; - fileSystems."/boot" = - { device = "/dev/disk/by-uuid/3691-F2E6"; - fsType = "vfat"; + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/3691-F2E6"; + fsType = "vfat"; }; - fileSystems."/nix" = - { device = "/dev/disk/by-uuid/e317d7a7-c11c-4f3a-afda-0fd949f5633c"; - fsType = "btrfs"; + fileSystems."/nix" = { + device = "/dev/disk/by-uuid/e317d7a7-c11c-4f3a-afda-0fd949f5633c"; + fsType = "btrfs"; }; - swapDevices = [ { label = "swap"; } ]; + swapDevices = [ { label = "swap"; } ]; + + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; - hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; } diff --git a/modules/default.nix b/modules/default.nix index 7b74a12..e48996b 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -2,6 +2,38 @@ { config, lib, pkgs, ... }: +with lib; with types; +let named = submodule { + options = { + normal = mkOption { type = str; }; + bright = mkOption { type = str; }; + pastel = mkOption { type = str; }; + }; + }; + special = submodule { + options = { + primary = mkOption { type = str; }; + normal = mkOption { type = str; }; + slight = mkOption { type = str; }; + }; + }; + themeType = submodule { + options = { + foreground = mkOption { type = special; }; + background = mkOption { type = special; }; + grayscales = mkOption { type = listOf str; }; + red = mkOption { type = named; }; + green = mkOption { type = named; }; + blue = mkOption { type = named; }; + yellow = mkOption { type = named; }; + purple = mkOption { type = named; }; + cyan = mkOption { type = named; }; + pink = mkOption { type = named; }; + orange = mkOption { type = named; }; + misc = mkOption { type = attrsOf str; }; + hex = mkOption { type = themeType; }; + }; + }; in { options.riley = with lib; { @@ -10,7 +42,8 @@ type = types.bool; description = '' Enable IDE-like plugins such as language servers for Rust, Haskell and - Nix in the editor, and configure accordingly. + Nix in the editor, and configure accordingly. If disabled, the editor + will lack some features such as semantic highlighting. ''; default = true; }; @@ -18,28 +51,92 @@ gui = mkOption { type = types.bool; description = '' - Enables GUI applications, a display server, audio server and related services. + Enable the display server and related graphical programs. ''; default = true; }; + theme = mkOption { + type = themeType; + description = '' + The theme used across the installation. Not used if gui is disabled. + ''; + }; + }; + options.devices = mkOption { + type = with types; submodule { + options = { + + audio = mkOption { + type = nullOr (submodule { + options = { + speakers = mkOption { type = str; }; + external = mkOption { type = str; }; + headset = mkOption { type = nullOr str; }; + main-mic = mkOption { type = nullOr str; }; + }; + }); + description = '' + Known audio devices: outputs & microphones. + Each string should be a pulseaudio sink or source. + ''; + }; + + video = mkOption { + type = submodule { + options = { + displays = let output = submodule { + options = { + primary = mkOption { + type = bool; + default = false; + }; + position = mkOption { + type = nullOr (listOf int); + default = null; + }; + rotate = mkOption { + type = enum [ "normal" "left" "right" "inverted" ]; + default = "normal"; + }; + }; + }; in mkOption { + type = attrsOf output; + description = '' + A list of outputs with information on how to place them. + ''; + }; + }; + }; + description = '' + Define the video devices (just the displays, for now). + ''; + }; + + }; + }; + }; + + imports = [ - ./kakoune - ./display + ./ide + ./gui - ./alacritty.nix ./fonts.nix ./git.nix + ./ssh.nix ]; config = { + riley.theme = (import ../colors.nix)."dark"; + environment.systemPackages = with pkgs; [ # Web utils diff --git a/modules/display/default.nix b/modules/display/default.nix deleted file mode 100644 index 4568bd7..0000000 --- a/modules/display/default.nix +++ /dev/null @@ -1,193 +0,0 @@ -{ pkgs, config, lib, ... }: - -let theme = (import ../../colors.nix)."dark".hex; - - # Keybinds that launch an application. - launchers = ({ browser }: mod: { - "${mod}+Tab" = "exec ${browser}"; - }); - - # Keybinds generated from a set of workspaces. - workspace = ({ numbered ? 0, named ? {} }: mod: with lib; - let nums = genAttrs (map toString (range 1 numbered)) id; - workspaces = named // nums; - genBinds = (n: k: { - - # Focus the workspace - "${mod}+${k}" = "workspace ${n}"; - - # Move a window to the workspace - "${mod}+Shift+${k}" = "move window to workspace ${n}"; - - }); - keybinds = mapAttrsToList genBinds workspaces; in - mkMerge (keybinds) - ); - - # Layout manipulation keybinds. - layout = (mod: { - - "${mod}+A" = "split v"; - "${mod}+S" = "split h"; - - "${mod}+F" = "fullscreen toggle"; - - }); - - # Directional keys are used for basic navigation. - directional = ({ left, right, up, down }: mod: { - - # Change window focus - "${mod}+${left}" = "focus left"; - "${mod}+${down}" = "focus down"; - "${mod}+${up}" = "focus up"; - "${mod}+${right}" = "focus right"; - - # Move windows - "${mod}+Shift+${left}" = "move left"; - "${mod}+Shift+${down}" = "move down"; - "${mod}+Shift+${up}" = "move up"; - "${mod}+Shift+${right}" = "move right"; - - }); - - # Media controls. - media = ({ mpc ? null }: mod: - if (mpc != null) - then (let cmd = "${mpc}/bin/${mpc.pname}"; in { - "${mod}+comma" = "exec ${cmd} prev"; - "${mod}+period" = "exec ${cmd} next"; - "${mod}+slash" = "exec ${cmd} toggle"; - }) - else {} - ); - - # Utility scripts and such. - scripts = (mod: {}); in - -{ - - services.xserver = { - enable = true; - windowManager.i3 = { - enable = true; - package = pkgs.i3; #-gaps; - }; - }; - - home-manager.users."riley" = - let browser = pkgs.google-chrome; - term = pkgs.alacritty; in - { - - home.packages = with pkgs; [ - - tdesktop - - xclip - - # Paste from clipboard - (writeShellApplication { - name = "xc.p"; - runtimeInputs = [ xclip ]; - text = "xclip -sel clip -o"; - }) - - # Copy to clipboard - (writeShellApplication { - name = "xc.c"; - runtimeInputs = [ xclip ]; - text = "xclip -sel clip -i"; - }) - - # Copy to clipboard with given mime type - (writeShellApplication { - name = "xc.t"; - runtimeInputs = [ xclip ]; - text = "xclip -sel clip -t \"$1\" -i"; - }) - - ] ++ [ - term - browser - ]; - - xsession.windowManager.i3 = { - enable = true; - - package = pkgs.i3; - - config = with lib; (rec { - - modifier = "Mod4"; - terminal = "${term}/bin/${term.pname}"; - - # Apply the modifier key to each of the keybinding generator functions - # and merge the resulting sets. - keybindings = let mod = modifier; in mkMerge (map (f: f (mod)) [ - (mod: { - "${mod}+Return" = "exec ${terminal}"; - "${mod}+BackSpace" = "kill"; - }) - (directional { - left = "H"; - right = "L"; - down = "J"; - up = "K"; - }) - (workspace { - numbered = 5; - named = { - "dev" = "0"; - "doc" = "minus"; - "net" = "equal"; - }; - }) - (launchers { - browser = "google-chrome-stable"; - }) - layout - (media { - mpc = pkgs.mpc_cli; - }) - scripts - ]); - - colors = { - focused = rec { - background = theme.background.normal; - text = theme."red".bright; - border = background; - childBorder = border; - indicator = border; - }; - unfocused = rec { - background = theme.background.normal; - text = theme.foreground.slight; - border = background; - childBorder = border; - indicator = border; - }; - focusedInactive = colors.unfocused; - }; - - window = { - border = 2; - commands = [ - { command = "border pixel 2"; criteria = { class = ".*"; }; } - ]; - }; - - fonts = { - names = [ "Source Sans 3" ]; - style = "Semibold"; - size = 10.0; - }; - - }); - - }; - - }; - -} diff --git a/modules/gui/README.md b/modules/gui/README.md new file mode 100644 index 0000000..46e1a81 --- /dev/null +++ b/modules/gui/README.md @@ -0,0 +1,7 @@ +# Display module + +The display module defines configuration for the window manager and related programs, +as well as the audio server. + +Currently, this sets up an environment with an X11 display server and the i3 window manager. +It also enables pulseaudio as the audio server. diff --git a/modules/alacritty.nix b/modules/gui/alacritty.nix similarity index 89% rename from modules/alacritty.nix rename to modules/gui/alacritty.nix index ee5604e..4e92456 100644 --- a/modules/alacritty.nix +++ b/modules/gui/alacritty.nix @@ -1,6 +1,6 @@ -{ pkgs, config, ... }: +{ pkgs, lib, config, ... }: -{ +(lib.mkIf (config.riley.gui) { home-manager.users."riley" = { programs.alacritty = { enable = true; @@ -13,7 +13,7 @@ bold = { family = "Fira Code"; style = "Medium"; }; }; - colors = with (import ../colors.nix)."dark".hex; { + colors = with config.riley.theme.hex; { primary = { background = background.primary; @@ -42,4 +42,4 @@ }; }; -} +}) diff --git a/modules/gui/clipboard.nix b/modules/gui/clipboard.nix new file mode 100644 index 0000000..0c33a8e --- /dev/null +++ b/modules/gui/clipboard.nix @@ -0,0 +1,24 @@ +{ config, lib, pkgs, ... }: + +(lib.mkIf (config.riley.gui) { + + # Add some shell scripts that abstract away the + # horrible reality that the clipboard is managed by + # the display server. + users.users."riley".packages = with pkgs; [ + + (writeShellApplication { + name = "copy"; + runtimeInputs = [ xclip ]; + text = "xclip -sel clip -i"; + }) + + (writeShellApplication { + name = "paste"; + runtimeInputs = [ xclip ]; + text = "xclip -sel clip -o"; + }) + + ]; + +}) diff --git a/modules/gui/default.nix b/modules/gui/default.nix new file mode 100644 index 0000000..0f2c18a --- /dev/null +++ b/modules/gui/default.nix @@ -0,0 +1,20 @@ +{ pkgs, config, lib, ... }: + +({ + + imports = [ + ./window-manager.nix + ./pulseaudio.nix + ./clipboard.nix + ./alacritty.nix + ]; + +}) // (lib.mkIf (config.riley.gui) { + + # Graphical applications + users.users."riley".packages = with pkgs; [ + google-chrome + tdesktop + ]; + +}) diff --git a/modules/gui/keybinds.nix b/modules/gui/keybinds.nix new file mode 100644 index 0000000..9b0601a --- /dev/null +++ b/modules/gui/keybinds.nix @@ -0,0 +1,110 @@ +{ lib, config, pkgs, modifier ? "Mod4", directional, workspace, launchers }: + +with lib; let mod = modifier; + + # Directional shortcuts. + # + # These are used to change focus and move windows around. + genDirectional = ({ left, right, up, down }: { + + # Change window focus + "${mod}+${left}" = "focus left"; + "${mod}+${down}" = "focus down"; + "${mod}+${up}" = "focus up"; + "${mod}+${right}" = "focus right"; + + # Move windows + "${mod}+Shift+${left}" = "move left"; + "${mod}+Shift+${down}" = "move down"; + "${mod}+Shift+${up}" = "move up"; + "${mod}+Shift+${right}" = "move right"; + + }); + + # Workspace shortcuts. + # + # The `numbered` parameter defines the number of numbered workspaces, + # which can be no more than 8. + # + # The `named` parameter defines a set of named workspaces and the key + # used to navigate to it. + # + # For each entry this generates two keybindings: + # - `+`: focus workspace + # - `+Shift+`: move focused window to workspace + # + # `` is set to the workspace number for numbered workspaces. + genWorkspaces = ({ numbered ? 0, named ? {} }: with lib; + let nums = genAttrs (map toString (range 1 (min numbered 9))) id; + workspaces = named // nums; + genBinds = (n: k: { + + # Focus the workspace + "${mod}+${k}" = "workspace ${n}"; + + # Move a window to the workspace + "${mod}+Shift+${k}" = "move window to workspace ${n}"; + + }); + keybinds = mapAttrsToList genBinds workspaces; in + mkMerge (keybinds) + ); + + # Application launchers + genLaunchers = ({ browser }: { + "${mod}+Tab" = "exec ${browser}"; + "${mod}+Return" = "exec alacritty"; + }); + + # Layout manipulation + layout = ({ + + "${mod}+A" = "split v"; + "${mod}+S" = "split h"; + + "${mod}+F" = "fullscreen toggle"; + + "${mod}+BackSpace" = "kill"; + + }); + + # Media-related keys + media = ({ mpc_cli ? null, pulseaudio }: let cmd = "${mpc_cli}/bin/mpc"; in + (optionalAttrs (mpc_cli != null) { + + "${mod}+comma" = "exec ${cmd} prev"; + "${mod}+period" = "exec ${cmd} next"; + "${mod}+slash" = "exec ${cmd} toggle"; + + }) // (with config.devices; optionalAttrs (audio != null) (with audio; { + + # Main speakers + + "${mod}+z" = "exec pactl set-sink-volume ${speakers} -10%"; + "${mod}+x" = "exec pactl set-sink-volume ${speakers} +10%"; + + # Secondary output + + "${mod}+Alt+z" = "exec pactl set-sink-volume ${external} -10%"; + "${mod}+Alt+x" = "exec pactl set-sink-volume ${external} +10%"; + + } // (optionalAttrs (main-mic != null) { + + # Microphone + + "${mod}+c" = "exec pactl set-source-mute ${main-mic} toggle"; + + }))) + ); + +in (mkMerge [ + + (media { inherit (pkgs) mpc_cli pulseaudio; }) + + (genDirectional directional) + (genWorkspaces workspace) + (genLaunchers launchers) + + layout + +]) diff --git a/modules/gui/pulseaudio.nix b/modules/gui/pulseaudio.nix new file mode 100644 index 0000000..93261d8 --- /dev/null +++ b/modules/gui/pulseaudio.nix @@ -0,0 +1,10 @@ +{ lib, config, pkgs, ... }: + +(lib.mkIf (config.riley.gui) { + sound.enable = true; + hardware.pulseaudio.enable = true; + + users.users."riley".packages = with pkgs; [ + pavucontrol + ]; +}) diff --git a/modules/gui/window-manager.nix b/modules/gui/window-manager.nix new file mode 100644 index 0000000..76cfffd --- /dev/null +++ b/modules/gui/window-manager.nix @@ -0,0 +1,80 @@ +{ pkgs, config, lib, ... }: + +let theme = config.riley.theme.hex; + modifier = "Mod4"; + keybindings = (import ./keybinds.nix { + + inherit modifier lib pkgs config; + + directional = { + left = "H"; + right = "L"; + up = "K"; + down = "J"; + }; + + workspace = { + numbered = 5; + named = { + "web" = "equal"; + "doc" = "minus"; + "dev" = "0"; + }; + }; + + launchers = { + browser = "google-chrome-stable"; + }; + + }); +in (lib.mkIf (config.riley.gui) { + services.xserver = { + enable = true; + windowManager.i3.enable = true; + }; + + home-manager.users."riley" = { + xsession.windowManager.i3 = { + enable = true; + + config = with lib; (rec { + + inherit modifier keybindings; + + terminal = "${pkgs.alacritty}/bin/alacritty"; + + colors = { + focused = rec { + background = theme.background.normal; + text = theme."red".bright; + border = background; + childBorder = border; + indicator = border; + }; + unfocused = rec { + background = theme.background.normal; + text = theme.foreground.slight; + border = background; + childBorder = border; + indicator = border; + }; + focusedInactive = colors.unfocused; + }; + + window = { + border = 2; + commands = [ + { command = "border pixel 2"; criteria = { class = ".*"; }; } + ]; + }; + + fonts = { + names = [ "Source Sans 3" ]; + style = "Semibold"; + size = 10.0; + }; + + }); + }; + }; +}) diff --git a/modules/ide/README.md b/modules/ide/README.md new file mode 100644 index 0000000..5c8467f --- /dev/null +++ b/modules/ide/README.md @@ -0,0 +1,4 @@ +# Kakoune + +This module sets the kakoune editor up like an IDE using language server +modules and plugins. diff --git a/modules/kakoune/colors/common.nix b/modules/ide/colors/common.nix similarity index 100% rename from modules/kakoune/colors/common.nix rename to modules/ide/colors/common.nix diff --git a/modules/kakoune/colors/default.nix b/modules/ide/colors/default.nix similarity index 100% rename from modules/kakoune/colors/default.nix rename to modules/ide/colors/default.nix diff --git a/modules/kakoune/colors/haskell.nix b/modules/ide/colors/haskell.nix similarity index 100% rename from modules/kakoune/colors/haskell.nix rename to modules/ide/colors/haskell.nix diff --git a/modules/kakoune/colors/nix.nix b/modules/ide/colors/nix.nix similarity index 100% rename from modules/kakoune/colors/nix.nix rename to modules/ide/colors/nix.nix diff --git a/modules/kakoune/colors/rust.nix b/modules/ide/colors/rust.nix similarity index 100% rename from modules/kakoune/colors/rust.nix rename to modules/ide/colors/rust.nix diff --git a/modules/kakoune/default.nix b/modules/ide/default.nix similarity index 98% rename from modules/kakoune/default.nix rename to modules/ide/default.nix index ada0ee7..357aa8f 100644 --- a/modules/kakoune/default.nix +++ b/modules/ide/default.nix @@ -3,7 +3,7 @@ let kakrc = pkgs.writeTextFile (rec { name = "kakrc.kak"; destination = "/share/kak/autoload/${name}"; - text = with (import ../../colors.nix)."dark"; '' + text = with config.riley.theme; '' # Line numbering add-highlighter global/ number-lines -separator ' │ ' -hlcursor @@ -105,7 +105,7 @@ let kakrc = pkgs.writeTextFile (rec { # Syntax colors colors = (import ./colors { - theme = (import ../../colors.nix)."dark"; + theme = config.riley.theme; inherit lib pkgs; }); diff --git a/modules/ssh.nix b/modules/ssh.nix new file mode 100644 index 0000000..434ed1b --- /dev/null +++ b/modules/ssh.nix @@ -0,0 +1,18 @@ +{ config, lib, pkgs, ... }: + +{ + services.openssh = { + enable = true; + passwordAuthentication = false; + }; + + users.users."riley" = { + + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGk/nBXhr3xWtbXBBkCuwqE6OixpRXCfscfxibgcCsTR me@riley.lgbt" + ]; + + packages = with pkgs; [ openssh ]; + + }; +}