mirror of
https://github.com/nix-community/home-manager.git
synced 2025-03-31 04:04:32 +00:00
484 lines
17 KiB
Nix
484 lines
17 KiB
Nix
{ config, lib, pkgs, appName, package, modulePath, profilePath }:
|
||
|
||
with lib;
|
||
|
||
let
|
||
jsonFormat = pkgs.formats.json { };
|
||
|
||
# Map of nice field names to internal field names.
|
||
# This is intended to be exhaustive and should be
|
||
# updated at every version bump.
|
||
internalFieldNames = (genAttrs [
|
||
"name"
|
||
"isAppProvided"
|
||
"loadPath"
|
||
"updateInterval"
|
||
"updateURL"
|
||
"iconMapObj"
|
||
"metaData"
|
||
"orderHint"
|
||
"definedAliases"
|
||
"urls"
|
||
] (name: "_${name}")) // {
|
||
searchForm = "__searchForm";
|
||
};
|
||
|
||
# Convenience to specify absolute path to icon
|
||
iconUrl = icon:
|
||
if isPath icon || hasPrefix "/" icon then "file://${icon}" else icon;
|
||
|
||
processCustomEngineInput = input:
|
||
{
|
||
name = input.id;
|
||
} // (removeAttrs input [ "icon" ])
|
||
// optionalAttrs (input ? icon || input ? iconMapObj) {
|
||
iconMapObj = mapAttrs (name: iconUrl) ((optionalAttrs (input ? icon) {
|
||
# Convenience to specify single icon instead of map
|
||
"16" = input.icon;
|
||
}) // (input.iconMapObj or { }));
|
||
} // {
|
||
# Required for custom engine configurations, loadPaths
|
||
# are unique identifiers that are generally formatted
|
||
# like: [source]/path/to/engine.xml
|
||
loadPath = "[home-manager]/${
|
||
lib.showAttrPath (modulePath ++ [ "engines" input.id ])
|
||
}";
|
||
};
|
||
|
||
processEngineInput = id: input:
|
||
let
|
||
requiredInput = {
|
||
inherit id;
|
||
isAppProvided =
|
||
input.isAppProvided or (removeAttrs input [ "metaData" ] == { });
|
||
metaData = input.metaData or { };
|
||
};
|
||
in if requiredInput.isAppProvided then
|
||
requiredInput
|
||
else
|
||
pipe (input // requiredInput) [
|
||
migrateEngineToV11
|
||
migrateEngineToV12
|
||
processCustomEngineInput
|
||
];
|
||
|
||
buildEngineConfig = name: input:
|
||
mapAttrs' (name: value: {
|
||
name = internalFieldNames.${name} or name;
|
||
inherit value;
|
||
}) (processEngineInput name input);
|
||
|
||
sortEngineConfigs = configs:
|
||
let
|
||
buildEngineConfigWithOrder = order: id:
|
||
let
|
||
config = configs.${id} or {
|
||
inherit id;
|
||
_isAppProvided = true;
|
||
_metaData = { };
|
||
};
|
||
in config // { _metaData = config._metaData // { inherit order; }; };
|
||
|
||
engineConfigsWithoutOrder = attrValues (removeAttrs configs config.order);
|
||
|
||
sortedEngineConfigs = (imap buildEngineConfigWithOrder config.order)
|
||
++ engineConfigsWithoutOrder;
|
||
in sortedEngineConfigs;
|
||
|
||
engineInput = config.engines // {
|
||
# Infer config.default as an app provided
|
||
# engine if it's not in config.engines
|
||
${config.default} = config.engines.${config.default} or { };
|
||
} // {
|
||
${config.privateDefault} = config.engines.${config.privateDefault} or { };
|
||
};
|
||
|
||
settings = {
|
||
version = 12;
|
||
engines = sortEngineConfigs (mapAttrs buildEngineConfig engineInput);
|
||
|
||
metaData = optionalAttrs (config.default != null) {
|
||
defaultEngineId = config.default;
|
||
defaultEngineIdHash = "@hash@";
|
||
} // optionalAttrs (config.privateDefault != null) {
|
||
privateDefaultEngineId = config.privateDefault;
|
||
privateDefaultEngineIdHash = "@privateHash@";
|
||
} // {
|
||
useSavedOrder = config.order != [ ];
|
||
};
|
||
};
|
||
|
||
# Home Manager doesn't circumvent user consent and isn't acting
|
||
# maliciously. We're modifying the search outside of the browser, but
|
||
# a claim by Mozilla to remove this would be very anti-user, and
|
||
# is unlikely to be an issue for our use case.
|
||
disclaimer = "By modifying this file, I agree that I am doing so "
|
||
+ "only within @appName@ itself, using official, user-driven search "
|
||
+ "engine selection processes, and in a way which does not circumvent "
|
||
+ "user consent. I acknowledge that any attempt to change this file "
|
||
+ "from outside of @appName@ is a malicious act, and will be responded "
|
||
+ "to accordingly.";
|
||
|
||
salt = if config.default != null then
|
||
profilePath + config.default + disclaimer
|
||
else
|
||
null;
|
||
|
||
privateSalt = if config.privateDefault != null then
|
||
profilePath + config.privateDefault + disclaimer
|
||
else
|
||
null;
|
||
|
||
appNameVariable = if package == null then
|
||
"appName=${lib.escapeShellArg appName}"
|
||
else ''
|
||
applicationIni="$(find ${lib.escapeShellArg package} -maxdepth 3 -path ${
|
||
lib.escapeShellArg package
|
||
}'/lib/*/application.ini' -print -quit)"
|
||
if test -n "$applicationIni"; then
|
||
appName="$(sed -n 's/^Name=\(.*\)$/\1/p' "$applicationIni" | head -n1)"
|
||
else
|
||
appName=${lib.escapeShellArg appName}
|
||
fi
|
||
'';
|
||
|
||
file = pkgs.runCommand "search.json.mozlz4" {
|
||
nativeBuildInputs = with pkgs; [ mozlz4a openssl ];
|
||
json = builtins.toJSON settings;
|
||
inherit salt privateSalt;
|
||
} ''
|
||
${appNameVariable}
|
||
|
||
salt=''${salt//@appName@/"$appName"}
|
||
privateSalt=''${privateSalt//@appName@/"$appName"}
|
||
|
||
if [[ -n $salt ]]; then
|
||
export hash=$(echo -n "$salt" | openssl dgst -sha256 -binary | base64)
|
||
export privateHash=$(echo -n "$privateSalt" | openssl dgst -sha256 -binary | base64)
|
||
mozlz4a <(substituteStream json search.json.in --subst-var hash --subst-var privateHash) "$out"
|
||
else
|
||
mozlz4a <(echo "$json") "$out"
|
||
fi
|
||
'';
|
||
|
||
engineNameToId = {
|
||
# Derived from https://searchfox.org/mozilla-central/rev/e3f42ec9320748b2aab3d474d1e47075def9000c/services/settings/dumps/main/search-config-v2.json
|
||
"1&1 Suche" = "1und1";
|
||
"Allegro" = "allegro-pl";
|
||
"Amazon.co.jp" = "amazon-jp";
|
||
"Amazon.com" = "amazondotcom-us";
|
||
"Azerdict" = "azerdict";
|
||
"百度" = "baidu";
|
||
"Bing" = "bing";
|
||
"Ordbok" = "bok-NO";
|
||
"Ceneje.si" = "ceneji";
|
||
"Cốc Cốc" = "coccoc";
|
||
"다음" = "daum-kr";
|
||
"DuckDuckGo" = "ddg";
|
||
"eBay" = "ebay";
|
||
"Ecosia" = "ecosia";
|
||
"EUdict Eng->Cro" = "eudict";
|
||
"Am Faclair Beag" = "faclair-beag";
|
||
"GMX Suche" = "gmx-de";
|
||
"GMX Search" = "gmx-en-GB";
|
||
"GMX - Búsqueda web" = "gmx-es";
|
||
"GMX - Recherche web" = "gmx-fr";
|
||
"GMX Shopping" = "gmx-shopping";
|
||
"Google" = "google";
|
||
"Gule sider" = "gulesider-NO";
|
||
"LEO Eng-Deu" = "leo_ende_de";
|
||
"พจนานุกรม ลองดู" = "longdo";
|
||
"mail.com search" = "mailcom";
|
||
"Mapy.cz" = "mapy-cz";
|
||
"MercadoLibre Argentina" = "mercadolibre-ar";
|
||
"MercadoLibre Chile" = "mercadolibre-cl";
|
||
"MercadoLibre Mexico" = "mercadolibre-mx";
|
||
"MercadoLivre" = "mercadolivre";
|
||
"네이버" = "naver-kr";
|
||
"Odpiralni Časi" = "odpiralni";
|
||
"Pazaruvaj" = "pazaruvaj";
|
||
"Priberam" = "priberam";
|
||
"Prisjakt" = "prisjakt-sv-SE";
|
||
"Qwant" = "qwant";
|
||
"Qwant Junior" = "qwantjr";
|
||
"楽天市場" = "rakuten";
|
||
"Readmoo 讀墨電子書" = "readmoo";
|
||
"Reddit" = "reddit";
|
||
"Salidzini.lv" = "salidzinilv";
|
||
"Seznam" = "seznam-cz";
|
||
"Tyda.se" = "tyda-sv-SE";
|
||
"Vatera.hu" = "vatera";
|
||
"WEB.DE Suche" = "webde";
|
||
"Wikipedia (en)" = "wikipedia";
|
||
"Wikipedia (nn)" = "wikipedia-NN";
|
||
"Wikipedia (nb)" = "wikipedia-NO";
|
||
"Wikipedia (af)" = "wikipedia-af";
|
||
"Biquipedia (an)" = "wikipedia-an";
|
||
"ويكيبيديا (ar)" = "wikipedia-ar";
|
||
"Wikipedia (ast)" = "wikipedia-ast";
|
||
"Vikipediya (az)" = "wikipedia-az";
|
||
"Вікіпедыя (be)" = "wikipedia-be";
|
||
"Вікіпэдыя (be-tarask)" = "wikipedia-be-tarask";
|
||
"Уикипедия (bg)" = "wikipedia-bg";
|
||
"উইকিপিডিয়া (bn)" = "wikipedia-bn";
|
||
"Wikipedia (br)" = "wikipedia-br";
|
||
"Wikipedia (bs)" = "wikipedia-bs";
|
||
"Viquipèdia (ca)" = "wikipedia-ca";
|
||
"Wicipedia (cy)" = "wikipedia-cy";
|
||
"Wikipedie (cs)" = "wikipedia-cz";
|
||
"Wikipedia (da)" = "wikipedia-da";
|
||
"Wikipedia (de)" = "wikipedia-de";
|
||
"Wikipedija (dsb)" = "wikipedia-dsb";
|
||
"Βικιπαίδεια (el)" = "wikipedia-el";
|
||
"Vikipedio (eo)" = "wikipedia-eo";
|
||
"Wikipedia (es)" = "wikipedia-es";
|
||
"Vikipeedia (et)" = "wikipedia-et";
|
||
"Wikipedia (eu)" = "wikipedia-eu";
|
||
"ویکیپدیا (fa)" = "wikipedia-fa";
|
||
"Wikipedia (fi)" = "wikipedia-fi";
|
||
"Wikipédia (fr)" = "wikipedia-fr";
|
||
"Wikipedy (fy)" = "wikipedia-fy-NL";
|
||
"Vicipéid (ga)" = "wikipedia-ga-IE";
|
||
"Uicipeid (gd)" = "wikipedia-gd";
|
||
"Wikipedia (gl)" = "wikipedia-gl";
|
||
"Vikipetã (gn)" = "wikipedia-gn";
|
||
"વિકિપીડિયા (gu)" = "wikipedia-gu";
|
||
"ויקיפדיה" = "wikipedia-he";
|
||
"विकिपीडिया (hi)" = "wikipedia-hi";
|
||
"Wikipedija (hr)" = "wikipedia-hr";
|
||
"Wikipedija (hsb)" = "wikipedia-hsb";
|
||
"Wikipédia (hu)" = "wikipedia-hu";
|
||
"Վիքիպեդիա (hy)" = "wikipedia-hy";
|
||
"Wikipedia (ia)" = "wikipedia-ia";
|
||
"Wikipedia (id)" = "wikipedia-id";
|
||
"Wikipedia (is)" = "wikipedia-is";
|
||
"Wikipedia (it)" = "wikipedia-it";
|
||
"Wikipedia (ja)" = "wikipedia-ja";
|
||
"ვიკიპედია (ka)" = "wikipedia-ka";
|
||
"Wikipedia (kab)" = "wikipedia-kab";
|
||
"Уикипедия (kk)" = "wikipedia-kk";
|
||
"វិគីភីឌា (km)" = "wikipedia-km";
|
||
"ವಿಕಿಪೀಡಿಯ (kn)" = "wikipedia-kn";
|
||
"위키백과 (ko)" = "wikipedia-kr";
|
||
"Wikipedia (lij)" = "wikipedia-lij";
|
||
"ວິກິພີເດຍ (lo)" = "wikipedia-lo";
|
||
"Vikipedija (lt)" = "wikipedia-lt";
|
||
"Vikipedeja (ltg)" = "wikipedia-ltg";
|
||
"Vikipēdija (lv)" = "wikipedia-lv";
|
||
"Википедија (mk)" = "wikipedia-mk";
|
||
"विकिपीडिया (mr)" = "wikipedia-mr";
|
||
"Wikipedia (ms)" = "wikipedia-ms";
|
||
"ဝီကီပီးဒီးယား (my)" = "wikipedia-my";
|
||
"विकिपिडिया (ne)" = "wikipedia-ne";
|
||
"Wikipedia (nl)" = "wikipedia-nl";
|
||
"Wikipèdia (oc)" = "wikipedia-oc";
|
||
"ਵਿਕੀਪੀਡੀਆ (pa)" = "wikipedia-pa";
|
||
"Wikipedia (pl)" = "wikipedia-pl";
|
||
"Wikipédia (pt)" = "wikipedia-pt";
|
||
"Wikipedia (rm)" = "wikipedia-rm";
|
||
"Wikipedia (ro)" = "wikipedia-ro";
|
||
"Википедия (ru)" = "wikipedia-ru";
|
||
"විකිපීඩියා (si)" = "wikipedia-si";
|
||
"Wikipédia (sk)" = "wikipedia-sk";
|
||
"Wikipedija (sl)" = "wikipedia-sl";
|
||
"Wikipedia (sq)" = "wikipedia-sq";
|
||
"Википедија (sr)" = "wikipedia-sr";
|
||
"Wikipedia (sv)" = "wikipedia-sv-SE";
|
||
"விக்கிப்பீடியா (ta)" = "wikipedia-ta";
|
||
"వికీపీడియా (te)" = "wikipedia-te";
|
||
"วิกิพีเดีย" = "wikipedia-th";
|
||
"Wikipedia (tl)" = "wikipedia-tl";
|
||
"Vikipedi (tr)" = "wikipedia-tr";
|
||
"Вікіпедія (uk)" = "wikipedia-uk";
|
||
"ویکیپیڈیا (ur)" = "wikipedia-ur";
|
||
"Vikipediya (uz)" = "wikipedia-uz";
|
||
"Wikipedia (vi)" = "wikipedia-vi";
|
||
"Wikipedia (wo)" = "wikipedia-wo";
|
||
"维基百科" = "wikipedia-zh-CN";
|
||
"Wikipedia (zh)" = "wikipedia-zh-TW";
|
||
"ವಿಕ್ಷನರಿ (kn)" = "wiktionary-kn";
|
||
"Wikiccionari (oc)" = "wiktionary-oc";
|
||
"விக்சனரி (ta)" = "wiktionary-ta";
|
||
"విక్షనరీ (te)" = "wiktionary-te";
|
||
"Wolne Lektury" = "wolnelektury-pl";
|
||
"Yahoo! JAPAN" = "yahoo-jp";
|
||
"Yahoo!オークション" = "yahoo-jp-auctions";
|
||
"YouTube" = "youtube";
|
||
|
||
# Derived from https://searchfox.org/mozilla-central/rev/e3f42ec9320748b2aab3d474d1e47075def9000c/toolkit/components/search/SearchSettings.sys.mjs#32-44
|
||
"Wikipedia (hy)" = "wikipedia-hy";
|
||
"Wikipedia (kn)" = "wikipedia-kn";
|
||
"Vikipēdija" = "wikipedia-lv";
|
||
"Wikipedia (no)" = "wikipedia-NO";
|
||
"Wikipedia (el)" = "wikipedia-el";
|
||
"Wikipedia (lt)" = "wikipedia-lt";
|
||
"Wikipedia (my)" = "wikipedia-my";
|
||
"Wikipedia (pa)" = "wikipedia-pa";
|
||
"Wikipedia (pt)" = "wikipedia-pt";
|
||
"Wikipedia (si)" = "wikipedia-si";
|
||
"Wikipedia (tr)" = "wikipedia-tr";
|
||
};
|
||
|
||
migrateEngineNameToIdV7 = engine:
|
||
if builtins.hasAttr engine engineNameToId then
|
||
warn "Search engines are now referenced by id instead of by name, use '${
|
||
engineNameToId.${engine}
|
||
}' instead of '${engine}'" engineNameToId.${engine}
|
||
else
|
||
engine;
|
||
|
||
migrateEngineToV11 = engine:
|
||
engine // lib.optionalAttrs (engine ? iconMapObj) {
|
||
iconMapObj = mapAttrs' (name: value:
|
||
let nameToIntResult = builtins.tryEval (toInt name);
|
||
in {
|
||
name = if nameToIntResult.success then
|
||
name
|
||
else
|
||
let size = toString (builtins.fromJSON name).width;
|
||
in warn
|
||
"JSON object names for 'iconMapObj' are deprecated, use '${size}' instead of '${name}'"
|
||
size;
|
||
|
||
inherit value;
|
||
}) engine.iconMapObj;
|
||
};
|
||
|
||
migrateEngineToV12 = engine:
|
||
let
|
||
iconMapObj = optionalAttrs (engine ? iconURL) {
|
||
"16" = warn "'iconURL' is deprecated, use 'icon = ${
|
||
strings.escapeNixString engine.iconURL
|
||
}' instead" engine.iconURL;
|
||
} // optionalAttrs (engine ? iconUpdateURL) {
|
||
"16" = warn "'iconUpdateURL' is deprecated, use 'icon = ${
|
||
strings.escapeNixString engine.iconUpdateURL
|
||
}' instead" engine.iconUpdateURL;
|
||
} // (engine.iconMapObj or { });
|
||
in throwIf (engine ? hasPreferredIcon) "hasPreferredIcon has been removed"
|
||
(removeAttrs engine [ "iconURL" "iconUpdateURL" ])
|
||
// lib.optionalAttrs (iconMapObj != { }) { inherit iconMapObj; };
|
||
in {
|
||
imports = [ (pkgs.path + "/nixos/modules/misc/meta.nix") ];
|
||
|
||
meta.maintainers = with maintainers; [ kira-bruneau ];
|
||
|
||
options = {
|
||
enable = mkOption {
|
||
type = with types; bool;
|
||
default = config.default != null || config.privateDefault != null
|
||
|| config.order != [ ] || config.engines != { };
|
||
internal = true;
|
||
};
|
||
|
||
force = mkOption {
|
||
type = with types; bool;
|
||
default = false;
|
||
description = ''
|
||
Whether to force replace the existing search
|
||
configuration. This is recommended since ${appName} will
|
||
replace the symlink for the search configuration on every
|
||
launch, but note that you'll lose any existing configuration
|
||
by enabling this.
|
||
'';
|
||
};
|
||
|
||
default = mkOption {
|
||
type = with types; nullOr str;
|
||
apply = engine:
|
||
if engine != null then migrateEngineNameToIdV7 engine else null;
|
||
default = null;
|
||
example = "ddg";
|
||
description = ''
|
||
The default search engine used in the address bar and search
|
||
bar.
|
||
'';
|
||
};
|
||
|
||
privateDefault = mkOption {
|
||
type = with types; nullOr str;
|
||
apply = engine:
|
||
if engine != null then migrateEngineNameToIdV7 engine else null;
|
||
default = null;
|
||
example = "ddg";
|
||
description = ''
|
||
The default search engine used in the Private Browsing.
|
||
'';
|
||
};
|
||
|
||
order = mkOption {
|
||
type = with types; uniq (listOf str);
|
||
apply = builtins.map migrateEngineNameToIdV7;
|
||
default = [ ];
|
||
example = [ "ddg" "google" ];
|
||
description = ''
|
||
The order the search engines are listed in. Any engines that
|
||
aren't included in this list will be listed after these in an
|
||
unspecified order.
|
||
'';
|
||
};
|
||
|
||
engines = mkOption {
|
||
type = with types; attrsOf (attrsOf jsonFormat.type);
|
||
|
||
apply = mapAttrs' (name: value: {
|
||
name = migrateEngineNameToIdV7 name;
|
||
inherit value;
|
||
});
|
||
|
||
default = { };
|
||
example = literalExpression ''
|
||
{
|
||
nix-packages = {
|
||
name = "Nix Packages";
|
||
urls = [{
|
||
template = "https://search.nixos.org/packages";
|
||
params = [
|
||
{ name = "type"; value = "packages"; }
|
||
{ name = "query"; value = "{searchTerms}"; }
|
||
];
|
||
}];
|
||
|
||
icon = "''${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
|
||
definedAliases = [ "@np" ];
|
||
};
|
||
|
||
nixos-wiki = {
|
||
name = "NixOS Wiki";
|
||
urls = [{ template = "https://wiki.nixos.org/w/index.php?search={searchTerms}"; }];
|
||
iconMapObj."16" = "https://wiki.nixos.org/favicon.ico";
|
||
definedAliases = [ "@nw" ];
|
||
};
|
||
|
||
bing.metaData.hidden = true;
|
||
google.metaData.alias = "@g"; # builtin engines only support specifying one additional alias
|
||
}
|
||
'';
|
||
|
||
description = ''
|
||
Attribute set of search engine configurations. Engines that
|
||
only have {var}`metaData` specified will be treated as builtin
|
||
to ${appName}.
|
||
|
||
See [SearchEngine.jsm](https://searchfox.org/mozilla-central/rev/e3f42ec9320748b2aab3d474d1e47075def9000c/toolkit/components/search/SearchEngine.sys.mjs#890-923)
|
||
in ${appName}'s source for available options. We maintain a
|
||
mapping to let you specify all options in the referenced link
|
||
without underscores, but it may fall out of date with future
|
||
options.
|
||
|
||
Note, {var}`icon` is also a special option added by Home
|
||
Manager to make it convenient to specify absolute icon paths.
|
||
'';
|
||
};
|
||
|
||
file = mkOption {
|
||
type = with types; path;
|
||
default = file;
|
||
internal = true;
|
||
readOnly = true;
|
||
description = ''
|
||
Resulting search.json.mozlz4 file.
|
||
'';
|
||
};
|
||
};
|
||
}
|