From 2a6928fb4cde593c530c3dd49cb9f80126c8df42 Mon Sep 17 00:00:00 2001 From: Profpatsch Date: Thu, 5 May 2022 21:10:12 +0200 Subject: feat(users/Profpatsch): init initial aerc config aerc is a mail client. It needs some ini files to work. This is an initial attempt at generating them. Change-Id: I087955f19d2c4527275500a1e13eeb071c98a7b9 Reviewed-on: https://cl.tvl.fyi/c/depot/+/5526 Tested-by: BuildkiteCI Reviewed-by: Profpatsch --- users/Profpatsch/aerc-no-config-perms.patch | 12 ++ users/Profpatsch/aerc.dhall | 253 ++++++++++++++++++++++++++++ users/Profpatsch/aerc.nix | 70 ++++++++ 3 files changed, 335 insertions(+) create mode 100644 users/Profpatsch/aerc-no-config-perms.patch create mode 100644 users/Profpatsch/aerc.dhall create mode 100644 users/Profpatsch/aerc.nix diff --git a/users/Profpatsch/aerc-no-config-perms.patch b/users/Profpatsch/aerc-no-config-perms.patch new file mode 100644 index 000000000000..86b41cd74b08 --- /dev/null +++ b/users/Profpatsch/aerc-no-config-perms.patch @@ -0,0 +1,12 @@ +diff --git a/config/config.go b/config/config.go +index 0472daf..5eed379 100644 +--- a/config/config.go ++++ b/config/config.go +@@ -779,6 +779,7 @@ func (config *AercConfig) LoadBinds(binds *ini.File, baseName string, baseGroup + // checkConfigPerms checks for too open permissions + // printing the fix on stdout and returning an error + func checkConfigPerms(filename string) error { ++ return nil; + info, err := os.Stat(filename) + if err != nil { + return nil // disregard absent files diff --git a/users/Profpatsch/aerc.dhall b/users/Profpatsch/aerc.dhall new file mode 100644 index 000000000000..5385a3983875 --- /dev/null +++ b/users/Profpatsch/aerc.dhall @@ -0,0 +1,253 @@ +let + -- DSL for building INI files + ToIniFns = + λ ( Ini + : { -- A Section in the ini + Section : Type + , -- A couple of sections + SectionList : Type + } + ) → + { -- Create a new section + newSection : Ini.Section + , -- Add a key/value pair to the section + add : Text → Text → Ini.Section → Ini.Section + , -- Add all these key/value pairs to the section + addAll : + List { name : Text, value : Text } → Ini.Section → Ini.Section + , -- Create a new SectionList + newSectionList : Ini.SectionList + , -- Add a section to the list of sections + addSection : Text → Ini.Section → Ini.SectionList → Ini.SectionList + } + +in λ ( imports + : { -- concatenate a list with newlines + concatNewline : List Text → Text + , -- Take an aerc filter from the aerc distribution /share directory + aercFilter : Text → Text + , -- given a dsl of functions to create an Ini, render the ini file + toIni : + ( ∀(Ini : { Section : Type, SectionList : Type }) → + ToIniFns Ini → + { globalSection : Ini.Section, sections : Ini.SectionList } + ) → + Text + } + ) → + let List/foldLeft + : ∀(a : Type) → + List a → + ∀(list : Type) → + ∀(cons : list → a → list) → + ∀(nil : list) → + list + = λ(a : Type) → + λ(xs : List a) → + λ(list : Type) → + λ(cons : list → a → list) → + λ(nil : list) → + List/fold + a + xs + (list → list) + (λ(x : a) → λ(f : list → list) → λ(l : list) → f (cons l x)) + (λ(l : list) → l) + nil + + let List/map + : ∀(a : Type) → ∀(b : Type) → (a → b) → List a → List b + = λ(a : Type) → + λ(b : Type) → + λ(f : a → b) → + λ(xs : List a) → + List/build + b + ( λ(list : Type) → + λ(cons : b → list → list) → + List/fold a xs list (λ(x : a) → cons (f x)) + ) + + let + -- A builder is a list of “build methods” that go from (a -> a) and change the a step by step. + Builder/build = + λ(a : Type) → + λ(init : a) → + λ(builders : List (a → a)) → + List/foldLeft + (a → a) + builders + a + (λ(acc : a) → λ(f : a → a) → f acc) + init + + in { accounts = + imports.toIni + ( λ(Ini : { Section : Type, SectionList : Type }) → + λ(ini : ToIniFns Ini) → + { globalSection = ini.newSection + , sections = + ini.addSection + "mail" + ( ini.addAll + [ { name = "archive", value = "Archive" } + , { name = "copy-to", value = "Sent" } + , { name = "default", value = "INBOX" } + , { name = "from" + , value = "Profpatsch " + } + , { name = "source" + , value = "maildir://~/.Mail/mail" + } + , { name = "postpone", value = "Drafts" } + ] + ini.newSection + ) + ini.newSectionList + } + ) + , aerc = + imports.toIni + ( λ(Ini : { Section : Type, SectionList : Type }) → + λ(ini : ToIniFns Ini) → + { globalSection = ini.newSection + , sections = + ini.addSection + "filters" + ( Builder/build + Ini.Section + ini.newSection + [ ini.add "text/html" (imports.aercFilter "html") + , let _ = + "-- TODO: this awk should be taken from nix!" + + in ini.add + "text/*" + "awk -f ${imports.aercFilter "plaintext"}" + ] + ) + ini.newSectionList + } + ) + , binds = + let + -- keybinding and command to run + Key = + { ctrl : Bool, key : Text, cmd : Text } + + in let + -- render a key to config format + renderKey = + λ(k : Key) → + if k.ctrl + then " = ${k.cmd}" + else "${k.key} = ${k.cmd}" + + let + + -- render a list of keys to config format + renderKeys = + λ(keys : List Key) → List/map Key Text renderKey keys + + let + -- create a section whith a name and a list of keys + sect = + λ(section : Text) → + λ(keys : List Key) → + { section, keys = renderKeys keys } + + let + + -- set key without modifiers + key = + λ(key : Text) → { key } + + let + -- set special key without modifiers + special = + λ(key : Text) → { key = "<${key}>" } + + let + -- no modifier + none = + { ctrl = False } + + let + -- set control key + ctrl = + { ctrl = True } + + let + -- set a command to execute + cmd = + λ(cmd : Text) → { cmd = ":${cmd}" } + + let + -- set a command, but stay on the prompt + prompt = + λ(cmd : Text) → { cmd = ":${cmd}" } + + let config = + { globalSection = + renderKeys + [ ctrl ∧ key "p" ∧ cmd "prev-tab" + , ctrl ∧ key "n" ∧ cmd "next-tab" + , ctrl ∧ key "t" ∧ cmd "term" + ] + , sections = + [ sect + "messages" + [ ctrl ∧ key "q" ∧ cmd "quit" + , none ∧ special "Up" ∧ cmd "prev" + , none ∧ special "Down" ∧ cmd "next" + , none ∧ special "PgUp" ∧ cmd "prev 100%" + , none ∧ special "PgDn" ∧ cmd "next 100%" + , none ∧ key "g" ∧ cmd "select 0" + , none ∧ key "G" ∧ cmd "select -1" + , ctrl ∧ key "Up" ∧ cmd "prev-folder" + , ctrl ∧ key "Down" ∧ cmd "next-folder" + , none ∧ key "v" ∧ cmd "mark -t" + , none ∧ key "V" ∧ cmd "mark -v" + , none ∧ special "Enter" ∧ cmd "view" + , none ∧ key "c" ∧ cmd "compose" + , none ∧ key "|" ∧ prompt "pipe" + , none ∧ key "t" ∧ prompt "term" + , none ∧ key "/" ∧ prompt "search" + , none ∧ key "n" ∧ cmd "next-result" + , none ∧ key "N" ∧ cmd "prev-result" + , none ∧ special "Esc" ∧ cmd "clear" + ] + , sect "view" [ none ∧ key "q" ∧ cmd "close" ] + ] + } + + let Section = { section : Text, keys : List Text } + + let iniToJson = + λ ( ini + : { globalSection : List Text + , sections : List Section + } + ) → + let mkKeys = imports.concatNewline + + let + -- TODO: escaping section header? + mkSection = + λ(section : Section) → + '' + [${section.section}] + '' + ++ mkKeys section.keys + + in mkKeys ini.globalSection + ++ mkKeys + ( List/map + Section + Text + mkSection + ini.sections + ) + + in iniToJson config + } diff --git a/users/Profpatsch/aerc.nix b/users/Profpatsch/aerc.nix new file mode 100644 index 000000000000..d37d10eb4626 --- /dev/null +++ b/users/Profpatsch/aerc.nix @@ -0,0 +1,70 @@ +{ depot, pkgs, lib, ... }: + +let + aerc-patched = pkgs.aerc.overrideAttrs (old: { + patches = old.patches or [ ] ++ [ + ./aerc-no-config-perms.patch + ]; + }); + + bins = depot.nix.getBins aerc-patched [ "aerc" ]; + + config = + depot.users.Profpatsch.importDhall.importDhall + { + root = ./.; + files = [ + "aerc.dhall" + ]; + main = "aerc.dhall"; + deps = [ ]; + } + { + concatNewline = lib.concatStringsSep "\n"; + aercFilter = name: "${aerc-patched}/share/aerc/filters/${name}"; + toIni = getSections: + lib.generators.toINIWithGlobalSection { } + (getSections { } toIniDhall); + }; + + toIniDhall = { + newSection = { }; + add = key: val: sect: sect // { ${key} = val; }; + addAll = keyVals: sect: sect // builtins.listToAttrs keyVals; + newSectionList = { }; + addSection = key: val: sect: sect // { ${key} = val; }; + }; + + + ini-file = name: ini: lib.pipe ini [ + (lib.generators.toINI { }) + (pkgs.writeText name) + ]; + + binds-file = name: binds: pkgs.writeText name binds; + + aerc-config = pkgs.linkFarm "alacritty-config" [ + { + name = "aerc/accounts.conf"; + path = pkgs.writeText "accounts.conf" config.accounts; + } + { + name = "aerc/aerc.conf"; + path = pkgs.writeText "aerc.conf" config.aerc; + } + { + name = "aerc/binds.conf"; + path = binds-file "binds.conf" config.binds; + } + ]; + + aerc = depot.nix.writeExecline "aerc" { } [ + "export" + "XDG_CONFIG_HOME" + aerc-config + bins.aerc + "$@" + ]; + +in +aerc -- cgit 1.4.1