~ruther/nixos-config

a1128e507b85a32d4a700727c24d11151284a954 — Frantisek Bohacek 8 months ago 0539e43
feat(home): add desktop session startup options
2 files changed, 201 insertions(+), 0 deletions(-)

A home/modules/sessions/default-hm-impl.nix
A home/modules/sessions/default.nix
A home/modules/sessions/default-hm-impl.nix => home/modules/sessions/default-hm-impl.nix +18 -0
@@ 0,0 1,18 @@
{ config, lib, ... }:

let
  cfg = config.desktopSessions;
in {
  options.desktopSessions.autoStart = {
    enableBashIntegration = lib.mkEnableOption "enable bash integration to .profile" // { default = true; };
    enableZshIntegration = lib.mkEnableOption "enable zsh integration to .zprofile" // { default = true; };
  };

  config = lib.mkIf (cfg.enable) {
    programs.zsh.profileExtra = lib.optionalString (cfg.autoStart.enable && cfg.autoStart.enableZshIntegration) cfg.autoStart.profileSelectContent;
    programs.bash.profileExtra = lib.optionalString (cfg.autoStart.enable && cfg.autoStart.enableBashIntegration) cfg.autoStart.profileSelectContent;

    home.file.".start-session".source = cfg.selectSession;
  };

}

A home/modules/sessions/default.nix => home/modules/sessions/default.nix +183 -0
@@ 0,0 1,183 @@
{ config, lib, pkgs, ... }:

let
  cfg = config.desktopSessions;

  availableSessionsConfig = lib.filterAttrs (name: x: x.enable) cfg.instances;
  availableSessions = lib.attrNames availableSessionsConfig;
  sessionStartScripts = lib.map (x: x.startSession) (lib.attrValues availableSessionsConfig);

  desktopSessionType = lib.types.submodule ({ config, name, ... }: {
    options = {
      enable = lib.mkEnableOption "desktop session instance enable" // { default = true; };
      name = lib.mkOption {
        type = lib.types.str;
        default = name;
      };

      startSession = lib.mkOption {
        type = lib.types.package;
      };

      preStartHook = lib.mkOption {
        type = lib.types.str;
        default = "";
      };

      postStartHook = lib.mkOption {
        type = lib.types.str;
        default = "";
        description = ''
          This is executed after the session is started.
          However, it's started outside of the session,
          so you won't get any environment variables from
          the session. If you need that, you need to utilize
          configuration, or flags of the session executable.

          There is $pid available to know the pid of the started
          session process.
        '';
      };
      exitHook = lib.mkOption {
        type = lib.types.str;
        default = ''
          systemctl stop --user graphical-session.target
        '';
      };

      executable = lib.mkOption {
        type = lib.types.path;
      };
      arguments = lib.mkOption {
        type = lib.types.listOf lib.types.str;
        default = [];
      };
      environment = lib.mkOption {
        type = lib.types.attrsOf (lib.types.oneOf [ lib.types.str lib.types.number ]);
      };
    };

    config = {
      startSession = pkgs.writeShellScript "start-${name}" ''
        ${lib.concatStringsSep "\n" (lib.attrValues (lib.mapAttrs (name: value: "export ${name}='${value}'") config.environment))}

        ${config.preStartHook}
        ${config.executable} ${lib.concatStringsSep " " config.arguments} &
        pid=$!
        ${config.postStartHook}
        wait $pid
        ${config.exitHook}
      '';
    };
  });
in {
  options.desktopSessions = {
    instances = lib.mkOption {
      type = lib.types.attrsOf desktopSessionType;
      default = {};
    };

    enable = lib.mkEnableOption "desktop session configuration";

    selectSession = lib.mkOption {
      type = lib.types.path;
    };

    defaultSession = lib.mkOption {
      type = lib.types.str;
      default = "tty";
    };

    availableSessions = lib.mkOption {
      type = lib.types.listOf lib.types.str;
      readOnly = true;
    };

    sessionStartScripts = lib.mkOption {
      type = lib.types.listOf lib.types.package;
      readOnly = true;
    };

    sessionStartScriptsPath = lib.mkOption {
      type = lib.types.package;
      readOnly = true;
    };

    autoStart = {
      enable = lib.mkEnableOption "auto start profile selection on tty login" // { default = true; };
      tty = lib.mkOption {
        type = lib.types.int;
        default = 1;
      };
      profileSelectContent = lib.mkOption {
        type = lib.types.str;
      };
    };
  };

  config.desktopSessions = {
    inherit availableSessions;
    inherit sessionStartScripts;

    sessionStartScriptsPath = let
      sessionsCopy = (lib.concatStringsSep "\n" (lib.map (x: ''
            cp "${x.startSession}" "$out/bin/start-${x.name}"
          '') (lib.attrValues availableSessionsConfig)));
    in pkgs.runCommandNoCCLocal "session-start-scripts" {} ''
      mkdir -p $out/bin
      ${sessionsCopy}
    '';

    autoStart.profileSelectContent = ''
      if [[ "$(tty)" == "/dev/tty${builtins.toString cfg.autoStart.tty}" && "$(id -u)" != 0 ]]; then
        ${cfg.selectSession}
      fi
    '';

    selectSession = pkgs.writeShellScript "select-session" ''
      sessions=(${lib.concatStringsSep " " cfg.availableSessions})
      session_indices=(''${!sessions[@]})

      timeout=3
      selected="${cfg.defaultSession}" # default

      echo "Default session to start is $selected"

      echo "Available sessions:"
      for i in ''${!sessions[@]}; do
          echo "  $((i+1))) ''${sessions[$i]}"
      done
      echo "  q) Enter tty."

      echo -n "Choose session to start: "
      read -t"$timeout" -n1 user_input
      echo

      if [[ $user_input == "q" ]]; then
          exit
      elif [[ $user_input ]]; then
          user_input=$((user_input-1))
          echo $user_input
          if [[ " ''${session_indices[@]} " =~ " $user_input " ]]; then
              selected="''${sessions[$user_input]}"
              echo "Got $user_input. Going to start $selected"
          else
              echo "Got unknown option. Exiting."
              exit
          fi
      else
          echo "Got no input, starting $selected"
      fi

      echo "Going to start $selected"

      # tty name is treated specially. It just exits. Use default session of tty,
      # to not start any session.
      if [[ $selected == "tty" ]]; then
       exit
      fi

      ${cfg.sessionStartScriptsPath}/bin/start-$selected
    '';
  };
}

Do not follow this link