mirror of
https://github.com/nix-community/home-manager.git
synced 2025-11-08 19:46:05 +01:00
Pull out of git module and deprecate old usage. Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
881 lines
25 KiB
Nix
881 lines
25 KiB
Nix
{
|
||
config,
|
||
lib,
|
||
pkgs,
|
||
...
|
||
}:
|
||
let
|
||
inherit (lib)
|
||
concatStringsSep
|
||
literalExpression
|
||
mkDefault
|
||
mkEnableOption
|
||
mkIf
|
||
mkOption
|
||
mkOptionDefault
|
||
mkPackageOption
|
||
types
|
||
;
|
||
|
||
cfg = config.programs.git;
|
||
|
||
gitIniType =
|
||
with types;
|
||
let
|
||
primitiveType = either str (either bool int);
|
||
multipleType = either primitiveType (listOf primitiveType);
|
||
sectionType = attrsOf multipleType;
|
||
supersectionType = attrsOf (either multipleType sectionType);
|
||
in
|
||
attrsOf supersectionType;
|
||
|
||
includeModule = types.submodule (
|
||
{ config, ... }:
|
||
{
|
||
options = {
|
||
condition = mkOption {
|
||
type = types.nullOr types.str;
|
||
default = null;
|
||
description = ''
|
||
Include this configuration only when {var}`condition`
|
||
matches. Allowed conditions are described in
|
||
{manpage}`git-config(1)`.
|
||
'';
|
||
};
|
||
|
||
path = mkOption {
|
||
type = with types; either str path;
|
||
description = "Path of the configuration file to include.";
|
||
};
|
||
|
||
contents = mkOption {
|
||
type = types.attrsOf types.anything;
|
||
default = { };
|
||
example = literalExpression ''
|
||
{
|
||
user = {
|
||
email = "bob@work.example.com";
|
||
name = "Bob Work";
|
||
signingKey = "1A2B3C4D5E6F7G8H";
|
||
};
|
||
commit = {
|
||
gpgSign = true;
|
||
};
|
||
};
|
||
'';
|
||
description = ''
|
||
Configuration to include. If empty then a path must be given.
|
||
|
||
This follows the configuration structure as described in
|
||
{manpage}`git-config(1)`.
|
||
'';
|
||
};
|
||
|
||
contentSuffix = mkOption {
|
||
type = types.str;
|
||
default = "gitconfig";
|
||
description = ''
|
||
Nix store name for the git configuration text file,
|
||
when generating the configuration text from nix options.
|
||
'';
|
||
|
||
};
|
||
};
|
||
config.path = mkIf (config.contents != { }) (
|
||
mkDefault (
|
||
pkgs.writeText (lib.hm.strings.storeFileName config.contentSuffix) (
|
||
lib.generators.toGitINI config.contents
|
||
)
|
||
)
|
||
);
|
||
}
|
||
);
|
||
|
||
in
|
||
{
|
||
meta.maintainers = with lib.maintainers; [
|
||
khaneliman
|
||
rycee
|
||
];
|
||
|
||
options = {
|
||
programs.git = {
|
||
enable = mkEnableOption "Git";
|
||
|
||
package = lib.mkPackageOption pkgs "git" {
|
||
example = "pkgs.gitFull";
|
||
extraDescription = ''
|
||
Use {var}`pkgs.gitFull`
|
||
to gain access to {command}`git send-email` for instance.
|
||
'';
|
||
};
|
||
|
||
userName = mkOption {
|
||
type = types.nullOr types.str;
|
||
default = null;
|
||
description = "Default user name to use.";
|
||
};
|
||
|
||
userEmail = mkOption {
|
||
type = types.nullOr types.str;
|
||
default = null;
|
||
description = "Default user email to use.";
|
||
};
|
||
|
||
aliases = mkOption {
|
||
type = types.attrsOf types.str;
|
||
default = { };
|
||
example = {
|
||
co = "checkout";
|
||
};
|
||
description = "Git aliases to define.";
|
||
};
|
||
|
||
signing = {
|
||
key = mkOption {
|
||
type = types.nullOr types.str;
|
||
default = null;
|
||
description = ''
|
||
The default signing key fingerprint.
|
||
|
||
Set to `null` to let the signer decide what signing key
|
||
to use depending on commit’s author.
|
||
'';
|
||
};
|
||
|
||
format = mkOption {
|
||
type = types.nullOr (
|
||
types.enum [
|
||
"openpgp"
|
||
"ssh"
|
||
"x509"
|
||
]
|
||
);
|
||
defaultText = literalExpression ''
|
||
"openpgp" for state version < 25.05,
|
||
undefined for state version ≥ 25.05
|
||
'';
|
||
description = ''
|
||
The signing method to use when signing commits and tags.
|
||
Valid values are `openpgp` (OpenPGP/GnuPG), `ssh` (SSH), and `x509` (X.509 certificates).
|
||
'';
|
||
};
|
||
|
||
signByDefault = mkOption {
|
||
type = types.nullOr types.bool;
|
||
default = null;
|
||
description = "Whether commits and tags should be signed by default.";
|
||
};
|
||
|
||
signer = mkOption {
|
||
type = types.nullOr types.str;
|
||
description = "Path to signer binary to use.";
|
||
};
|
||
};
|
||
|
||
extraConfig = mkOption {
|
||
type = types.either types.lines gitIniType;
|
||
default = { };
|
||
example = {
|
||
core = {
|
||
whitespace = "trailing-space,space-before-tab";
|
||
};
|
||
url."ssh://git@host".insteadOf = "otherhost";
|
||
};
|
||
description = ''
|
||
Additional configuration to add. The use of string values is
|
||
deprecated and will be removed in the future.
|
||
'';
|
||
};
|
||
|
||
hooks = mkOption {
|
||
type = types.attrsOf types.path;
|
||
default = { };
|
||
example = literalExpression ''
|
||
{
|
||
pre-commit = ./pre-commit-script;
|
||
}
|
||
'';
|
||
description = ''
|
||
Configuration helper for Git hooks.
|
||
See <https://git-scm.com/docs/githooks>
|
||
for reference.
|
||
'';
|
||
};
|
||
|
||
iniContent = mkOption {
|
||
type = gitIniType;
|
||
internal = true;
|
||
};
|
||
|
||
ignores = mkOption {
|
||
type = types.listOf types.str;
|
||
default = [ ];
|
||
example = [
|
||
"*~"
|
||
"*.swp"
|
||
];
|
||
description = "List of paths that should be globally ignored.";
|
||
};
|
||
|
||
attributes = mkOption {
|
||
type = types.listOf types.str;
|
||
default = [ ];
|
||
example = [ "*.pdf diff=pdf" ];
|
||
description = "List of defining attributes set globally.";
|
||
};
|
||
|
||
includes = mkOption {
|
||
type = types.listOf includeModule;
|
||
default = [ ];
|
||
example = literalExpression ''
|
||
[
|
||
{ path = "~/path/to/config.inc"; }
|
||
{
|
||
path = "~/path/to/conditional.inc";
|
||
condition = "gitdir:~/src/dir";
|
||
}
|
||
]
|
||
'';
|
||
description = "List of configuration files to include.";
|
||
};
|
||
|
||
lfs = {
|
||
enable = mkEnableOption "Git Large File Storage";
|
||
|
||
skipSmudge = mkOption {
|
||
type = types.bool;
|
||
default = false;
|
||
description = ''
|
||
Skip automatic downloading of objects on clone or pull.
|
||
This requires a manual {command}`git lfs pull`
|
||
every time a new commit is checked out on your repository.
|
||
'';
|
||
};
|
||
};
|
||
|
||
maintenance = {
|
||
enable = mkEnableOption "" // {
|
||
description = ''
|
||
Enable the automatic {command}`git maintenance`.
|
||
|
||
If you have SSH remotes, set {option}`programs.git.package` to a
|
||
git version with SSH support (eg: `pkgs.gitFull`).
|
||
|
||
See <https://git-scm.com/docs/git-maintenance>.
|
||
'';
|
||
};
|
||
|
||
repositories = mkOption {
|
||
type = with types; listOf str;
|
||
default = [ ];
|
||
description = ''
|
||
Repositories on which {command}`git maintenance` should run.
|
||
|
||
Should be a list of absolute paths.
|
||
'';
|
||
};
|
||
|
||
timers = mkOption {
|
||
type = types.attrsOf types.str;
|
||
default = {
|
||
hourly = "*-*-* 1..23:53:00";
|
||
daily = "Tue..Sun *-*-* 0:53:00";
|
||
weekly = "Mon 0:53:00";
|
||
};
|
||
description = ''
|
||
Systemd timers to create for scheduled {command}`git maintenance`.
|
||
|
||
Key is passed to `--schedule` argument in {command}`git maintenance run`
|
||
and value is passed to `Timer.OnCalendar` in `systemd.user.timers`.
|
||
'';
|
||
};
|
||
};
|
||
|
||
diff-highlight = {
|
||
enable = mkEnableOption "" // {
|
||
description = ''
|
||
Enable the contrib {command}`diff-highlight` syntax highlighter.
|
||
See <https://github.com/git/git/blob/master/contrib/diff-highlight/README>,
|
||
'';
|
||
};
|
||
|
||
pagerOpts = mkOption {
|
||
type = types.listOf types.str;
|
||
default = [ ];
|
||
example = [
|
||
"--tabs=4"
|
||
"-RFX"
|
||
];
|
||
description = ''
|
||
Arguments to be passed to {command}`less`.
|
||
'';
|
||
};
|
||
};
|
||
|
||
difftastic = {
|
||
enable = mkEnableOption "" // {
|
||
description = ''
|
||
Enable the {command}`difftastic` syntax highlighter.
|
||
See <https://github.com/Wilfred/difftastic>.
|
||
'';
|
||
};
|
||
|
||
package = mkPackageOption pkgs "difftastic" { };
|
||
|
||
enableAsDifftool = mkEnableOption "" // {
|
||
description = ''
|
||
Enable the {command}`difftastic` syntax highlighter as a git difftool.
|
||
See <https://github.com/Wilfred/difftastic>.
|
||
'';
|
||
};
|
||
|
||
options = mkOption {
|
||
type =
|
||
with lib.types;
|
||
attrsOf (oneOf [
|
||
str
|
||
number
|
||
bool
|
||
]);
|
||
default = { };
|
||
example = {
|
||
color = "dark";
|
||
sort-path = true;
|
||
tab-width = 8;
|
||
};
|
||
description = "Configuration options for {command}`difftastic`. See {command}`difft --help`";
|
||
};
|
||
};
|
||
|
||
diff-so-fancy = {
|
||
enable = mkEnableOption "" // {
|
||
description = ''
|
||
Enable the {command}`diff-so-fancy` diff colorizer.
|
||
See <https://github.com/so-fancy/diff-so-fancy>.
|
||
'';
|
||
};
|
||
|
||
pagerOpts = mkOption {
|
||
type = types.listOf types.str;
|
||
default = [
|
||
"--tabs=4"
|
||
"-RFX"
|
||
];
|
||
description = ''
|
||
Arguments to be passed to {command}`less`.
|
||
'';
|
||
};
|
||
|
||
markEmptyLines = mkOption {
|
||
type = types.bool;
|
||
default = true;
|
||
example = false;
|
||
description = ''
|
||
Whether the first block of an empty line should be colored.
|
||
'';
|
||
};
|
||
|
||
changeHunkIndicators = mkOption {
|
||
type = types.bool;
|
||
default = true;
|
||
example = false;
|
||
description = ''
|
||
Simplify git header chunks to a more human readable format.
|
||
'';
|
||
};
|
||
|
||
stripLeadingSymbols = mkOption {
|
||
type = types.bool;
|
||
default = true;
|
||
example = false;
|
||
description = ''
|
||
Whether the `+` or `-` at
|
||
line-start should be removed.
|
||
'';
|
||
};
|
||
|
||
useUnicodeRuler = mkOption {
|
||
type = types.bool;
|
||
default = true;
|
||
example = false;
|
||
description = ''
|
||
By default, the separator for the file header uses Unicode
|
||
line-drawing characters. If this is causing output errors on
|
||
your terminal, set this to false to use ASCII characters instead.
|
||
'';
|
||
};
|
||
|
||
rulerWidth = mkOption {
|
||
type = types.nullOr types.int;
|
||
default = null;
|
||
example = false;
|
||
description = ''
|
||
By default, the separator for the file header spans the full
|
||
width of the terminal. Use this setting to set the width of
|
||
the file header manually.
|
||
'';
|
||
};
|
||
};
|
||
|
||
riff = {
|
||
enable = mkEnableOption "" // {
|
||
description = ''
|
||
Enable the <command>riff</command> diff highlighter.
|
||
See <link xlink:href="https://github.com/walles/riff" />.
|
||
'';
|
||
};
|
||
|
||
package = mkPackageOption pkgs "riffdiff" { };
|
||
|
||
commandLineOptions = mkOption {
|
||
type = types.listOf types.str;
|
||
default = [ ];
|
||
example = literalExpression ''[ "--no-adds-only-special" ]'';
|
||
apply = lib.concatStringsSep " ";
|
||
description = ''
|
||
Command line arguments to include in the <command>RIFF</command> environment variable.
|
||
|
||
Run <command>riff --help</command> for a full list of options
|
||
'';
|
||
};
|
||
};
|
||
|
||
patdiff = {
|
||
enable = mkEnableOption "" // {
|
||
description = ''
|
||
Whether to enable the {command}`patdiff` differ.
|
||
See <https://opensource.janestreet.com/patdiff/>
|
||
'';
|
||
};
|
||
|
||
package = mkPackageOption pkgs "patdiff" { };
|
||
};
|
||
};
|
||
};
|
||
|
||
imports = [
|
||
(lib.mkRenamedOptionModule
|
||
[ "programs" "git" "signing" "gpgPath" ]
|
||
[
|
||
"programs"
|
||
"git"
|
||
"signing"
|
||
"signer"
|
||
]
|
||
)
|
||
]
|
||
++ (
|
||
let
|
||
mkRenamed =
|
||
opt:
|
||
lib.mkRenamedOptionModule
|
||
[ "programs" "git" "difftastic" opt ]
|
||
[ "programs" "git" "difftastic" "options" opt ];
|
||
in
|
||
map mkRenamed [
|
||
"background"
|
||
"color"
|
||
"context"
|
||
"display"
|
||
]
|
||
)
|
||
++ [
|
||
(lib.mkRemovedOptionModule [ "programs" "git" "difftastic" "extraArgs" ] ''
|
||
'programs.git.difftastic.extraArgs' has been replaced by 'programs.git.difftastic.options'
|
||
'')
|
||
];
|
||
|
||
config = mkIf cfg.enable (
|
||
lib.mkMerge [
|
||
{
|
||
home.packages = [ cfg.package ];
|
||
|
||
assertions = [
|
||
{
|
||
assertion =
|
||
let
|
||
enabled = [
|
||
(config.programs.delta.enable && config.programs.delta.enableGitIntegration)
|
||
cfg.diff-so-fancy.enable
|
||
cfg.difftastic.enable
|
||
cfg.diff-highlight.enable
|
||
cfg.riff.enable
|
||
cfg.patdiff.enable
|
||
];
|
||
in
|
||
lib.count lib.id enabled <= 1;
|
||
message = "Only one of 'programs.git.delta.enable' or 'programs.git.difftastic.enable' or 'programs.git.diff-so-fancy.enable' or 'programs.git.diff-highlight' or 'programs.git.patdiff' can be set to true at the same time.";
|
||
}
|
||
];
|
||
|
||
programs.git.iniContent.user = {
|
||
name = mkIf (cfg.userName != null) cfg.userName;
|
||
email = mkIf (cfg.userEmail != null) cfg.userEmail;
|
||
};
|
||
|
||
xdg.configFile = {
|
||
"git/config".text = lib.generators.toGitINI cfg.iniContent;
|
||
|
||
"git/ignore" = mkIf (cfg.ignores != [ ]) {
|
||
text = concatStringsSep "\n" cfg.ignores + "\n";
|
||
};
|
||
|
||
"git/attributes" = mkIf (cfg.attributes != [ ]) {
|
||
text = concatStringsSep "\n" cfg.attributes + "\n";
|
||
};
|
||
};
|
||
}
|
||
|
||
{
|
||
programs.git.iniContent =
|
||
let
|
||
hasSmtp = name: account: account.enable && account.smtp != null;
|
||
|
||
genIdentity =
|
||
name: account:
|
||
let
|
||
inherit (account)
|
||
address
|
||
realName
|
||
smtp
|
||
userName
|
||
;
|
||
in
|
||
lib.nameValuePair "sendemail.${name}" (
|
||
if account.msmtp.enable then
|
||
{
|
||
sendmailCmd = "${pkgs.msmtp}/bin/msmtp";
|
||
envelopeSender = "auto";
|
||
from = "${realName} <${address}>";
|
||
}
|
||
else
|
||
{
|
||
smtpEncryption =
|
||
if smtp.tls.enable then
|
||
(if smtp.tls.useStartTls || lib.versionOlder config.home.stateVersion "20.09" then "tls" else "ssl")
|
||
else
|
||
"";
|
||
smtpSslCertPath = mkIf smtp.tls.enable (toString smtp.tls.certificatesFile);
|
||
smtpServer = smtp.host;
|
||
smtpUser = userName;
|
||
from = "${realName} <${address}>";
|
||
}
|
||
// lib.optionalAttrs (smtp.port != null) {
|
||
smtpServerPort = smtp.port;
|
||
}
|
||
);
|
||
in
|
||
lib.mapAttrs' genIdentity (lib.filterAttrs hasSmtp config.accounts.email.accounts);
|
||
}
|
||
|
||
(mkIf (cfg.signing != { }) {
|
||
programs.git = {
|
||
signing = {
|
||
format =
|
||
if (lib.versionOlder config.home.stateVersion "25.05") then
|
||
(mkOptionDefault "openpgp")
|
||
else
|
||
(mkOptionDefault null);
|
||
signer =
|
||
let
|
||
defaultSigners = {
|
||
openpgp = lib.getExe config.programs.gpg.package;
|
||
ssh = lib.getExe' pkgs.openssh "ssh-keygen";
|
||
x509 = lib.getExe' config.programs.gpg.package "gpgsm";
|
||
};
|
||
in
|
||
mkIf (cfg.signing.format != null) (mkOptionDefault defaultSigners.${cfg.signing.format});
|
||
};
|
||
|
||
iniContent = lib.mkMerge [
|
||
(mkIf (cfg.signing.key != null) {
|
||
user.signingKey = mkDefault cfg.signing.key;
|
||
})
|
||
(mkIf (cfg.signing.signByDefault != null) {
|
||
commit.gpgSign = mkDefault cfg.signing.signByDefault;
|
||
tag.gpgSign = mkDefault cfg.signing.signByDefault;
|
||
})
|
||
(mkIf (cfg.signing.format != null) {
|
||
gpg = {
|
||
format = mkDefault cfg.signing.format;
|
||
${cfg.signing.format}.program = mkDefault cfg.signing.signer;
|
||
};
|
||
})
|
||
];
|
||
};
|
||
})
|
||
|
||
(mkIf (cfg.hooks != { }) {
|
||
programs.git.iniContent = {
|
||
core.hooksPath =
|
||
let
|
||
entries = lib.mapAttrsToList (name: path: { inherit name path; }) cfg.hooks;
|
||
in
|
||
toString (pkgs.linkFarm "git-hooks" entries);
|
||
};
|
||
})
|
||
|
||
(mkIf (cfg.aliases != { }) { programs.git.iniContent.alias = cfg.aliases; })
|
||
|
||
(mkIf (lib.isAttrs cfg.extraConfig) {
|
||
programs.git.iniContent = cfg.extraConfig;
|
||
})
|
||
|
||
(mkIf (lib.isString cfg.extraConfig) {
|
||
warnings = [
|
||
''
|
||
Using programs.git.extraConfig as a string option is
|
||
deprecated and will be removed in the future. Please
|
||
change to using it as an attribute set instead.
|
||
''
|
||
];
|
||
|
||
xdg.configFile."git/config".text = cfg.extraConfig;
|
||
})
|
||
|
||
(mkIf (cfg.includes != [ ]) {
|
||
xdg.configFile."git/config".text =
|
||
let
|
||
include =
|
||
i:
|
||
with i;
|
||
if condition != null then
|
||
{
|
||
includeIf.${condition}.path = "${path}";
|
||
}
|
||
else
|
||
{
|
||
include.path = "${path}";
|
||
};
|
||
in
|
||
lib.mkAfter (concatStringsSep "\n" (map lib.generators.toGitINI (map include cfg.includes)));
|
||
})
|
||
|
||
(mkIf cfg.lfs.enable {
|
||
home.packages = [ pkgs.git-lfs ];
|
||
|
||
programs.git.iniContent.filter.lfs =
|
||
let
|
||
skipArg = lib.optional cfg.lfs.skipSmudge "--skip";
|
||
in
|
||
{
|
||
clean = "git-lfs clean -- %f";
|
||
process = concatStringsSep " " (
|
||
[
|
||
"git-lfs"
|
||
"filter-process"
|
||
]
|
||
++ skipArg
|
||
);
|
||
required = true;
|
||
smudge = concatStringsSep " " (
|
||
[
|
||
"git-lfs"
|
||
"smudge"
|
||
]
|
||
++ skipArg
|
||
++ [
|
||
"--"
|
||
"%f"
|
||
]
|
||
);
|
||
};
|
||
})
|
||
|
||
(mkIf cfg.maintenance.enable {
|
||
programs.git.iniContent.maintenance.repo = cfg.maintenance.repositories;
|
||
|
||
systemd.user.services."git-maintenance@" = {
|
||
Unit = {
|
||
Description = "Optimize Git repositories data";
|
||
Documentation = [ "man:git-maintenance(1)" ];
|
||
};
|
||
|
||
Service = {
|
||
Type = "oneshot";
|
||
ExecStart =
|
||
let
|
||
exe = lib.getExe cfg.package;
|
||
in
|
||
''
|
||
"${exe}" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%i
|
||
'';
|
||
LockPersonality = "yes";
|
||
MemoryDenyWriteExecute = "yes";
|
||
NoNewPrivileges = "yes";
|
||
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_VSOCK";
|
||
RestrictNamespaces = "yes";
|
||
RestrictRealtime = "yes";
|
||
RestrictSUIDSGID = "yes";
|
||
SystemCallArchitectures = "native";
|
||
SystemCallFilter = "@system-service";
|
||
};
|
||
};
|
||
|
||
systemd.user.timers =
|
||
let
|
||
toSystemdTimer =
|
||
name: time:
|
||
lib.attrsets.nameValuePair "git-maintenance@${name}" {
|
||
Unit.Description = "Optimize Git repositories data";
|
||
|
||
Timer = {
|
||
OnCalendar = time;
|
||
Persistent = true;
|
||
};
|
||
|
||
Install.WantedBy = [ "timers.target" ];
|
||
};
|
||
in
|
||
lib.attrsets.mapAttrs' toSystemdTimer cfg.maintenance.timers;
|
||
|
||
launchd.agents =
|
||
let
|
||
baseArguments = [
|
||
"${lib.getExe cfg.package}"
|
||
"for-each-repo"
|
||
"--keep-going"
|
||
"--config=maintenance.repo"
|
||
"maintenance"
|
||
"run"
|
||
];
|
||
in
|
||
{
|
||
"git-maintenance-hourly" = {
|
||
enable = true;
|
||
config = {
|
||
ProgramArguments = baseArguments ++ [ "--schedule=hourly" ];
|
||
StartCalendarInterval = map (hour: {
|
||
Hour = hour;
|
||
Minute = 53;
|
||
}) (lib.range 1 23);
|
||
};
|
||
};
|
||
"git-maintenance-daily" = {
|
||
enable = true;
|
||
config = {
|
||
ProgramArguments = baseArguments ++ [ "--schedule=daily" ];
|
||
StartCalendarInterval = map (weekday: {
|
||
Weekday = weekday;
|
||
Hour = 0;
|
||
Minute = 53;
|
||
}) (lib.range 1 6);
|
||
};
|
||
};
|
||
"git-maintenance-weekly" = {
|
||
enable = true;
|
||
config = {
|
||
ProgramArguments = baseArguments ++ [ "--schedule=weekly" ];
|
||
StartCalendarInterval = [
|
||
{
|
||
Weekday = 0;
|
||
Hour = 0;
|
||
Minute = 53;
|
||
}
|
||
];
|
||
};
|
||
};
|
||
};
|
||
})
|
||
|
||
(mkIf cfg.diff-highlight.enable {
|
||
programs.git.iniContent =
|
||
let
|
||
dhCommand = "${cfg.package}/share/git/contrib/diff-highlight/diff-highlight";
|
||
in
|
||
{
|
||
core.pager = "${dhCommand} | ${lib.getExe pkgs.less} ${lib.escapeShellArgs cfg.diff-highlight.pagerOpts}";
|
||
interactive.diffFilter = dhCommand;
|
||
};
|
||
})
|
||
|
||
(
|
||
let
|
||
difftCommand = "${lib.getExe cfg.difftastic.package} ${
|
||
lib.cli.toGNUCommandLineShell { } cfg.difftastic.options
|
||
}";
|
||
in
|
||
(lib.mkMerge [
|
||
(mkIf cfg.difftastic.enable {
|
||
home.packages = [ cfg.difftastic.package ];
|
||
programs.git.iniContent = {
|
||
diff.external = difftCommand;
|
||
};
|
||
})
|
||
(mkIf cfg.difftastic.enableAsDifftool {
|
||
home.packages = [ cfg.difftastic.package ];
|
||
programs.git.iniContent = {
|
||
diff = {
|
||
tool = lib.mkDefault "difftastic";
|
||
};
|
||
difftool = {
|
||
difftastic = {
|
||
cmd = "${difftCommand} $LOCAL $REMOTE";
|
||
};
|
||
};
|
||
};
|
||
})
|
||
])
|
||
)
|
||
|
||
(mkIf cfg.diff-so-fancy.enable {
|
||
home.packages = [ pkgs.diff-so-fancy ];
|
||
|
||
programs.git.iniContent =
|
||
let
|
||
dsfCommand = "${pkgs.diff-so-fancy}/bin/diff-so-fancy";
|
||
in
|
||
{
|
||
core.pager = "${dsfCommand} | ${pkgs.less}/bin/less ${lib.escapeShellArgs cfg.diff-so-fancy.pagerOpts}";
|
||
interactive.diffFilter = "${dsfCommand} --patch";
|
||
diff-so-fancy = {
|
||
markEmptyLines = cfg.diff-so-fancy.markEmptyLines;
|
||
changeHunkIndicators = cfg.diff-so-fancy.changeHunkIndicators;
|
||
stripLeadingSymbols = cfg.diff-so-fancy.stripLeadingSymbols;
|
||
useUnicodeRuler = cfg.diff-so-fancy.useUnicodeRuler;
|
||
rulerWidth = mkIf (cfg.diff-so-fancy.rulerWidth != null) (cfg.diff-so-fancy.rulerWidth);
|
||
};
|
||
};
|
||
})
|
||
|
||
(
|
||
let
|
||
riffExe = baseNameOf (lib.getExe cfg.riff.package);
|
||
in
|
||
mkIf cfg.riff.enable {
|
||
home.packages = [ cfg.riff.package ];
|
||
|
||
# https://github.com/walles/riff/blob/b17e6f17ce807c8652bc59cd46758661d23ce358/README.md#usage
|
||
programs.git.iniContent = {
|
||
pager = {
|
||
diff = riffExe;
|
||
log = riffExe;
|
||
show = riffExe;
|
||
};
|
||
|
||
interactive.diffFilter = "${riffExe} --color=on";
|
||
};
|
||
}
|
||
)
|
||
|
||
(
|
||
let
|
||
patdiffPackage = cfg.patdiff.package;
|
||
patdiffCommand = "${lib.getExe' patdiffPackage "patdiff-git-wrapper"}";
|
||
in
|
||
mkIf cfg.patdiff.enable {
|
||
home.packages = [ patdiffPackage ];
|
||
|
||
programs.git.iniContent = {
|
||
diff.external = patdiffCommand;
|
||
};
|
||
}
|
||
)
|
||
|
||
(mkIf (cfg.riff.enable && cfg.riff.commandLineOptions != "") {
|
||
home.sessionVariables.RIFF = cfg.riff.commandLineOptions;
|
||
})
|
||
]
|
||
);
|
||
}
|