Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions modules/programs/inkscape/config.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
config,
lib,
pkgs,
...
}:

let
xml = import ./xml.nix { inherit lib; };
xmlFormat = pkgs.formats.xml { };

cfg = config.programs.inkscape;

# Resolve a user-supplied value (either a store path or inline text) to a store path :0
toSource =
name: content:
if builtins.isPath content || lib.isStorePath content then content else pkgs.writeText name content;

# Build xdg.configFile entries from an attrsOf (either path lines) option.
mkConfigFiles =
subdir: items:
lib.mapAttrs' (
name: content: lib.nameValuePair "inkscape/${subdir}/${name}" { source = toSource name content; }
) items;

in
{
config = lib.mkIf cfg.enable {
home.packages = [ cfg.package ];

xdg.configFile = lib.mkMerge [
(lib.mkIf (cfg.settings != { }) {
"inkscape/preferences.xml".text = xml.preferencesToXml cfg.settings;
})

(lib.mkIf (cfg.keymap != { } || cfg.keymapSet != null) {
"inkscape/keys/default.xml".source = xmlFormat.generate "default.xml" (
if cfg.keymap != { } then
cfg.keymap
else
{
keys = {
"@name" = "default";
"xi:include" = {
"@href" = "${cfg.package}/share/inkscape/keys/${cfg.keymapSet}.xml";
"@xmlns:xi" = "http://www.w3.org/2001/XInclude";
};
};
}
);
})

(mkConfigFiles "templates" cfg.templates)
(mkConfigFiles "symbols" cfg.symbols)
(mkConfigFiles "palettes" cfg.colorPalettes)
(mkConfigFiles "paint" cfg.patterns)
(mkConfigFiles "filters" cfg.filters)
(mkConfigFiles "extensions" cfg.extensions)

(lib.listToAttrs (
map (
font: lib.nameValuePair "inkscape/fonts/${baseNameOf (toString font)}" { source = font; }
) cfg.fonts
))

(lib.mapAttrs' (
name: text: lib.nameValuePair "inkscape/fontscollections/${name}" { inherit text; }
) cfg.fontCollections)
];
};
}
245 changes: 245 additions & 0 deletions modules/programs/inkscape/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
{
lib,
pkgs,
...
}:

let
inherit (lib)
literalExpression
mkEnableOption
mkOption
mkPackageOption
types
;

xmlFormat = pkgs.formats.xml { };

in
{
meta.maintainers = with lib.maintainers; [ philocalyst ];

imports = [ ./config.nix ];

options.programs.inkscape = {
enable = mkEnableOption "Inkscape vector graphics editor";

package = mkPackageOption pkgs "inkscape" { };

settings = mkOption {
type = types.attrsOf xmlFormat.type;
default = { };
example = literalExpression ''
{
ui = {
"@theme" = "Adwaita";
"@iconset" = "multicolor";
};
"tools.nodes" = {
"@show_handles" = 1;
"@show_outline" = 0;
};
behavior = {
"@some_flag" = 0;
transforms = { "@transform" = 1; };
};
snap = { "@global" = 1; };
}
'';
description = ''
Preferences written to
{file}`$XDG_CONFIG_HOME/inkscape/preferences.xml`.

Each top-level attribute becomes a `<group id="…">` element under the
`<group id="preferences">` root. Within a group:

- Keys prefixed with `@` (e.g. `"@theme"`) become XML attributes.
- Plain keys whose values are attrsets become nested `<group>` children.

Consult your existing {file}`preferences.xml` or the
[Inkscape wiki](https://inkscape.org/doc/) for available group IDs
and attribute names.

::: {.note}
Inkscape overwrites {file}`preferences.xml` on exit. The file is a
read-only store symlink when managed by Home Manager; Inkscape will
log a warning but continue working, and settings are restored on
every `home-manager switch`.
:::
'';
};

keymapSet = mkOption {
type = types.nullOr (
types.enum [
"inkscape"
"inkscape-13"
"illustrator"
"xara"
"corel"
"default"
]
);
default = null;
example = "illustrator";
description = ''
Predefined keyboard shortcut set bundled with Inkscape to activate.
Writes {file}`$XDG_CONFIG_HOME/inkscape/keys/default.xml` with an
XInclude reference to the chosen keymap.

Ignored when {option}`programs.inkscape.keymapXml` is set.
'';
};

keymap = mkOption {
type = types.attrsOf xmlFormat.type;
default = { };
example = literalExpression ''
{
keys = {
"@name" = "default";
bind = [
{
"@key" = "F1";
"@action" = "select-tool";
"@display" = "true";
}
{
"@key" = "F2";
"@action" = "node-tool";
"@display" = "true";
}
];
};
}
'';
description = ''
Custom keyboard shortcut XML written verbatim to
{file}`$XDG_CONFIG_HOME/inkscape/keys/default.xml`.

Takes precedence over {option}`programs.inkscape.keymap`.
Same XML writing logic as settings.
'';
};

templates = mkOption {
type = types.attrsOf (types.either types.path types.lines);
default = { };
example = literalExpression ''
{ "my-a4.svg" = ./templates/my-a4.svg; }
'';
description = ''
SVG templates installed to
{file}`$XDG_CONFIG_HOME/inkscape/templates/`.
Appear in **File → New from Template**.
Each attribute name is the filename; the value is either a path or
inline text.
'';
};

symbols = mkOption {
type = types.attrsOf (types.either types.path types.lines);
default = { };
example = literalExpression ''
{ "my-icons.svg" = ./my-icons.svg; }
'';
description = ''
SVG files with symbol definitions installed to
{file}`$XDG_CONFIG_HOME/inkscape/symbols/`.
Appear as collections in **Object → Symbols**.
'';
};

colorPalettes = mkOption {
type = types.attrsOf (types.either types.path types.lines);
default = { };
example = literalExpression ''
{ "brand.gpl" = ./brand-colors.gpl; }
'';
description = ''
Palette files installed to
{file}`$XDG_CONFIG_HOME/inkscape/palettes/`.
Supported formats: SVG swatches, GIMP Palette (`.gpl`),
Adobe Swatch Exchange (`.ase`), Adobe Color Book (`.acb`).
Appear in the palette bar and **Object → Swatches**.
'';
};

patterns = mkOption {
type = types.attrsOf (types.either types.path types.lines);
default = { };
example = literalExpression ''
{ "hatching.svg" = ./hatching-patterns.svg; }
'';
description = ''
SVG files with pattern definitions installed to
{file}`$XDG_CONFIG_HOME/inkscape/paint/`.
Appear in the pattern dropdown in
**Object → Fill and Stroke**.
'';
};

filters = mkOption {
type = types.attrsOf (types.either types.path types.lines);
default = { };
example = literalExpression ''
{ "vintage.svg" = ./vintage-filters.svg; }
'';
description = ''
SVG files with filter effect definitions installed to
{file}`$XDG_CONFIG_HOME/inkscape/filters/`.
Appear under **Filters → Custom**.
'';
};

extensions = mkOption {
type = types.attrsOf (types.either types.path types.lines);
default = { };
example = literalExpression ''
{
"my-ext/my-ext.inx" = ./my-ext.inx;
"my-ext/my-ext.py" = ./my-ext.py;
}
'';
description = ''
Extension files installed to
{file}`$XDG_CONFIG_HOME/inkscape/extensions/`.
Prefix the attribute name with a subdirectory to group multi-file
extensions (e.g. `"my-ext/my-ext.inx"`).
'';
};

fonts = mkOption {
type = types.listOf types.path;
default = [ ];
example = literalExpression ''
[ "''${pkgs.inter}/share/fonts/truetype/inter/Inter-Regular.ttf" ]
'';
description = ''
Font files installed to
{file}`$XDG_CONFIG_HOME/inkscape/fonts/`.
Available inside Inkscape without a system-wide install.
'';
};

fontCollections = mkOption {
type = types.attrsOf types.lines;
default = { };
example = literalExpression ''
{
"design.txt" = '''
Inter
Roboto Mono
Source Sans Pro
''';
}
'';
description = ''
Font collection files installed to
{file}`$XDG_CONFIG_HOME/inkscape/fontscollections/`.
Each attribute name is the filename; the value is a
newline-separated list of font family names.
'';
};
};
}
39 changes: 39 additions & 0 deletions modules/programs/inkscape/xml.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{ lib }:

let
generateGroup =
name: value:
let
keys = builtins.attrNames value;
attrKeys = builtins.filter (k: lib.hasPrefix "@" k) keys;
childKeys = builtins.filter (k: !(lib.hasPrefix "@" k)) keys;

attrs = lib.concatStrings (
map (k: " ${builtins.substring 1 999 k}=\"${lib.escapeXML (toString value.${k})}\"") attrKeys
);

children = lib.concatStringsSep "\n" (map (k: " ${generateGroup k value.${k}}") childKeys);
in
if children == "" then
"<group id=\"${name}\"${attrs}/>"
else
"<group id=\"${name}\"${attrs}>\n${children}\n </group>";

in
{
# Render a settings attrset as a complete preferences.xml file.
preferencesToXml =
settings:
lib.concatStringsSep "\n" [
''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>''
"<!-- Generated by Home Manager — do not edit directly -->"
''<inkscape version="0.92.0+devel">''
''<group id="preferences">''
(lib.concatStringsSep "\n" (
lib.mapAttrsToList (name: value: " ${generateGroup name value}") settings
))
"</group>"
"</inkscape>"
""
];
}
6 changes: 6 additions & 0 deletions tests/modules/programs/inkscape/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
inkscape-settings = ./inkscape-settings.nix;
inkscape-keymap-predefined = ./inkscape-keymap-predefined.nix;
inkscape-keymap-custom-xml = ./inkscape-keymap-custom-xml.nix;
inkscape-content = ./inkscape-content.nix;
}
Loading