mirror of
https://github.com/nix-community/home-manager.git
synced 2026-01-11 17:39:37 +08:00
Compare commits
138 Commits
release-17
...
release-18
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbe82a3ac5 | ||
|
|
ee242ec757 | ||
|
|
038f1eac11 | ||
|
|
44a1e72d2e | ||
|
|
f34e5f1c6c | ||
|
|
d268605244 | ||
|
|
091f52197d | ||
|
|
68228fce93 | ||
|
|
26b16162b7 | ||
|
|
b17b760755 | ||
|
|
9d7f7fe3a8 | ||
|
|
b19478d820 | ||
|
|
e11f110b4b | ||
|
|
451f376231 | ||
|
|
f3c02513a9 | ||
|
|
85cd97e616 | ||
|
|
b641138602 | ||
|
|
310b604f92 | ||
|
|
94fad32e41 | ||
|
|
163588b61b | ||
|
|
8d2cb0ef9b | ||
|
|
2bff6e5188 | ||
|
|
453d0494fb | ||
|
|
97c6073d39 | ||
|
|
9fe6fa7f44 | ||
|
|
7699ed3fc8 | ||
|
|
5eca556fe7 | ||
|
|
4602c00dcf | ||
|
|
629d66e0b9 | ||
|
|
859c132ee2 | ||
|
|
99a0e2469b | ||
|
|
2548c43175 | ||
|
|
90bcaaf582 | ||
|
|
da8307cd26 | ||
|
|
cfa06c3f38 | ||
|
|
906965b48b | ||
|
|
d5bbbbd41d | ||
|
|
8e05229e62 | ||
|
|
7a8d50a803 | ||
|
|
6630cfbe16 | ||
|
|
dd25fbcb4b | ||
|
|
f9ac73732b | ||
|
|
26342588ab | ||
|
|
29191eb2c7 | ||
|
|
168d546304 | ||
|
|
34133ca7f3 | ||
|
|
4b32f16747 | ||
|
|
99c900946d | ||
|
|
39213a1847 | ||
|
|
c18b1328a5 | ||
|
|
93ef6aefce | ||
|
|
2e9e1909da | ||
|
|
4f67e8d0c3 | ||
|
|
30cba446f2 | ||
|
|
dda65c0877 | ||
|
|
cf80199bfc | ||
|
|
6694330bb2 | ||
|
|
a5a49c350d | ||
|
|
6ae2d74fca | ||
|
|
29ad012763 | ||
|
|
9570cedff6 | ||
|
|
d3871ed774 | ||
|
|
34db8df6d9 | ||
|
|
092706eff8 | ||
|
|
f4a1a5e94c | ||
|
|
dadfaed829 | ||
|
|
e365943a70 | ||
|
|
86fcfc74da | ||
|
|
eecebbf186 | ||
|
|
8dc1737e39 | ||
|
|
34bb9b5766 | ||
|
|
299e01722f | ||
|
|
97ee4578c9 | ||
|
|
0d3f9ba913 | ||
|
|
6aa44d62ad | ||
|
|
5641ee3f94 | ||
|
|
2e9fbbc978 | ||
|
|
ad634c0a94 | ||
|
|
7190f46938 | ||
|
|
e27cd96494 | ||
|
|
4caa45b8bb | ||
|
|
f3473b9eba | ||
|
|
06a984e4ff | ||
|
|
53f10f4d46 | ||
|
|
ed0cd78e05 | ||
|
|
faf04b009b | ||
|
|
965bad626a | ||
|
|
69445cb4a0 | ||
|
|
30c97391d7 | ||
|
|
cacb8d410e | ||
|
|
4b388ee902 | ||
|
|
10865f9952 | ||
|
|
dfaccdd03b | ||
|
|
f812260c23 | ||
|
|
b6da6569c4 | ||
|
|
bbcef2fd33 | ||
|
|
ec3cbf81c4 | ||
|
|
1a471b0a45 | ||
|
|
73b8aa8bcc | ||
|
|
394045f68a | ||
|
|
f9af8e0390 | ||
|
|
1260349384 | ||
|
|
74f4ed5fd2 | ||
|
|
91725ddced | ||
|
|
e055e4a092 | ||
|
|
f26cc3b957 | ||
|
|
9a3b1ec222 | ||
|
|
9141d11a7d | ||
|
|
6dc4f31ba1 | ||
|
|
d294aa4356 | ||
|
|
f314ee3d6a | ||
|
|
581ad6fc29 | ||
|
|
8ff7d934b2 | ||
|
|
5bdebf5ab0 | ||
|
|
96250b7ad3 | ||
|
|
7c9278bd92 | ||
|
|
4205c91609 | ||
|
|
75c4075345 | ||
|
|
f8398339a3 | ||
|
|
9bf9e7ac5c | ||
|
|
567b21b1d6 | ||
|
|
fa7d63d9d1 | ||
|
|
46a94cce56 | ||
|
|
bc50202d0d | ||
|
|
8fc8e158e2 | ||
|
|
06e7d087f2 | ||
|
|
fbff38de33 | ||
|
|
19b4002f25 | ||
|
|
b47cc4bc66 | ||
|
|
e307ceeee7 | ||
|
|
4745c7a00d | ||
|
|
5c783e1a63 | ||
|
|
05ad0c9e06 | ||
|
|
6d7b5c9513 | ||
|
|
de001e05da | ||
|
|
08ce0579aa | ||
|
|
be60600a47 | ||
|
|
f2265b10e4 |
14
.gitlab-ci.yml
Normal file
14
.gitlab-ci.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
image: nixos/nix:latest
|
||||
|
||||
pages:
|
||||
script:
|
||||
- mkdir -p ~/.config/nixpkgs
|
||||
- echo '{ manual.html.enable = true; }' > ~/.config/nixpkgs/home.nix
|
||||
- nix-shell . -A install
|
||||
- mkdir public
|
||||
- cp -r ~/.nix-profile/share/doc/home-manager/* public/
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
only:
|
||||
- master
|
||||
13
.travis.yml
Normal file
13
.travis.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
language: nix
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
before_script:
|
||||
- mkdir -m 0755 -p /nix/var/nix/{profiles,gcroots}/per-user/$USER
|
||||
- mkdir -p ~/.config/nixpkgs
|
||||
- echo "{}" > ~/.config/nixpkgs/home.nix
|
||||
|
||||
script:
|
||||
nix-shell . -A install
|
||||
14
README.md
14
README.md
@@ -19,7 +19,7 @@ will write to your dconf store and cannot tell whether a configuration
|
||||
that it is about to be overwrite was from a previous Home Manager
|
||||
generation or from manual configuration.
|
||||
|
||||
Home Manager targets [NixOS][] unstable and NixOS version 17.09 (the
|
||||
Home Manager targets [NixOS][] unstable and NixOS version 18.03 (the
|
||||
current stable version), it may or may not work on other Linux
|
||||
distributions and NixOS versions.
|
||||
|
||||
@@ -61,13 +61,13 @@ Currently the easiest way to install Home Manager is as follows:
|
||||
$ HM_PATH=https://github.com/rycee/home-manager/archive/master.tar.gz
|
||||
```
|
||||
|
||||
or
|
||||
if you are following Nixpkgs master or an unstable channel and
|
||||
|
||||
```console
|
||||
$ HM_PATH=https://github.com/rycee/home-manager/archive/release-17.09.tar.gz
|
||||
$ HM_PATH=https://github.com/rycee/home-manager/archive/release-18.03.tar.gz
|
||||
```
|
||||
|
||||
depending on whether you follow Nixpkgs unstable or version 17.09.
|
||||
if you follow a Nixpkgs version 18.03 channel.
|
||||
|
||||
3. Create an initial Home Manager configuration file:
|
||||
|
||||
@@ -179,8 +179,9 @@ $ home-manager build
|
||||
which will create a `result` link to a directory containing an
|
||||
activation script and the generated home directory files.
|
||||
|
||||
To see available configuration options with descriptions and usage
|
||||
examples run
|
||||
Documentation of available configuration options, including
|
||||
descriptions and usage examples, is available in the [Home Manager
|
||||
manual][configuration options] or offline by running
|
||||
|
||||
```console
|
||||
$ man home-configuration.nix
|
||||
@@ -299,3 +300,4 @@ in your Home Manager configuration.
|
||||
[nixAllowedUsers]: https://nixos.org/nix/manual/#conf-allowed-users
|
||||
[nixosAllowedUsers]: https://nixos.org/nixos/manual/options.html#opt-nix.allowedUsers
|
||||
[Z shell]: http://zsh.sourceforge.net/
|
||||
[configuration options]: https://rycee.github.io/home-manager/options.html
|
||||
|
||||
327
doc/default.nix
Normal file
327
doc/default.nix
Normal file
@@ -0,0 +1,327 @@
|
||||
{ pkgs, options, config, version, revision, extraSources ? [] }:
|
||||
|
||||
with pkgs;
|
||||
|
||||
let
|
||||
lib = pkgs.lib;
|
||||
|
||||
# Remove invisible and internal options.
|
||||
optionsListVisible = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options);
|
||||
|
||||
# Replace functions by the string <function>
|
||||
substFunction = x:
|
||||
if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x
|
||||
else if builtins.isList x then map substFunction x
|
||||
else if lib.isFunction x then "<function>"
|
||||
else x;
|
||||
|
||||
# Generate DocBook documentation for a list of packages. This is
|
||||
# what `relatedPackages` option of `mkOption` from
|
||||
# ../../../lib/options.nix influences.
|
||||
#
|
||||
# Each element of `relatedPackages` can be either
|
||||
# - a string: that will be interpreted as an attribute name from `pkgs`,
|
||||
# - a list: that will be interpreted as an attribute path from `pkgs`,
|
||||
# - an attrset: that can specify `name`, `path`, `package`, `comment`
|
||||
# (either of `name`, `path` is required, the rest are optional).
|
||||
genRelatedPackages = packages:
|
||||
let
|
||||
unpack = p: if lib.isString p then { name = p; }
|
||||
else if lib.isList p then { path = p; }
|
||||
else p;
|
||||
describe = args:
|
||||
let
|
||||
name = args.name or (lib.concatStringsSep "." args.path);
|
||||
path = args.path or [ args.name ];
|
||||
package = args.package or (lib.attrByPath path (throw "Invalid package attribute path `${toString path}'") pkgs);
|
||||
in "<listitem>"
|
||||
+ "<para><literal>pkgs.${name} (${package.meta.name})</literal>"
|
||||
+ lib.optionalString (!package.meta.available) " <emphasis>[UNAVAILABLE]</emphasis>"
|
||||
+ ": ${package.meta.description or "???"}.</para>"
|
||||
+ lib.optionalString (args ? comment) "\n<para>${args.comment}</para>"
|
||||
# Lots of `longDescription's break DocBook, so we just wrap them into <programlisting>
|
||||
+ lib.optionalString (package.meta ? longDescription) "\n<programlisting>${package.meta.longDescription}</programlisting>"
|
||||
+ "</listitem>";
|
||||
in "<itemizedlist>${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}</itemizedlist>";
|
||||
|
||||
optionsListDesc = lib.flip map optionsListVisible (opt: opt // {
|
||||
# Clean up declaration sites to not refer to the NixOS source tree.
|
||||
declarations = map stripAnyPrefixes opt.declarations;
|
||||
}
|
||||
// lib.optionalAttrs (opt ? example) { example = substFunction opt.example; }
|
||||
// lib.optionalAttrs (opt ? default) { default = substFunction opt.default; }
|
||||
// lib.optionalAttrs (opt ? type) { type = substFunction opt.type; }
|
||||
// lib.optionalAttrs (opt ? relatedPackages) { relatedPackages = genRelatedPackages opt.relatedPackages; });
|
||||
|
||||
# We need to strip references to /nix/store/* from options,
|
||||
# including any `extraSources` if some modules came from elsewhere,
|
||||
# or else the build will fail.
|
||||
#
|
||||
# E.g. if some `options` came from modules in ${pkgs.customModules}/nix,
|
||||
# you'd need to include `extraSources = [ pkgs.customModules ]`
|
||||
prefixesToStrip = map (p: "${toString p}/") ([ ./.. ] ++ extraSources);
|
||||
stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix) prefixesToStrip;
|
||||
|
||||
# Custom "less" that pushes up all the things ending in ".enable*"
|
||||
# and ".package*"
|
||||
optionLess = a: b:
|
||||
let
|
||||
ise = lib.hasPrefix "enable";
|
||||
isp = lib.hasPrefix "package";
|
||||
cmp = lib.splitByAndCompare ise lib.compare
|
||||
(lib.splitByAndCompare isp lib.compare lib.compare);
|
||||
in lib.compareLists cmp a.loc b.loc < 0;
|
||||
|
||||
# Customly sort option list for the man page.
|
||||
optionsList = lib.sort optionLess optionsListDesc;
|
||||
|
||||
# Convert the list of options into an XML file.
|
||||
optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList);
|
||||
|
||||
optionsDocBook = runCommand "options-db.xml"
|
||||
{
|
||||
nativeBuildInputs = [ buildPackages.libxslt.bin ];
|
||||
}
|
||||
''
|
||||
optionsXML=${optionsXML}
|
||||
xsltproc \
|
||||
--stringparam program 'home-manager' \
|
||||
--stringparam revision '${revision}' \
|
||||
-o $out ${./options-to-docbook.xsl} $optionsXML
|
||||
'';
|
||||
|
||||
sources = lib.sourceFilesBySuffices ./. [".xml"];
|
||||
|
||||
modulesDoc = builtins.toFile "modules.xml" ''
|
||||
<section xmlns:xi="http://www.w3.org/2001/XInclude" id="modules">
|
||||
${(lib.concatMapStrings (path: ''
|
||||
<xi:include href="${path}" />
|
||||
'') (lib.catAttrs "value" config.meta.doc))}
|
||||
</section>
|
||||
'';
|
||||
|
||||
generatedSources = runCommand "generated-docbook" {} ''
|
||||
mkdir $out
|
||||
ln -s ${modulesDoc} $out/modules.xml
|
||||
ln -s ${optionsDocBook} $out/options-db.xml
|
||||
printf "%s" "${version}" > $out/version
|
||||
'';
|
||||
|
||||
copySources =
|
||||
''
|
||||
cp -prd $sources/* . # */
|
||||
ln -s ${generatedSources} ./generated
|
||||
chmod -R u+w .
|
||||
'';
|
||||
|
||||
toc = builtins.toFile "toc.xml"
|
||||
''
|
||||
<toc role="chunk-toc">
|
||||
<d:tocentry xmlns:d="http://docbook.org/ns/docbook" linkend="book-home-manager-manual"><?dbhtml filename="index.html"?>
|
||||
<d:tocentry linkend="ch-options"><?dbhtml filename="options.html"?></d:tocentry>
|
||||
</d:tocentry>
|
||||
</toc>
|
||||
'';
|
||||
|
||||
manualXsltprocOptions = toString [
|
||||
"--param section.autolabel 1"
|
||||
"--param section.label.includes.component.label 1"
|
||||
"--stringparam html.stylesheet 'style.css overrides.css highlightjs/mono-blue.css'"
|
||||
"--stringparam html.script './highlightjs/highlight.pack.js ./highlightjs/loader.js'"
|
||||
"--param xref.with.number.and.title 1"
|
||||
"--param toc.section.depth 3"
|
||||
"--stringparam admon.style ''"
|
||||
"--stringparam callout.graphics.extension .svg"
|
||||
"--stringparam current.docid manual"
|
||||
"--param chunk.section.depth 0"
|
||||
"--param chunk.first.sections 1"
|
||||
"--param use.id.as.filename 1"
|
||||
"--stringparam generate.toc 'book toc appendix toc'"
|
||||
"--stringparam chunk.toc ${toc}"
|
||||
];
|
||||
|
||||
manual-combined = runCommand "home-manager-manual-combined"
|
||||
{ inherit sources;
|
||||
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
|
||||
meta.description = "The Home Manager manual as plain docbook XML";
|
||||
}
|
||||
''
|
||||
${copySources}
|
||||
|
||||
xmllint --xinclude --output ./manual-combined.xml ./manual.xml
|
||||
xmllint --xinclude --noxincludenode \
|
||||
--output ./man-pages-combined.xml ./man-pages.xml
|
||||
|
||||
# outputs the context of an xmllint error output
|
||||
# LEN lines around the failing line are printed
|
||||
function context {
|
||||
# length of context
|
||||
local LEN=6
|
||||
# lines to print before error line
|
||||
local BEFORE=4
|
||||
|
||||
# xmllint output lines are:
|
||||
# file.xml:1234: there was an error on line 1234
|
||||
while IFS=':' read -r file line rest; do
|
||||
echo
|
||||
if [[ -n "$rest" ]]; then
|
||||
echo "$file:$line:$rest"
|
||||
local FROM=$(($line>$BEFORE ? $line - $BEFORE : 1))
|
||||
# number lines & filter context
|
||||
nl --body-numbering=a "$file" | sed -n "$FROM,+$LEN p"
|
||||
else
|
||||
if [[ -n "$line" ]]; then
|
||||
echo "$file:$line"
|
||||
else
|
||||
echo "$file"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function lintrng {
|
||||
xmllint --debug --noout --nonet \
|
||||
--relaxng ${docbook5}/xml/rng/docbook/docbook.rng \
|
||||
"$1" \
|
||||
2>&1 | context 1>&2
|
||||
# ^ redirect assumes xmllint doesn’t print to stdout
|
||||
}
|
||||
|
||||
lintrng manual-combined.xml
|
||||
lintrng man-pages-combined.xml
|
||||
|
||||
mkdir $out
|
||||
cp manual-combined.xml $out/
|
||||
cp man-pages-combined.xml $out/
|
||||
'';
|
||||
|
||||
olinkDB = runCommand "manual-olinkdb"
|
||||
{ inherit sources;
|
||||
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
|
||||
}
|
||||
''
|
||||
xsltproc \
|
||||
${manualXsltprocOptions} \
|
||||
--stringparam collect.xref.targets only \
|
||||
--stringparam targets.filename "$out/manual.db" \
|
||||
--nonet \
|
||||
${docbook5_xsl}/xml/xsl/docbook/xhtml/chunktoc.xsl \
|
||||
${manual-combined}/manual-combined.xml
|
||||
|
||||
cat > "$out/olinkdb.xml" <<EOF
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE targetset SYSTEM
|
||||
"file://${docbook5_xsl}/xml/xsl/docbook/common/targetdatabase.dtd" [
|
||||
<!ENTITY manualtargets SYSTEM "file://$out/manual.db">
|
||||
]>
|
||||
<targetset>
|
||||
<targetsetinfo>
|
||||
Allows for cross-referencing olinks between the manpages
|
||||
and manual.
|
||||
</targetsetinfo>
|
||||
|
||||
<document targetdoc="manual">&manualtargets;</document>
|
||||
</targetset>
|
||||
EOF
|
||||
'';
|
||||
|
||||
in rec {
|
||||
inherit generatedSources;
|
||||
|
||||
# The Home Manager options in JSON format.
|
||||
optionsJSON = runCommand "options-json"
|
||||
{ meta.description = "List of Home Manager options in JSON format";
|
||||
}
|
||||
''
|
||||
# Export list of options in different format.
|
||||
dst=$out/share/doc/home-manager
|
||||
mkdir -p $dst
|
||||
|
||||
cp ${builtins.toFile "options.json" (builtins.unsafeDiscardStringContext (builtins.toJSON
|
||||
(builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList))))
|
||||
} $dst/options.json
|
||||
|
||||
mkdir -p $out/nix-support
|
||||
echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products
|
||||
''; # */
|
||||
|
||||
# Generate the Home Manager manual.
|
||||
manual = runCommand "home-manager-manual"
|
||||
{ inherit sources;
|
||||
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
|
||||
meta.description = "The Home Manager manual in HTML format";
|
||||
allowedReferences = ["out"];
|
||||
}
|
||||
''
|
||||
# Generate the HTML manual.
|
||||
dst=$out/share/doc/home-manager
|
||||
mkdir -p $dst
|
||||
xsltproc \
|
||||
${manualXsltprocOptions} \
|
||||
--stringparam target.database.document "${olinkDB}/olinkdb.xml" \
|
||||
--nonet --output $dst/ \
|
||||
${docbook5_xsl}/xml/xsl/docbook/xhtml/chunktoc.xsl \
|
||||
${manual-combined}/manual-combined.xml
|
||||
|
||||
mkdir -p $dst/images/callouts
|
||||
cp ${docbook5_xsl}/xml/xsl/docbook/images/callouts/*.svg $dst/images/callouts/
|
||||
|
||||
cp ${./style.css} $dst/style.css
|
||||
cp ${./overrides.css} $dst/overrides.css
|
||||
cp -r ${pkgs.documentation-highlighter} $dst/highlightjs
|
||||
|
||||
mkdir -p $out/nix-support
|
||||
echo "nix-build out $out" >> $out/nix-support/hydra-build-products
|
||||
echo "doc manual $dst" >> $out/nix-support/hydra-build-products
|
||||
''; # */
|
||||
|
||||
|
||||
manualEpub = runCommand "home-manager-manual-epub"
|
||||
{ inherit sources;
|
||||
buildInputs = [ libxml2.bin libxslt.bin zip ];
|
||||
}
|
||||
''
|
||||
# Generate the epub manual.
|
||||
dst=$out/share/doc/home-manager
|
||||
|
||||
xsltproc \
|
||||
${manualXsltprocOptions} \
|
||||
--stringparam target.database.document "${olinkDB}/olinkdb.xml" \
|
||||
--nonet --xinclude --output $dst/epub/ \
|
||||
${docbook5_xsl}/xml/xsl/docbook/epub/docbook.xsl \
|
||||
${manual-combined}/manual-combined.xml
|
||||
|
||||
mkdir -p $dst/epub/OEBPS/images/callouts
|
||||
cp -r ${docbook5_xsl}/xml/xsl/docbook/images/callouts/*.svg $dst/epub/OEBPS/images/callouts # */
|
||||
echo "application/epub+zip" > mimetype
|
||||
manual="$dst/home-manager-manual.epub"
|
||||
zip -0Xq "$manual" mimetype
|
||||
cd $dst/epub && zip -Xr9D "$manual" *
|
||||
|
||||
rm -rf $dst/epub
|
||||
|
||||
mkdir -p $out/nix-support
|
||||
echo "doc-epub manual $manual" >> $out/nix-support/hydra-build-products
|
||||
'';
|
||||
|
||||
|
||||
# Generate the Home Manager manpages.
|
||||
manpages = runCommand "home-manager-manpages"
|
||||
{ inherit sources;
|
||||
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
|
||||
allowedReferences = ["out"];
|
||||
}
|
||||
''
|
||||
# Generate manpages.
|
||||
mkdir -p $out/share/man
|
||||
xsltproc --nonet \
|
||||
--param man.output.in.separate.dir 1 \
|
||||
--param man.output.base.dir "'$out/share/man/'" \
|
||||
--param man.endnotes.are.numbered 0 \
|
||||
--param man.break.after.slash 1 \
|
||||
--stringparam target.database.document "${olinkDB}/olinkdb.xml" \
|
||||
${docbook5_xsl}/xml/xsl/docbook/manpages/docbook.xsl \
|
||||
${manual-combined}/man-pages-combined.xml
|
||||
'';
|
||||
|
||||
}
|
||||
34
doc/man-configuration.xml
Normal file
34
doc/man-configuration.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<refmeta>
|
||||
<refentrytitle><filename>home-configuration.nix</filename></refentrytitle>
|
||||
<manvolnum>5</manvolnum>
|
||||
<refmiscinfo class="source">Home Manager</refmiscinfo>
|
||||
<!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname><filename>home-configuration.nix</filename></refname>
|
||||
<refpurpose>Home Manager configuration specification</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsection>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
The file <filename>~/.config/nixpkgs/home.nix</filename> contains
|
||||
the declarative specification of your Home Manager configuration.
|
||||
The command <command>home-manager</command> takes this file and
|
||||
realises the user environment configuration specified therein.
|
||||
</para>
|
||||
</refsection>
|
||||
|
||||
<refsection>
|
||||
<title>Options</title>
|
||||
<para>
|
||||
You can use the following options in
|
||||
<filename>home-configuration.nix</filename>:
|
||||
</para>
|
||||
<xi:include href="./generated/options-db.xml" xpointer="configuration-variable-list" />
|
||||
</refsection>
|
||||
</refentry>
|
||||
62
doc/man-home-manager.xml
Normal file
62
doc/man-home-manager.xml
Normal file
@@ -0,0 +1,62 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<refmeta>
|
||||
<refentrytitle><command>home-manager</command></refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
<refmiscinfo class="source">Home Manager</refmiscinfo>
|
||||
<!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname><command>home-manager</command></refname>
|
||||
<refpurpose>reconfigure a user environment</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>home-manager</command>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>help</option></arg>
|
||||
<arg choice='plain'><option>build</option></arg>
|
||||
<arg choice='plain'><option>switch</option></arg>
|
||||
<arg choice='plain'><option>generations</option></arg>
|
||||
<arg choice='plain'><option>remove-generations</option></arg>
|
||||
<arg choice='plain'><option>packages</option></arg>
|
||||
<arg choice='plain'><option>news</option></arg>
|
||||
</group>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsection>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
This command updates the user environment so that it corresponds to the configuration
|
||||
specified in <filename>~/.config/nixpkgs/home.nix</filename>.
|
||||
</para>
|
||||
</refsection>
|
||||
|
||||
<refsection>
|
||||
<title>Files</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><filename>~/.local/share/home-manager/news-read-ids</filename></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Identifiers of news items that have been shown. Can be deleted
|
||||
to reset the read news indicator.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsection>
|
||||
|
||||
<refsection>
|
||||
<title>Bugs</title>
|
||||
<para>
|
||||
Please report any bugs on the <link
|
||||
xlink:href="https://github.com/rycee/home-manager/issues">project
|
||||
issue tracker</link>.
|
||||
</para>
|
||||
</refsection>
|
||||
</refentry>
|
||||
16
doc/man-pages.xml
Normal file
16
doc/man-pages.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<reference xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<title>Home Manager Reference Pages</title>
|
||||
<info>
|
||||
<author>
|
||||
<personname>Home Manager contributors</personname>
|
||||
<contrib>Author</contrib>
|
||||
</author>
|
||||
<copyright>
|
||||
<year>2017-2018</year><holder>Home Manager contributors</holder>
|
||||
</copyright>
|
||||
</info>
|
||||
<xi:include href="man-configuration.xml" />
|
||||
<xi:include href="man-home-manager.xml" />
|
||||
</reference>
|
||||
31
doc/manual.xml
Normal file
31
doc/manual.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<book xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="book-home-manager-manual">
|
||||
<info>
|
||||
<title>Home Manager Manual</title>
|
||||
</info>
|
||||
<preface>
|
||||
<title>Preface</title>
|
||||
<para>
|
||||
This manual will eventually describes how to install, use, and
|
||||
extend Home Manager.
|
||||
</para>
|
||||
<para>
|
||||
If you encounter problems or bugs then please report them on the
|
||||
<link xlink:href="https://github.com/rycee/home-manager/issues">Home Manager issue tracker</link>.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
Commands prefixed with <literal>#</literal> have to be run as root, either
|
||||
requiring to login as root user or temporarily switching to it using
|
||||
<literal>sudo</literal> for example.
|
||||
</para>
|
||||
</note>
|
||||
</preface>
|
||||
<appendix xml:id="ch-options">
|
||||
<title>Configuration Options</title>
|
||||
<xi:include href="./generated/options-db.xml" xpointer="configuration-variable-list" />
|
||||
</appendix>
|
||||
</book>
|
||||
239
doc/options-to-docbook.xsl
Normal file
239
doc/options-to-docbook.xsl
Normal file
@@ -0,0 +1,239 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:str="http://exslt.org/strings"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://docbook.org/ns/docbook"
|
||||
extension-element-prefixes="str"
|
||||
>
|
||||
|
||||
<xsl:output method='xml' encoding="UTF-8" />
|
||||
|
||||
<xsl:param name="revision" />
|
||||
<xsl:param name="program" />
|
||||
|
||||
|
||||
<xsl:template match="/expr/list">
|
||||
<appendix>
|
||||
<title>Configuration Options</title>
|
||||
<variablelist xml:id="configuration-variable-list">
|
||||
<xsl:for-each select="attrs">
|
||||
<xsl:variable name="id" select="concat('opt-', str:replace(str:replace(str:replace(str:replace(attr[@name = 'name']/string/@value, '*', '_'), '<', '_'), '>', '_'), '?', '_'))" />
|
||||
<varlistentry>
|
||||
<term xlink:href="#{$id}">
|
||||
<xsl:attribute name="xml:id"><xsl:value-of select="$id"/></xsl:attribute>
|
||||
<option>
|
||||
<xsl:value-of select="attr[@name = 'name']/string/@value" />
|
||||
</option>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
|
||||
<para>
|
||||
<xsl:value-of disable-output-escaping="yes"
|
||||
select="attr[@name = 'description']/string/@value" />
|
||||
</para>
|
||||
|
||||
<xsl:if test="attr[@name = 'type']">
|
||||
<para>
|
||||
<emphasis>Type:</emphasis>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:value-of select="attr[@name = 'type']/string/@value"/>
|
||||
<xsl:if test="attr[@name = 'readOnly']/bool/@value = 'true'">
|
||||
<xsl:text> </xsl:text>
|
||||
<emphasis>(read only)</emphasis>
|
||||
</xsl:if>
|
||||
</para>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="attr[@name = 'default']">
|
||||
<para>
|
||||
<emphasis>Default:</emphasis>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:apply-templates select="attr[@name = 'default']" mode="top" />
|
||||
</para>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="attr[@name = 'example']">
|
||||
<para>
|
||||
<emphasis>Example:</emphasis>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="attr[@name = 'example']/attrs[attr[@name = '_type' and string[@value = 'literalExample']]]">
|
||||
<programlisting><xsl:value-of select="attr[@name = 'example']/attrs/attr[@name = 'text']/string/@value" /></programlisting>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:apply-templates select="attr[@name = 'example']" mode="top" />
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</para>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="attr[@name = 'relatedPackages']">
|
||||
<para>
|
||||
<emphasis>Related packages:</emphasis>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:value-of disable-output-escaping="yes"
|
||||
select="attr[@name = 'relatedPackages']/string/@value" />
|
||||
</para>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="count(attr[@name = 'declarations']/list/*) != 0">
|
||||
<para>
|
||||
<emphasis>Declared by:</emphasis>
|
||||
</para>
|
||||
<xsl:apply-templates select="attr[@name = 'declarations']" />
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="count(attr[@name = 'definitions']/list/*) != 0">
|
||||
<para>
|
||||
<emphasis>Defined by:</emphasis>
|
||||
</para>
|
||||
<xsl:apply-templates select="attr[@name = 'definitions']" />
|
||||
</xsl:if>
|
||||
|
||||
</listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
</xsl:for-each>
|
||||
|
||||
</variablelist>
|
||||
</appendix>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="*" mode="top">
|
||||
<xsl:choose>
|
||||
<xsl:when test="string[contains(@value, '
')]">
|
||||
<programlisting>
|
||||
<xsl:text>''
|
||||
</xsl:text><xsl:value-of select='str:replace(string/@value, "${", "''${")' /><xsl:text>''</xsl:text></programlisting>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<literal><xsl:apply-templates /></literal>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="null">
|
||||
<xsl:text>null</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="string">
|
||||
<xsl:choose>
|
||||
<xsl:when test="(contains(@value, '"') or contains(@value, '\')) and not(contains(@value, '
'))">
|
||||
<xsl:text>''</xsl:text><xsl:value-of select='str:replace(@value, "${", "''${")' /><xsl:text>''</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>"</xsl:text><xsl:value-of select="str:replace(str:replace(str:replace(str:replace(@value, '\', '\\'), '"', '\"'), '
', '\n'), '$', '\$')" /><xsl:text>"</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="int">
|
||||
<xsl:value-of select="@value" />
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="bool[@value = 'true']">
|
||||
<xsl:text>true</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="bool[@value = 'false']">
|
||||
<xsl:text>false</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="list">
|
||||
[
|
||||
<xsl:for-each select="*">
|
||||
<xsl:apply-templates select="." />
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:for-each>
|
||||
]
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="attrs[attr[@name = '_type' and string[@value = 'literalExample']]]">
|
||||
<xsl:value-of select="attr[@name = 'text']/string/@value" />
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="attrs">
|
||||
{
|
||||
<xsl:for-each select="attr">
|
||||
<xsl:value-of select="@name" />
|
||||
<xsl:text> = </xsl:text>
|
||||
<xsl:apply-templates select="*" /><xsl:text>; </xsl:text>
|
||||
</xsl:for-each>
|
||||
}
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="derivation">
|
||||
<replaceable>(build of <xsl:value-of select="attr[@name = 'name']/string/@value" />)</replaceable>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="attr[@name = 'declarations' or @name = 'definitions']">
|
||||
<simplelist>
|
||||
<xsl:for-each select="list/string">
|
||||
<member><filename>
|
||||
<!-- Hyperlink the filename either to the NixOS Subversion
|
||||
repository (if it’s a module and we have a revision number),
|
||||
or to the local filesystem. -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="not(starts-with(@value, '/'))">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$program = 'home-manager'">
|
||||
<xsl:attribute name="xlink:href">https://github.com/rycee/home-manager/blob/<xsl:value-of select="$revision"/>/<xsl:value-of select="@value"/>#blob-path</xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:when test="$revision = 'local'">
|
||||
<xsl:attribute name="xlink:href">https://github.com/NixOS/nixpkgs/blob/master/<xsl:value-of select="@value"/></xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:attribute name="xlink:href">https://github.com/NixOS/nixpkgs/blob/<xsl:value-of select="$revision"/>/<xsl:value-of select="@value"/></xsl:attribute>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
<xsl:when test="$revision != 'local' and $program = 'nixops' and contains(@value, '/nix/')">
|
||||
<xsl:attribute name="xlink:href">https://github.com/NixOS/nixops/blob/<xsl:value-of select="$revision"/>/nix/<xsl:value-of select="substring-after(@value, '/nix/')"/></xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:attribute name="xlink:href">file://<xsl:value-of select="@value"/></xsl:attribute>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<!-- Print the filename and make it user-friendly by replacing the
|
||||
/nix/store/<hash> prefix by the default location of nixos
|
||||
sources. -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="$program = 'home-manager'">
|
||||
<home-manager/<xsl:value-of select="@value"/>>
|
||||
</xsl:when>
|
||||
<xsl:when test="not(starts-with(@value, '/'))">
|
||||
<nixpkgs/<xsl:value-of select="@value"/>>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains(@value, 'nixops') and contains(@value, '/nix/')">
|
||||
<nixops/<xsl:value-of select="substring-after(@value, '/nix/')"/>>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="@value" />
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</filename></member>
|
||||
</xsl:for-each>
|
||||
</simplelist>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="function">
|
||||
<xsl:text>λ</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
</xsl:stylesheet>
|
||||
9
doc/overrides.css
Normal file
9
doc/overrides.css
Normal file
@@ -0,0 +1,9 @@
|
||||
.docbook .xref img[src^=images\/callouts\/],
|
||||
.screen img,
|
||||
.programlisting img {
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
.calloutlist img {
|
||||
width: 1.5em;
|
||||
}
|
||||
271
doc/style.css
Normal file
271
doc/style.css
Normal file
@@ -0,0 +1,271 @@
|
||||
/* Copied from http://bakefile.sourceforge.net/, which appears
|
||||
licensed under the GNU GPL. */
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Basic headers and text:
|
||||
***************************************************************************/
|
||||
|
||||
body
|
||||
{
|
||||
font-family: "Nimbus Sans L", sans-serif;
|
||||
background: white;
|
||||
margin: 2em 1em 2em 1em;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4
|
||||
{
|
||||
color: #005aa0;
|
||||
}
|
||||
|
||||
h1 /* title */
|
||||
{
|
||||
font-size: 200%;
|
||||
}
|
||||
|
||||
h2 /* chapters, appendices, subtitle */
|
||||
{
|
||||
font-size: 180%;
|
||||
}
|
||||
|
||||
/* Extra space between chapters, appendices. */
|
||||
div.chapter > div.titlepage h2, div.appendix > div.titlepage h2
|
||||
{
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
div.section > div.titlepage h2 /* sections */
|
||||
{
|
||||
font-size: 150%;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
h3 /* subsections */
|
||||
{
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
div.simplesect h2
|
||||
{
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
div.appendix h3
|
||||
{
|
||||
font-size: 150%;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
div.refnamediv h2, div.refsynopsisdiv h2, div.refsection h2 /* refentry parts */
|
||||
{
|
||||
margin-top: 1.4em;
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
div.refsection h3
|
||||
{
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Examples:
|
||||
***************************************************************************/
|
||||
|
||||
div.example
|
||||
{
|
||||
border: 1px solid #b0b0b0;
|
||||
padding: 6px 6px;
|
||||
margin-left: 1.5em;
|
||||
margin-right: 1.5em;
|
||||
background: #f4f4f8;
|
||||
border-radius: 0.4em;
|
||||
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
|
||||
}
|
||||
|
||||
div.example p.title
|
||||
{
|
||||
margin-top: 0em;
|
||||
}
|
||||
|
||||
div.example pre
|
||||
{
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Screen dumps:
|
||||
***************************************************************************/
|
||||
|
||||
pre.screen, pre.programlisting
|
||||
{
|
||||
border: 1px solid #b0b0b0;
|
||||
padding: 3px 3px;
|
||||
margin-left: 1.5em;
|
||||
margin-right: 1.5em;
|
||||
|
||||
background: #f4f4f8;
|
||||
font-family: monospace;
|
||||
border-radius: 0.4em;
|
||||
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
|
||||
}
|
||||
|
||||
div.example pre.programlisting
|
||||
{
|
||||
border: 0px;
|
||||
padding: 0 0;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Notes, warnings etc:
|
||||
***************************************************************************/
|
||||
|
||||
.note, .warning
|
||||
{
|
||||
border: 1px solid #b0b0b0;
|
||||
padding: 3px 3px;
|
||||
margin-left: 1.5em;
|
||||
margin-right: 1.5em;
|
||||
margin-bottom: 1em;
|
||||
padding: 0.3em 0.3em 0.3em 0.3em;
|
||||
background: #fffff5;
|
||||
border-radius: 0.4em;
|
||||
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
|
||||
}
|
||||
|
||||
div.note, div.warning
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.note h3, div.warning h3
|
||||
{
|
||||
color: red;
|
||||
font-size: 100%;
|
||||
padding-right: 0.5em;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.note p, div.warning p
|
||||
{
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
div.note h3 + p, div.warning h3 + p
|
||||
{
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.note h3
|
||||
{
|
||||
color: blue;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
div.navfooter *
|
||||
{
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Links colors and highlighting:
|
||||
***************************************************************************/
|
||||
|
||||
a { text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
a:link { color: #0048b3; }
|
||||
a:visited { color: #002a6a; }
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Table of contents:
|
||||
***************************************************************************/
|
||||
|
||||
div.toc
|
||||
{
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.toc dl
|
||||
{
|
||||
margin-top: 0em;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Special elements:
|
||||
***************************************************************************/
|
||||
|
||||
tt, code
|
||||
{
|
||||
color: #400000;
|
||||
}
|
||||
|
||||
.term
|
||||
{
|
||||
font-weight: bold;
|
||||
|
||||
}
|
||||
|
||||
div.variablelist dd p, div.glosslist dd p
|
||||
{
|
||||
margin-top: 0em;
|
||||
}
|
||||
|
||||
div.variablelist dd, div.glosslist dd
|
||||
{
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
div.glosslist dt
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.varname
|
||||
{
|
||||
color: #400000;
|
||||
}
|
||||
|
||||
span.command strong
|
||||
{
|
||||
font-weight: normal;
|
||||
color: #400000;
|
||||
}
|
||||
|
||||
div.calloutlist table
|
||||
{
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
table
|
||||
{
|
||||
border-collapse: collapse;
|
||||
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
|
||||
}
|
||||
|
||||
table.simplelist
|
||||
{
|
||||
text-align: left;
|
||||
color: #005aa0;
|
||||
border: 0;
|
||||
padding: 5px;
|
||||
background: #fffff5;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
box-shadow: none;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
div.navheader table, div.navfooter table {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
div.affiliation
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
||||
@@ -12,6 +12,14 @@ function errorEcho() {
|
||||
echo $* >&2
|
||||
}
|
||||
|
||||
function setWorkDir() {
|
||||
if [[ ! -v WORK_DIR ]]; then
|
||||
WORK_DIR="$(mktemp --tmpdir -d home-manager-build.XXXXXXXXXX)"
|
||||
# shellcheck disable=2064
|
||||
trap "rm -r '$WORK_DIR'" EXIT
|
||||
fi
|
||||
}
|
||||
|
||||
# Attempts to set the HOME_MANAGER_CONFIG global variable.
|
||||
#
|
||||
# If no configuration file can be found then this function will print
|
||||
@@ -32,7 +40,7 @@ function setConfigFile() {
|
||||
for confFile in "$defaultConfFile" \
|
||||
"$HOME/.nixpkgs/home.nix" ; do
|
||||
if [[ -e "$confFile" ]] ; then
|
||||
HOME_MANAGER_CONFIG="$confFile"
|
||||
HOME_MANAGER_CONFIG="$(realpath "$confFile")"
|
||||
return
|
||||
fi
|
||||
done
|
||||
@@ -69,11 +77,19 @@ function doBuildAttr() {
|
||||
fi
|
||||
|
||||
# shellcheck disable=2086
|
||||
nix-build \
|
||||
"<home-manager/home-manager/home-manager.nix>" \
|
||||
$extraArgs \
|
||||
--argstr confPath "$HOME_MANAGER_CONFIG" \
|
||||
--argstr confAttr "$HOME_MANAGER_CONFIG_ATTRIBUTE"
|
||||
if [[ -v USE_NIX2_COMMAND ]]; then
|
||||
nix build \
|
||||
-f "<home-manager/home-manager/home-manager.nix>" \
|
||||
$extraArgs \
|
||||
--argstr confPath "$HOME_MANAGER_CONFIG" \
|
||||
--argstr confAttr "$HOME_MANAGER_CONFIG_ATTRIBUTE"
|
||||
else
|
||||
nix-build \
|
||||
"<home-manager/home-manager/home-manager.nix>" \
|
||||
$extraArgs \
|
||||
--argstr confPath "$HOME_MANAGER_CONFIG" \
|
||||
--argstr confAttr "$HOME_MANAGER_CONFIG_ATTRIBUTE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Presents news to the user. Takes as argument the path to a "news
|
||||
@@ -121,12 +137,20 @@ function doBuild() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
setWorkDir
|
||||
|
||||
local newsInfo
|
||||
newsInfo=$(buildNews)
|
||||
|
||||
local exitCode
|
||||
doBuildAttr -A activationPackage \
|
||||
&& exitCode=0 || exitCode=1
|
||||
|
||||
if [[ -v USE_NIX2_COMMAND ]]; then
|
||||
doBuildAttr activationPackage \
|
||||
&& exitCode=0 || exitCode=1
|
||||
else
|
||||
doBuildAttr --attr activationPackage \
|
||||
&& exitCode=0 || exitCode=1
|
||||
fi
|
||||
|
||||
presentNews "$newsInfo"
|
||||
|
||||
@@ -134,24 +158,31 @@ function doBuild() {
|
||||
}
|
||||
|
||||
function doSwitch() {
|
||||
setWorkDir
|
||||
|
||||
local newsInfo
|
||||
newsInfo=$(buildNews)
|
||||
|
||||
local generation
|
||||
local exitCode=0
|
||||
local wrkdir
|
||||
|
||||
# Build the generation and run the activate script. Note, we
|
||||
# specify an output link so that it is treated as a GC root. This
|
||||
# prevents an unfortunately timed GC from removing the generation
|
||||
# before activation completes.
|
||||
wrkdir="$(mktemp -d)"
|
||||
generation=$(doBuildAttr -o "$wrkdir/result" -A activationPackage) \
|
||||
&& $generation/activate || exitCode=1
|
||||
generation="$WORK_DIR/generation"
|
||||
|
||||
# Because the previous command never fails, the script keeps
|
||||
# running and $wrkdir is always removed.
|
||||
rm -r "$wrkdir"
|
||||
if [[ -v USE_NIX2_COMMAND ]]; then
|
||||
doBuildAttr \
|
||||
--out-link "$generation" \
|
||||
activationPackage \
|
||||
&& "$generation/activate" || exitCode=1
|
||||
else
|
||||
doBuildAttr \
|
||||
--out-link "$generation" \
|
||||
--attr activationPackage \
|
||||
&& "$generation/activate" || exitCode=1
|
||||
fi
|
||||
|
||||
presentNews "$newsInfo"
|
||||
|
||||
@@ -159,9 +190,15 @@ function doSwitch() {
|
||||
}
|
||||
|
||||
function doListGens() {
|
||||
# Whether to colorize the generations output.
|
||||
local color="never"
|
||||
if [[ -t 1 ]]; then
|
||||
color="always"
|
||||
fi
|
||||
|
||||
pushd "/nix/var/nix/profiles/per-user/$USER" > /dev/null
|
||||
# shellcheck disable=2012
|
||||
ls --color=yes -gG --time-style=long-iso --sort time home-manager-*-link \
|
||||
ls --color=$color -gG --time-style=long-iso --sort time home-manager-*-link \
|
||||
| cut -d' ' -f 4- \
|
||||
| sed -E 's/home-manager-([[:digit:]]*)-link/: id \1/'
|
||||
popd > /dev/null
|
||||
@@ -227,18 +264,36 @@ function newsReadIdsFile() {
|
||||
# Builds news meta information to be sourced into this script.
|
||||
#
|
||||
# Note, we suppress build output to remove unnecessary verbosity. We
|
||||
# also use "no out link" to avoid the need for a build directory
|
||||
# (although this exposes the risk of GC removing the result before we
|
||||
# manage to source it).
|
||||
# put the output in the work directory to avoid the risk of an
|
||||
# unfortunately timed GC removing it.
|
||||
function buildNews() {
|
||||
doBuildAttr --quiet \
|
||||
--attr newsInfo \
|
||||
--no-out-link \
|
||||
--arg check false \
|
||||
--argstr newsReadIdsFile "$(newsReadIdsFile)"
|
||||
local output
|
||||
output="$WORK_DIR/news-info.sh"
|
||||
|
||||
if [[ -v USE_NIX2_COMMAND ]]; then
|
||||
doBuildAttr \
|
||||
--out-link "$output" \
|
||||
--quiet \
|
||||
--arg check false \
|
||||
--argstr newsReadIdsFile "$(newsReadIdsFile)" \
|
||||
newsInfo
|
||||
else
|
||||
doBuildAttr \
|
||||
--out-link "$output" \
|
||||
--no-build-output \
|
||||
--quiet \
|
||||
--arg check false \
|
||||
--argstr newsReadIdsFile "$(newsReadIdsFile)" \
|
||||
--attr newsInfo \
|
||||
> /dev/null
|
||||
fi
|
||||
|
||||
echo "$output"
|
||||
}
|
||||
|
||||
function doShowNews() {
|
||||
setWorkDir
|
||||
|
||||
local infoFile
|
||||
infoFile=$(buildNews) || return 1
|
||||
|
||||
@@ -311,8 +366,11 @@ for arg in "$@"; do
|
||||
fi
|
||||
done
|
||||
|
||||
while getopts f:I:A:vnh opt; do
|
||||
while getopts 2f:I:A:vnh opt; do
|
||||
case $opt in
|
||||
2)
|
||||
USE_NIX2_COMMAND=1
|
||||
;;
|
||||
f)
|
||||
HOME_MANAGER_CONFIG="$OPTARG"
|
||||
;;
|
||||
|
||||
@@ -4,6 +4,8 @@ pkgs.runCommand
|
||||
"home-manager-install"
|
||||
{
|
||||
propagatedBuildInputs = [ home-manager ];
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
shellHook = ''
|
||||
echo
|
||||
echo "Creating initial Home Manager generation..."
|
||||
|
||||
413
modules/accounts/email.nix
Normal file
413
modules/accounts/email.nix
Normal file
@@ -0,0 +1,413 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.accounts.email;
|
||||
|
||||
gpgModule = types.submodule {
|
||||
options = {
|
||||
key = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
The key to use as listed in <command>gpg --list-keys</command>.
|
||||
'';
|
||||
};
|
||||
|
||||
signByDefault = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Sign messages by default.";
|
||||
};
|
||||
|
||||
encryptByDefault = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Encrypt outgoing messages by default.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
signatureModule = types.submodule {
|
||||
options = {
|
||||
text = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = ''
|
||||
--
|
||||
Luke Skywalker
|
||||
May the force be with you.
|
||||
'';
|
||||
description = ''
|
||||
Signature content.
|
||||
'';
|
||||
};
|
||||
|
||||
showSignature = mkOption {
|
||||
type = types.enum [ "append" "attach" "none" ];
|
||||
default = "none";
|
||||
description = "Method to communicate the signature.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
tlsModule = types.submodule {
|
||||
options = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable TLS/SSL.
|
||||
'';
|
||||
};
|
||||
|
||||
useStartTls = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to use STARTTLS.
|
||||
'';
|
||||
};
|
||||
|
||||
certificatesFile = mkOption {
|
||||
type = types.path;
|
||||
default = config.accounts.email.certificatesFile;
|
||||
defaultText = "config.accounts.email.certificatesFile";
|
||||
description = ''
|
||||
Path to file containing certificate authorities that should
|
||||
be used to validate the connection authenticity. If
|
||||
<literal>null</literal> then the system default is used.
|
||||
Note, if set then the system default may still be accepted.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
imapModule = types.submodule {
|
||||
options = {
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
example = "imap.example.org";
|
||||
description = ''
|
||||
Hostname of IMAP server.
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.nullOr types.ints.positive;
|
||||
default = null;
|
||||
example = 993;
|
||||
description = ''
|
||||
The port on which the IMAP server listens. If
|
||||
<literal>null</literal> then the default port is used.
|
||||
'';
|
||||
};
|
||||
|
||||
tls = mkOption {
|
||||
type = tlsModule;
|
||||
default = {};
|
||||
description = ''
|
||||
Configuration for secure connections.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
smtpModule = types.submodule {
|
||||
options = {
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
example = "smtp.example.org";
|
||||
description = ''
|
||||
Hostname of SMTP server.
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.nullOr types.ints.positive;
|
||||
default = null;
|
||||
example = 465;
|
||||
description = ''
|
||||
The port on which the SMTP server listens. If
|
||||
<literal>null</literal> then the default port is used.
|
||||
'';
|
||||
};
|
||||
|
||||
tls = mkOption {
|
||||
type = tlsModule;
|
||||
default = {};
|
||||
description = ''
|
||||
Configuration for secure connections.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
maildirModule = types.submodule ({ config, ... }: {
|
||||
options = {
|
||||
path = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Path to maildir directory where mail for this account is
|
||||
stored. This is relative to the base maildir path.
|
||||
'';
|
||||
};
|
||||
|
||||
absPath = mkOption {
|
||||
type = types.path;
|
||||
readOnly = true;
|
||||
internal = true;
|
||||
default = "${cfg.maildirBasePath}/${config.path}";
|
||||
description = ''
|
||||
A convenience option whose value is the absolute path of
|
||||
this maildir.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
mailAccountOpts = { name, config, ... }: {
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
Unique identifier of the account. This is set to the
|
||||
attribute name of the account configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
primary = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether this is the primary account. Only one account may be
|
||||
set as primary.
|
||||
'';
|
||||
};
|
||||
|
||||
flavor = mkOption {
|
||||
type = types.enum [ "plain" "gmail.com" "runbox.com" ];
|
||||
default = "plain";
|
||||
description = ''
|
||||
Some email providers have peculiar behavior that require
|
||||
special treatment. This option is therefore intended to
|
||||
indicate the nature of the provider.
|
||||
</para><para>
|
||||
When this indicates a specific provider then, for example,
|
||||
the IMAP and SMTP server configuration may be set
|
||||
automatically.
|
||||
'';
|
||||
};
|
||||
|
||||
address = mkOption {
|
||||
type = types.strMatching ".*@.*";
|
||||
example = "jane.doe@example.org";
|
||||
description = "The email address of this account.";
|
||||
};
|
||||
|
||||
realName = mkOption {
|
||||
type = types.str;
|
||||
example = "Jane Doe";
|
||||
description = "Name displayed when sending mails.";
|
||||
};
|
||||
|
||||
userName = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
The server username of this account. This will be used as
|
||||
the SMTP and IMAP user name.
|
||||
'';
|
||||
};
|
||||
|
||||
passwordCommand = mkOption {
|
||||
type = types.nullOr (types.either types.str (types.listOf types.str));
|
||||
default = null;
|
||||
apply = p: if isString p then splitString " " p else p;
|
||||
example = "secret-tool lookup email me@example.org";
|
||||
description = ''
|
||||
A command, which when run writes the account password on
|
||||
standard output.
|
||||
'';
|
||||
};
|
||||
|
||||
folders = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
inbox = mkOption {
|
||||
type = types.str;
|
||||
default = "Inbox";
|
||||
description = ''
|
||||
Relative path of the inbox mail.
|
||||
'';
|
||||
};
|
||||
|
||||
sent = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = "Sent";
|
||||
description = ''
|
||||
Relative path of the sent mail folder.
|
||||
'';
|
||||
};
|
||||
|
||||
drafts = mkOption {
|
||||
type = types.str;
|
||||
default = "Drafts";
|
||||
description = ''
|
||||
Relative path of the drafts mail folder.
|
||||
'';
|
||||
};
|
||||
|
||||
trash = mkOption {
|
||||
type = types.str;
|
||||
default = "Trash";
|
||||
description = ''
|
||||
Relative path of the deleted mail folder.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = ''
|
||||
Standard email folders.
|
||||
'';
|
||||
};
|
||||
|
||||
imap = mkOption {
|
||||
type = types.nullOr imapModule;
|
||||
default = null;
|
||||
description = ''
|
||||
The IMAP configuration to use for this account.
|
||||
'';
|
||||
};
|
||||
|
||||
signature = mkOption {
|
||||
type = signatureModule;
|
||||
default = {};
|
||||
description = ''
|
||||
Signature configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
gpg = mkOption {
|
||||
type = types.nullOr gpgModule;
|
||||
default = null;
|
||||
description = ''
|
||||
GPG configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
smtp = mkOption {
|
||||
type = types.nullOr smtpModule;
|
||||
default = null;
|
||||
description = ''
|
||||
The SMTP configuration to use for this account.
|
||||
'';
|
||||
};
|
||||
|
||||
maildir = mkOption {
|
||||
type = types.nullOr maildirModule;
|
||||
defaultText = { path = "\${name}"; };
|
||||
description = ''
|
||||
Maildir configuration for this account.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
{
|
||||
name = name;
|
||||
maildir = mkOptionDefault { path = "${name}"; };
|
||||
}
|
||||
|
||||
(mkIf (config.flavor == "gmail.com") {
|
||||
userName = mkDefault config.address;
|
||||
|
||||
imap = {
|
||||
host = "imap.gmail.com";
|
||||
};
|
||||
|
||||
smtp = {
|
||||
host = "smtp.gmail.com";
|
||||
port = if config.smtp.tls.useStartTls then 587 else 465;
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf (config.flavor == "runbox.com") {
|
||||
imap = {
|
||||
host = "mail.runbox.com";
|
||||
};
|
||||
|
||||
smtp = {
|
||||
host = "mail.runbox.com";
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.accounts.email = {
|
||||
certificatesFile = mkOption {
|
||||
type = types.path;
|
||||
default = "/etc/ssl/certs/ca-certificates.crt";
|
||||
description = ''
|
||||
Path to default file containing certificate authorities that
|
||||
should be used to validate the connection authenticity. This
|
||||
path may be overridden on a per-account basis.
|
||||
'';
|
||||
};
|
||||
|
||||
maildirBasePath = mkOption {
|
||||
type = types.str;
|
||||
default = "${config.home.homeDirectory}/Maildir";
|
||||
defaultText = "$HOME/Maildir";
|
||||
apply = p:
|
||||
if hasPrefix "/" p
|
||||
then p
|
||||
else "${config.home.homeDirectory}/${p}";
|
||||
description = ''
|
||||
The base directory for account maildir directories. May be a
|
||||
relative path, in which case it is relative the home
|
||||
directory.
|
||||
'';
|
||||
};
|
||||
|
||||
accounts = mkOption {
|
||||
type = types.attrsOf (types.submodule [
|
||||
mailAccountOpts
|
||||
(import ../programs/alot-accounts.nix)
|
||||
(import ../programs/mbsync-accounts.nix)
|
||||
(import ../programs/msmtp-accounts.nix)
|
||||
(import ../programs/notmuch-accounts.nix)
|
||||
(import ../programs/offlineimap-accounts.nix)
|
||||
]);
|
||||
default = {};
|
||||
description = "List of email accounts.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf (cfg.accounts != {}) {
|
||||
assertions = [
|
||||
(
|
||||
let
|
||||
primaries =
|
||||
catAttrs "name"
|
||||
(filter (a: a.primary)
|
||||
(attrValues cfg.accounts));
|
||||
in
|
||||
{
|
||||
assertion = length primaries == 1;
|
||||
message =
|
||||
"Must have exactly one primary mail account but found "
|
||||
+ toString (length primaries)
|
||||
+ optionalString (length primaries > 1)
|
||||
(", namely " + concatStringsSep ", " primaries);
|
||||
}
|
||||
)
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -197,11 +197,32 @@ in
|
||||
''
|
||||
);
|
||||
|
||||
home.activation.checkFilesChanged = dag.entryBefore ["linkGeneration"] (
|
||||
''
|
||||
declare -A changedFiles
|
||||
'' + concatMapStrings (v: ''
|
||||
cmp --quiet "${v.source}" "${config.home.homeDirectory}/${v.target}" \
|
||||
&& changedFiles["${v.target}"]=0 \
|
||||
|| changedFiles["${v.target}"]=1
|
||||
'') (filter (v: v.onChange != "") (attrValues cfg))
|
||||
);
|
||||
|
||||
home.activation.onFilesChange = dag.entryAfter ["linkGeneration"] (
|
||||
concatMapStrings (v: ''
|
||||
if [[ ${"$\{changedFiles"}["${v.target}"]} -eq 1 ]]; then
|
||||
${v.onChange}
|
||||
fi
|
||||
'') (filter (v: v.onChange != "") (attrValues cfg))
|
||||
);
|
||||
|
||||
home-files = pkgs.stdenv.mkDerivation {
|
||||
name = "home-manager-files";
|
||||
|
||||
nativeBuildInputs = [ pkgs.xlibs.lndir ];
|
||||
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
|
||||
# Symlink directories and files that have the right execute bit.
|
||||
# Copy files that need their execute bit changed.
|
||||
buildCommand = ''
|
||||
|
||||
@@ -121,6 +121,17 @@ in
|
||||
description = "The user's home directory.";
|
||||
};
|
||||
|
||||
home.profileDirectory = mkOption {
|
||||
type = types.path;
|
||||
defaultText = "~/.nix-profile";
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
The profile directory where Home Manager generations are
|
||||
installed.
|
||||
'';
|
||||
};
|
||||
|
||||
home.language = mkOption {
|
||||
type = languageSubModule;
|
||||
default = {};
|
||||
@@ -249,6 +260,8 @@ in
|
||||
home.username = mkDefault (builtins.getEnv "USER");
|
||||
home.homeDirectory = mkDefault (builtins.getEnv "HOME");
|
||||
|
||||
home.profileDirectory = cfg.homeDirectory + "/.nix-profile";
|
||||
|
||||
home.sessionVariables =
|
||||
let
|
||||
maybeSet = n: v: optionalAttrs (v != null) { ${n} = v; };
|
||||
@@ -313,7 +326,6 @@ in
|
||||
pkgs.gnugrep
|
||||
pkgs.gnused
|
||||
pkgs.ncurses # For `tput`.
|
||||
pkgs.nix
|
||||
]
|
||||
+ optionalString (!cfg.emptyActivationPath) "\${PATH:+:}$PATH";
|
||||
|
||||
@@ -337,6 +349,9 @@ in
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "home-manager-generation";
|
||||
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
|
||||
buildCommand = ''
|
||||
mkdir -p $out
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
function setupVars() {
|
||||
local profilesPath="/nix/var/nix/profiles/per-user/$USER"
|
||||
local gcPath="/nix/var/nix/gcroots/per-user/$USER"
|
||||
@@ -9,27 +11,38 @@ function setupVars() {
|
||||
| sort -rn \
|
||||
| head -1)
|
||||
|
||||
if [[ -n "$greatestGenNum" ]] ; then
|
||||
if [[ -n $greatestGenNum ]] ; then
|
||||
oldGenNum=$greatestGenNum
|
||||
newGenNum=$((oldGenNum + 1))
|
||||
else
|
||||
newGenNum=1
|
||||
fi
|
||||
|
||||
if [[ -e "$gcPath/current-home" ]] ; then
|
||||
if [[ -e $gcPath/current-home ]] ; then
|
||||
oldGenPath="$(readlink -e "$gcPath/current-home")"
|
||||
fi
|
||||
|
||||
$VERBOSE_ECHO "Sanity checking oldGenNum and oldGenPath"
|
||||
if [[ -v oldGenNum && ! -v oldGenPath
|
||||
|| ! -v oldGenNum && -v oldGenPath ]]; then
|
||||
errorEcho "Invalid profile number and GC root values! These must be"
|
||||
errorEcho "either both empty or both set but are now set to"
|
||||
errorEcho " '${oldGenNum:-}' and '${oldGenPath:-}'"
|
||||
errorEcho "If you don't mind losing previous profile generations then"
|
||||
errorEcho "the easiest solution is probably to run"
|
||||
errorEcho " rm $profilesPath/home-manager*"
|
||||
errorEcho " rm $gcPath/current-home"
|
||||
errorEcho "and trying home-manager switch again. Good luck!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
genProfilePath="$profilesPath/home-manager"
|
||||
newGenPath="@GENERATION_DIR@";
|
||||
newGenProfilePath="$profilesPath/home-manager-$newGenNum-link"
|
||||
newGenGcPath="$gcPath/current-home"
|
||||
}
|
||||
|
||||
setupVars
|
||||
|
||||
echo "Starting home manager activation"
|
||||
|
||||
if [[ -v VERBOSE ]]; then
|
||||
export VERBOSE_ECHO=echo
|
||||
export VERBOSE_ARG="--verbose"
|
||||
@@ -38,6 +51,10 @@ else
|
||||
export VERBOSE_ARG=""
|
||||
fi
|
||||
|
||||
echo "Starting home manager activation"
|
||||
|
||||
setupVars
|
||||
|
||||
if [[ -v DRY_RUN ]] ; then
|
||||
echo "This is a dry run"
|
||||
export DRY_RUN_CMD=echo
|
||||
@@ -46,6 +63,11 @@ else
|
||||
export DRY_RUN_CMD=""
|
||||
fi
|
||||
|
||||
if [[ -v VERBOSE ]]; then
|
||||
echo -n "Using Nix version: "
|
||||
nix-env --version
|
||||
fi
|
||||
|
||||
$VERBOSE_ECHO "Activation variables:"
|
||||
if [[ -v oldGenNum ]] ; then
|
||||
$VERBOSE_ECHO " oldGenNum=$oldGenNum"
|
||||
|
||||
@@ -95,6 +95,17 @@ in
|
||||
are symbolic links to the files of the source directory.
|
||||
'';
|
||||
};
|
||||
|
||||
onChange = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Shell commands to run when file has changed between
|
||||
generations. The script will be run
|
||||
<emphasis>after</emphasis> the new files have been linked
|
||||
into place.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
|
||||
@@ -4,19 +4,21 @@ with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.manual;
|
||||
|
||||
/* For the purpose of generating docs, evaluate options with each derivation
|
||||
in `pkgs` (recursively) replaced by a fake with path "\${pkgs.attribute.path}".
|
||||
It isn't perfect, but it seems to cover a vast majority of use cases.
|
||||
Caveat: even if the package is reached by a different means,
|
||||
the path above will be shown and not e.g. `${config.services.foo.package}`. */
|
||||
nixosManual = import <nixpkgs/nixos/doc/manual> {
|
||||
homeManagerManual = import ../doc {
|
||||
inherit pkgs config;
|
||||
version = "0.1";
|
||||
revision = "release-0.1";
|
||||
revision = "master";
|
||||
options =
|
||||
let
|
||||
scrubbedEval = evalModules {
|
||||
modules = [ { nixpkgs.system = pkgs.stdenv.system; } ] ++ baseModules;
|
||||
modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ baseModules;
|
||||
args = (config._module.args) // { modules = [ ]; };
|
||||
specialArgs = { pkgs = scrubDerivations "pkgs" pkgs; };
|
||||
};
|
||||
@@ -32,18 +34,42 @@ let
|
||||
in scrubbedEval.options;
|
||||
};
|
||||
|
||||
homeEnvironmentManPages = pkgs.runCommand "home-environment-manpages" {
|
||||
allowedReferences = [ "out" ];
|
||||
} ''
|
||||
install -v -D -m444 \
|
||||
${nixosManual.manpages}/share/man/man5/configuration.nix.5 \
|
||||
$out/share/man/man5/home-configuration.nix.5
|
||||
'';
|
||||
manualHtmlRoot = "${homeManagerManual.manual}/share/doc/home-manager/index.html";
|
||||
|
||||
helpScript = pkgs.writeScriptBin "home-manager-help" ''
|
||||
#!${pkgs.bash}/bin/bash -e
|
||||
|
||||
if [ -z "$BROWSER" ]; then
|
||||
for candidate in xdg-open open w3m; do
|
||||
BROWSER="$(type -P $candidate || true)"
|
||||
if [ -x "$BROWSER" ]; then
|
||||
break;
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -z "$BROWSER" ]; then
|
||||
echo "$0: unable to start a web browser; please set \$BROWSER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$BROWSER" ${manualHtmlRoot}
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
manual.html.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to install the HTML manual. This also installs the
|
||||
<command>home-manager-help</command> tool, which opens a local
|
||||
copy of the Home Manager manual in the system web browser.
|
||||
'';
|
||||
};
|
||||
|
||||
manual.manpages.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
@@ -59,23 +85,17 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf config.manual.manpages.enable {
|
||||
home.packages = [ homeEnvironmentManPages ];
|
||||
config = {
|
||||
home.packages = mkMerge [
|
||||
(mkIf cfg.html.enable [ helpScript homeManagerManual.manual ])
|
||||
|
||||
(mkIf cfg.manpages.enable [ homeManagerManual.manpages ])
|
||||
];
|
||||
};
|
||||
|
||||
# To fix error during manpage build.
|
||||
meta = {
|
||||
maintainers = [ maintainers.rycee ];
|
||||
doc = builtins.toFile "nothingness" ''
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-nothing">
|
||||
<title>this is just to make the docs compile</title>
|
||||
<para xml:id="sec-grsecurity"></para>
|
||||
<para xml:id="sec-emacs-docbook-xml"></para>
|
||||
</chapter>
|
||||
'';
|
||||
doc = builtins.toFile "nothingness" "";
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ in
|
||||
<?xml version='1.0'?>
|
||||
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
|
||||
<fontconfig>
|
||||
<dir>~/.nix-profile/lib/X11/fonts</dir>
|
||||
<dir>~/.nix-profile/share/fonts</dir>
|
||||
<dir>${config.home.profileDirectory}/lib/X11/fonts</dir>
|
||||
<dir>${config.home.profileDirectory}/share/fonts</dir>
|
||||
</fontconfig>
|
||||
'';
|
||||
};
|
||||
|
||||
14
modules/misc/lib.nix
Normal file
14
modules/misc/lib.nix
Normal file
@@ -0,0 +1,14 @@
|
||||
{ lib, ... }:
|
||||
|
||||
{
|
||||
options = {
|
||||
lib = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.attrs;
|
||||
default = {};
|
||||
description = ''
|
||||
This option allows modules to define helper functions,
|
||||
constants, etc.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -479,17 +479,6 @@ in
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-01-25T11:35:08+00:00";
|
||||
condition = options.services.qsyncthingtray.enable.isDefined;
|
||||
message = ''
|
||||
'services.qsyncthingtray' has been merged into 'services.syncthing'.
|
||||
Please, use 'services.syncthing.tray' option to activate the tray service.
|
||||
|
||||
The old module will be removed on February 25, 2018.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-02-02T11:15:00+00:00";
|
||||
message = ''
|
||||
@@ -560,6 +549,264 @@ in
|
||||
feature is slowly forthcoming.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-02-09T21:14:42+00:00";
|
||||
condition = with config.programs.rofi; enable && colors != null;
|
||||
message = ''
|
||||
The new and preferred way to configure the rofi theme is
|
||||
using rasi themes through the 'programs.rofi.theme' option.
|
||||
This option can take as value either the name of a
|
||||
pre-installed theme or the path to a theme file.
|
||||
|
||||
A rasi theme can be generated from an Xresources config
|
||||
using 'rofi -dump-theme'.
|
||||
|
||||
The option 'programs.rofi.colors' is still supported but may
|
||||
become deprecated and removed in the future.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-02-19T21:45:26+00:00";
|
||||
message = ''
|
||||
A new module is available: 'programs.pidgin'
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-03-04T06:54:26+00:00";
|
||||
message = ''
|
||||
A new module is available: 'services.unclutter'
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-03-07T21:38:27+00:00";
|
||||
message = ''
|
||||
A new module is available: 'programs.fzf'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-03-25T06:49:57+00:00";
|
||||
condition = with config.programs.ssh; enable && matchBlocks != {};
|
||||
message = ''
|
||||
Options set through the 'programs.ssh' module are now placed
|
||||
at the end of the SSH configuration file. This was done to
|
||||
make it possible to override global options such as
|
||||
'ForwardAgent' or 'Compression' inside a host match block.
|
||||
|
||||
If you truly need to override an SSH option across all match
|
||||
blocks then the new option
|
||||
|
||||
programs.ssh.extraOptionOverrides
|
||||
|
||||
can be used.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-04-19T07:42:01+00:00";
|
||||
message = ''
|
||||
A new module is available: 'programs.autorandr'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-04-19T15:44:55+00:00";
|
||||
condition = config.programs.git.enable;
|
||||
message = ''
|
||||
A new option 'programs.git.includes' is available. Additional
|
||||
Git configuration files may be included via
|
||||
|
||||
programs.git.includes = [
|
||||
{ path = "~/path/to/config.inc"; }
|
||||
];
|
||||
|
||||
or conditionally via
|
||||
|
||||
programs.git.includes = [
|
||||
{ path = "~/path/to/config.inc"; condition = "gitdir:~/src/"; }
|
||||
];
|
||||
|
||||
and the corresponding '[include]' or '[includeIf]' sections will be
|
||||
appended to the main Git configuration file.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-05-01T20:49:31+00:00";
|
||||
message = ''
|
||||
A new module is available: 'services.mbsync'.
|
||||
'';
|
||||
}
|
||||
{
|
||||
time = "2018-05-03T12:34:47+00:00";
|
||||
message = ''
|
||||
A new module is available: 'services.flameshot'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-05-18T18:34:15+00:00";
|
||||
message = ''
|
||||
A new module is available: 'qt'
|
||||
|
||||
At the moment this module allows you to set up Qt to use the
|
||||
GTK+ theme, and not much else.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-06-05T01:36:45+00:00";
|
||||
message = ''
|
||||
A new module is available: 'services.kdeconnect'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-06-09T09:11:59+00:00";
|
||||
message = ''
|
||||
A new module is available: `programs.newsboat`.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-07-01T14:33:15+00:00";
|
||||
message = ''
|
||||
A new module is available: 'accounts.email'.
|
||||
|
||||
As the name suggests, this new module offers a number of
|
||||
options for configuring email accounts. This, for example,
|
||||
includes the email address and owner's real name but also
|
||||
server settings for IMAP and SMTP.
|
||||
|
||||
The intent is to have a central location for account
|
||||
specific configuration that other modules can use.
|
||||
|
||||
Note, this module is still somewhat experimental and its
|
||||
structure should not be seen as final. Feedback is greatly
|
||||
appreciated, both positive and negative.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-07-01T16:07:04+00:00";
|
||||
message = ''
|
||||
A new module is available: 'programs.mbsync'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-07-01T16:12:20+00:00";
|
||||
message = ''
|
||||
A new module is available: 'programs.notmuch'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-07-07T15:48:56+00:00";
|
||||
message = ''
|
||||
A new module is available: 'xsession.windowManager.awesome'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-07-18T20:14:11+00:00";
|
||||
message = ''
|
||||
A new module is available: 'services.mpd'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-07-31T13:33:39+00:00";
|
||||
message = ''
|
||||
A new module is available: 'services.status-notifier-watcher'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-07-31T13:47:06+00:00";
|
||||
message = ''
|
||||
A new module is available: 'programs.direnv'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-08-17T20:30:14+00:00";
|
||||
message = ''
|
||||
A new module is available: 'programs.fish'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-08-18T19:03:42+00:00";
|
||||
condition = config.services.gpg-agent.enable;
|
||||
message = ''
|
||||
A new option is available: 'services.gpg-agent.extraConfig'.
|
||||
|
||||
Extra lines may be appended to $HOME/.gnupg/gpg-agent.conf
|
||||
using this option.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-08-19T20:46:09+00:00";
|
||||
condition = pkgs.stdenv.isLinux;
|
||||
message = ''
|
||||
A new modules is available: 'programs.chromium'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-08-20T20:27:26+00:00";
|
||||
message = ''
|
||||
A new module is available: 'programs.msmtp'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-08-21T20:13:50+00:00";
|
||||
message = ''
|
||||
A new module is available: 'services.pasystray'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-08-29T20:27:04+00:00";
|
||||
message = ''
|
||||
A new module is available: 'programs.offlineimap'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-09-18T21:25:14+00:00";
|
||||
message = ''
|
||||
A new module is available: 'programs.taskwarrior'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-09-18T21:43:54+00:00";
|
||||
message = ''
|
||||
A new module is available: 'programs.zathura'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-09-20T22:10:45+00:00";
|
||||
message = ''
|
||||
A new module is available: 'programs.go'.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
time = "2018-09-28T21:38:48+00:00";
|
||||
message = ''
|
||||
A new module is available: 'programs.alot'.
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -34,7 +34,11 @@ let
|
||||
configType = mkOptionType {
|
||||
name = "nixpkgs-config";
|
||||
description = "nixpkgs config";
|
||||
check = traceValIfNot isConfig;
|
||||
check = x:
|
||||
let traceXIfNot = c:
|
||||
if c x then true
|
||||
else lib.traceSeqN 1 x false;
|
||||
in traceXIfNot isConfig;
|
||||
merge = args: fold (def: mergeConfig def.value) {};
|
||||
};
|
||||
|
||||
@@ -61,10 +65,28 @@ in
|
||||
The configuration of the Nix Packages collection. (For
|
||||
details, see the Nixpkgs documentation.) It allows you to set
|
||||
package configuration options.
|
||||
|
||||
</para><para>
|
||||
|
||||
If <literal>null</literal>, then configuration is taken from
|
||||
the fallback location, for example,
|
||||
<filename>~/.config/nixpkgs/config.nix</filename>.
|
||||
|
||||
</para><para>
|
||||
|
||||
Note, this option will not apply outside your Home Manager
|
||||
configuration like when installing manually through
|
||||
<command>nix-env</command>. If you want to apply it both
|
||||
inside and outside Home Manager you can put it in a separate
|
||||
file and include something like
|
||||
|
||||
<programlisting>
|
||||
nixpkgs.config = import ./nixpkgs-config.nix;
|
||||
xdg.configFile."nixpkgs/config.nix".source =
|
||||
./nixpkgs-config.nix;
|
||||
</programlisting>
|
||||
|
||||
in your Home Manager configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -89,10 +111,19 @@ in
|
||||
an argument the <emphasis>original</emphasis> Nixpkgs. The
|
||||
first argument should be used for finding dependencies, and
|
||||
the second should be used for overriding recipes.
|
||||
|
||||
</para><para>
|
||||
|
||||
If <literal>null</literal>, then the overlays are taken from
|
||||
the fallback location, for example,
|
||||
<filename>~/.config/nixpkgs/overlays</filename>.
|
||||
|
||||
</para><para>
|
||||
|
||||
Like <varname>nixpkgs.config</varname> this option only
|
||||
applies within the Home Manager configuration. See
|
||||
<varname>nixpkgs.config</varname> for a suggested setup that
|
||||
works both internally and externally.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -113,7 +144,7 @@ in
|
||||
config = {
|
||||
_module.args = {
|
||||
pkgs = _pkgs;
|
||||
pkgs_i686 = _pkgs.pkgsi686Linux;
|
||||
pkgs_i686 = if _pkgs.stdenv.isLinux then _pkgs.pkgsi686Linux else {};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
41
modules/misc/qt.nix
Normal file
41
modules/misc/qt.nix
Normal file
@@ -0,0 +1,41 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.qt;
|
||||
dag = config.lib.dag;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
qt = {
|
||||
enable = mkEnableOption "Qt 4 and 5 configuration";
|
||||
|
||||
useGtkTheme = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether Qt 4 and 5 should be set up to use the GTK theme
|
||||
settings.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf (cfg.enable && cfg.useGtkTheme) {
|
||||
home.sessionVariables.QT_QPA_PLATFORMTHEME = "gtk2";
|
||||
home.packages = [ pkgs.libsForQt5.qtstyleplugins ];
|
||||
xsession.profileExtra =
|
||||
"systemctl --user import-environment QT_QPA_PLATFORMTHEME";
|
||||
|
||||
home.activation.useGtkThemeInQt4 = dag.entryAfter ["writeBoundary"] ''
|
||||
$DRY_RUN_CMD ${pkgs.crudini}/bin/crudini $VERBOSE_ARG \
|
||||
--set $HOME/.config/Trolltech.conf Qt style GTK+
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -6,6 +6,8 @@ let
|
||||
|
||||
cfg = config.xdg;
|
||||
|
||||
dag = config.lib.dag;
|
||||
|
||||
fileType = (import ../lib/file-type.nix {
|
||||
inherit (config.home) homeDirectory;
|
||||
inherit lib pkgs;
|
||||
@@ -91,6 +93,9 @@ in
|
||||
|
||||
{
|
||||
home.file = mkMerge [ cfg.configFile cfg.dataFile ];
|
||||
home.activation.xdgCreateCache = dag.entryAfter [ "writeBoundary" ] ''
|
||||
$DRY_RUN_CMD mkdir $VERBOSE_ARG -m0700 -p "${config.xdg.cacheHome}"
|
||||
'';
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -13,58 +13,83 @@ with lib;
|
||||
let
|
||||
|
||||
modules = [
|
||||
./accounts/email.nix
|
||||
./files.nix
|
||||
./home-environment.nix
|
||||
./manual.nix
|
||||
./misc/fontconfig.nix
|
||||
./misc/gtk.nix
|
||||
./misc/lib.nix
|
||||
./misc/news.nix
|
||||
./misc/nixpkgs.nix
|
||||
./misc/pam.nix
|
||||
./misc/qt.nix
|
||||
./misc/xdg.nix
|
||||
./programs/alot.nix
|
||||
./programs/autorandr.nix
|
||||
./programs/bash.nix
|
||||
./programs/beets.nix
|
||||
./programs/browserpass.nix
|
||||
./programs/command-not-found/command-not-found.nix
|
||||
./programs/direnv.nix
|
||||
./programs/eclipse.nix
|
||||
./programs/emacs.nix
|
||||
./programs/feh.nix
|
||||
./programs/firefox.nix
|
||||
./programs/fish.nix
|
||||
./programs/fzf.nix
|
||||
./programs/git.nix
|
||||
./programs/gnome-terminal.nix
|
||||
./programs/go.nix
|
||||
./programs/home-manager.nix
|
||||
./programs/htop.nix
|
||||
./programs/info.nix
|
||||
./programs/lesspipe.nix
|
||||
./programs/man.nix
|
||||
./programs/mbsync.nix
|
||||
./programs/mercurial.nix
|
||||
./programs/msmtp.nix
|
||||
./programs/neovim.nix
|
||||
./programs/newsboat.nix
|
||||
./programs/notmuch.nix
|
||||
./programs/offlineimap.nix
|
||||
./programs/pidgin.nix
|
||||
./programs/rofi.nix
|
||||
./programs/ssh.nix
|
||||
./programs/taskwarrior.nix
|
||||
./programs/termite.nix
|
||||
./programs/texlive.nix
|
||||
./programs/vim.nix
|
||||
./programs/zathura.nix
|
||||
./programs/zsh.nix
|
||||
./services/blueman-applet.nix
|
||||
./services/compton.nix
|
||||
./services/dunst.nix
|
||||
./services/flameshot.nix
|
||||
./services/gnome-keyring.nix
|
||||
./services/gpg-agent.nix
|
||||
./services/kbfs.nix
|
||||
./services/kdeconnect.nix
|
||||
./services/keepassx.nix
|
||||
./services/keybase.nix
|
||||
./services/mbsync.nix
|
||||
./services/mpd.nix
|
||||
./services/network-manager-applet.nix
|
||||
./services/owncloud-client.nix
|
||||
./services/parcellite.nix
|
||||
./services/pasystray.nix
|
||||
./services/polybar.nix
|
||||
./services/random-background.nix
|
||||
./services/redshift.nix
|
||||
./services/screen-locker.nix
|
||||
./services/stalonetray.nix
|
||||
./services/status-notifier-watcher.nix
|
||||
./services/syncthing.nix
|
||||
./services/taffybar.nix
|
||||
./services/tahoe-lafs.nix
|
||||
./services/udiskie.nix
|
||||
./services/unclutter.nix
|
||||
./services/window-managers/awesome.nix
|
||||
./services/window-managers/i3.nix
|
||||
./services/window-managers/xmonad.nix
|
||||
./services/xscreensaver.nix
|
||||
@@ -73,9 +98,10 @@ let
|
||||
./xresources.nix
|
||||
./xsession.nix
|
||||
<nixpkgs/nixos/modules/misc/assertions.nix>
|
||||
<nixpkgs/nixos/modules/misc/lib.nix>
|
||||
<nixpkgs/nixos/modules/misc/meta.nix>
|
||||
];
|
||||
]
|
||||
++
|
||||
optional pkgs.stdenv.isLinux ./programs/chromium.nix;
|
||||
|
||||
pkgsModule = {
|
||||
options.nixosSubmodule = mkOption {
|
||||
|
||||
32
modules/programs/alot-accounts.nix
Normal file
32
modules/programs/alot-accounts.nix
Normal file
@@ -0,0 +1,32 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
options.alot = {
|
||||
sendMailCommand = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
description = ''
|
||||
Command to send a mail. If msmtp is enabled for the account,
|
||||
then this is set to
|
||||
<command>msmtpq --read-envelope-from --read-recipients</command>.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra settings to add to this Alot account configuration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf config.notmuch.enable {
|
||||
alot.sendMailCommand = mkOptionDefault (
|
||||
if config.msmtp.enable
|
||||
then "msmtpq --read-envelope-from --read-recipients"
|
||||
else null
|
||||
);
|
||||
};
|
||||
}
|
||||
167
modules/programs/alot.nix
Normal file
167
modules/programs/alot.nix
Normal file
@@ -0,0 +1,167 @@
|
||||
# alot config loader is sensitive to leading space !
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.alot;
|
||||
|
||||
alotAccounts = filter (a: a.notmuch.enable)
|
||||
(attrValues config.accounts.email.accounts);
|
||||
|
||||
boolStr = v: if v then "True" else "False";
|
||||
|
||||
accountStr = account: with account;
|
||||
concatStringsSep "\n" (
|
||||
[ "[[${name}]]" ]
|
||||
++ mapAttrsToList (n: v: n + "=" + v) (
|
||||
{
|
||||
address = address;
|
||||
realname = realName;
|
||||
sendmail_command =
|
||||
optionalString (alot.sendMailCommand != null) alot.sendMailCommand;
|
||||
}
|
||||
// optionalAttrs (gpg != null) {
|
||||
gpg_key = gpg.key;
|
||||
encrypt_by_default = if gpg.encryptByDefault then "all" else "none";
|
||||
sign_by_default = boolStr gpg.signByDefault;
|
||||
}
|
||||
// optionalAttrs (signature.showSignature != "none") {
|
||||
signature = pkgs.writeText "signature.txt" signature.text;
|
||||
signature_as_attachment =
|
||||
boolStr (signature.showSignature == "attach");
|
||||
}
|
||||
)
|
||||
)
|
||||
+ "\n"
|
||||
+ alot.extraConfig;
|
||||
|
||||
configFile =
|
||||
let
|
||||
bindingsToStr = attrSet:
|
||||
concatStringsSep "\n" (mapAttrsToList (n: v: "${n} = ${v}") attrSet);
|
||||
in
|
||||
''
|
||||
# Generated by Home Manager.
|
||||
# See http://alot.readthedocs.io/en/latest/configuration/config_options.html
|
||||
|
||||
${cfg.extraConfig}
|
||||
|
||||
[bindings]
|
||||
${bindingsToStr cfg.bindings.global}
|
||||
|
||||
[[bufferlist]]
|
||||
${bindingsToStr cfg.bindings.bufferlist}
|
||||
[[search]]
|
||||
${bindingsToStr cfg.bindings.search}
|
||||
[[envelope]]
|
||||
${bindingsToStr cfg.bindings.envelope}
|
||||
[[taglist]]
|
||||
${bindingsToStr cfg.bindings.taglist}
|
||||
[[thread]]
|
||||
${bindingsToStr cfg.bindings.thread}
|
||||
|
||||
[accounts]
|
||||
|
||||
${concatStringsSep "\n\n" (map accountStr alotAccounts)}
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.programs.alot = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether to enable the Alot mail user agent. Alot uses the
|
||||
Notmuch email system and will therefore be automatically
|
||||
enabled for each email account that is managed by Notmuch.
|
||||
'';
|
||||
};
|
||||
|
||||
hooks = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Content of the hooks file.
|
||||
'';
|
||||
};
|
||||
|
||||
bindings = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
global = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = "Global keybindings.";
|
||||
};
|
||||
|
||||
bufferlist = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = "Bufferlist mode keybindings.";
|
||||
};
|
||||
|
||||
search = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = "Search mode keybindings.";
|
||||
};
|
||||
|
||||
envelope = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = "Envelope mode keybindings.";
|
||||
};
|
||||
|
||||
taglist = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = "Taglist mode keybindings.";
|
||||
};
|
||||
|
||||
thread = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = "Thread mode keybindings.";
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = ''
|
||||
Keybindings.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = ''
|
||||
auto_remove_unread = True
|
||||
ask_subject = False
|
||||
handle_mouse = True
|
||||
initial_command = "search tag:inbox AND NOT tag:killed"
|
||||
input_timeout = 0.3
|
||||
prefer_plaintext = True
|
||||
thread_indent_replies = 4
|
||||
'';
|
||||
description = ''
|
||||
Extra lines added to alot configuration file.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.alot ];
|
||||
|
||||
xdg.configFile."alot/config".text = configFile;
|
||||
|
||||
xdg.configFile."alot/hooks.py".text =
|
||||
''
|
||||
# Generated by Home Manager.
|
||||
''
|
||||
+ cfg.hooks;
|
||||
};
|
||||
}
|
||||
239
modules/programs/autorandr.nix
Normal file
239
modules/programs/autorandr.nix
Normal file
@@ -0,0 +1,239 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.autorandr;
|
||||
|
||||
profileModule = types.submodule {
|
||||
options = {
|
||||
fingerprint = mkOption {
|
||||
type = types.attrsOf types.string;
|
||||
description = ''
|
||||
Output name to EDID mapping.
|
||||
Use <code>autorandr --fingerprint</code> to get current setup values.
|
||||
'';
|
||||
default = {};
|
||||
};
|
||||
|
||||
config = mkOption {
|
||||
type = types.attrsOf configModule;
|
||||
description = "Per output profile configuration.";
|
||||
default = {};
|
||||
};
|
||||
|
||||
hooks = mkOption {
|
||||
type = profileHooksModule;
|
||||
description = "Profile hook scripts.";
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
configModule = types.submodule {
|
||||
options = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
description = "Whether to enable the output.";
|
||||
default = true;
|
||||
};
|
||||
|
||||
primary = mkOption {
|
||||
type = types.bool;
|
||||
description = "Whether output should be marked as primary";
|
||||
default = false;
|
||||
};
|
||||
|
||||
position = mkOption {
|
||||
type = types.string;
|
||||
description = "Output position";
|
||||
default = "";
|
||||
example = "5760x0";
|
||||
};
|
||||
|
||||
mode = mkOption {
|
||||
type = types.string;
|
||||
description = "Output resolution.";
|
||||
default = "";
|
||||
example = "3840x2160";
|
||||
};
|
||||
|
||||
rate = mkOption {
|
||||
type = types.string;
|
||||
description = "Output framerate.";
|
||||
default = "";
|
||||
example = "60.00";
|
||||
};
|
||||
|
||||
gamma = mkOption {
|
||||
type = types.string;
|
||||
description = "Output gamma configuration.";
|
||||
default = "";
|
||||
example = "1.0:0.909:0.833";
|
||||
};
|
||||
|
||||
rotate = mkOption {
|
||||
type = types.nullOr (types.enum ["normal" "left" "right" "inverted"]);
|
||||
description = "Output rotate configuration.";
|
||||
default = null;
|
||||
example = "left";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hookType = types.lines;
|
||||
|
||||
globalHooksModule = types.submodule {
|
||||
options = {
|
||||
postswitch = mkOption {
|
||||
type = types.attrsOf hookType;
|
||||
description = "Postswitch hook executed after mode switch.";
|
||||
default = {};
|
||||
};
|
||||
|
||||
preswitch = mkOption {
|
||||
type = types.attrsOf hookType;
|
||||
description = "Preswitch hook executed before mode switch.";
|
||||
default = {};
|
||||
};
|
||||
|
||||
predetect = mkOption {
|
||||
type = types.attrsOf hookType;
|
||||
description = "Predetect hook executed before autorandr attempts to run xrandr.";
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
profileHooksModule = types.submodule {
|
||||
options = {
|
||||
postswitch = mkOption {
|
||||
type = hookType;
|
||||
description = "Postswitch hook executed after mode switch.";
|
||||
default = "";
|
||||
};
|
||||
|
||||
preswitch = mkOption {
|
||||
type = hookType;
|
||||
description = "Preswitch hook executed before mode switch.";
|
||||
default = "";
|
||||
};
|
||||
|
||||
predetect = mkOption {
|
||||
type = hookType;
|
||||
description = "Predetect hook executed before autorandr attempts to run xrandr.";
|
||||
default = "";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hookToFile = folder: name: hook:
|
||||
nameValuePair
|
||||
"autorandr/${folder}/${name}"
|
||||
{ source = "${pkgs.writeShellScriptBin "hook" hook}/bin/hook"; };
|
||||
profileToFiles = name: profile: with profile; mkMerge ([
|
||||
{
|
||||
"autorandr/${name}/setup".text = concatStringsSep "\n" (mapAttrsToList fingerprintToString fingerprint);
|
||||
"autorandr/${name}/config".text = concatStringsSep "\n" (mapAttrsToList configToString profile.config);
|
||||
}
|
||||
(mkIf (hooks.postswitch != "") (listToAttrs [ (hookToFile name "postswitch" hooks.postswitch) ]))
|
||||
(mkIf (hooks.preswitch != "") (listToAttrs [ (hookToFile name "preswitch" hooks.preswitch) ]))
|
||||
(mkIf (hooks.predetect != "") (listToAttrs [ (hookToFile name "predetect" hooks.predetect) ]))
|
||||
]);
|
||||
fingerprintToString = name: edid: "${name} ${edid}";
|
||||
configToString = name: config: if config.enable then ''
|
||||
output ${name}
|
||||
${optionalString (config.position != "") "pos ${config.position}"}
|
||||
${optionalString config.primary "primary"}
|
||||
${optionalString (config.gamma != "") "gamma ${config.gamma}"}
|
||||
${optionalString (config.mode != "") "mode ${config.mode}"}
|
||||
${optionalString (config.rate != "") "rate ${config.rate}"}
|
||||
${optionalString (config.rotate != null) "rotate ${config.rotate}"}
|
||||
'' else ''
|
||||
output ${name}
|
||||
off
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.autorandr = {
|
||||
enable = mkEnableOption "Autorandr";
|
||||
|
||||
hooks = mkOption {
|
||||
type = globalHooksModule;
|
||||
description = "Global hook scripts";
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
postswitch = {
|
||||
"notify-i3" = "''${pkgs.i3}/bin/i3-msg restart";
|
||||
"change-background" = readFile ./change-background.sh;
|
||||
"change-dpi" = '''
|
||||
case "$AUTORANDR_CURRENT_PROFILE" in
|
||||
default)
|
||||
DPI=120
|
||||
;;
|
||||
home)
|
||||
DPI=192
|
||||
;;
|
||||
work)
|
||||
DPI=144
|
||||
;;
|
||||
*)
|
||||
echo "Unknown profle: $AUTORANDR_CURRENT_PROFILE"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
echo "Xft.dpi: $DPI" | ''${pkgs.xorg.xrdb}/bin/xrdb -merge
|
||||
'''
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
profiles = mkOption {
|
||||
type = types.attrsOf profileModule;
|
||||
description = "Autorandr profiles specification.";
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
"work" = {
|
||||
fingerprint = {
|
||||
eDP1 = "<EDID>";
|
||||
DP1 = "<EDID>";
|
||||
};
|
||||
config = {
|
||||
eDP1.enable = false;
|
||||
DP1 = {
|
||||
enable = true;
|
||||
primary = true;
|
||||
position = "0x0";
|
||||
mode = "3840x2160";
|
||||
gamma = "1.0:0.909:0.833";
|
||||
rate = "60.00";
|
||||
rotate = "left";
|
||||
};
|
||||
};
|
||||
hooks.postswitch = readFile ./work-postswitch.sh;
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.autorandr ];
|
||||
xdg.configFile = mkMerge ([
|
||||
(mapAttrs' (hookToFile "postswitch.d") cfg.hooks.postswitch)
|
||||
(mapAttrs' (hookToFile "preswitch.d") cfg.hooks.preswitch)
|
||||
(mapAttrs' (hookToFile "predetect.d") cfg.hooks.predetect)
|
||||
(mkMerge (mapAttrsToList profileToFiles cfg.profiles))
|
||||
]);
|
||||
};
|
||||
|
||||
meta.maintainers = [ maintainers.uvnikita ];
|
||||
}
|
||||
@@ -84,8 +84,7 @@ in
|
||||
example = { ll = "ls -l"; ".." = "cd .."; };
|
||||
description = ''
|
||||
An attribute set that maps aliases (the top level attribute names in
|
||||
this option) to command strings or directly to build outputs. The
|
||||
aliases are added to all users' shells.
|
||||
this option) to command strings or directly to build outputs.
|
||||
'';
|
||||
type = types.attrs;
|
||||
};
|
||||
@@ -130,7 +129,7 @@ in
|
||||
config = (
|
||||
let
|
||||
aliasesStr = concatStringsSep "\n" (
|
||||
mapAttrsToList (k: v: "alias ${k}='${v}'") cfg.shellAliases
|
||||
mapAttrsToList (k: v: "alias ${k}=${escapeShellArg v}") cfg.shellAliases
|
||||
);
|
||||
|
||||
shoptsStr = concatStringsSep "\n" (
|
||||
@@ -156,7 +155,7 @@ in
|
||||
in mkIf cfg.enable {
|
||||
programs.bash.bashrcExtra = ''
|
||||
# Commands that should be applied only for interactive shells.
|
||||
if [[ -n $PS1 ]]; then
|
||||
if [[ $- == *i* ]]; then
|
||||
${historyControlStr}
|
||||
|
||||
${shoptsStr}
|
||||
@@ -183,7 +182,7 @@ in
|
||||
home.file.".profile".text = ''
|
||||
# -*- mode: sh -*-
|
||||
|
||||
. "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh"
|
||||
. "${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh"
|
||||
|
||||
${sessionVarsStr}
|
||||
|
||||
|
||||
93
modules/programs/chromium.nix
Normal file
93
modules/programs/chromium.nix
Normal file
@@ -0,0 +1,93 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
browserModule = defaultPkg: name: visible:
|
||||
let
|
||||
browser = (builtins.parseDrvName defaultPkg.name).name;
|
||||
in
|
||||
{
|
||||
enable = mkOption {
|
||||
inherit visible;
|
||||
default = false;
|
||||
example = true;
|
||||
description = "Whether to enable ${name}.";
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
inherit visible;
|
||||
type = types.package;
|
||||
default = defaultPkg;
|
||||
defaultText = "pkgs.${browser}";
|
||||
description = "The ${name} package to use.";
|
||||
};
|
||||
|
||||
extensions = mkOption {
|
||||
inherit visible;
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = literalExample ''
|
||||
[
|
||||
"chlffgpmiacpedhhbkiomidkjlcfhogd" # pushbullet
|
||||
"mbniclmhobmnbdlbpiphghaielnnpgdp" # lightshot
|
||||
"gcbommkclmclpchllfjekcdonpmejbdp" # https everywhere
|
||||
"cjpalhdlnbpafiamejdnhcphjbkeiagm" # ublock origin
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
List of ${name} extensions to install.
|
||||
To find the extension ID, check its URL on the
|
||||
<link xlink:href="https://chrome.google.com/webstore/category/extensions">Chrome Web Store</link>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
browserConfig = cfg:
|
||||
let
|
||||
|
||||
browser = (builtins.parseDrvName cfg.package.name).name;
|
||||
|
||||
darwinDirs = {
|
||||
chromium = "Chromium";
|
||||
google-chrome = "Google/Chrome";
|
||||
google-chrome-beta = "Google/Chrome Beta";
|
||||
google-chrome-dev = "Google/Chrome Dev";
|
||||
};
|
||||
|
||||
configDir = if pkgs.stdenv.isDarwin
|
||||
then "Library/Application Support/${getAttr browser darwinDirs}"
|
||||
else "${config.xdg.configHome}/${browser}";
|
||||
|
||||
extensionJson = ext: {
|
||||
target = "${configDir}/External Extensions/${ext}.json";
|
||||
text = builtins.toJSON {
|
||||
external_update_url = "https://clients2.google.com/service/update2/crx";
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
mkIf cfg.enable {
|
||||
home.packages = [ cfg.package ];
|
||||
home.file = map extensionJson cfg.extensions;
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.programs = {
|
||||
chromium = browserModule pkgs.chromium "Chromium" true;
|
||||
google-chrome = browserModule pkgs.google-chrome "Google Chrome" false;
|
||||
google-chrome-beta = browserModule pkgs.google-chrome-beta "Google Chrome Beta" false;
|
||||
google-chrome-dev = browserModule pkgs.google-chrome-dev "Google Chrome Dev" false;
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
(browserConfig config.programs.chromium)
|
||||
(browserConfig config.programs.google-chrome)
|
||||
(browserConfig config.programs.google-chrome-beta)
|
||||
(browserConfig config.programs.google-chrome-dev)
|
||||
];
|
||||
}
|
||||
62
modules/programs/direnv.nix
Normal file
62
modules/programs/direnv.nix
Normal file
@@ -0,0 +1,62 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.direnv;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options.programs.direnv = {
|
||||
enable = mkEnableOption "direnv, the environment switcher";
|
||||
|
||||
enableBashIntegration = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to enable Bash integration.
|
||||
'';
|
||||
};
|
||||
|
||||
enableZshIntegration = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to enable Zsh integration.
|
||||
'';
|
||||
};
|
||||
|
||||
enableFishIntegration = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to enable Fish integration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.direnv ];
|
||||
|
||||
programs.bash.initExtra =
|
||||
mkIf cfg.enableBashIntegration (
|
||||
# Using mkAfter to make it more likely to appear after other
|
||||
# manipulations of the prompt.
|
||||
mkAfter ''
|
||||
eval "$(${pkgs.direnv}/bin/direnv hook bash)"
|
||||
''
|
||||
);
|
||||
|
||||
programs.zsh.initExtra = mkIf cfg.enableZshIntegration ''
|
||||
eval "$(${pkgs.direnv}/bin/direnv hook zsh)"
|
||||
'';
|
||||
|
||||
programs.fish.shellInit = mkIf cfg.enableFishIntegration ''
|
||||
eval (${pkgs.direnv}/bin/direnv hook fish)
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -33,10 +33,19 @@ in
|
||||
example = literalExample "epkgs: [ epkgs.emms epkgs.magit ]";
|
||||
description = "Extra packages available to Emacs.";
|
||||
};
|
||||
|
||||
finalPackage = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
description = "The Emacs package including any extra packages.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ (emacsWithPackages cfg.extraPackages) ];
|
||||
home.packages = [ cfg.finalPackage ];
|
||||
|
||||
programs.emacs.finalPackage = emacsWithPackages cfg.extraPackages;
|
||||
};
|
||||
}
|
||||
|
||||
119
modules/programs/fish.nix
Normal file
119
modules/programs/fish.nix
Normal file
@@ -0,0 +1,119 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.fish;
|
||||
|
||||
abbrsStr = concatStringsSep "\n" (
|
||||
mapAttrsToList (k: v: "abbr --add ${k} '${v}'") cfg.shellAbbrs
|
||||
);
|
||||
|
||||
aliasesStr = concatStringsSep "\n" (
|
||||
mapAttrsToList (k: v: "alias ${k}='${v}'") cfg.shellAliases
|
||||
);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.fish = {
|
||||
enable = mkEnableOption "fish friendly interactive shell";
|
||||
|
||||
shellAliases = mkOption {
|
||||
default = {};
|
||||
description = ''
|
||||
Set of aliases for fish shell. See
|
||||
<option>environment.shellAliases</option> for an option
|
||||
format description.
|
||||
'';
|
||||
type = types.attrs;
|
||||
};
|
||||
|
||||
shellAbbrs = mkOption {
|
||||
default = {};
|
||||
description = ''
|
||||
Set of abbreviations for fish shell.
|
||||
'';
|
||||
type = types.attrs;
|
||||
};
|
||||
|
||||
shellInit = mkOption {
|
||||
default = "";
|
||||
description = ''
|
||||
Shell script code called during fish shell initialisation.
|
||||
'';
|
||||
type = types.lines;
|
||||
};
|
||||
|
||||
loginShellInit = mkOption {
|
||||
default = "";
|
||||
description = ''
|
||||
Shell script code called during fish login shell initialisation.
|
||||
'';
|
||||
type = types.lines;
|
||||
};
|
||||
|
||||
interactiveShellInit = mkOption {
|
||||
default = "";
|
||||
description = ''
|
||||
Shell script code called during interactive fish shell initialisation.
|
||||
'';
|
||||
type = types.lines;
|
||||
};
|
||||
|
||||
promptInit = mkOption {
|
||||
default = "";
|
||||
description = ''
|
||||
Shell script code used to initialise fish prompt.
|
||||
'';
|
||||
type = types.lines;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.fish ];
|
||||
|
||||
xdg.configFile."fish/config.fish".text = ''
|
||||
# ~/.config/fish/config.fish: DO NOT EDIT -- this file has been generated automatically.
|
||||
# if we haven't sourced the general config, do it
|
||||
if not set -q __fish_general_config_sourced
|
||||
set fish_function_path ${pkgs.fish-foreign-env}/share/fish-foreign-env/functions $fish_function_path
|
||||
fenv source ${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh > /dev/null
|
||||
set -e fish_function_path[1]
|
||||
|
||||
${cfg.shellInit}
|
||||
# and leave a note so we don't source this config section again from
|
||||
# this very shell (children will source the general config anew)
|
||||
set -g __fish_general_config_sourced 1
|
||||
end
|
||||
# if we haven't sourced the login config, do it
|
||||
status --is-login; and not set -q __fish_login_config_sourced
|
||||
and begin
|
||||
|
||||
${cfg.loginShellInit}
|
||||
# and leave a note so we don't source this config section again from
|
||||
# this very shell (children will source the general config anew)
|
||||
set -g __fish_login_config_sourced 1
|
||||
end
|
||||
# if we haven't sourced the interactive config, do it
|
||||
status --is-interactive; and not set -q __fish_interactive_config_sourced
|
||||
and begin
|
||||
# Abbrs
|
||||
${abbrsStr}
|
||||
|
||||
# Aliases
|
||||
${aliasesStr}
|
||||
|
||||
${cfg.promptInit}
|
||||
${cfg.interactiveShellInit}
|
||||
# and leave a note so we don't source this config section again from
|
||||
# this very shell (children will source the general config anew,
|
||||
# allowing configuration changes in, e.g, aliases, to propagate)
|
||||
set -g __fish_interactive_config_sourced 1
|
||||
end
|
||||
'';
|
||||
};
|
||||
}
|
||||
134
modules/programs/fzf.nix
Normal file
134
modules/programs/fzf.nix
Normal file
@@ -0,0 +1,134 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.fzf;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.programs.fzf = {
|
||||
enable = mkEnableOption "fzf - a command-line fuzzy finder";
|
||||
|
||||
defaultCommand = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "fd --type f";
|
||||
description = ''
|
||||
The command that gets executed as the default source for fzf
|
||||
when running.
|
||||
'';
|
||||
};
|
||||
|
||||
defaultOptions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "--height 40%" "--border" ];
|
||||
description = ''
|
||||
Extra command line options given to fzf by default.
|
||||
'';
|
||||
};
|
||||
|
||||
fileWidgetCommand = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "fd --type f";
|
||||
description = ''
|
||||
The command that gets executed as the source for fzf for the
|
||||
CTRL-T keybinding.
|
||||
'';
|
||||
};
|
||||
|
||||
fileWidgetOptions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "--preview 'head {}'" ];
|
||||
description = ''
|
||||
Command line options for the CTRL-T keybinding.
|
||||
'';
|
||||
};
|
||||
|
||||
changeDirWidgetCommand = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "fd --type d" ;
|
||||
description = ''
|
||||
The command that gets executed as the source for fzf for the
|
||||
ALT-C keybinding.
|
||||
'';
|
||||
};
|
||||
|
||||
changeDirWidgetOptions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "--preview 'tree -C {} | head -200'" ];
|
||||
description = ''
|
||||
Command line options for the ALT-C keybinding.
|
||||
'';
|
||||
};
|
||||
|
||||
historyWidgetCommand = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
The command that gets executed as the source for fzf for the
|
||||
CTRL-R keybinding.
|
||||
'';
|
||||
};
|
||||
|
||||
historyWidgetOptions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "--sort" "--exact" ];
|
||||
description = ''
|
||||
Command line options for the CTRL-R keybinding.
|
||||
'';
|
||||
};
|
||||
|
||||
enableBashIntegration = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to enable Bash integration.
|
||||
'';
|
||||
};
|
||||
|
||||
enableZshIntegration = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to enable Zsh integration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.fzf ];
|
||||
|
||||
home.sessionVariables =
|
||||
mapAttrs (n: v: toString v) (
|
||||
filterAttrs (n: v: v != [] && v != null) {
|
||||
FZF_ALT_C_COMMAND = cfg.changeDirWidgetCommand;
|
||||
FZF_ALT_C_OPTS = cfg.changeDirWidgetOptions;
|
||||
FZF_CTRL_R_COMMAND = cfg.historyWidgetCommand;
|
||||
FZF_CTRL_R_OPTS = cfg.historyWidgetOptions;
|
||||
FZF_CTRL_T_COMMAND = cfg.fileWidgetCommand;
|
||||
FZF_CTRL_T_OPTS = cfg.fileWidgetOptions;
|
||||
FZF_DEFAULT_COMMAND = cfg.defaultCommand;
|
||||
FZF_DEFAULT_OPTS = cfg.defaultOptions;
|
||||
}
|
||||
);
|
||||
|
||||
programs.bash.initExtra = mkIf cfg.enableBashIntegration ''
|
||||
. ${pkgs.fzf}/share/fzf/completion.bash
|
||||
. ${pkgs.fzf}/share/fzf/key-bindings.bash
|
||||
'';
|
||||
|
||||
programs.zsh.initExtra = mkIf cfg.enableZshIntegration ''
|
||||
. ${pkgs.fzf}/share/fzf/completion.zsh
|
||||
. ${pkgs.fzf}/share/fzf/key-bindings.zsh
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -28,6 +28,28 @@ let
|
||||
};
|
||||
};
|
||||
|
||||
includeModule = types.submodule {
|
||||
options = {
|
||||
condition = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Include this configuration only when <varname>condition</varname>
|
||||
matches. Allowed conditions are described in
|
||||
<citerefentry>
|
||||
<refentrytitle>git-config</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</citerefentry>.
|
||||
'';
|
||||
};
|
||||
|
||||
path = mkOption {
|
||||
type = types.str;
|
||||
description = "Path of the configuration file to include.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
@@ -83,6 +105,21 @@ in
|
||||
example = [ "*~" "*.swp" ];
|
||||
description = "List of paths that should be globally ignored.";
|
||||
};
|
||||
|
||||
includes = mkOption {
|
||||
type = types.listOf includeModule;
|
||||
default = [];
|
||||
example = literalExample ''
|
||||
[
|
||||
{ path = "~/path/to/config.inc"; }
|
||||
{
|
||||
path = "~/path/to/conditional.inc";
|
||||
condition = "gitdir:~/src/dir";
|
||||
}
|
||||
]
|
||||
'';
|
||||
description = "List of configuration files to include.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -124,6 +161,16 @@ in
|
||||
(mkIf (lib.isString cfg.extraConfig) {
|
||||
xdg.configFile."git/config".text = cfg.extraConfig;
|
||||
})
|
||||
|
||||
(mkIf (cfg.includes != []) {
|
||||
xdg.configFile."git/config".text = mkAfter
|
||||
(concatMapStringsSep "\n"
|
||||
(i: with i; ''
|
||||
[${if (condition == null) then "include" else "includeIf \"${condition}\""}]
|
||||
path = ${path}
|
||||
'')
|
||||
cfg.includes);
|
||||
})
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
75
modules/programs/go.nix
Normal file
75
modules/programs/go.nix
Normal file
@@ -0,0 +1,75 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.go;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rvolosatovs ];
|
||||
|
||||
options = {
|
||||
programs.go = {
|
||||
enable = mkEnableOption "Go";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.go;
|
||||
defaultText = "pkgs.go";
|
||||
description = "The Go package to use.";
|
||||
};
|
||||
|
||||
packages = mkOption {
|
||||
type = with types; attrsOf path;
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
"golang.org/x/text" = builtins.fetchGit "https://go.googlesource.com/text";
|
||||
"golang.org/x/time" = builtins.fetchGit "https://go.googlesource.com/time";
|
||||
}
|
||||
'';
|
||||
description = "Packages to add to GOPATH.";
|
||||
};
|
||||
|
||||
goPath = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
example = "go";
|
||||
description = "GOPATH relative to HOME";
|
||||
};
|
||||
|
||||
goBin = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
example = ".local/bin.go";
|
||||
description = "GOBIN relative to HOME";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (mkMerge [
|
||||
{
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
home.file =
|
||||
let
|
||||
goPath = if cfg.goPath != null then cfg.goPath else "go";
|
||||
|
||||
mkSrc = n: v: {
|
||||
target = "${goPath}/src/${n}";
|
||||
source = v;
|
||||
};
|
||||
in
|
||||
mapAttrsToList mkSrc cfg.packages;
|
||||
}
|
||||
(mkIf (cfg.goPath != null) {
|
||||
home.sessionVariables.GOPATH = builtins.toPath "${config.home.homeDirectory}/${cfg.goPath}";
|
||||
})
|
||||
(mkIf (cfg.goBin != null) {
|
||||
home.sessionVariables.GOBIN = builtins.toPath "${config.home.homeDirectory}/${cfg.goBin}";
|
||||
})
|
||||
]);
|
||||
}
|
||||
@@ -29,7 +29,7 @@ let
|
||||
dag = config.lib.dag;
|
||||
|
||||
# Indexes info files found in this location
|
||||
homeInfoPath = "$HOME/.nix-profile/share/info";
|
||||
homeInfoPath = "${config.home.profileDirectory}/share/info";
|
||||
|
||||
# Installs this package -- the interactive just means that it
|
||||
# includes the curses `info` program. We also use `install-info`
|
||||
|
||||
107
modules/programs/mbsync-accounts.nix
Normal file
107
modules/programs/mbsync-accounts.nix
Normal file
@@ -0,0 +1,107 @@
|
||||
{ lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
extraConfigType = with lib.types; attrsOf (either (either str int) bool);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.mbsync = {
|
||||
enable = mkEnableOption "synchronization using mbsync";
|
||||
|
||||
flatten = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = ".";
|
||||
description = ''
|
||||
If set, flattens the hierarchy within the maildir by
|
||||
substituting the canonical hierarchy delimiter
|
||||
<literal>/</literal> with this value.
|
||||
'';
|
||||
};
|
||||
|
||||
create = mkOption {
|
||||
type = types.enum [ "none" "maildir" "imap" "both" ];
|
||||
default = "none";
|
||||
example = "maildir";
|
||||
description = ''
|
||||
Automatically create missing mailboxes within the
|
||||
given mail store.
|
||||
'';
|
||||
};
|
||||
|
||||
remove = mkOption {
|
||||
type = types.enum [ "none" "maildir" "imap" "both" ];
|
||||
default = "none";
|
||||
example = "imap";
|
||||
description = ''
|
||||
Propagate mailbox deletions to the given mail store.
|
||||
'';
|
||||
};
|
||||
|
||||
expunge = mkOption {
|
||||
type = types.enum [ "none" "maildir" "imap" "both" ];
|
||||
default = "none";
|
||||
example = "both";
|
||||
description = ''
|
||||
Permanently remove messages marked for deletion from
|
||||
the given mail store.
|
||||
'';
|
||||
};
|
||||
|
||||
patterns = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ "*" ];
|
||||
description = ''
|
||||
Pattern of mailboxes to synchronize.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.channel = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
MaxMessages = 10000;
|
||||
MaxSize = "1m";
|
||||
};
|
||||
'';
|
||||
description = ''
|
||||
Per channel extra configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.local = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
description = ''
|
||||
Local store extra configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.remote = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
description = ''
|
||||
Remote store extra configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.account = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
PipelineDepth = 10;
|
||||
Timeout = 60;
|
||||
};
|
||||
'';
|
||||
description = ''
|
||||
Account section extra configuration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
194
modules/programs/mbsync.nix
Normal file
194
modules/programs/mbsync.nix
Normal file
@@ -0,0 +1,194 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
dag = config.lib.dag;
|
||||
|
||||
cfg = config.programs.mbsync;
|
||||
|
||||
# Accounts for which mbsync is enabled.
|
||||
mbsyncAccounts =
|
||||
filter (a: a.mbsync.enable) (attrValues config.accounts.email.accounts);
|
||||
|
||||
genTlsConfig = tls: {
|
||||
SSLType =
|
||||
if !tls.enable then "None"
|
||||
else if tls.useStartTls then "STARTTLS"
|
||||
else "IMAPS";
|
||||
}
|
||||
//
|
||||
optionalAttrs (tls.enable && tls.certificatesFile != null) {
|
||||
CertificateFile = tls.certificatesFile;
|
||||
};
|
||||
|
||||
masterSlaveMapping = {
|
||||
none = "None";
|
||||
imap = "Master";
|
||||
maildir = "Slave";
|
||||
both = "Both";
|
||||
};
|
||||
|
||||
genSection = header: entries:
|
||||
let
|
||||
escapeValue = escape [ "\"" ];
|
||||
hasSpace = v: builtins.match ".* .*" v != null;
|
||||
genValue = v:
|
||||
if isList v
|
||||
then concatMapStringsSep " " genValue v
|
||||
else if isBool v then (if v then "yes" else "no")
|
||||
else if isInt v then toString v
|
||||
else if hasSpace v then "\"${escapeValue v}\""
|
||||
else v;
|
||||
in
|
||||
''
|
||||
${header}
|
||||
${concatStringsSep "\n"
|
||||
(mapAttrsToList (n: v: "${n} ${genValue v}") entries)}
|
||||
'';
|
||||
|
||||
genAccountConfig = account: with account;
|
||||
if (imap == null || maildir == null)
|
||||
then ""
|
||||
else
|
||||
genSection "IMAPAccount ${name}" (
|
||||
{
|
||||
Host = imap.host;
|
||||
User = userName;
|
||||
PassCmd = toString passwordCommand;
|
||||
}
|
||||
// genTlsConfig imap.tls
|
||||
// optionalAttrs (imap.port != null) { Port = toString imap.port; }
|
||||
// mbsync.extraConfig.account
|
||||
)
|
||||
+ "\n"
|
||||
+ genSection "IMAPStore ${name}-remote" (
|
||||
{
|
||||
Account = name;
|
||||
}
|
||||
// mbsync.extraConfig.remote
|
||||
)
|
||||
+ "\n"
|
||||
+ genSection "MaildirStore ${name}-local" (
|
||||
{
|
||||
Path = "${maildir.absPath}/";
|
||||
Inbox = "${maildir.absPath}/${folders.inbox}";
|
||||
SubFolders = "Verbatim";
|
||||
}
|
||||
// optionalAttrs (mbsync.flatten != null) { Flatten = mbsync.flatten; }
|
||||
// mbsync.extraConfig.local
|
||||
)
|
||||
+ "\n"
|
||||
+ genSection "Channel ${name}" (
|
||||
{
|
||||
Master = ":${name}-remote:";
|
||||
Slave = ":${name}-local:";
|
||||
Patterns = mbsync.patterns;
|
||||
Create = masterSlaveMapping.${mbsync.create};
|
||||
Remove = masterSlaveMapping.${mbsync.remove};
|
||||
Expunge = masterSlaveMapping.${mbsync.expunge};
|
||||
SyncState = "*";
|
||||
}
|
||||
// mbsync.extraConfig.channel
|
||||
)
|
||||
+ "\n";
|
||||
|
||||
genGroupConfig = name: channels:
|
||||
let
|
||||
genGroupChannel = n: boxes: "Channel ${n}:${concatStringsSep "," boxes}";
|
||||
in
|
||||
concatStringsSep "\n" (
|
||||
[ "Group ${name}" ] ++ mapAttrsToList genGroupChannel channels
|
||||
);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.mbsync = {
|
||||
enable = mkEnableOption "mbsync IMAP4 and Maildir mailbox synchronizer";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.isync;
|
||||
defaultText = "pkgs.isync";
|
||||
example = literalExample "pkgs.isync";
|
||||
description = "The package to use for the mbsync binary.";
|
||||
};
|
||||
|
||||
groups = mkOption {
|
||||
type = types.attrsOf (types.attrsOf (types.listOf types.str));
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
inboxes = {
|
||||
account1 = [ "Inbox" ];
|
||||
account2 = [ "Inbox" ];
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Definition of groups.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra configuration lines to add to the mbsync configuration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
(
|
||||
let
|
||||
badAccounts = filter (a: a.maildir == null) mbsyncAccounts;
|
||||
in
|
||||
{
|
||||
assertion = badAccounts == [];
|
||||
message = "mbsync: Missing maildir configuration for accounts: "
|
||||
+ concatMapStringsSep ", " (a: a.name) badAccounts;
|
||||
}
|
||||
)
|
||||
|
||||
(
|
||||
let
|
||||
badAccounts = filter (a: a.imap == null) mbsyncAccounts;
|
||||
in
|
||||
{
|
||||
assertion = badAccounts == [];
|
||||
message = "mbsync: Missing IMAP configuration for accounts: "
|
||||
+ concatMapStringsSep ", " (a: a.name) badAccounts;
|
||||
}
|
||||
)
|
||||
];
|
||||
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
programs.notmuch.new.ignore = [ ".uidvalidity" ".mbsyncstate" ];
|
||||
|
||||
home.file.".mbsyncrc".text =
|
||||
let
|
||||
accountsConfig = map genAccountConfig mbsyncAccounts;
|
||||
groupsConfig = mapAttrsToList genGroupConfig cfg.groups;
|
||||
in
|
||||
concatStringsSep "\n" (
|
||||
[ "# Generated by Home Manager.\n" ]
|
||||
++ accountsConfig
|
||||
++ groupsConfig
|
||||
++ optional (cfg.extraConfig != "") cfg.extraConfig
|
||||
);
|
||||
|
||||
home.activation.createMaildir =
|
||||
dag.entryBetween [ "linkGeneration" ] [ "writeBoundary" ] ''
|
||||
$DRY_RUN_CMD mkdir -m700 -p $VERBOSE_ARG ${
|
||||
concatMapStringsSep " " (a: a.maildir.absPath) mbsyncAccounts
|
||||
}
|
||||
'';
|
||||
};
|
||||
}
|
||||
25
modules/programs/msmtp-accounts.nix
Normal file
25
modules/programs/msmtp-accounts.nix
Normal file
@@ -0,0 +1,25 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
options.msmtp = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable msmtp.
|
||||
</para><para>
|
||||
If enabled then it is possible to use the
|
||||
<option>--account</option> command line option to send a
|
||||
message for a given account using the <command>msmtp</command>
|
||||
or <command>msmtpq</command> tool. For example,
|
||||
<command>msmtp --account=private</command>
|
||||
would send using the account defined in
|
||||
<option>accounts.email.accounts.private</option>. If the
|
||||
<option>--account</option> option is not given then the
|
||||
primary account will be used.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
75
modules/programs/msmtp.nix
Normal file
75
modules/programs/msmtp.nix
Normal file
@@ -0,0 +1,75 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.msmtp;
|
||||
|
||||
msmtpAccounts = filter (a: a.msmtp.enable)
|
||||
(attrValues config.accounts.email.accounts);
|
||||
|
||||
onOff = p: if p then "on" else "off";
|
||||
|
||||
accountStr = account: with account;
|
||||
concatStringsSep "\n" (
|
||||
[ "account ${name}" ]
|
||||
++ mapAttrsToList (n: v: n + " " + v) (
|
||||
{
|
||||
host = smtp.host;
|
||||
from = address;
|
||||
auth = "on";
|
||||
user = userName;
|
||||
tls = onOff smtp.tls.enable;
|
||||
tls_starttls = onOff smtp.tls.useStartTls;
|
||||
tls_trust_file = smtp.tls.certificatesFile;
|
||||
}
|
||||
// optionalAttrs (smtp.port != null) {
|
||||
port = toString smtp.port;
|
||||
}
|
||||
// optionalAttrs (passwordCommand != null) {
|
||||
# msmtp requires the password to finish with a newline.
|
||||
passwordeval = ''${pkgs.bash}/bin/bash -c "${toString passwordCommand}; echo"'';
|
||||
}
|
||||
)
|
||||
++ optional primary "\naccount default : ${name}"
|
||||
);
|
||||
|
||||
configFile = mailAccounts: ''
|
||||
# Generated by Home Manager.
|
||||
|
||||
${cfg.extraConfig}
|
||||
|
||||
${concatStringsSep "\n\n" (map accountStr mailAccounts)}
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
options = {
|
||||
programs.msmtp = {
|
||||
enable = mkEnableOption "msmtp";
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra configuration lines to add to <filename>~/.msmtprc</filename>.
|
||||
See <link xlink:href="https://marlam.de/msmtp/msmtprc.txt"/> for examples.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.msmtp ];
|
||||
|
||||
home.file.".msmtprc".text = configFile msmtpAccounts;
|
||||
|
||||
home.sessionVariables = {
|
||||
MSMTP_QUEUE = "${config.xdg.dataHome}/msmtp/queue";
|
||||
MSMTP_LOG = "${config.xdg.dataHome}/msmtp/queue.log";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -13,6 +13,22 @@ in
|
||||
programs.neovim = {
|
||||
enable = mkEnableOption "Neovim";
|
||||
|
||||
viAlias = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Symlink `vi` to `nvim` binary.
|
||||
'';
|
||||
};
|
||||
|
||||
vimAlias = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Symlink `vim` to `nvim` binary.
|
||||
'';
|
||||
};
|
||||
|
||||
withPython = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
@@ -58,6 +74,28 @@ in
|
||||
List here Python 3 packages required for your plugins to work.
|
||||
'';
|
||||
};
|
||||
|
||||
configure = mkOption {
|
||||
type = types.nullOr types.attrs;
|
||||
default = null;
|
||||
example = literalExample ''
|
||||
configure = {
|
||||
customRC = $''''
|
||||
" here your custom configuration goes!
|
||||
$'''';
|
||||
packages.myVimPackage = with pkgs.vimPlugins; {
|
||||
# loaded on launch
|
||||
start = [ fugitive ];
|
||||
# manually loadable by calling `:packadd $plugin-name`
|
||||
opt = [ ];
|
||||
};
|
||||
};
|
||||
'';
|
||||
description = ''
|
||||
Generate your init file from your list of plugins and custom commands,
|
||||
and loads it from the store via <command>nvim -u /nix/store/hash-vimrc</command>
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -67,7 +105,7 @@ in
|
||||
inherit (cfg)
|
||||
extraPython3Packages withPython3
|
||||
extraPythonPackages withPython
|
||||
withRuby;
|
||||
withRuby viAlias vimAlias configure;
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
98
modules/programs/newsboat.nix
Normal file
98
modules/programs/newsboat.nix
Normal file
@@ -0,0 +1,98 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.programs.newsboat;
|
||||
wrapQuote = x: "\"${x}\"";
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.newsboat = {
|
||||
enable = mkEnableOption "the Newsboat feed reader";
|
||||
|
||||
urls = mkOption {
|
||||
type = types.listOf types.attrs;
|
||||
default = [];
|
||||
example = [{url = "http://example.com"; tags = ["foo" "bar"];}];
|
||||
description = "List of urls and tokens.";
|
||||
};
|
||||
|
||||
maxItems = mkOption {
|
||||
type = types.int;
|
||||
default = 0;
|
||||
description = "Maximum number of items per feed, 0 for infinite.";
|
||||
};
|
||||
|
||||
reloadThreads = mkOption {
|
||||
type = types.int;
|
||||
default = 5;
|
||||
description = "How many threads to use for updating the feeds.";
|
||||
};
|
||||
|
||||
autoReload = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to enable automatic reloading while newsboat is running.";
|
||||
};
|
||||
|
||||
reloadTime = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = 60;
|
||||
description = "Time in minutes between reloads.";
|
||||
};
|
||||
|
||||
browser = mkOption {
|
||||
type = types.string;
|
||||
default = "${pkgs.xdg_utils}/bin/xdg-open";
|
||||
description = "External browser to use.";
|
||||
};
|
||||
|
||||
queries = mkOption {
|
||||
type = types.attrsOf types.string;
|
||||
default = {};
|
||||
example = {
|
||||
"foo" = "rssurl =~ \"example.com\"";
|
||||
};
|
||||
description = "A list of queries to use.";
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "Extra configuration values that will be appended to the end.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.newsboat ];
|
||||
home.file.".newsboat/urls".text =
|
||||
let
|
||||
urls = builtins.concatStringsSep "\n" (
|
||||
map (u: builtins.concatStringsSep " " ([u.url] ++ (map wrapQuote u.tags)))
|
||||
cfg.urls);
|
||||
queries = builtins.concatStringsSep "\n" (
|
||||
mapAttrsToList (n: v: "\"query:${n}:${escape ["\""] v}\"") cfg.queries);
|
||||
|
||||
in
|
||||
|
||||
''
|
||||
${urls}
|
||||
|
||||
${queries}
|
||||
'';
|
||||
home.file.".newsboat/config".text = ''
|
||||
max-items ${toString cfg.maxItems}
|
||||
browser ${cfg.browser}
|
||||
reload-threads ${toString cfg.reloadThreads}
|
||||
auto-reload ${if cfg.autoReload then "yes" else "no"}
|
||||
${optionalString (cfg.reloadTime != null) (toString "reload-time ${toString cfg.reloadTime}")}
|
||||
prepopulate-query-feeds yes
|
||||
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
};
|
||||
}
|
||||
7
modules/programs/notmuch-accounts.nix
Normal file
7
modules/programs/notmuch-accounts.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ lib, ... }:
|
||||
|
||||
{
|
||||
options.notmuch = {
|
||||
enable = lib.mkEnableOption "notmuch indexing";
|
||||
};
|
||||
}
|
||||
184
modules/programs/notmuch.nix
Normal file
184
modules/programs/notmuch.nix
Normal file
@@ -0,0 +1,184 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.notmuch;
|
||||
|
||||
mkIniKeyValue = key: value:
|
||||
let
|
||||
tweakVal = v:
|
||||
if isString v then v
|
||||
else if isList v then concatMapStringsSep ";" tweakVal v
|
||||
else if isBool v then toJSON v
|
||||
else toString v;
|
||||
in
|
||||
"${key}=${tweakVal value}";
|
||||
|
||||
notmuchIni =
|
||||
recursiveUpdate
|
||||
{
|
||||
database = {
|
||||
path = config.accounts.email.maildirBasePath;
|
||||
};
|
||||
|
||||
new = {
|
||||
ignore = cfg.new.ignore;
|
||||
tags = cfg.new.tags;
|
||||
};
|
||||
|
||||
user =
|
||||
let
|
||||
accounts =
|
||||
filter (a: a.notmuch.enable)
|
||||
(attrValues config.accounts.email.accounts);
|
||||
primary = filter (a: a.primary) accounts;
|
||||
secondaries = filter (a: !a.primary) accounts;
|
||||
in {
|
||||
name = catAttrs "realName" primary;
|
||||
primary_email = catAttrs "address" primary;
|
||||
other_email = catAttrs "address" secondaries;
|
||||
};
|
||||
|
||||
search = {
|
||||
exclude_tags = [ "deleted" "spam" ];
|
||||
};
|
||||
}
|
||||
cfg.extraConfig;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.notmuch = {
|
||||
enable = mkEnableOption "Notmuch mail indexer";
|
||||
|
||||
new = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
ignore = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = ''
|
||||
A list to specify files and directories that will not be
|
||||
searched for messages by <command>notmuch new</command>.
|
||||
'';
|
||||
};
|
||||
|
||||
tags = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ "unread" "inbox" ];
|
||||
example = [ "new" ];
|
||||
description = ''
|
||||
A list of tags that will be added to all messages
|
||||
incorporated by <command>notmuch new</command>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = ''
|
||||
Options related to email processing performed by
|
||||
<command>notmuch new</command>.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.attrsOf (types.attrsOf types.str);
|
||||
default = {
|
||||
maildir = { synchronize_flags = "true"; };
|
||||
};
|
||||
description = ''
|
||||
Options that should be appended to the notmuch configuration file.
|
||||
'';
|
||||
};
|
||||
|
||||
hooks = {
|
||||
preNew = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = "mbsync --all";
|
||||
description = ''
|
||||
Bash statements run before scanning or importing new
|
||||
messages into the database.
|
||||
'';
|
||||
};
|
||||
|
||||
postNew = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = ''
|
||||
notmuch tag +nixos -- tag:new and from:nixos1@discoursemail.com
|
||||
'';
|
||||
description = ''
|
||||
Bash statements run after new messages have been imported
|
||||
into the database and initial tags have been applied.
|
||||
'';
|
||||
};
|
||||
|
||||
postInsert = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Bash statements run after a message has been inserted
|
||||
into the database and initial tags have been applied.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = notmuchIni.user.name != [];
|
||||
message = "notmuch: Must have a user name set.";
|
||||
}
|
||||
{
|
||||
assertion = notmuchIni.user.primary_email != [];
|
||||
message = "notmuch: Must have a user primary email address set.";
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = [ pkgs.notmuch ];
|
||||
|
||||
home.sessionVariables = {
|
||||
NOTMUCH_CONFIG = "${config.xdg.configHome}/notmuch/notmuchrc";
|
||||
NMBGIT = "${config.xdg.dataHome}/notmuch/nmbug";
|
||||
};
|
||||
|
||||
xdg.configFile."notmuch/notmuchrc".text =
|
||||
let
|
||||
toIni = generators.toINI { mkKeyValue = mkIniKeyValue; };
|
||||
in
|
||||
"# Generated by Home Manager.\n\n"
|
||||
+ toIni notmuchIni;
|
||||
|
||||
home.file =
|
||||
let
|
||||
hook = name: cmds:
|
||||
{
|
||||
target = "${notmuchIni.database.path}/.notmuch/hooks/${name}";
|
||||
source = pkgs.writeScript name ''
|
||||
#!${pkgs.stdenv.shell}
|
||||
|
||||
export PATH="${pkgs.notmuch}/bin''${PATH:+:}$PATH"
|
||||
export NOTMUCH_CONFIG="${config.xdg.configHome}/notmuch/notmuchrc"
|
||||
export NMBGIT="${config.xdg.dataHome}/notmuch/nmbug"
|
||||
|
||||
${cmds}
|
||||
'';
|
||||
executable = true;
|
||||
};
|
||||
in
|
||||
optional (cfg.hooks.preNew != "")
|
||||
(hook "pre-new" cfg.hooks.preNew)
|
||||
++
|
||||
optional (cfg.hooks.postNew != "")
|
||||
(hook "post-new" cfg.hooks.postNew)
|
||||
++
|
||||
optional (cfg.hooks.postInsert != "")
|
||||
(hook "post-insert" cfg.hooks.postInsert);
|
||||
};
|
||||
}
|
||||
46
modules/programs/offlineimap-accounts.nix
Normal file
46
modules/programs/offlineimap-accounts.nix
Normal file
@@ -0,0 +1,46 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
extraConfigType = with types; attrsOf (either (either str int) bool);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.offlineimap = {
|
||||
enable = mkEnableOption "OfflineIMAP";
|
||||
|
||||
extraConfig.local = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = {
|
||||
sync_deletes = true;
|
||||
};
|
||||
description = ''
|
||||
Extra configuration options to add to the local account
|
||||
section.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.remote = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = {
|
||||
maxconnections = 2;
|
||||
expunge = false;
|
||||
};
|
||||
description = ''
|
||||
Extra configuration options to add to the remote account
|
||||
section.
|
||||
'';
|
||||
};
|
||||
|
||||
postSyncHookCommand = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "Command to run after fetching new mails.";
|
||||
};
|
||||
};
|
||||
}
|
||||
206
modules/programs/offlineimap.nix
Normal file
206
modules/programs/offlineimap.nix
Normal file
@@ -0,0 +1,206 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.offlineimap;
|
||||
|
||||
accounts = filter (a: a.offlineimap.enable)
|
||||
(attrValues config.accounts.email.accounts);
|
||||
|
||||
toIni = generators.toINI {
|
||||
mkKeyValue = key: value:
|
||||
let
|
||||
value' =
|
||||
if isBool value then (if value then "yes" else "no")
|
||||
else toString value;
|
||||
in
|
||||
"${key} = ${value'}";
|
||||
};
|
||||
|
||||
# Generates a script to fetch only a specific account.
|
||||
#
|
||||
# Note, these scripts are not actually created and installed at the
|
||||
# moment. It will need some thinking on whether this is a good idea
|
||||
# and whether other modules should have some similar functionality.
|
||||
#
|
||||
# Perhaps have a single tool `email` that wraps the command?
|
||||
# Something like
|
||||
#
|
||||
# $ email <account name> <program name> <program args>
|
||||
genOfflineImapScript = account: with account;
|
||||
pkgs.writeShellScriptBin "offlineimap-${name}" ''
|
||||
exec ${pkgs.offlineimap}/bin/offlineimap -a${account.name} "$@"
|
||||
'';
|
||||
|
||||
accountStr = account: with account;
|
||||
let
|
||||
postSyncHook = optionalAttrs (offlineimap.postSyncHookCommand != "") {
|
||||
postsynchook =
|
||||
pkgs.writeShellScriptBin
|
||||
"postsynchook"
|
||||
offlineimap.postSyncHookCommand
|
||||
+ "/bin/postsynchook";
|
||||
};
|
||||
|
||||
localType =
|
||||
if account.flavor == "gmail.com"
|
||||
then "GmailMaildir"
|
||||
else "Maildir";
|
||||
|
||||
remoteType =
|
||||
if account.flavor == "gmail.com"
|
||||
then "Gmail"
|
||||
else "IMAP";
|
||||
|
||||
remoteHost = optionalAttrs (imap.host != null) {
|
||||
remotehost = imap.host;
|
||||
};
|
||||
|
||||
remotePort = optionalAttrs ((imap.port or null) != null) {
|
||||
remoteport = imap.port;
|
||||
};
|
||||
|
||||
ssl =
|
||||
if imap.tls.enable
|
||||
then
|
||||
{
|
||||
ssl = true;
|
||||
sslcacertfile = imap.tls.certificatesFile;
|
||||
starttls = imap.tls.useStartTls;
|
||||
}
|
||||
else
|
||||
{
|
||||
ssl = false;
|
||||
};
|
||||
|
||||
remotePassEval =
|
||||
let
|
||||
arglist = concatMapStringsSep "," (x: "'${x}'") passwordCommand;
|
||||
in
|
||||
optionalAttrs (passwordCommand != null) {
|
||||
remotepasseval = ''get_pass("${name}", [${arglist}])'';
|
||||
};
|
||||
in
|
||||
toIni {
|
||||
"Account ${name}" = {
|
||||
localrepository = "${name}-local";
|
||||
remoterepository = "${name}-remote";
|
||||
}
|
||||
// postSyncHook;
|
||||
|
||||
"Repository ${name}-local" = {
|
||||
type = localType;
|
||||
localfolders = maildir.absPath;
|
||||
}
|
||||
// offlineimap.extraConfig.local;
|
||||
|
||||
"Repository ${name}-remote" = {
|
||||
type = remoteType;
|
||||
remoteuser = userName;
|
||||
}
|
||||
// remoteHost
|
||||
// remotePort
|
||||
// remotePassEval
|
||||
// ssl
|
||||
// offlineimap.extraConfig.remote;
|
||||
};
|
||||
|
||||
extraConfigType = with types; attrsOf (either (either str int) bool);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.offlineimap = {
|
||||
enable = mkEnableOption "OfflineIMAP";
|
||||
|
||||
pythonFile = mkOption {
|
||||
type = types.lines;
|
||||
default = ''
|
||||
import subprocess
|
||||
|
||||
def get_pass(service, cmd):
|
||||
return subprocess.check_output(cmd, )
|
||||
'';
|
||||
description = ''
|
||||
Python code that can then be used in other parts of the
|
||||
configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.general = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = {
|
||||
maxage = 30;
|
||||
ui = "blinkenlights";
|
||||
};
|
||||
description = ''
|
||||
Extra configuration options added to the
|
||||
<option>general</option> section.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.default = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = {
|
||||
gmailtrashfolder = "[Gmail]/Papierkorb";
|
||||
};
|
||||
description = ''
|
||||
Extra configuration options added to the
|
||||
<option>DEFAULT</option> section.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.mbnames = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
filename = "~/.config/mutt/mailboxes";
|
||||
header = "'mailboxes '";
|
||||
peritem = "'+%(accountname)s/%(foldername)s'";
|
||||
sep = "' '";
|
||||
footer = "'\\n'";
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Extra configuration options added to the
|
||||
<code>mbnames</code> section.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.offlineimap ];
|
||||
|
||||
xdg.configFile."offlineimap/get_settings.py".text = cfg.pythonFile;
|
||||
|
||||
xdg.configFile."offlineimap/config".text =
|
||||
''
|
||||
# Generated by Home Manager.
|
||||
# See https://github.com/OfflineIMAP/offlineimap/blob/master/offlineimap.conf
|
||||
# for an exhaustive list of options.
|
||||
''
|
||||
+ toIni ({
|
||||
general = {
|
||||
accounts = concatMapStringsSep "," (a: a.name) accounts;
|
||||
pythonfile = "${config.xdg.configHome}/offlineimap/get_settings.py";
|
||||
metadata = "${config.xdg.dataHome}/offlineimap";
|
||||
}
|
||||
// cfg.extraConfig.general;
|
||||
}
|
||||
// optionalAttrs (cfg.extraConfig.mbnames != {}) {
|
||||
mbnames = { enabled = true; } // cfg.extraConfig.mbnames;
|
||||
}
|
||||
// optionalAttrs (cfg.extraConfig.default != {}) {
|
||||
DEFAULT = cfg.extraConfig.default;
|
||||
})
|
||||
+ "\n"
|
||||
+ concatStringsSep "\n" (map accountStr accounts);
|
||||
};
|
||||
}
|
||||
36
modules/programs/pidgin.nix
Normal file
36
modules/programs/pidgin.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.pidgin;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
programs.pidgin = {
|
||||
enable = mkEnableOption "Pidgin messaging client";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.pidgin;
|
||||
defaultText = "pkgs.pidgin";
|
||||
description = "The Pidgin package to use.";
|
||||
};
|
||||
|
||||
plugins = mkOption {
|
||||
default = [];
|
||||
example = literalExample "[ pkgs.pidgin-otr pkgs.pidgin-osd ]";
|
||||
description = "Plugins that should be available to Pidgin.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ (cfg.package.override { inherit (cfg) plugins; }) ];
|
||||
};
|
||||
}
|
||||
@@ -124,6 +124,14 @@ let
|
||||
bottom-left = 7;
|
||||
left = 8;
|
||||
};
|
||||
|
||||
themeName =
|
||||
if (cfg.theme == null) then null
|
||||
else if (lib.isString cfg.theme) then cfg.theme
|
||||
else lib.removeSuffix ".rasi" (baseNameOf cfg.theme);
|
||||
|
||||
themePath = if (lib.isString cfg.theme) then null else cfg.theme;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
@@ -232,8 +240,10 @@ in
|
||||
default = null;
|
||||
type = types.nullOr colorsSubmodule;
|
||||
description = ''
|
||||
Color scheme settings.
|
||||
Colors can be specified in CSS color formats.
|
||||
Color scheme settings. Colors can be specified in CSS color
|
||||
formats. This option may become deprecated in the future and
|
||||
therefore the <varname>programs.rofi.theme</varname> option
|
||||
should be used whenever possible.
|
||||
'';
|
||||
example = literalExample ''
|
||||
colors = {
|
||||
@@ -258,8 +268,19 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
theme = mkOption {
|
||||
default = null;
|
||||
type = with types; nullOr (either string path);
|
||||
example = "Arc";
|
||||
description = ''
|
||||
Name of theme or path to theme file in rasi format. Available
|
||||
named themes can be viewed using the
|
||||
<command>rofi-theme-selector</command> tool.
|
||||
'';
|
||||
};
|
||||
|
||||
configPath = mkOption {
|
||||
default = ".config/rofi/config";
|
||||
default = "${config.xdg.configHome}/rofi/config";
|
||||
type = types.string;
|
||||
description = "Path where to put generated configuration file.";
|
||||
};
|
||||
@@ -273,6 +294,15 @@ in
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.theme == null || cfg.colors == null;
|
||||
message = ''
|
||||
Cannot use the rofi options 'theme' and 'colors' simultaneously.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = [ pkgs.rofi ];
|
||||
|
||||
home.file."${cfg.configPath}".text = ''
|
||||
@@ -296,8 +326,13 @@ in
|
||||
${setOption "yoffset" cfg.yoffset}
|
||||
|
||||
${setColorScheme cfg.colors}
|
||||
${setOption "theme" themeName}
|
||||
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
|
||||
xdg.dataFile = mkIf (themePath != null) {
|
||||
"rofi/themes/${themeName}.rasi".source = themePath;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -220,9 +220,18 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
extraOptionOverrides = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = ''
|
||||
Extra SSH configuration options that take precedence over any
|
||||
host specific configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
matchBlocks = mkOption {
|
||||
type = types.loaOf matchBlockModule;
|
||||
default = [];
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
"john.example.com" = {
|
||||
@@ -248,20 +257,24 @@ in
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.file.".ssh/config".text = ''
|
||||
ForwardAgent ${yn cfg.forwardAgent}
|
||||
Compression ${yn cfg.compression}
|
||||
ServerAliveInterval ${toString cfg.serverAliveInterval}
|
||||
HashKnownHosts ${yn cfg.hashKnownHosts}
|
||||
UserKnownHostsFile ${cfg.userKnownHostsFile}
|
||||
ControlMaster ${cfg.controlMaster}
|
||||
ControlPath ${cfg.controlPath}
|
||||
ControlPersist ${cfg.controlPersist}
|
||||
|
||||
${cfg.extraConfig}
|
||||
${concatStringsSep "\n" (
|
||||
mapAttrsToList (n: v: "${n} ${v}") cfg.extraOptionOverrides)}
|
||||
|
||||
${concatStringsSep "\n\n" (
|
||||
map matchBlockStr (
|
||||
builtins.attrValues cfg.matchBlocks))}
|
||||
|
||||
Host *
|
||||
ForwardAgent ${yn cfg.forwardAgent}
|
||||
Compression ${yn cfg.compression}
|
||||
ServerAliveInterval ${toString cfg.serverAliveInterval}
|
||||
HashKnownHosts ${yn cfg.hashKnownHosts}
|
||||
UserKnownHostsFile ${cfg.userKnownHostsFile}
|
||||
ControlMaster ${cfg.controlMaster}
|
||||
ControlPath ${cfg.controlPath}
|
||||
ControlPersist ${cfg.controlPersist}
|
||||
|
||||
${replaceStrings ["\n"] ["\n "] cfg.extraConfig}
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
112
modules/programs/taskwarrior.nix
Normal file
112
modules/programs/taskwarrior.nix
Normal file
@@ -0,0 +1,112 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.taskwarrior;
|
||||
|
||||
themePath = theme: "${pkgs.taskwarrior}/share/doc/task/rc/${theme}.theme";
|
||||
|
||||
includeTheme = location:
|
||||
if location == null then ""
|
||||
else if isString location then "include ${themePath location}"
|
||||
else "include ${location}";
|
||||
|
||||
formatValue = value:
|
||||
if isBool value then if value then "true" else "false"
|
||||
else if isList value then concatMapStringsSep "," formatValue value
|
||||
else toString value;
|
||||
|
||||
formatLine = key: value:
|
||||
"${key}=${formatValue value}";
|
||||
|
||||
formatSet = key: values:
|
||||
(concatStringsSep "\n"
|
||||
(mapAttrsToList
|
||||
(subKey: subValue: formatPair "${key}.${subKey}" subValue)
|
||||
values));
|
||||
|
||||
formatPair = key: value:
|
||||
if isAttrs value then formatSet key value
|
||||
else formatLine key value;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.taskwarrior = {
|
||||
enable = mkEnableOption "Task Warrior";
|
||||
|
||||
config = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
confirmation = false;
|
||||
report.minimal.filter = "status:pending";
|
||||
report.active.columns = [ "id" "start" "entry.age" "priority" "project" "due" "description" ];
|
||||
report.active.labels = [ "ID" "Started" "Age" "Priority" "Project" "Due" "Description" ];
|
||||
taskd = {
|
||||
certificate = "/path/to/cert";
|
||||
key = "/path/to/key";
|
||||
ca = "/path/to/ca";
|
||||
server = "host.domain:53589";
|
||||
credentials = "Org/First Last/cf31f287-ee9e-43a8-843e-e8bbd5de4294";
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Key-value configuration written to
|
||||
<filename>~/.taskrc</filename>.
|
||||
'';
|
||||
};
|
||||
|
||||
dataLocation = mkOption {
|
||||
type = types.str;
|
||||
default = "${config.xdg.dataHome}/task";
|
||||
defaultText = "$XDG_DATA_HOME/task";
|
||||
description = ''
|
||||
Location where Task Warrior will store its data.
|
||||
</para><para>
|
||||
Home Manager will attempt to create this directory.
|
||||
'';
|
||||
};
|
||||
|
||||
colorTheme = mkOption {
|
||||
type = with types; nullOr (either str path);
|
||||
default = null;
|
||||
example = "dark-blue-256";
|
||||
description = ''
|
||||
Either one of the default provided theme as string, or a
|
||||
path to a theme configuration file.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Additional content written at the end of
|
||||
<filename>~/.taskrc</filename>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.taskwarrior ];
|
||||
|
||||
home.file."${cfg.dataLocation}/.keep".text = "";
|
||||
|
||||
home.file.".taskrc".text = ''
|
||||
data.location=${cfg.dataLocation}
|
||||
${includeTheme cfg.colorTheme}
|
||||
|
||||
${concatStringsSep "\n" (
|
||||
mapAttrsToList formatPair cfg.config)}
|
||||
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -150,7 +150,11 @@ in
|
||||
type = types.nullOr types.bool;
|
||||
description = ''
|
||||
Emit escape sequences for extra keys,
|
||||
like the modifyOtherKeys resource for xterm(1).
|
||||
like the modifyOtherKeys resource for
|
||||
<citerefentry>
|
||||
<refentrytitle>xterm</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</citerefentry>.
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
@@ -22,13 +22,18 @@ in
|
||||
'';
|
||||
description = "Extra packages available to Texlive.";
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
description = "Resulting customized Texlive package.";
|
||||
readOnly = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [
|
||||
(pkgs.texlive.combine (cfg.extraPackages pkgs.texlive))
|
||||
];
|
||||
|
||||
home.packages = [ cfg.package ];
|
||||
programs.texlive.package =
|
||||
pkgs.texlive.combine (cfg.extraPackages pkgs.texlive);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,8 +75,8 @@ in
|
||||
default = defaultPlugins;
|
||||
example = [ "YankRing" ];
|
||||
description = ''
|
||||
List of vim plugins to install. For supported plugins see:
|
||||
<link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/vim-plugins/vim-plugin-names"/>.
|
||||
List of vim plugins to install. To get a list of supported plugins run:
|
||||
<command>nix-env -f '<nixpkgs>' -qaP -A vimPlugins</command>.
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
61
modules/programs/zathura.nix
Normal file
61
modules/programs/zathura.nix
Normal file
@@ -0,0 +1,61 @@
|
||||
{ config, lib, pkgs, ...}:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.zathura;
|
||||
|
||||
formatLine = n: v:
|
||||
let
|
||||
formatValue = v:
|
||||
if isBool v then (if v then "true" else "false")
|
||||
else toString v;
|
||||
in
|
||||
"set ${n}\t\"${formatValue v}\"";
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rprospero ];
|
||||
|
||||
options.programs.zathura = {
|
||||
enable = mkEnableOption ''
|
||||
Zathura, a highly customizable and functional document viewer
|
||||
focused on keyboard interaction'';
|
||||
|
||||
options = mkOption {
|
||||
default = {};
|
||||
type = with types; attrsOf (either str (either bool int));
|
||||
description = ''
|
||||
Add <option>:set</option> command options to zathura and make
|
||||
them permanent. See
|
||||
<citerefentry>
|
||||
<refentrytitle>zathurarc</refentrytitle>
|
||||
<manvolnum>5</manvolnum>
|
||||
</citerefentry>
|
||||
for the full list of options.
|
||||
'';
|
||||
example = { default-bg = "#000000"; default-fg = "#FFFFFF"; };
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Additional commands for zathura that will be added to the
|
||||
<filename>zathurarc</filename> file.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.zathura ];
|
||||
|
||||
xdg.configFile."zathura/zathurarc".text =
|
||||
concatStringsSep "\n" ([]
|
||||
++ optional (cfg.extraConfig != "") cfg.extraConfig
|
||||
++ mapAttrsToList formatLine cfg.options
|
||||
) + "\n";
|
||||
};
|
||||
}
|
||||
@@ -50,6 +50,18 @@ let
|
||||
'';
|
||||
};
|
||||
|
||||
expireDuplicatesFirst = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Expire duplicates first.";
|
||||
};
|
||||
|
||||
extended = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Save timestamp into the history file.";
|
||||
};
|
||||
|
||||
share = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
@@ -302,7 +314,7 @@ in
|
||||
}
|
||||
|
||||
# Environment variables
|
||||
. "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh"
|
||||
. "${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh"
|
||||
${envVarsStr}
|
||||
|
||||
${optionalString cfg.oh-my-zsh.enable ''
|
||||
@@ -320,7 +332,9 @@ in
|
||||
''}
|
||||
|
||||
${concatStrings (map (plugin: ''
|
||||
source "$HOME/${pluginsDir}/${plugin.name}/${plugin.file}"
|
||||
if [ -f "$HOME/${pluginsDir}/${plugin.name}/${plugin.file}" ]; then
|
||||
source "$HOME/${pluginsDir}/${plugin.name}/${plugin.file}"
|
||||
fi
|
||||
'') cfg.plugins)}
|
||||
|
||||
# History options should be set in .zshrc and after oh-my-zsh sourcing.
|
||||
@@ -331,7 +345,9 @@ in
|
||||
|
||||
setopt HIST_FCNTL_LOCK
|
||||
${if cfg.history.ignoreDups then "setopt" else "unsetopt"} HIST_IGNORE_DUPS
|
||||
${if cfg.history.expireDuplicatesFirst then "setopt" else "unsetopt"} HIST_EXPIRE_DUPS_FIRST
|
||||
${if cfg.history.share then "setopt" else "unsetopt"} SHARE_HISTORY
|
||||
${if cfg.history.extended then "setopt" else "unsetopt"} EXTENDED_HISTORY
|
||||
|
||||
${cfg.initExtra}
|
||||
|
||||
|
||||
@@ -24,11 +24,20 @@ let
|
||||
shadow-offset-y = ${toString (elemAt cfg.shadowOffsets 1)};
|
||||
shadow-opacity = ${cfg.shadowOpacity};
|
||||
shadow-exclude = ${toJSON cfg.shadowExclude};
|
||||
'' +
|
||||
optionalString cfg.blur ''
|
||||
|
||||
# blur
|
||||
blur-background = true;
|
||||
blur-background-exclude = ${toJSON cfg.blurExclude};
|
||||
no-dock-blur = ${toJSON cfg.noDockBlur};
|
||||
'' + ''
|
||||
|
||||
# opacity
|
||||
active-opacity = ${cfg.activeOpacity};
|
||||
inactive-opacity = ${cfg.inactiveOpacity};
|
||||
menu-opacity = ${cfg.menuOpacity};
|
||||
opacity-rule = ${toJSON cfg.opacityRule};
|
||||
|
||||
# other options
|
||||
backend = ${toJSON cfg.backend};
|
||||
@@ -41,6 +50,40 @@ in {
|
||||
options.services.compton = {
|
||||
enable = mkEnableOption "Compton X11 compositor";
|
||||
|
||||
blur = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Enable background blur on transparent windows.
|
||||
'';
|
||||
};
|
||||
|
||||
noDockBlur = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Avoid blur on docks.
|
||||
'';
|
||||
};
|
||||
|
||||
blurExclude = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [
|
||||
"class_g = 'slop'"
|
||||
"class_i = 'polybar'"
|
||||
];
|
||||
description = ''
|
||||
List of windows to exclude background blur.
|
||||
See the
|
||||
<citerefentry>
|
||||
<refentrytitle>compton</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</citerefentry>
|
||||
man page for more examples.
|
||||
'';
|
||||
};
|
||||
|
||||
fade = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -77,7 +120,12 @@ in {
|
||||
];
|
||||
description = ''
|
||||
List of conditions of windows that should not be faded.
|
||||
See <literal>compton(1)</literal> man page for more examples.
|
||||
See the
|
||||
<citerefentry>
|
||||
<refentrytitle>compton</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</citerefentry>
|
||||
man page for more examples.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -94,7 +142,7 @@ in {
|
||||
default = [ (-15) (-15) ];
|
||||
example = [ (-10) (-15) ];
|
||||
description = ''
|
||||
Left and right offset for shadows (in pixels).
|
||||
Horizontal and vertical offsets for shadows (in pixels).
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -117,7 +165,12 @@ in {
|
||||
];
|
||||
description = ''
|
||||
List of conditions of windows that should have no shadow.
|
||||
See <literal>compton(1)</literal> man page for more examples.
|
||||
See the
|
||||
<citerefentry>
|
||||
<refentrytitle>compton</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</citerefentry>
|
||||
man page for more examples.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -148,6 +201,24 @@ in {
|
||||
'';
|
||||
};
|
||||
|
||||
opacityRule = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [
|
||||
"87:class_i ?= 'scratchpad'"
|
||||
"91:class_i ?= 'xterm'"
|
||||
];
|
||||
description = ''
|
||||
List of opacity rules.
|
||||
See the
|
||||
<citerefentry>
|
||||
<refentrytitle>compton</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</citerefentry>
|
||||
man page for more examples.
|
||||
'';
|
||||
};
|
||||
|
||||
backend = mkOption {
|
||||
type = types.str;
|
||||
default = "glx";
|
||||
@@ -157,13 +228,18 @@ in {
|
||||
};
|
||||
|
||||
vSync = mkOption {
|
||||
type = types.str;
|
||||
default = "none";
|
||||
example = "opengl-swc";
|
||||
description = ''
|
||||
Enable vertical synchronization using the specified method.
|
||||
See <literal>compton(1)</literal> man page available methods.
|
||||
'';
|
||||
type = types.str;
|
||||
default = "none";
|
||||
example = "opengl-swc";
|
||||
description = ''
|
||||
Enable vertical synchronization using the specified method.
|
||||
See the
|
||||
<citerefentry>
|
||||
<refentrytitle>compton</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</citerefentry>
|
||||
man page for available methods.
|
||||
'';
|
||||
};
|
||||
|
||||
refreshRate = mkOption {
|
||||
|
||||
@@ -99,7 +99,7 @@ in
|
||||
|
||||
basePaths = [
|
||||
"/run/current-system/sw"
|
||||
"${config.home.homeDirectory}/.nix-profile"
|
||||
config.home.profileDirectory
|
||||
cfg.iconTheme.package
|
||||
] ++ optional useCustomTheme hicolorTheme.package;
|
||||
|
||||
|
||||
42
modules/services/flameshot.nix
Normal file
42
modules/services/flameshot.nix
Normal file
@@ -0,0 +1,42 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.services.flameshot;
|
||||
package = pkgs.flameshot;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.hamhut1066 ];
|
||||
|
||||
options = {
|
||||
services.flameshot = {
|
||||
enable = mkEnableOption "Flameshot";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ package ];
|
||||
|
||||
systemd.user.services.flameshot = {
|
||||
Unit = {
|
||||
Description = "Powerful yet simple to use screenshot software";
|
||||
After = [ "graphical-session-pre.target" ];
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
Environment = "PATH=${config.home.profileDirectory}/bin";
|
||||
ExecStart = "${package}/bin/flameshot";
|
||||
Restart = "on-abort";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -9,8 +9,9 @@ let
|
||||
gpgInitStr = ''
|
||||
GPG_TTY="$(tty)"
|
||||
export GPG_TTY
|
||||
${pkgs.gnupg}/bin/gpg-connect-agent updatestartuptty /bye > /dev/null
|
||||
'';
|
||||
''
|
||||
+ optionalString cfg.enableSshSupport
|
||||
"${pkgs.gnupg}/bin/gpg-connect-agent updatestartuptty /bye > /dev/null";
|
||||
|
||||
in
|
||||
|
||||
@@ -39,6 +40,28 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
maxCacheTtl = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
Set the maximum time a cache entry is valid to n seconds. After this
|
||||
time a cache entry will be expired even if it has been accessed
|
||||
recently or has been set using gpg-preset-passphrase. The default is
|
||||
2 hours (7200 seconds).
|
||||
'';
|
||||
};
|
||||
|
||||
maxCacheTtlSsh = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
Set the maximum time a cache entry used for SSH keys is valid to n
|
||||
seconds. After this time a cache entry will be expired even if it has
|
||||
been accessed recently or has been set using gpg-preset-passphrase.
|
||||
The default is 2 hours (7200 seconds).
|
||||
'';
|
||||
};
|
||||
|
||||
enableSshSupport = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -47,6 +70,23 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
enableExtraSocket = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable extra socket of the GnuPG key agent (useful for GPG
|
||||
Agent forwarding).
|
||||
'';
|
||||
};
|
||||
|
||||
verbose = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to produce verbose output.
|
||||
'';
|
||||
};
|
||||
|
||||
grabKeyboardAndMouse = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
@@ -68,6 +108,19 @@ in
|
||||
<option>disable-scdaemon</option> setting to gpg-agent.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = ''
|
||||
allow-emacs-pinentry
|
||||
allow-loopback-pinentry
|
||||
'';
|
||||
description = ''
|
||||
Extra configuration lines to append to the gpg-agent
|
||||
configuration file.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -85,6 +138,14 @@ in
|
||||
++
|
||||
optional (cfg.defaultCacheTtlSsh != null)
|
||||
"default-cache-ttl-ssh ${toString cfg.defaultCacheTtlSsh}"
|
||||
++
|
||||
optional (cfg.maxCacheTtl != null)
|
||||
"max-cache-ttl ${toString cfg.maxCacheTtl}"
|
||||
++
|
||||
optional (cfg.maxCacheTtlSsh != null)
|
||||
"max-cache-ttl-ssh ${toString cfg.maxCacheTtlSsh}"
|
||||
++
|
||||
[ cfg.extraConfig ]
|
||||
);
|
||||
|
||||
home.sessionVariables =
|
||||
@@ -114,7 +175,8 @@ in
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = "${pkgs.gnupg}/bin/gpg-agent --supervised";
|
||||
ExecStart = "${pkgs.gnupg}/bin/gpg-agent --supervised"
|
||||
+ optionalString cfg.verbose " --verbose";
|
||||
ExecReload = "${pkgs.gnupg}/bin/gpgconf --reload gpg-agent";
|
||||
};
|
||||
};
|
||||
@@ -158,5 +220,26 @@ in
|
||||
};
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf cfg.enableExtraSocket {
|
||||
systemd.user.sockets.gpg-agent-extra = {
|
||||
Unit = {
|
||||
Description = "GnuPG cryptographic agent and passphrase cache (restricted)";
|
||||
Documentation = "man:gpg-agent(1) man:ssh(1)";
|
||||
};
|
||||
|
||||
Socket = {
|
||||
ListenStream = "%t/gnupg/S.gpg-agent.extra";
|
||||
FileDescriptorName = "extra";
|
||||
Service = "gpg-agent.service";
|
||||
SocketMode = "0600";
|
||||
DirectoryMode = "0700";
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "sockets.target" ];
|
||||
};
|
||||
};
|
||||
})
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ in
|
||||
let
|
||||
mountPoint = "\"%h/${cfg.mountPoint}\"";
|
||||
in {
|
||||
Environment = "PATH=/run/wrappers KEYBASE_SYSTEMD=1";
|
||||
Environment = "PATH=/run/wrappers/bin KEYBASE_SYSTEMD=1";
|
||||
ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p ${mountPoint}";
|
||||
ExecStart ="${pkgs.kbfs}/bin/kbfsfuse ${toString cfg.extraFlags} ${mountPoint}";
|
||||
ExecStopPost = "/run/wrappers/bin/fusermount -u ${mountPoint}";
|
||||
|
||||
75
modules/services/kdeconnect.nix
Normal file
75
modules/services/kdeconnect.nix
Normal file
@@ -0,0 +1,75 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.services.kdeconnect;
|
||||
package = pkgs.kdeconnect;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.adisbladis ];
|
||||
|
||||
options = {
|
||||
services.kdeconnect = {
|
||||
enable = mkEnableOption "KDE connect";
|
||||
|
||||
indicator = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to enable kdeconnect-indicator service.";
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
(mkIf cfg.enable {
|
||||
home.packages = [ package ];
|
||||
|
||||
systemd.user.services.kdeconnect = {
|
||||
Unit = {
|
||||
Description = "Adds communication between your desktop and your smartphone";
|
||||
After = [ "graphical-session-pre.target" ];
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
Environment = "PATH=${config.home.profileDirectory}/bin";
|
||||
ExecStart = "${package}/lib/libexec/kdeconnectd";
|
||||
Restart = "on-abort";
|
||||
};
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf cfg.indicator {
|
||||
systemd.user.services.kdeconnect-indicator = {
|
||||
Unit = {
|
||||
Description = "kdeconnect-indicator";
|
||||
After = [ "graphical-session-pre.target"
|
||||
"polybar.service"
|
||||
"taffybar.service"
|
||||
"stalonetray.service" ];
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
Environment = "PATH=${config.home.profileDirectory}/bin";
|
||||
ExecStart = "${package}/bin/kdeconnect-indicator";
|
||||
Restart = "on-abort";
|
||||
};
|
||||
};
|
||||
})
|
||||
|
||||
];
|
||||
}
|
||||
111
modules/services/mbsync.nix
Normal file
111
modules/services/mbsync.nix
Normal file
@@ -0,0 +1,111 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.services.mbsync;
|
||||
|
||||
mbsyncOptions =
|
||||
[ "--all"
|
||||
] ++ optional (cfg.verbose) "--verbose"
|
||||
++ optional (cfg.configFile != null) "--config ${cfg.configFile}";
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.pjones ];
|
||||
|
||||
options.services.mbsync = {
|
||||
enable = mkEnableOption "mbsync";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.isync;
|
||||
defaultText = "pkgs.isync";
|
||||
example = literalExample "pkgs.isync";
|
||||
description = "The package to use for the mbsync binary.";
|
||||
};
|
||||
|
||||
frequency = mkOption {
|
||||
type = types.str;
|
||||
default = "*:0/5";
|
||||
description = ''
|
||||
How often to run mbsync. This value is passed to the systemd
|
||||
timer configuration as the onCalendar option. See
|
||||
<citerefentry>
|
||||
<refentrytitle>systemd.time</refentrytitle>
|
||||
<manvolnum>7</manvolnum>
|
||||
</citerefentry>
|
||||
for more information about the format.
|
||||
'';
|
||||
};
|
||||
|
||||
verbose = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether mbsync should produce verbose output.
|
||||
'';
|
||||
};
|
||||
|
||||
configFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
Optional configuration file to link to use instead of
|
||||
the default file (<filename>~/.mbsyncrc</filename>).
|
||||
'';
|
||||
};
|
||||
|
||||
preExec = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "mkdir -p %h/mail";
|
||||
description = ''
|
||||
An optional command to run before mbsync executes. This is
|
||||
useful for creating the directories mbsync is going to use.
|
||||
'';
|
||||
};
|
||||
|
||||
postExec = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "mu index";
|
||||
description = ''
|
||||
An optional command to run after mbsync executes successfully.
|
||||
This is useful for running mailbox indexing tools.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.user.services.mbsync = {
|
||||
Unit = {
|
||||
Description = "mbsync mailbox synchronization";
|
||||
PartOf = [ "network-online.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = "${cfg.package}/bin/mbsync ${concatStringsSep " " mbsyncOptions}";
|
||||
} // (optionalAttrs (cfg.postExec != null) { ExecStartPost = cfg.postExec; })
|
||||
// (optionalAttrs (cfg.preExec != null) { ExecStartPre = cfg.preExec; });
|
||||
};
|
||||
|
||||
systemd.user.timers.mbsync = {
|
||||
Unit = {
|
||||
Description = "mbsync mailbox synchronization";
|
||||
};
|
||||
|
||||
Timer = {
|
||||
OnCalendar = cfg.frequency;
|
||||
Unit = "mbsync.service";
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "timers.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
148
modules/services/mpd.nix
Normal file
148
modules/services/mpd.nix
Normal file
@@ -0,0 +1,148 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
name = "mpd";
|
||||
|
||||
cfg = config.services.mpd;
|
||||
|
||||
mpdConf = pkgs.writeText "mpd.conf" ''
|
||||
music_directory "${cfg.musicDirectory}"
|
||||
playlist_directory "${cfg.playlistDirectory}"
|
||||
${lib.optionalString (cfg.dbFile != null) ''
|
||||
db_file "${cfg.dbFile}"
|
||||
''}
|
||||
state_file "${cfg.dataDir}/state"
|
||||
sticker_file "${cfg.dataDir}/sticker.sql"
|
||||
log_file "syslog"
|
||||
|
||||
${optionalString (cfg.network.listenAddress != "any")
|
||||
''bind_to_address "${cfg.network.listenAddress}"''}
|
||||
${optionalString (cfg.network.port != 6600)
|
||||
''port "${toString cfg.network.port}"''}
|
||||
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
|
||||
in {
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
services.mpd = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable MPD, the music player daemon.
|
||||
'';
|
||||
};
|
||||
|
||||
musicDirectory = mkOption {
|
||||
type = types.path;
|
||||
default = "${config.home.homeDirectory}/music";
|
||||
defaultText = "$HOME/music";
|
||||
description = ''
|
||||
The directory where mpd reads music from.
|
||||
'';
|
||||
};
|
||||
|
||||
playlistDirectory = mkOption {
|
||||
type = types.path;
|
||||
default = "${cfg.dataDir}/playlists";
|
||||
defaultText = ''''${dataDir}/playlists'';
|
||||
description = ''
|
||||
The directory where mpd stores playlists.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra directives added to to the end of MPD's configuration
|
||||
file, <filename>mpd.conf</filename>. Basic configuration
|
||||
like file location and uid/gid is added automatically to the
|
||||
beginning of the file. For available options see
|
||||
<citerefentry>
|
||||
<refentrytitle>mpd.conf</refentrytitle>
|
||||
<manvolnum>5</manvolnum>
|
||||
</citerefentry>.
|
||||
'';
|
||||
};
|
||||
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "${config.xdg.dataHome}/${name}";
|
||||
defaultText = "$XDG_DATA_HOME/mpd";
|
||||
description = ''
|
||||
The directory where MPD stores its state, tag cache,
|
||||
playlists etc.
|
||||
'';
|
||||
};
|
||||
|
||||
network = {
|
||||
|
||||
listenAddress = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
example = "any";
|
||||
description = ''
|
||||
The address for the daemon to listen on.
|
||||
Use <literal>any</literal> to listen on all addresses.
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.ints.positive;
|
||||
default = 6600;
|
||||
description = ''
|
||||
The TCP port on which the the daemon will listen.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
dbFile = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = "${cfg.dataDir}/tag_cache";
|
||||
defaultText = ''''${dataDir}/tag_cache'';
|
||||
description = ''
|
||||
The path to MPD's database. If set to
|
||||
<literal>null</literal> the parameter is omitted from the
|
||||
configuration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
systemd.user.services.mpd = {
|
||||
Unit = {
|
||||
After = [ "network.target" "sound.target" ];
|
||||
Description = "Music Player Daemon";
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "default.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
Environment = "PATH=${config.home.profileDirectory}/bin";
|
||||
ExecStart = "${pkgs.mpd}/bin/mpd --no-daemon ${mpdConf}";
|
||||
Type = "notify";
|
||||
ExecStartPre = ''${pkgs.bash}/bin/bash -c "${pkgs.coreutils}/bin/mkdir -p '${cfg.dataDir}' '${cfg.playlistDirectory}'"'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.services.network-manager-applet;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
@@ -11,7 +17,7 @@ with lib;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf config.services.network-manager-applet.enable {
|
||||
config = mkIf cfg.enable {
|
||||
systemd.user.services.network-manager-applet = {
|
||||
Unit = {
|
||||
Description = "Network Manager applet";
|
||||
@@ -24,7 +30,12 @@ with lib;
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = "${pkgs.networkmanagerapplet}/bin/nm-applet --sm-disable";
|
||||
ExecStart = toString (
|
||||
[
|
||||
"${pkgs.networkmanagerapplet}/bin/nm-applet"
|
||||
"--sm-disable"
|
||||
] ++ optional config.xsession.preferStatusNotifierItems "--indicator"
|
||||
);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@ with lib;
|
||||
};
|
||||
|
||||
Service = {
|
||||
Environment = "PATH=${config.home.profileDirectory}/bin";
|
||||
ExecStart = "${pkgs.owncloud-client}/bin/owncloud";
|
||||
};
|
||||
|
||||
|
||||
31
modules/services/pasystray.nix
Normal file
31
modules/services/pasystray.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.pltanton ];
|
||||
|
||||
options = {
|
||||
services.pasystray = {
|
||||
enable = mkEnableOption "PulseAudio system tray";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf config.services.pasystray.enable {
|
||||
systemd.user.services.pasystray = {
|
||||
Unit = {
|
||||
Description = "PulseAudio system tray";
|
||||
After = [ "graphical-session-pre.target" ];
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = "${pkgs.pasystray}/bin/pasystray";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -6,17 +6,20 @@ let
|
||||
|
||||
cfg = config.services.polybar;
|
||||
|
||||
dag = config.lib.dag;
|
||||
|
||||
toPolybarIni = generators.toINI {
|
||||
mkKeyValue = key: value:
|
||||
let
|
||||
value' =
|
||||
if isBool value then (if value then "true" else "false")
|
||||
else if (isString value && key != "include-file") then ''"${value}"''
|
||||
else toString value;
|
||||
in
|
||||
"${key}=${value'}";
|
||||
let
|
||||
quoted = v:
|
||||
if hasPrefix " " v || hasSuffix " " v
|
||||
then ''"${v}"''
|
||||
else v;
|
||||
|
||||
value' =
|
||||
if isBool value then (if value then "true" else "false")
|
||||
else if (isString value && key != "include-file") then quoted value
|
||||
else toString value;
|
||||
in
|
||||
"${key}=${value'}";
|
||||
};
|
||||
|
||||
configFile = pkgs.writeText "polybar.conf"
|
||||
@@ -56,7 +59,7 @@ in
|
||||
(p: { "section/base" = { include-file = "${p}"; }; })
|
||||
(types.attrsOf types.attrs);
|
||||
description = ''
|
||||
Polybar configuration. Can be either path to a file, or set of attibutes
|
||||
Polybar configuration. Can be either path to a file, or set of attributes
|
||||
that will be used to create the final configuration.
|
||||
'';
|
||||
default = {};
|
||||
@@ -119,6 +122,7 @@ in
|
||||
Description = "Polybar status bar";
|
||||
After = [ "graphical-session-pre.target" ];
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
X-Restart-Triggers = [ config.xdg.configFile."polybar/config".source ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
@@ -131,21 +135,6 @@ in
|
||||
WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
};
|
||||
|
||||
home.activation.checkPolybar = dag.entryBefore [ "linkGeneration" ] ''
|
||||
if ! cmp --quiet \
|
||||
"${configFile}" \
|
||||
"$HOME/.config/polybar/config"; then
|
||||
polybarChanged=1
|
||||
fi
|
||||
'';
|
||||
|
||||
home.activation.applyPolybar = dag.entryAfter [ "reloadSystemD" ] ''
|
||||
if [[ -v polybarChanged && -v DISPLAY ]]; then
|
||||
echo "Restarting polybar"
|
||||
${config.systemd.user.systemctlPath} --user restart polybar.service
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -25,18 +25,33 @@ in
|
||||
};
|
||||
|
||||
latitude = mkOption {
|
||||
type = types.str;
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Your current latitude, between
|
||||
<literal>-90.0</literal> and <literal>90.0</literal>.
|
||||
Your current latitude, between <literal>-90.0</literal> and
|
||||
<literal>90.0</literal>. Must be provided along with
|
||||
longitude.
|
||||
'';
|
||||
};
|
||||
|
||||
longitude = mkOption {
|
||||
type = types.str;
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Your current longitude, between
|
||||
between <literal>-180.0</literal> and <literal>180.0</literal>.
|
||||
Your current longitude, between <literal>-180.0</literal> and
|
||||
<literal>180.0</literal>. Must be provided along with
|
||||
latitude.
|
||||
'';
|
||||
};
|
||||
|
||||
provider = mkOption {
|
||||
type = types.enum [ "manual" "geoclue2" ];
|
||||
default = "manual";
|
||||
description = ''
|
||||
The location provider to use for determining your location. If set to
|
||||
<literal>manual</literal> you must also provide latitude/longitude.
|
||||
If set to <literal>geoclue2</literal>, you must also enable the global
|
||||
geoclue2 service.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -122,11 +137,17 @@ in
|
||||
Service = {
|
||||
ExecStart =
|
||||
let
|
||||
providerString =
|
||||
if cfg.provider == "manual"
|
||||
then "${cfg.latitude}:${cfg.longitude}"
|
||||
else cfg.provider;
|
||||
|
||||
args = [
|
||||
"-l ${cfg.latitude}:${cfg.longitude}"
|
||||
"-l ${providerString}"
|
||||
"-t ${toString cfg.temperature.day}:${toString cfg.temperature.night}"
|
||||
"-b ${toString cfg.brightness.day}:${toString cfg.brightness.night}"
|
||||
] ++ cfg.extraOptions;
|
||||
|
||||
command = if cfg.tray then "redshift-gtk" else "redshift";
|
||||
in
|
||||
"${cfg.package}/bin/${command} ${concatStringsSep " " args}";
|
||||
|
||||
@@ -26,6 +26,23 @@ in {
|
||||
See <link xlink:href="https://linux.die.net/man/1/xautolock"/>.
|
||||
'';
|
||||
};
|
||||
|
||||
xautolockExtraOptions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = ''
|
||||
Extra command-line arguments to pass to <command>xautolock</command>.
|
||||
'';
|
||||
};
|
||||
|
||||
xssLockExtraOptions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = ''
|
||||
Extra command-line arguments to pass to <command>xss-lock</command>.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
@@ -45,7 +62,8 @@ in {
|
||||
${pkgs.xautolock}/bin/xautolock \
|
||||
-detectsleep \
|
||||
-time ${toString cfg.inactiveInterval} \
|
||||
-locker '${pkgs.systemd}/bin/loginctl lock-session $XDG_SESSION_ID'
|
||||
-locker '${pkgs.systemd}/bin/loginctl lock-session $XDG_SESSION_ID' \
|
||||
${concatStringsSep " " cfg.xautolockExtraOptions}
|
||||
'';
|
||||
};
|
||||
};
|
||||
@@ -53,7 +71,7 @@ in {
|
||||
# xss-lock will run specified screen locker when the session is locked via loginctl
|
||||
# can't be started as a systemd service,
|
||||
# see https://bitbucket.org/raymonad/xss-lock/issues/13/allow-operation-as-systemd-user-unit
|
||||
xsession.initExtra = "${pkgs.xss-lock}/bin/xss-lock -- ${cfg.lockCmd} &";
|
||||
xsession.initExtra = "${pkgs.xss-lock}/bin/xss-lock ${concatStringsSep " " cfg.xssLockExtraOptions} -- ${cfg.lockCmd} &";
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
46
modules/services/status-notifier-watcher.nix
Normal file
46
modules/services/status-notifier-watcher.nix
Normal file
@@ -0,0 +1,46 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.services.status-notifier-watcher;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.pltanton ];
|
||||
|
||||
options = {
|
||||
services.status-notifier-watcher = {
|
||||
enable = mkEnableOption "Status Notifier Watcher";
|
||||
|
||||
package = mkOption {
|
||||
default = pkgs.haskellPackages.status-notifier-item;
|
||||
defaultText = "pkgs.haskellPackages.status-notifier-item";
|
||||
type = types.package;
|
||||
example = literalExample "pkgs.haskellPackages.status-notifier-item";
|
||||
description = "The package to use for the status notifier watcher binary.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.user.services.status-notifier-watcher = {
|
||||
Unit = {
|
||||
Description = "SNI watcher";
|
||||
After = [ "graphical-session-pre.target" ];
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
Before = [ "taffybar.service" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = "${cfg.package}/bin/status-notifier-watcher";
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "graphical-session.target" "taffybar.service" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -3,12 +3,6 @@
|
||||
with lib;
|
||||
|
||||
{
|
||||
imports = [
|
||||
(mkRenamedOptionModule
|
||||
[ "services" "qsyncthingtray" "enable" ]
|
||||
[ "services" "syncthing" "tray" ])
|
||||
];
|
||||
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
@@ -60,6 +54,7 @@ with lib;
|
||||
};
|
||||
|
||||
Service = {
|
||||
Environment = "PATH=${config.home.profileDirectory}/bin";
|
||||
ExecStart = "${pkgs.qsyncthingtray}/bin/QSyncthingTray";
|
||||
};
|
||||
|
||||
|
||||
@@ -27,19 +27,19 @@ in
|
||||
|
||||
config = mkIf config.services.taffybar.enable {
|
||||
systemd.user.services.taffybar = {
|
||||
Unit = {
|
||||
Description = "Taffybar desktop bar";
|
||||
After = [ "graphical-session-pre.target" ];
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
};
|
||||
Unit = {
|
||||
Description = "Taffybar desktop bar";
|
||||
After = [ "graphical-session-pre.target" ];
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = "${cfg.package}/bin/taffybar";
|
||||
};
|
||||
Service = {
|
||||
ExecStart = "${cfg.package}/bin/taffybar";
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ let
|
||||
(if cfg.notify then "n" else "N")
|
||||
({ always = "t"; auto = "s"; never = "T"; }.${cfg.tray})
|
||||
]
|
||||
++ optional config.xsession.preferStatusNotifierItems "--appindicator"
|
||||
);
|
||||
|
||||
in
|
||||
@@ -20,6 +21,16 @@ in
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
imports = [
|
||||
(mkRemovedOptionModule [ "services" "udiskie" "sni" ] ''
|
||||
Support for Status Notifier Items is now configured globally through the
|
||||
|
||||
xsession.preferStatusNotifierItems
|
||||
|
||||
option. Please change to use that instead.
|
||||
'')
|
||||
];
|
||||
|
||||
options = {
|
||||
services.udiskie = {
|
||||
enable = mkEnableOption "udiskie mount daemon";
|
||||
@@ -73,7 +84,7 @@ in
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = "${pkgs.pythonPackages.udiskie}/bin/udiskie -2 ${commandArgs}";
|
||||
ExecStart = "${pkgs.udiskie}/bin/udiskie -2 ${commandArgs}";
|
||||
};
|
||||
|
||||
Install = {
|
||||
|
||||
63
modules/services/unclutter.nix
Normal file
63
modules/services/unclutter.nix
Normal file
@@ -0,0 +1,63 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let cfg = config.services.unclutter;
|
||||
|
||||
in {
|
||||
options.services.unclutter = {
|
||||
|
||||
enable = mkEnableOption "unclutter";
|
||||
|
||||
package = mkOption {
|
||||
description = "unclutter derivation to use.";
|
||||
type = types.package;
|
||||
default = pkgs.unclutter-xfixes;
|
||||
defaultText = "pkgs.unclutter-xfixes";
|
||||
};
|
||||
|
||||
timeout = mkOption {
|
||||
description = "Number of seconds before the cursor is marked inactive.";
|
||||
type = types.int;
|
||||
default = 1;
|
||||
};
|
||||
|
||||
threshold = mkOption {
|
||||
description = "Minimum number of pixels considered cursor movement.";
|
||||
type = types.int;
|
||||
default = 1;
|
||||
};
|
||||
|
||||
extraOptions = mkOption {
|
||||
description = "More arguments to pass to the unclutter command.";
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
example = [ "exclude-root" "ignore-scrolling" ];
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.user.services.unclutter = {
|
||||
Unit = {
|
||||
Description = "unclutter";
|
||||
After = [ "graphical-session-pre.target" ];
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = ''
|
||||
${cfg.package}/bin/unclutter \
|
||||
--timeout ${toString cfg.timeout} \
|
||||
--jitter ${toString (cfg.threshold - 1)} \
|
||||
${concatMapStrings (x: " --${x}") cfg.extraOptions}
|
||||
'';
|
||||
RestartSec = 3;
|
||||
Restart = "always";
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
57
modules/services/window-managers/awesome.nix
Normal file
57
modules/services/window-managers/awesome.nix
Normal file
@@ -0,0 +1,57 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.xsession.windowManager.awesome;
|
||||
awesome = cfg.package;
|
||||
getLuaPath = lib: dir: "${lib}/${dir}/lua/${pkgs.luaPackages.lua.luaversion}";
|
||||
makeSearchPath = lib.concatMapStrings (path:
|
||||
" --search ${getLuaPath path "share"}"
|
||||
+ " --search ${getLuaPath path "lib"}"
|
||||
);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
xsession.windowManager.awesome = {
|
||||
enable = mkEnableOption "Awesome window manager.";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.awesome;
|
||||
defaultText = "pkgs.awesome";
|
||||
description = "Package to use for running the Awesome WM.";
|
||||
};
|
||||
|
||||
luaModules = mkOption {
|
||||
default = [];
|
||||
type = types.listOf types.package;
|
||||
description = ''
|
||||
List of lua packages available for being
|
||||
used in the Awesome configuration.
|
||||
'';
|
||||
example = literalExample "[ luaPackages.oocairo ]";
|
||||
};
|
||||
|
||||
noArgb = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Disable client transparency support, which can be greatly
|
||||
detrimental to performance in some setups
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ awesome ];
|
||||
xsession.windowManager.command =
|
||||
"${awesome}/bin/awesome "
|
||||
+ optionalString cfg.noArgb "--no-argb "
|
||||
+ makeSearchPath cfg.luaModules;
|
||||
};
|
||||
}
|
||||
@@ -6,7 +6,17 @@ let
|
||||
|
||||
cfg = config.xsession.windowManager.i3;
|
||||
|
||||
dag = config.lib.dag;
|
||||
commonOptions = {
|
||||
fonts = mkOption {
|
||||
type = types.listOf types.string;
|
||||
default = ["monospace 8"];
|
||||
description = ''
|
||||
Font list used for window titles. Only FreeType fonts are supported.
|
||||
The order here is improtant (e.g. icons font should go before the one used for text).
|
||||
'';
|
||||
example = [ "FontAwesome 10" "Terminus 10" ];
|
||||
};
|
||||
};
|
||||
|
||||
startupModule = types.submodule {
|
||||
options = {
|
||||
@@ -33,7 +43,30 @@ let
|
||||
workspace = mkOption {
|
||||
type = types.nullOr types.string;
|
||||
default = null;
|
||||
description = "Launch application on a particular workspace.";
|
||||
description = ''
|
||||
Launch application on a particular workspace. DEPRECATED:
|
||||
Use <varname><link linkend="opt-xsession.windowManager.i3.config.assigns">xsession.windowManager.i3.config.assigns</link></varname>
|
||||
instead. See <link xlink:href="https://github.com/rycee/home-manager/issues/265"/>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
barColorSetModule = types.submodule {
|
||||
options = {
|
||||
border = mkOption {
|
||||
type = types.string;
|
||||
visible = false;
|
||||
};
|
||||
|
||||
background = mkOption {
|
||||
type = types.string;
|
||||
visible = false;
|
||||
};
|
||||
|
||||
text = mkOption {
|
||||
type = types.string;
|
||||
visible = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -69,6 +102,18 @@ let
|
||||
|
||||
barModule = types.submodule {
|
||||
options = {
|
||||
inherit (commonOptions) fonts;
|
||||
|
||||
id = mkOption {
|
||||
type = types.nullOr types.string;
|
||||
default = null;
|
||||
description = ''
|
||||
Specifies the bar ID for the configured bar instance.
|
||||
If this option is missing, the ID is set to bar-x, where x corresponds
|
||||
to the position of the embedding bar block in the config file.
|
||||
'';
|
||||
};
|
||||
|
||||
mode = mkOption {
|
||||
type = types.enum [ "dock" "hide" "invisible" ];
|
||||
default = "dock";
|
||||
@@ -93,12 +138,98 @@ let
|
||||
description = "Whether workspace buttons should be shown or not.";
|
||||
};
|
||||
|
||||
workspaceNumbers = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Whether workspace numbers should be displayed within the workspace buttons.";
|
||||
};
|
||||
|
||||
command = mkOption {
|
||||
type = types.string;
|
||||
default = "${cfg.package}/bin/i3bar";
|
||||
defaultText = "i3bar";
|
||||
description = "Command that will be used to start a bar.";
|
||||
example = "\${pkgs.i3-gaps}/bin/i3bar -t";
|
||||
};
|
||||
|
||||
statusCommand = mkOption {
|
||||
type = types.string;
|
||||
default = "${pkgs.i3status}/bin/i3status";
|
||||
description = "Command that will be used to get status lines.";
|
||||
};
|
||||
|
||||
colors = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
background = mkOption {
|
||||
type = types.string;
|
||||
default = "#000000";
|
||||
description = "Background color of the bar.";
|
||||
};
|
||||
|
||||
statusline = mkOption {
|
||||
type = types.string;
|
||||
default = "#ffffff";
|
||||
description = "Text color to be used for the statusline.";
|
||||
};
|
||||
|
||||
separator = mkOption {
|
||||
type = types.string;
|
||||
default = "#666666";
|
||||
description = "Text color to be used for the separator.";
|
||||
};
|
||||
|
||||
focusedWorkspace = mkOption {
|
||||
type = barColorSetModule;
|
||||
default = { border = "#4c7899"; background = "#285577"; text = "#ffffff"; };
|
||||
description = ''
|
||||
Border, background and text color for a workspace button when the workspace has focus.
|
||||
'';
|
||||
};
|
||||
|
||||
activeWorkspace = mkOption {
|
||||
type = barColorSetModule;
|
||||
default = { border = "#333333"; background = "#5f676a"; text = "#ffffff"; };
|
||||
description = ''
|
||||
Border, background and text color for a workspace button when the workspace is active.
|
||||
'';
|
||||
};
|
||||
|
||||
inactiveWorkspace = mkOption {
|
||||
type = barColorSetModule;
|
||||
default = { border = "#333333"; background = "#222222"; text = "#888888"; };
|
||||
description = ''
|
||||
Border, background and text color for a workspace button when the workspace does not
|
||||
have focus and is not active.
|
||||
'';
|
||||
};
|
||||
|
||||
urgentWorkspace = mkOption {
|
||||
type = barColorSetModule;
|
||||
default = { border = "#2f343a"; background = "#900000"; text = "#ffffff"; };
|
||||
description = ''
|
||||
Border, background and text color for a workspace button when the workspace contains
|
||||
a window with the urgency hint set.
|
||||
'';
|
||||
};
|
||||
|
||||
bindingMode = mkOption {
|
||||
type = barColorSetModule;
|
||||
default = { border = "#2f343a"; background = "#900000"; text = "#ffffff"; };
|
||||
description = "Border, background and text color for the binding mode indicator";
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = ''
|
||||
Bar color settings. All color classes can be specified using submodules
|
||||
with 'border', 'background', 'text', fields and RGB color hex-codes as values.
|
||||
See default values for the reference.
|
||||
Note that 'background', 'status', and 'separator' parameters take a single RGB value.
|
||||
|
||||
See <link xlink:href="https://i3wm.org/docs/userguide.html#_colors"/>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -122,15 +253,7 @@ let
|
||||
|
||||
configModule = types.submodule {
|
||||
options = {
|
||||
fonts = mkOption {
|
||||
type = types.listOf types.string;
|
||||
default = ["monospace 8"];
|
||||
description = ''
|
||||
Font list used for window titles. Only FreeType fonts are supported.
|
||||
The order here is improtant (e.g. icons font should go before the one used for text).
|
||||
'';
|
||||
example = [ "FontAwesome 10" "Terminus 10" ];
|
||||
};
|
||||
inherit (commonOptions) fonts;
|
||||
|
||||
window = mkOption {
|
||||
type = types.submodule {
|
||||
@@ -187,7 +310,8 @@ let
|
||||
|
||||
modifier = mkOption {
|
||||
type = types.enum [ "Shift" "Control" "Mod1" "Mod2" "Mod3" "Mod4" "Mod5" ];
|
||||
default = "Mod1";
|
||||
default = cfg.config.modifier;
|
||||
defaultText = "i3.config.modifier";
|
||||
description = "Modifier key that can be used to drag floating windows.";
|
||||
example = "Mod4";
|
||||
};
|
||||
@@ -252,7 +376,7 @@ let
|
||||
type = types.attrsOf (types.listOf criteriaModule);
|
||||
default = {};
|
||||
description = ''
|
||||
An attribute set that assignes applications to workspaces based
|
||||
An attribute set that assigns applications to workspaces based
|
||||
on criteria.
|
||||
'';
|
||||
example = literalExample ''
|
||||
@@ -263,64 +387,84 @@ let
|
||||
'';
|
||||
};
|
||||
|
||||
modifier = mkOption {
|
||||
type = types.enum [ "Shift" "Control" "Mod1" "Mod2" "Mod3" "Mod4" "Mod5" ];
|
||||
default = "Mod1";
|
||||
description = "Modifier key that is used for all default keybindings.";
|
||||
example = "Mod4";
|
||||
};
|
||||
|
||||
keybindings = mkOption {
|
||||
type = types.attrs;
|
||||
default = {
|
||||
"Mod1+Return" = "exec i3-sensible-terminal";
|
||||
"Mod1+Shift+q" = "kill";
|
||||
"Mod1+d" = "exec ${pkgs.dmenu}/bin/dmenu_run";
|
||||
"${cfg.config.modifier}+Return" = "exec i3-sensible-terminal";
|
||||
"${cfg.config.modifier}+Shift+q" = "kill";
|
||||
"${cfg.config.modifier}+d" = "exec ${pkgs.dmenu}/bin/dmenu_run";
|
||||
|
||||
"Mod1+Left" = "focus left";
|
||||
"Mod1+Down" = "focus down";
|
||||
"Mod1+Up" = "focus up";
|
||||
"Mod1+Right" = "focus right";
|
||||
"${cfg.config.modifier}+Left" = "focus left";
|
||||
"${cfg.config.modifier}+Down" = "focus down";
|
||||
"${cfg.config.modifier}+Up" = "focus up";
|
||||
"${cfg.config.modifier}+Right" = "focus right";
|
||||
|
||||
"Mod1+h" = "split h";
|
||||
"Mod1+v" = "split v";
|
||||
"Mod1+f" = "fullscreen toggle";
|
||||
"${cfg.config.modifier}+Shift+Left" = "move left";
|
||||
"${cfg.config.modifier}+Shift+Down" = "move down";
|
||||
"${cfg.config.modifier}+Shift+Up" = "move up";
|
||||
"${cfg.config.modifier}+Shift+Right" = "move right";
|
||||
|
||||
"Mod1+s" = "layout stacking";
|
||||
"Mod1+w" = "layout tabbed";
|
||||
"Mod1+e" = "layout toggle split";
|
||||
"${cfg.config.modifier}+h" = "split h";
|
||||
"${cfg.config.modifier}+v" = "split v";
|
||||
"${cfg.config.modifier}+f" = "fullscreen toggle";
|
||||
|
||||
"Mod1+Shift+space" = "floating toggle";
|
||||
"${cfg.config.modifier}+s" = "layout stacking";
|
||||
"${cfg.config.modifier}+w" = "layout tabbed";
|
||||
"${cfg.config.modifier}+e" = "layout toggle split";
|
||||
|
||||
"Mod1+1" = "workspace 1";
|
||||
"Mod1+2" = "workspace 2";
|
||||
"Mod1+3" = "workspace 3";
|
||||
"Mod1+4" = "workspace 4";
|
||||
"Mod1+5" = "workspace 5";
|
||||
"Mod1+6" = "workspace 6";
|
||||
"Mod1+7" = "workspace 7";
|
||||
"Mod1+8" = "workspace 8";
|
||||
"Mod1+9" = "workspace 9";
|
||||
"${cfg.config.modifier}+Shift+space" = "floating toggle";
|
||||
"${cfg.config.modifier}+space" = "focus mode_toggle";
|
||||
|
||||
"Mod1+Shift+1" = "move container to workspace 1";
|
||||
"Mod1+Shift+2" = "move container to workspace 2";
|
||||
"Mod1+Shift+3" = "move container to workspace 3";
|
||||
"Mod1+Shift+4" = "move container to workspace 4";
|
||||
"Mod1+Shift+5" = "move container to workspace 5";
|
||||
"Mod1+Shift+6" = "move container to workspace 6";
|
||||
"Mod1+Shift+7" = "move container to workspace 7";
|
||||
"Mod1+Shift+8" = "move container to workspace 8";
|
||||
"Mod1+Shift+9" = "move container to workspace 9";
|
||||
"${cfg.config.modifier}+1" = "workspace 1";
|
||||
"${cfg.config.modifier}+2" = "workspace 2";
|
||||
"${cfg.config.modifier}+3" = "workspace 3";
|
||||
"${cfg.config.modifier}+4" = "workspace 4";
|
||||
"${cfg.config.modifier}+5" = "workspace 5";
|
||||
"${cfg.config.modifier}+6" = "workspace 6";
|
||||
"${cfg.config.modifier}+7" = "workspace 7";
|
||||
"${cfg.config.modifier}+8" = "workspace 8";
|
||||
"${cfg.config.modifier}+9" = "workspace 9";
|
||||
|
||||
"Mod1+Shift+c" = "reload";
|
||||
"Mod1+Shift+r" = "restart";
|
||||
"Mod1+Shift+e" = "exec i3-nagbar -t warning -m 'Do you want to exit i3?' -b 'Yes' 'i3-msg exit'";
|
||||
"${cfg.config.modifier}+Shift+1" = "move container to workspace 1";
|
||||
"${cfg.config.modifier}+Shift+2" = "move container to workspace 2";
|
||||
"${cfg.config.modifier}+Shift+3" = "move container to workspace 3";
|
||||
"${cfg.config.modifier}+Shift+4" = "move container to workspace 4";
|
||||
"${cfg.config.modifier}+Shift+5" = "move container to workspace 5";
|
||||
"${cfg.config.modifier}+Shift+6" = "move container to workspace 6";
|
||||
"${cfg.config.modifier}+Shift+7" = "move container to workspace 7";
|
||||
"${cfg.config.modifier}+Shift+8" = "move container to workspace 8";
|
||||
"${cfg.config.modifier}+Shift+9" = "move container to workspace 9";
|
||||
|
||||
"Mod1+r" = "mode resize";
|
||||
"${cfg.config.modifier}+Shift+c" = "reload";
|
||||
"${cfg.config.modifier}+Shift+r" = "restart";
|
||||
"${cfg.config.modifier}+Shift+e" = "exec i3-nagbar -t warning -m 'Do you want to exit i3?' -b 'Yes' 'i3-msg exit'";
|
||||
|
||||
"${cfg.config.modifier}+r" = "mode resize";
|
||||
};
|
||||
defaultText = "Default i3 keybindings.";
|
||||
description = ''
|
||||
An attribute set that assignes key press to an action using key symbol.
|
||||
An attribute set that assigns a key press to an action using a key symbol.
|
||||
See <link xlink:href="https://i3wm.org/docs/userguide.html#keybindings"/>.
|
||||
</para><para>
|
||||
Consider to use <code>lib.mkOptionDefault</code> function to extend or override
|
||||
default keybindings instead of specifying all of them from scratch.
|
||||
'';
|
||||
example = literalExample ''
|
||||
{
|
||||
"Mod1+Return" = "exec i3-sensible-terminal";
|
||||
"Mod1+Shift+q" = "kill";
|
||||
"Mod1+d" = "exec ${pkgs.dmenu}/bin/dmenu_run";
|
||||
let
|
||||
modifier = xsession.windowManager.i3.config.modifier;
|
||||
in
|
||||
|
||||
lib.mkOptionDefault {
|
||||
"''${modifier}+Return" = "exec i3-sensible-terminal";
|
||||
"''${modifier}+Shift+q" = "kill";
|
||||
"''${modifier}+d" = "exec \${pkgs.dmenu}/bin/dmenu_run";
|
||||
}
|
||||
'';
|
||||
};
|
||||
@@ -329,7 +473,7 @@ let
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = ''
|
||||
An attribute set that assignes keypress to an action using key code.
|
||||
An attribute set that assigns keypress to an action using key code.
|
||||
See <link xlink:href="https://i3wm.org/docs/userguide.html#keybindings"/>.
|
||||
'';
|
||||
example = { "214" = "exec --no-startup-id /bin/script.sh"; };
|
||||
@@ -503,14 +647,15 @@ let
|
||||
};
|
||||
|
||||
keybindingsStr = keybindings: concatStringsSep "\n" (
|
||||
mapAttrsToList (keycomb: action: "bindsym ${keycomb} ${action}") keybindings
|
||||
mapAttrsToList (keycomb: action: optionalString (action != null) "bindsym ${keycomb} ${action}") keybindings
|
||||
);
|
||||
|
||||
keycodebindingsStr = keycodebindings: concatStringsSep "\n" (
|
||||
mapAttrsToList (keycomb: action: "bindcode ${keycomb} ${action}") keycodebindings
|
||||
mapAttrsToList (keycomb: action: optionalString (action != null) "bindcode ${keycomb} ${action}") keycodebindings
|
||||
);
|
||||
|
||||
colorSetStr = c: concatStringsSep " " [ c.border c.background c.text c.indicator c.childBorder ];
|
||||
barColorSetStr = c: concatStringsSep " " [ c.border c.background c.text ];
|
||||
|
||||
criteriaStr = criteria: "[${concatStringsSep " " (mapAttrsToList (k: v: ''${k}="${v}"'') criteria)}]";
|
||||
|
||||
@@ -524,13 +669,30 @@ let
|
||||
map (c: "assign ${criteriaStr c} ${workspace}") criteria
|
||||
);
|
||||
|
||||
barStr = { mode, hiddenState, position, workspaceButtons, statusCommand, ... }: ''
|
||||
barStr = {
|
||||
id, fonts, mode, hiddenState, position, workspaceButtons,
|
||||
workspaceNumbers, command, statusCommand, colors, ...
|
||||
}: ''
|
||||
bar {
|
||||
${optionalString (id != null) "id ${id}"}
|
||||
font pango:${concatStringsSep ", " fonts}
|
||||
mode ${mode}
|
||||
hidden_state ${hiddenState}
|
||||
position ${position}
|
||||
status_command ${statusCommand}
|
||||
i3bar_command ${command}
|
||||
workspace_buttons ${if workspaceButtons then "yes" else "no"}
|
||||
strip_workspace_numbers ${if !workspaceNumbers then "yes" else "no"}
|
||||
colors {
|
||||
background ${colors.background}
|
||||
statusline ${colors.statusline}
|
||||
separator ${colors.separator}
|
||||
focused_workspace ${barColorSetStr colors.focusedWorkspace}
|
||||
active_workspace ${barColorSetStr colors.activeWorkspace}
|
||||
inactive_workspace ${barColorSetStr colors.inactiveWorkspace}
|
||||
urgent_workspace ${barColorSetStr colors.urgentWorkspace}
|
||||
binding_mode ${barColorSetStr colors.bindingMode}
|
||||
}
|
||||
}
|
||||
'';
|
||||
|
||||
@@ -620,22 +782,16 @@ in
|
||||
{
|
||||
home.packages = [ cfg.package ];
|
||||
xsession.windowManager.command = "${cfg.package}/bin/i3";
|
||||
xdg.configFile."i3/config".source = configFile;
|
||||
|
||||
home.activation.checkI3 = dag.entryBefore [ "linkGeneration" ] ''
|
||||
if ! cmp --quiet \
|
||||
"${configFile}" \
|
||||
"${config.xdg.configHome}/i3/config"; then
|
||||
i3Changed=1
|
||||
fi
|
||||
'';
|
||||
|
||||
home.activation.reloadI3 = dag.entryAfter [ "linkGeneration" ] ''
|
||||
if [[ -v i3Changed && -v DISPLAY ]]; then
|
||||
echo "Reloading i3"
|
||||
${cfg.package}/bin/i3-msg reload 1>/dev/null
|
||||
fi
|
||||
'';
|
||||
xdg.configFile."i3/config" = {
|
||||
source = configFile;
|
||||
onChange = ''
|
||||
i3Socket=''${XDG_RUNTIME_DIR:-/run/user/$UID}/i3/ipc-socket.*
|
||||
if [ -S $i3Socket ]; then
|
||||
echo "Reloading i3"
|
||||
$DRY_RUN_CMD ${cfg.package}/bin/i3-msg -s $i3Socket reload 1>/dev/null
|
||||
fi
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
(mkIf (cfg.config != null) {
|
||||
@@ -643,5 +799,13 @@ in
|
||||
if (cfg.config.gaps != null) then pkgs.i3-gaps else pkgs.i3
|
||||
);
|
||||
})
|
||||
|
||||
(mkIf (cfg.config != null && (any (s: s.workspace != null) cfg.config.startup)) {
|
||||
warnings = [
|
||||
("'xsession.windowManager.i3.config.startup.*.workspace' is deprecated, "
|
||||
+ "use 'xsession.windowManager.i3.config.assigns' instead."
|
||||
+ "See https://github.com/rycee/home-manager/issues/265.")
|
||||
];
|
||||
})
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ let
|
||||
|
||||
cfg = config.xsession.windowManager.xmonad;
|
||||
|
||||
dag = config.lib.dag;
|
||||
|
||||
xmonad = pkgs.xmonad-with-packages.override {
|
||||
ghcWithPackages = cfg.haskellPackages.ghcWithPackages;
|
||||
packages = self:
|
||||
@@ -90,23 +88,14 @@ in
|
||||
|
||||
(mkIf (cfg.config != null) {
|
||||
home.file.".xmonad/xmonad.hs".source = cfg.config;
|
||||
home.file.".xmonad/xmonad.hs".onChange = ''
|
||||
echo "Recompiling xmonad"
|
||||
$DRY_RUN_CMD ${config.xsession.windowManager.command} --recompile
|
||||
|
||||
home.activation.checkXmonad = dag.entryBefore [ "linkGeneration" ] ''
|
||||
if ! cmp --quiet "${cfg.config}" "$HOME/.xmonad/xmonad.hs"; then
|
||||
xmonadChanged=1
|
||||
fi
|
||||
'';
|
||||
|
||||
home.activation.applyXmonad = dag.entryAfter [ "linkGeneration" ] ''
|
||||
if [[ -v xmonadChanged ]]; then
|
||||
echo "Recompiling xmonad"
|
||||
${config.xsession.windowManager.command} --recompile
|
||||
|
||||
# Attempt to restart xmonad if X is running.
|
||||
if [[ -v DISPLAY ]] ; then
|
||||
echo "Restarting xmonad"
|
||||
${config.xsession.windowManager.command} --restart
|
||||
fi
|
||||
# Attempt to restart xmonad if X is running.
|
||||
if [[ -v DISPLAY ]] ; then
|
||||
echo "Restarting xmonad"
|
||||
$DRY_RUN_CMD ${config.xsession.windowManager.command} --restart
|
||||
fi
|
||||
'';
|
||||
})
|
||||
|
||||
@@ -12,6 +12,9 @@ with lib;
|
||||
};
|
||||
|
||||
config = mkIf config.services.xscreensaver.enable {
|
||||
# To make the xscreensaver-command tool available.
|
||||
home.packages = [ pkgs.xscreensaver ];
|
||||
|
||||
systemd.user.services.xscreensaver = {
|
||||
Unit = {
|
||||
Description = "XScreenSaver";
|
||||
|
||||
@@ -14,7 +14,7 @@ UnitsDir = 'home-files/.config/systemd/user'
|
||||
# that failed to start. This helps debugging quickly failing services.
|
||||
#
|
||||
# Whenever service failures are detected, show the output of
|
||||
# 'systemd --home status' for the affected services.
|
||||
# 'systemd --user status' for the affected services.
|
||||
#
|
||||
def setup_services(old_gen_path, new_gen_path, start_timeout_ms_string)
|
||||
start_timeout_ms = start_timeout_ms_string.to_i
|
||||
@@ -27,6 +27,7 @@ def setup_services(old_gen_path, new_gen_path, start_timeout_ms_string)
|
||||
|
||||
exit if old_services.empty? && new_services.empty?
|
||||
|
||||
# These services should be running when this script is finished
|
||||
services_to_run = get_services_to_run(new_units_path)
|
||||
maybe_changed_services = services_to_run & old_services
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ let
|
||||
enabled = cfg.services != {}
|
||||
|| cfg.sockets != {}
|
||||
|| cfg.targets != {}
|
||||
|| cfg.timers != {};
|
||||
|| cfg.timers != {}
|
||||
|| cfg.paths != {};
|
||||
|
||||
toSystemdIni = generators.toINI {
|
||||
mkKeyValue = key: value:
|
||||
@@ -50,6 +51,10 @@ let
|
||||
|
||||
servicesStartTimeoutMs = builtins.toString cfg.servicesStartTimeoutMs;
|
||||
|
||||
attrsRecursivelyMerged = types.attrs // {
|
||||
merge = loc: foldl' (res: def: recursiveUpdate res def.value) {};
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
@@ -70,26 +75,47 @@ in
|
||||
|
||||
services = mkOption {
|
||||
default = {};
|
||||
type = types.attrs;
|
||||
description = "Definition of systemd per-user service units.";
|
||||
type = attrsRecursivelyMerged;
|
||||
description = ''
|
||||
Definition of systemd per-user service units. Attributes are
|
||||
merged recursively.
|
||||
'';
|
||||
};
|
||||
|
||||
sockets = mkOption {
|
||||
default = {};
|
||||
type = types.attrs;
|
||||
description = "Definition of systemd per-user sockets";
|
||||
type = attrsRecursivelyMerged;
|
||||
description = ''
|
||||
Definition of systemd per-user sockets. Attributes are
|
||||
merged recursively.
|
||||
'';
|
||||
};
|
||||
|
||||
targets = mkOption {
|
||||
default = {};
|
||||
type = types.attrs;
|
||||
description = "Definition of systemd per-user targets";
|
||||
type = attrsRecursivelyMerged;
|
||||
description = ''
|
||||
Definition of systemd per-user targets. Attributes are
|
||||
merged recursively.
|
||||
'';
|
||||
};
|
||||
|
||||
timers = mkOption {
|
||||
default = {};
|
||||
type = types.attrs;
|
||||
description = "Definition of systemd per-user timers";
|
||||
type = attrsRecursivelyMerged;
|
||||
description = ''
|
||||
Definition of systemd per-user timers. Attributes are merged
|
||||
recursively.
|
||||
'';
|
||||
};
|
||||
|
||||
paths = mkOption {
|
||||
default = {};
|
||||
type = attrsRecursivelyMerged;
|
||||
description = ''
|
||||
Definition of systemd per-user path units. Attributes are
|
||||
merged recursively.
|
||||
'';
|
||||
};
|
||||
|
||||
startServices = mkOption {
|
||||
@@ -122,7 +148,7 @@ in
|
||||
let
|
||||
names = concatStringsSep ", " (
|
||||
attrNames (
|
||||
cfg.services // cfg.sockets // cfg.targets // cfg.timers
|
||||
cfg.services // cfg.sockets // cfg.targets // cfg.timers // cfg.paths
|
||||
)
|
||||
);
|
||||
in
|
||||
@@ -143,6 +169,8 @@ in
|
||||
(buildServices "target" cfg.targets)
|
||||
++
|
||||
(buildServices "timer" cfg.timers)
|
||||
++
|
||||
(buildServices "path" cfg.paths)
|
||||
);
|
||||
|
||||
# Run systemd service reload if user is logged in. If we're
|
||||
@@ -159,14 +187,16 @@ in
|
||||
legacyReloadCmd = ''
|
||||
bash ${./systemd-activate.sh} "''${oldGenPath=}" "$newGenPath"
|
||||
'';
|
||||
|
||||
ensureRuntimeDir = "XDG_RUNTIME_DIR=\${XDG_RUNTIME_DIR:-/run/user/$(id -u)}";
|
||||
in
|
||||
''
|
||||
if who | grep -q '^${config.home.username} '; then
|
||||
XDG_RUNTIME_DIR=''${XDG_RUNTIME_DIR:-/run/user/$(id -u)} \
|
||||
if ${ensureRuntimeDir} ${cfg.systemctlPath} --quiet --user is-system-running 2> /dev/null; then
|
||||
${ensureRuntimeDir} \
|
||||
PATH=${dirOf cfg.systemctlPath}:$PATH \
|
||||
${if cfg.startServices then autoReloadCmd else legacyReloadCmd}
|
||||
else
|
||||
echo "User ${config.home.username} not logged in. Skipping."
|
||||
echo "User systemd daemon not running. Skipping reload."
|
||||
fi
|
||||
''
|
||||
);
|
||||
|
||||
@@ -26,6 +26,13 @@ let
|
||||
example = 64;
|
||||
description = "The cursor size.";
|
||||
};
|
||||
|
||||
defaultCursor = mkOption {
|
||||
type = types.str;
|
||||
default = "left_ptr";
|
||||
example = "X_cursor";
|
||||
description = "The default cursor file to use within the package.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -54,7 +61,7 @@ in
|
||||
home.packages = [cfg.package];
|
||||
|
||||
xsession.initExtra = ''
|
||||
${pkgs.xorg.xsetroot}/bin/xsetroot -xcf ${cfg.package}/share/icons/${cfg.name}/cursors/X_cursor ${toString cfg.size}
|
||||
${pkgs.xorg.xsetroot}/bin/xsetroot -xcf ${cfg.package}/share/icons/${cfg.name}/cursors/${cfg.defaultCursor} ${toString cfg.size}
|
||||
'';
|
||||
|
||||
xresources.properties = {
|
||||
|
||||
@@ -8,11 +8,17 @@ let
|
||||
|
||||
formatLine = n: v:
|
||||
let
|
||||
v' =
|
||||
formatList = x:
|
||||
if isList x
|
||||
then throw "can not convert 2-dimensional lists to Xresources format"
|
||||
else formatValue x;
|
||||
|
||||
formatValue = v:
|
||||
if isBool v then (if v then "true" else "false")
|
||||
else if isList v then concatMapStringsSep ", " formatList v
|
||||
else toString v;
|
||||
in
|
||||
"${n}: ${v'}";
|
||||
"${n}: ${formatValue v}";
|
||||
|
||||
in
|
||||
|
||||
@@ -24,21 +30,56 @@ in
|
||||
type = types.nullOr types.attrs;
|
||||
default = null;
|
||||
example = {
|
||||
"XTerm*faceName" = "dejavu sans mono";
|
||||
"Emacs*toolBar" = 0;
|
||||
"XTerm*faceName" = "dejavu sans mono";
|
||||
"XTerm*charClass" = [ "37:48" "45-47:48" "58:48" "64:48" "126:48" ];
|
||||
};
|
||||
description = ''
|
||||
X server resources that should be set. If <code>null</code>,
|
||||
then this feature is disabled and no
|
||||
X server resources that should be set.
|
||||
Booleans are formatted as "true" or "false" respectively.
|
||||
List elements are recursively formatted as a string and joined by commas.
|
||||
All other values are directly formatted using builtins.toString.
|
||||
Note, that 2-dimensional lists are not supported and specifying one will throw an exception.
|
||||
If this and all other xresources options are
|
||||
<code>null</code>, then this feature is disabled and no
|
||||
<filename>~/.Xresources</filename> link is produced.
|
||||
'';
|
||||
};
|
||||
|
||||
xresources.extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = literalExample ''
|
||||
builtins.readFile (
|
||||
pkgs.fetchFromGitHub {
|
||||
owner = "solarized";
|
||||
repo = "xresources";
|
||||
rev = "025ceddbddf55f2eb4ab40b05889148aab9699fc";
|
||||
sha256 = "0lxv37gmh38y9d3l8nbnsm1mskcv10g3i83j0kac0a2qmypv1k9f";
|
||||
} + "/Xresources.dark"
|
||||
)
|
||||
'';
|
||||
description = ''
|
||||
Additional X server resources contents.
|
||||
If this and all other xresources options are
|
||||
<code>null</code>, then this feature is disabled and no
|
||||
<filename>~/.Xresources</filename> link is produced.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf (cfg.properties != null) {
|
||||
home.file.".Xresources".text =
|
||||
concatStringsSep "\n" (
|
||||
mapAttrsToList formatLine cfg.properties
|
||||
) + "\n";
|
||||
config = mkIf (cfg.properties != null || cfg.extraConfig != "") {
|
||||
home.file.".Xresources" = {
|
||||
text =
|
||||
concatStringsSep "\n" ([]
|
||||
++ optional (cfg.extraConfig != "") cfg.extraConfig
|
||||
++ optionals (cfg.properties != null) (mapAttrsToList formatLine cfg.properties)
|
||||
) + "\n";
|
||||
onChange = ''
|
||||
if [[ -v DISPLAY ]] ; then
|
||||
$DRY_RUN_CMD ${pkgs.xorg.xrdb}/bin/xrdb -merge $HOME/.Xresources
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,6 +15,16 @@ in
|
||||
xsession = {
|
||||
enable = mkEnableOption "X Session";
|
||||
|
||||
scriptPath = mkOption {
|
||||
type = types.str;
|
||||
default = ".xsession";
|
||||
example = ".xsession-hm";
|
||||
description = ''
|
||||
Path, relative <envar>HOME</envar>, where Home Manager
|
||||
should write the X session script.
|
||||
'';
|
||||
};
|
||||
|
||||
windowManager.command = mkOption {
|
||||
type = types.str;
|
||||
example = literalExample ''
|
||||
@@ -30,6 +40,17 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
preferStatusNotifierItems = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether tray applets should prefer using the Status Notifier
|
||||
Items (SNI) protocol, commonly called App Indicators. Note,
|
||||
not all tray applets or status bars support SNI.
|
||||
'';
|
||||
};
|
||||
|
||||
profileExtra = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
@@ -82,7 +103,7 @@ in
|
||||
};
|
||||
|
||||
home.file.".xprofile".text = ''
|
||||
. "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh"
|
||||
. "${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh"
|
||||
|
||||
if [[ -e "$HOME/.profile" ]]; then
|
||||
. "$HOME/.profile"
|
||||
@@ -106,7 +127,7 @@ in
|
||||
export HM_XPROFILE_SOURCED=1
|
||||
'';
|
||||
|
||||
home.file.".xsession" = {
|
||||
home.file.${cfg.scriptPath} = {
|
||||
executable = true;
|
||||
text = ''
|
||||
if [[ ! -v HM_XPROFILE_SOURCED ]]; then
|
||||
|
||||
@@ -36,6 +36,8 @@ in
|
||||
nameValuePair ("home-manager-${utils.escapeSystemdPath username}") {
|
||||
description = "Home Manager environment for ${username}";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "nix-daemon.socket" ];
|
||||
after = [ "nix-daemon.socket" ];
|
||||
|
||||
serviceConfig = {
|
||||
User = username;
|
||||
|
||||
Reference in New Issue
Block a user