265 lines
8.2 KiB
Nix
265 lines
8.2 KiB
Nix
{ config, pkgs, lib, extendedLib, ... }: let
|
|
cfg = config.local.shell;
|
|
|
|
shellAliasesFormat = let
|
|
formatLib = {
|
|
functors = let
|
|
inherit (extendedLib.termColors.front) blue;
|
|
in
|
|
{
|
|
"|" = {
|
|
apply = f: lib.concatStringsSep " | " f.alias;
|
|
stringify = f: lib.concatStringsSep (blue "\n| ") f.alias;
|
|
};
|
|
"&&" = {
|
|
apply = f: lib.concatStringsSep " && " f.alias;
|
|
stringify = f: lib.concatStringsSep (blue "\n&& ") f.alias;
|
|
};
|
|
";" = {
|
|
apply = f: lib.concatStringsSep "; " f.alias;
|
|
stringify = f: lib.concatStringsSep (blue ";\n ") f.alias;
|
|
};
|
|
" " = {
|
|
apply = f: lib.concatStringsSep " " f.alias;
|
|
stringify = f: lib.concatStringsSep " \\\n " f.alias;
|
|
};
|
|
};
|
|
|
|
isAlias = v: builtins.isAttrs v && v ? "alias" && v ? "type";
|
|
};
|
|
in {
|
|
lib = formatLib;
|
|
|
|
type = let
|
|
rawAliasType = lib.types.submodule {
|
|
options = {
|
|
type = lib.mkOption {
|
|
description = "If the alias is a list of commands, this is the kind of separator that will be used.";
|
|
type = lib.types.enum (lib.attrNames formatLib.functors);
|
|
default = ";";
|
|
example = "&&";
|
|
};
|
|
alias = lib.mkOption {
|
|
description = "List of commands that will be concatenated together.";
|
|
type = with lib.types; listOf str;
|
|
example = [
|
|
"ls"
|
|
"grep nix"
|
|
];
|
|
};
|
|
};
|
|
};
|
|
|
|
coercedAliasType = with lib.types; let
|
|
coerce = str: {
|
|
type = " ";
|
|
alias = [ str ];
|
|
};
|
|
in (coercedTo str coerce rawAliasType) // {
|
|
check = v: builtins.isString v || formatLib.isAlias v;
|
|
};
|
|
|
|
aliasTreeType = with lib.types; attrsOf (either coercedAliasType aliasTreeType);
|
|
in aliasTreeType;
|
|
|
|
# Alias Tree -> { :: Alias }
|
|
generateAttrs = let
|
|
inherit (lib) mapAttrs attrValues filterAttrs isAttrs
|
|
isString concatStringsSep foldr;
|
|
|
|
applyFunctor = attrset: formatLib.functors.${attrset.type}.apply attrset;
|
|
|
|
# TODO: better naming
|
|
allAttrValuesAreStrings = attrset: let
|
|
|
|
# [ {String} ]
|
|
filteredAliases = [(filterAttrs (_: isString) attrset)];
|
|
|
|
# [ {String} ]
|
|
remainingFunctors = let
|
|
functorSet = filterAttrs (_: formatLib.isAlias) attrset;
|
|
appliedFunctorSet = mapAttrs (_: applyFunctor) functorSet;
|
|
in [ appliedFunctorSet ];
|
|
|
|
# [ {AttrSet} ]
|
|
remainingAliasSets = attrValues (filterAttrs (_: v: isAttrs v && !formatLib.isAlias v) attrset);
|
|
|
|
# [ {String} ]
|
|
recursedAliasSets = filteredAliases
|
|
++ (remainingFunctors)
|
|
++ (map allAttrValuesAreStrings remainingAliasSets);
|
|
in foldr (a: b: a // b) {} recursedAliasSets;
|
|
|
|
in
|
|
allAttrValuesAreStrings;
|
|
|
|
# TODO:
|
|
# generateAttrs = pipe [
|
|
# collect leave nodes
|
|
# map apply functor
|
|
# ]
|
|
|
|
# Alias Tree -> String
|
|
generateText = aliases: let
|
|
inherit (extendedLib.termColors.front) red green blue;
|
|
|
|
# String -> Alias -> String
|
|
stringifyAlias = aliasName: alias: let
|
|
# String -> String
|
|
removeNixLinks = text: let
|
|
maybeMatches = lib.match "(|.*[^)])(/nix/store/.*/bin/).*" text;
|
|
matches = lib.mapNullable (lib.remove "") maybeMatches;
|
|
in
|
|
if (maybeMatches == null)
|
|
then text
|
|
else lib.replaceStrings matches (lib.replicate (lib.length matches) "") text;
|
|
|
|
# Alias -> String
|
|
applyFunctor = attrset: let
|
|
applied = formatLib.functors.${attrset.type}.stringify attrset;
|
|
indent' = lib.strings.replicate (lib.stringLength "${aliasName} -> ") " ";
|
|
in
|
|
lib.replaceStrings ["\n"] [("\n" + indent')] applied;
|
|
in "${red aliasName} -> ${blue "\""}${removeNixLinks (applyFunctor alias)}${blue "\""}";
|
|
|
|
# String -> String
|
|
indent = x: lib.pipe x [
|
|
(x: "\n" + x)
|
|
(lib.replaceStrings ["\n"] [("\n" + (lib.strings.replicate 2 " "))])
|
|
(lib.removePrefix "\n")
|
|
];
|
|
|
|
# String -> { :: Alias | Category } -> String
|
|
stringifyCategory = categoryName: category: lib.pipe category [
|
|
(category: let
|
|
aliases = lib.filterAttrs (_: formatLib.isAlias) category;
|
|
in {
|
|
inherit aliases;
|
|
subcategories = lib.removeAttrs category (lib.attrNames aliases);
|
|
})
|
|
({ aliases, subcategories }: {
|
|
aliases = lib.mapAttrsToList stringifyAlias aliases;
|
|
subcategories = lib.mapAttrsToList stringifyCategory subcategories;
|
|
})
|
|
({ aliases, subcategories }:
|
|
lib.concatStringsSep "\n" (lib.filter (x: lib.trim x != "") [
|
|
"[${green categoryName}]"
|
|
(indent (lib.concatStringsSep "\n" aliases) + "\n")
|
|
(indent (lib.concatStringsSep "\n" subcategories) + "\n")
|
|
])
|
|
)
|
|
];
|
|
in (stringifyCategory "Aliases" aliases);
|
|
};
|
|
in {
|
|
options.local.shell = {
|
|
aliases = lib.mkOption {
|
|
# TODO: freeformType
|
|
type = shellAliasesFormat.type;
|
|
description = "A tree of aliases";
|
|
default = { };
|
|
example = {
|
|
"My first alias category" = {
|
|
cmd1 = ''echo "hello world"'';
|
|
cmd2 = {
|
|
type = "|";
|
|
alias = [
|
|
"ls -la"
|
|
"grep -i hello"
|
|
];
|
|
};
|
|
};
|
|
|
|
"My second alias category" = {
|
|
cmd1 = {
|
|
type = "&&";
|
|
alias = [
|
|
''echo "hello world"''
|
|
''echo "goodbye world"''
|
|
];
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
variables = lib.mkOption {
|
|
type = with lib.types; attrsOf str;
|
|
description = "Environment variables";
|
|
default = { };
|
|
};
|
|
|
|
# TODO: I want a similar system for functions at some point.
|
|
# functions = {
|
|
|
|
# };
|
|
|
|
enablePackageManagerLecture = lib.mkEnableOption "distro reminder messages, aliased to common package manager commands";
|
|
|
|
enableAliasOverview = lib.mkEnableOption "`aliases` command that prints out a list of all aliases" // {
|
|
default = true;
|
|
example = false;
|
|
};
|
|
};
|
|
|
|
config = {
|
|
xdg.dataFile = {
|
|
"aliases".text = shellAliasesFormat.generateText cfg.aliases;
|
|
|
|
"packageManagerLecture" = lib.mkIf cfg.enablePackageManagerLecture {
|
|
target = "package-manager.lecture";
|
|
text = let
|
|
inherit (extendedLib.termColors.front) red blue;
|
|
in lib.concatStringsSep "\n" [
|
|
((red "This package manager is not installed on ") + (blue "NixOS") + (red "."))
|
|
((red "Either use ") + ("\"nix-env -i\"") + (red " or install it through a configuration file."))
|
|
""
|
|
];
|
|
};
|
|
};
|
|
|
|
local.shell.aliases."Package Managers" = lib.mkIf cfg.enablePackageManagerLecture (let
|
|
inherit (lib.attrsets) nameValuePair listToAttrs;
|
|
|
|
packageManagers = [
|
|
"apt"
|
|
"dpkg"
|
|
"flatpak"
|
|
"pacman"
|
|
"pamac"
|
|
"paru"
|
|
"rpm"
|
|
"snap"
|
|
"xbps"
|
|
"yay"
|
|
"yum"
|
|
];
|
|
|
|
command = "${pkgs.coreutils}/bin/cat $HOME/${config.xdg.dataFile.packageManagerLecture.target}";
|
|
nameValuePairs = map (pm: nameValuePair pm command) packageManagers;
|
|
in listToAttrs nameValuePairs);
|
|
|
|
local.shell.aliases.aliases = lib.mkIf cfg.enableAliasOverview
|
|
"${pkgs.coreutils}/bin/cat $HOME/${config.xdg.dataFile.aliases.target}";
|
|
|
|
programs = {
|
|
zsh = {
|
|
shellAliases = shellAliasesFormat.generateAttrs cfg.aliases;
|
|
sessionVariables = cfg.variables;
|
|
};
|
|
bash = {
|
|
shellAliases = shellAliasesFormat.generateAttrs cfg.aliases;
|
|
sessionVariables = cfg.variables;
|
|
};
|
|
fish = {
|
|
shellAliases = shellAliasesFormat.generateAttrs cfg.aliases;
|
|
# TODO: fish does not support session variables?
|
|
# localVariables = cfg.variables;
|
|
};
|
|
nushell = {
|
|
shellAliases = shellAliasesFormat.generateAttrs cfg.aliases;
|
|
environmentVariables = cfg.variables;
|
|
};
|
|
};
|
|
};
|
|
}
|