* [sup.git] branch develop updated (c20d8fe5 -> 5a12acfc)
@ 2026-10-03 9:31 Dan Callaghan
2026-10-03 9:31 ` [sup.git] 01/03: contrib/nix: bump nixpkgs Dan Callaghan
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Dan Callaghan @ 2026-10-03 9:31 UTC (permalink / raw)
To: sup-commits
Pushed branch develop:
from c20d8fe5 don't fix_encoding! in Message#indexable_body
new 6ad17df6 contrib/nix: bump nixpkgs
new a41cecf8 contrib/nix: bump all gem dependencies to their latest versions
new 5a12acfc add a script to generate screenshots
Summary of changes:
contrib/nix/Gemfile.lock | 32 +--
contrib/nix/gemset.nix | 52 ++---
contrib/nix/ruby3.3-shell.nix | 2 +-
contrib/nix/ruby3.4-shell.nix | 2 +-
contrib/nix/ruby4.0-shell.nix | 3 +-
contrib/screenshot-generator/.gitignore | 1 +
contrib/screenshot-generator/default.nix | 250 +++++++++++++++++++++
contrib/screenshot-generator/scenes.yaml | 51 +++++
contrib/screenshot-generator/shoot.rb | 127 +++++++++++
.../sup-is-plain-text-applied.msg | 83 +++++++
contrib/screenshot-generator/sup-is-plain-text.msg | 78 +++++++
11 files changed, 636 insertions(+), 45 deletions(-)
create mode 100644 contrib/screenshot-generator/.gitignore
create mode 100644 contrib/screenshot-generator/default.nix
create mode 100644 contrib/screenshot-generator/scenes.yaml
create mode 100755 contrib/screenshot-generator/shoot.rb
create mode 100644 contrib/screenshot-generator/sup-is-plain-text-applied.msg
create mode 100644 contrib/screenshot-generator/sup-is-plain-text.msg
^ permalink raw reply [flat|nested] 4+ messages in thread
* [sup.git] 01/03: contrib/nix: bump nixpkgs
2026-10-03 9:31 [sup.git] branch develop updated (c20d8fe5 -> 5a12acfc) Dan Callaghan
@ 2026-10-03 9:31 ` Dan Callaghan
2026-10-03 9:31 ` [sup.git] 02/03: contrib/nix: bump all gem dependencies to their latest versions Dan Callaghan
2026-10-03 9:31 ` [sup.git] 03/03: add a script to generate screenshots Dan Callaghan
2 siblings, 0 replies; 4+ messages in thread
From: Dan Callaghan @ 2026-10-03 9:31 UTC (permalink / raw)
To: sup-commits
New commit on branch develop:
https://supmua.dev/git/sup/commit/6ad17df6e1e291c478a899a5f742c544966a9ed6.html
commit 6ad17df6e1e291c478a899a5f742c544966a9ed6
Author: Dan Callaghan <djc@djc.id.au>
AuthorDate: Sat Sep 26 19:08:43 2026 +1000
contrib/nix: bump nixpkgs
---
contrib/nix/ruby3.3-shell.nix | 2 +-
contrib/nix/ruby3.4-shell.nix | 2 +-
contrib/nix/ruby4.0-shell.nix | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/contrib/nix/ruby3.3-shell.nix b/contrib/nix/ruby3.3-shell.nix
index 9c758f99..4064000e 100644
--- a/contrib/nix/ruby3.3-shell.nix
+++ b/contrib/nix/ruby3.3-shell.nix
@@ -2,7 +2,7 @@ let
pkgs = import (builtins.fetchGit {
url = "https://github.com/NixOS/nixpkgs";
ref = "refs/heads/master";
- rev = "6de3b4b649253e8e0c7229edc3726d8a717b93fe";
+ rev = "a61d303b15cd7bd393d97a472db4bf4d27640959";
}) {};
gems = pkgs.bundlerEnv {
name = "ruby3.3-gems-for-sup";
diff --git a/contrib/nix/ruby3.4-shell.nix b/contrib/nix/ruby3.4-shell.nix
index 11f0df48..39a842b1 100644
--- a/contrib/nix/ruby3.4-shell.nix
+++ b/contrib/nix/ruby3.4-shell.nix
@@ -2,7 +2,7 @@ let
pkgs = import (builtins.fetchGit {
url = "https://github.com/NixOS/nixpkgs";
ref = "refs/heads/master";
- rev = "6de3b4b649253e8e0c7229edc3726d8a717b93fe";
+ rev = "a61d303b15cd7bd393d97a472db4bf4d27640959";
}) {};
gems = pkgs.bundlerEnv {
name = "ruby3.4-gems-for-sup";
diff --git a/contrib/nix/ruby4.0-shell.nix b/contrib/nix/ruby4.0-shell.nix
index d24921e3..a436cf37 100644
--- a/contrib/nix/ruby4.0-shell.nix
+++ b/contrib/nix/ruby4.0-shell.nix
@@ -2,7 +2,7 @@ let
pkgs = import (builtins.fetchGit {
url = "https://github.com/NixOS/nixpkgs";
ref = "refs/heads/master";
- rev = "6de3b4b649253e8e0c7229edc3726d8a717b93fe";
+ rev = "a61d303b15cd7bd393d97a472db4bf4d27640959";
}) { };
gems = pkgs.bundlerEnv {
name = "ruby4.0-gems-for-sup";
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [sup.git] 02/03: contrib/nix: bump all gem dependencies to their latest versions
2026-10-03 9:31 [sup.git] branch develop updated (c20d8fe5 -> 5a12acfc) Dan Callaghan
2026-10-03 9:31 ` [sup.git] 01/03: contrib/nix: bump nixpkgs Dan Callaghan
@ 2026-10-03 9:31 ` Dan Callaghan
2026-10-03 9:31 ` [sup.git] 03/03: add a script to generate screenshots Dan Callaghan
2 siblings, 0 replies; 4+ messages in thread
From: Dan Callaghan @ 2026-10-03 9:31 UTC (permalink / raw)
To: sup-commits
New commit on branch develop:
https://supmua.dev/git/sup/commit/a41cecf8414e7b593e6ea0ba0d77b81eea93c57f.html
commit a41cecf8414e7b593e6ea0ba0d77b81eea93c57f
Author: Dan Callaghan <djc@djc.id.au>
AuthorDate: Sat Sep 26 20:52:28 2026 +1000
contrib/nix: bump all gem dependencies to their latest versions
---
contrib/nix/Gemfile.lock | 32 ++++++++++++++---------------
contrib/nix/gemset.nix | 52 ++++++++++++++++++++++++------------------------
2 files changed, 42 insertions(+), 42 deletions(-)
diff --git a/contrib/nix/Gemfile.lock b/contrib/nix/Gemfile.lock
index 3dae22ca..32a29b24 100644
--- a/contrib/nix/Gemfile.lock
+++ b/contrib/nix/Gemfile.lock
@@ -10,9 +10,9 @@ GEM
mini_portile2 (~> 2.7)
highline (3.1.2)
reline
- io-console (0.8.2)
- json (2.19.3)
- language_server-protocol (3.17.0.5)
+ io-console (0.9.4)
+ json (3.0.2)
+ language_server-protocol (3.17.0.6)
lint_roller (1.1.0)
locale (2.1.5)
fiddle
@@ -22,13 +22,13 @@ GEM
mime-types (3.7.0)
logger
mime-types-data (~> 3.2025, >= 3.2025.0507)
- mime-types-data (3.2026.0331)
+ mime-types-data (3.2026.0922)
mini_portile2 (2.8.9)
minitest (5.27.0)
ncursesw (1.4.13)
optimist (3.2.1)
- parallel (1.28.0)
- parser (3.3.11.1)
+ parallel (2.2.0)
+ parser (3.3.12.0)
ast (~> 2.4.1)
racc
prism (1.9.0)
@@ -38,24 +38,24 @@ GEM
reline (>= 0.6.0)
racc (1.8.1)
rainbow (3.1.1)
- rake (13.3.1)
- regexp_parser (2.12.0)
- reline (0.6.3)
+ rake (13.4.2)
+ regexp_parser (2.13.0)
+ reline (0.7.0)
io-console (~> 0.5)
rmail (1.1.4)
rr (1.2.1)
- rubocop (1.86.0)
- json (~> 2.3)
+ rubocop (1.91.0)
+ json (>= 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
- parallel (~> 1.10)
+ parallel (>= 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.49.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0)
- rubocop-ast (1.49.1)
+ rubocop-ast (1.50.0)
parser (>= 3.3.7.2)
prism (~> 1.7)
rubocop-packaging (0.6.0)
@@ -63,9 +63,9 @@ GEM
rubocop (>= 1.72.1, < 2.0)
ruby-progressbar (1.13.0)
unicode (0.4.4.5)
- unicode-display_width (3.2.0)
- unicode-emoji (~> 4.1)
- unicode-emoji (4.2.0)
+ unicode-display_width (3.3.0)
+ unicode-emoji (~> 4.3)
+ unicode-emoji (4.3.0)
xapian-ruby (1.4.27)
PLATFORMS
diff --git a/contrib/nix/gemset.nix b/contrib/nix/gemset.nix
index 54516d59..adb5ed3e 100644
--- a/contrib/nix/gemset.nix
+++ b/contrib/nix/gemset.nix
@@ -76,30 +76,30 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
- sha256 = "1k0lk3pwadm2myvpg893n8jshmrf2sigrd4ki15lymy7gixaxqyn";
+ sha256 = "1cgvhm0d4awr8j42b8v1nl1jfgx45ihv8mylargfi3lj697k00x4";
type = "gem";
};
- version = "0.8.2";
+ version = "0.9.4";
};
json = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
- sha256 = "0il6qxkxqql7n7sgrws5bi5a36v51dswqcxb6j6gm8aj62shp6r8";
+ sha256 = "1pqrpn0wkxvhcrwm4i0z9ailjj7if45zkkih0hij2k1q25xpwvcf";
type = "gem";
};
- version = "2.19.3";
+ version = "3.0.2";
};
language_server-protocol = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
- sha256 = "1k0311vah76kg5m6zr7wmkwyk5p2f9d9hyckjpn3xgr83ajkj7px";
+ sha256 = "1w5p8c2145lmqzr25bxh4ikzjm6k8y1k5lriqqdpw9pq730w1wjy";
type = "gem";
};
- version = "3.17.0.5";
+ version = "3.17.0.6";
};
lint_roller = {
groups = ["default"];
@@ -168,10 +168,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
- sha256 = "19cpbiwrfib7ai83l16az1gfyl3n5v2k430v40mjwlvjmhgjp579";
+ sha256 = "1bjq9hppcmpawin2a6px1msc3mdxjvndj73rfklg771v1zr8r6zl";
type = "gem";
};
- version = "3.2026.0331";
+ version = "3.2026.0922";
};
mini_portile2 = {
groups = ["default"];
@@ -218,10 +218,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
- sha256 = "0w697335hi5dk5ay9kyn53399sy87y8v0y6ij93m5wmshhadxrik";
+ sha256 = "1n0w07z55hsrb803sl20vcmr8hkay1lsff7c1a55ajdnsxgrq1g1";
type = "gem";
};
- version = "1.28.0";
+ version = "2.2.0";
};
parser = {
dependencies = ["ast" "racc"];
@@ -229,10 +229,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
- sha256 = "0m2xqvn1la62hji1mn04y59giikww95p2hs0r4y2rrz3mdxcwyni";
+ sha256 = "0a4q5h2hcihk79dbr20scgkm56l79qp7fsvfvkxlv8nmapvxg9i1";
type = "gem";
};
- version = "3.3.11.1";
+ version = "3.3.12.0";
};
prism = {
groups = ["default"];
@@ -280,20 +280,20 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
- sha256 = "175iisqb211n0qbfyqd8jz2g01q6xj038zjf4q0nm8k6kz88k7lc";
+ sha256 = "009p524zl0p0kfa65nii8wdmaigkmawv9pbvlcffky7islmmp0nb";
type = "gem";
};
- version = "13.3.1";
+ version = "13.4.2";
};
regexp_parser = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
- sha256 = "1fwfw26a32rps78920nn29shqg2zmqv72i89j1fap41isshida9m";
+ sha256 = "0w5pgh8bjy1fqdj9is5395d61y58s2rvybsdj5rlx59q45fxj1fi";
type = "gem";
};
- version = "2.12.0";
+ version = "2.13.0";
};
reline = {
dependencies = ["io-console"];
@@ -301,10 +301,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
- sha256 = "0d8q5c4nh2g9pp758kizh8sfrvngynrjlm0i1zn3cnsnfd4v160i";
+ sha256 = "0gaq2lc463ap1srz7y5kh2p4dxazs7vjrpiby58d9yfvan72s0av";
type = "gem";
};
- version = "0.6.3";
+ version = "0.7.0";
};
rmail = {
groups = ["default"];
@@ -332,10 +332,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
- sha256 = "11nicljvmns665vryhfdrpssnk5dn1mxdap7ynprpgkfw5piiwag";
+ sha256 = "1l4nh82hq54nxgyisdcf8vbkpzm149p9kff5k0vpwp8w76zvg0lw";
type = "gem";
};
- version = "1.86.0";
+ version = "1.91.0";
};
rubocop-ast = {
dependencies = ["parser" "prism"];
@@ -343,10 +343,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
- sha256 = "0dahfpnzz63hyqxa03x8rypnrxzwyvh4i5a8ri34bzpnf3pg64j4";
+ sha256 = "1nw84xk6vc2ls8sxqvyhxs2agh4l0jrws85d4bi3x0501lq8ijmr";
type = "gem";
};
- version = "1.49.1";
+ version = "1.50.0";
};
rubocop-packaging = {
dependencies = ["lint_roller" "rubocop"];
@@ -385,20 +385,20 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
- sha256 = "0hiwhnqpq271xqari6mg996fgjps42sffm9cpk6ljn8sd2srdp8c";
+ sha256 = "04xnl0zwpjjvxipd6rdnxkm11pfhbhhi3179yzv51nqi9dmacyjb";
type = "gem";
};
- version = "3.2.0";
+ version = "3.3.0";
};
unicode-emoji = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
- sha256 = "03zqn207zypycbz5m9mn7ym763wgpk7hcqbkpx02wrbm1wank7ji";
+ sha256 = "1kp89lja8ii7l6f0bq5vdxq1p3kxr3a2qmmhdc38qdwh6akjzh0i";
type = "gem";
};
- version = "4.2.0";
+ version = "4.3.0";
};
xapian-ruby = {
groups = ["default"];
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [sup.git] 03/03: add a script to generate screenshots
2026-10-03 9:31 [sup.git] branch develop updated (c20d8fe5 -> 5a12acfc) Dan Callaghan
2026-10-03 9:31 ` [sup.git] 01/03: contrib/nix: bump nixpkgs Dan Callaghan
2026-10-03 9:31 ` [sup.git] 02/03: contrib/nix: bump all gem dependencies to their latest versions Dan Callaghan
@ 2026-10-03 9:31 ` Dan Callaghan
2 siblings, 0 replies; 4+ messages in thread
From: Dan Callaghan @ 2026-10-03 9:31 UTC (permalink / raw)
To: sup-commits
New commit on branch develop:
https://supmua.dev/git/sup/commit/5a12acfccb3a471082d49aa862d5845bd0edd95e.html
commit 5a12acfccb3a471082d49aa862d5845bd0edd95e
Author: Dan Callaghan <djc@djc.id.au>
AuthorDate: Sat Oct 3 19:29:12 2026 +1000
add a script to generate screenshots
---
contrib/nix/ruby4.0-shell.nix | 1 +
contrib/screenshot-generator/.gitignore | 1 +
contrib/screenshot-generator/default.nix | 250 +++++++++++++++++++++
contrib/screenshot-generator/scenes.yaml | 51 +++++
contrib/screenshot-generator/shoot.rb | 127 +++++++++++
.../sup-is-plain-text-applied.msg | 83 +++++++
contrib/screenshot-generator/sup-is-plain-text.msg | 78 +++++++
7 files changed, 591 insertions(+)
diff --git a/contrib/nix/ruby4.0-shell.nix b/contrib/nix/ruby4.0-shell.nix
index a436cf37..37716a16 100644
--- a/contrib/nix/ruby4.0-shell.nix
+++ b/contrib/nix/ruby4.0-shell.nix
@@ -37,4 +37,5 @@ pkgs.mkShell {
gems.wrappedRuby
pkgs.pandoc
];
+ passthru = { inherit pkgs gems; };
}
diff --git a/contrib/screenshot-generator/.gitignore b/contrib/screenshot-generator/.gitignore
new file mode 100644
index 00000000..b2be92b7
--- /dev/null
+++ b/contrib/screenshot-generator/.gitignore
@@ -0,0 +1 @@
+result
diff --git a/contrib/screenshot-generator/default.nix b/contrib/screenshot-generator/default.nix
new file mode 100644
index 00000000..c642c252
--- /dev/null
+++ b/contrib/screenshot-generator/default.nix
@@ -0,0 +1,250 @@
+let
+ sup-shell = import ../nix/ruby4.0-shell.nix;
+ pkgs = sup-shell.pkgs;
+ fileset = pkgs.lib.fileset;
+ sup = fileset.toSource {
+ root = ../..;
+ fileset = fileset.difference ../.. ../../contrib;
+ };
+ ht = pkgs.rustPlatform.buildRustPackage (finalAttrs: {
+ pname = "ht";
+ version = "0.4.0";
+ src = pkgs.fetchFromGitHub {
+ owner = "andyk";
+ repo = "ht";
+ tag = "v${finalAttrs.version}";
+ hash = "sha256-LKa5nnGhQITf0SDzE17NUJ9KQ6Soq6jOBWoTONRxiCc=";
+ };
+ cargoHash = "sha256-FlR7bvQAZZIJaONOGsZUtSuUOvAVeDXJQaEkvXYxp1w=";
+ });
+ deps = with pkgs; [
+ sup-shell.gems.wrappedRuby
+ gnupg
+ ncurses
+ which
+ rsync
+ libfaketime
+ ht
+ ];
+
+ now = "2026-04-21 20:00:00";
+ lists.supmua = pkgs.fetchgit {
+ name = "supmua-list";
+ url = "https://supmua.dev/lists/supmua/0";
+ rev = "5bb23abca5490dc0d946312a8dbc3ece92bbfa95";
+ hash = "sha256-c25+ZfDOz8oSx95p1Mq7LI35n1F4IFDWog4YZUn644M=";
+ deepClone = true;
+ };
+ lists.sup-devel = pkgs.fetchgit {
+ name = "sup-devel-list";
+ url = "https://supmua.dev/lists/sup-devel/0";
+ rev = "5e44841d194d5bfb581022d5951e0964a1d85edd";
+ hash = "sha256-g9tPF97noIVoc3xfWM6D+aNDWOyn2SX967YsO4jabpM=";
+ deepClone = true;
+ };
+ lists.sup-talk = pkgs.fetchgit {
+ name = "sup-talk-list";
+ url = "https://supmua.dev/lists/sup-talk/0";
+ rev = "93f1725cde6bb046a7a086eb1b99342a3371802c";
+ hash = "sha256-ksbTPTcE7ueGKWjC+rC1xkiRF4/MpJcSqJhoA735G/Y=";
+ deepClone = true;
+ };
+ lists-as-maildir = builtins.mapAttrs (
+ name: pirepo:
+ pkgs.stdenv.mkDerivation {
+ name = "${name}-as-maildir";
+ nativeBuildInputs = with pkgs; [ git ];
+ buildCommand = ''
+ mkdir -p $out/{cur,new,tmp}
+ export GIT_DIR=${pirepo}/.git
+ git rev-list HEAD | while read sha ; do
+ git show $sha:m >$out/new/$sha:2,S
+ done
+ '';
+ }
+ ) lists;
+ sup-is-plain-text = ./sup-is-plain-text.msg;
+ sup-is-plain-text-applied = ./sup-is-plain-text-applied.msg;
+ misc-maildir = pkgs.stdenv.mkDerivation {
+ name = "sup-screenshots-misc-maildir";
+ nativeBuildInputs = with pkgs; [
+ curl
+ python3
+ ];
+ buildCommand = ''
+ mkdir -p $out/{cur,new,tmp}
+ cp ${sup-is-plain-text} $out/cur/sup-is-plain-text:2,S
+ cp ${sup-is-plain-text-applied} $out/cur/sup-is-plain-text-applied:2,S
+ '';
+ };
+
+ # Build a fake .sup directory for screenshots.
+ sup-base = pkgs.stdenv.mkDerivation {
+ name = "sup-base-for-screenshots";
+ nativeBuildInputs = deps;
+ env = {
+ TZ = "UTC";
+ USER = "nobody";
+ LANG = "C.UTF-8";
+ };
+ buildCommand = ''
+ mkdir -p $out
+
+ cat >$out/config.yaml <<EOF
+ ---
+ :accounts:
+ :default:
+ :name: Sup User
+ :email: sup@example.invalid
+ :sendmail: /bin/false
+ :sync_back_to_maildir: false
+ :editor: /bin/false
+ :poll_interval: 86400
+ EOF
+
+ cat >$out/sources.yaml <<EOF
+ ---
+ - !<tag:supmua.org,2006-10-01/Redwood/Maildir>
+ uri: maildir://${lists-as-maildir.supmua}
+ usual: true
+ archived: false
+ id: 1
+ labels: [supmua]
+ - !<tag:supmua.org,2006-10-01/Redwood/Maildir>
+ uri: maildir://${lists-as-maildir.sup-devel}
+ usual: true
+ archived: false
+ id: 2
+ labels: [sup-devel]
+ - !<tag:supmua.org,2006-10-01/Redwood/Maildir>
+ uri: maildir://${lists-as-maildir.sup-talk}
+ usual: true
+ archived: false
+ id: 3
+ labels: [sup-talk]
+ - !<tag:supmua.org,2006-10-01/Redwood/Maildir>
+ uri: maildir://${misc-maildir}
+ usual: true
+ archived: false
+ id: 4
+ labels: []
+ EOF
+
+ export SUP_BASE=$(readlink -f $out)
+ faketime -m "${now}" ruby ${sup}/bin/sup-sync
+ '';
+ };
+
+ # For each scene in scenes.yaml, drive sup in ht (a headless terminal)
+ # and capture the final screen state.
+ screenshots-ansi = pkgs.stdenv.mkDerivation {
+ name = "sup-screenshots-ansi";
+ nativeBuildInputs = deps;
+ env = {
+ TZ = "UTC";
+ USER = "nobody";
+ LANG = "C.UTF-8";
+ };
+ buildCommand = ''
+ faketime -m "${now}" ruby ${./shoot.rb} \
+ --sup-base=${sup-base} \
+ --sup=${sup}/bin/sup \
+ --scenes-yaml=${./scenes.yaml} \
+ --out=$out
+ '';
+ };
+
+ # Render the ANSI screens in a headless Wayland terminal.
+ iosevka = pkgs.iosevka-bin.override { variant = "SS09"; };
+ fonts-conf = pkgs.writeText "sup-screenshots-fonts.conf" ''
+ <?xml version="1.0"?>
+ <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
+ <fontconfig>
+ <dir>${iosevka}/share/fonts</dir>
+ <dir>${pkgs.dejavu_fonts.minimal}/share/fonts</dir>
+ <cachedir prefix="xdg">fontconfig</cachedir>
+ <config></config>
+ </fontconfig>
+ '';
+ sway-conf = pkgs.writeText "sup-screenshots-sway.conf" ''
+ output HEADLESS-1 mode 3840x2160 scale 2
+ output HEADLESS-1 background #000000 solid_color
+ default_border none
+ default_floating_border none
+ gaps inner 0
+ gaps outer 0
+ xwayland disable
+ '';
+ foot-conf = pkgs.writeText "sup-screenshots-foot.ini" ''
+ [main]
+ font=Iosevka Term:size=12
+ [colors-dark]
+ # https://github.com/tinted-theming/tinted-terminal/blob/main/themes/foot/base16-pop.ini
+ foreground=d0d0d0
+ background=000000
+ regular0=000000 # black
+ regular1=eb008a # red
+ regular2=37b349 # green
+ regular3=f8ca12 # yellow
+ regular4=0e5a94 # blue
+ regular5=b31e8d # magenta
+ regular6=00aabb # cyan
+ regular7=d0d0d0 # white
+ bright0=505050 # bright black
+ bright1=eb008a # bright red
+ bright2=37b349 # bright green
+ bright3=f8ca12 # bright yellow
+ bright4=0e5a94 # bright blue
+ bright5=b31e8d # bright magenta
+ bright6=00aabb # bright cyan
+ bright7=ffffff # bright white
+ 16=f29333
+ 17=7a2d00
+ 18=202020
+ 19=303030
+ 20=b0b0b0
+ 21=e0e0e0
+ '';
+ screenshots = pkgs.stdenv.mkDerivation {
+ name = "sup-screenshots";
+ nativeBuildInputs = with pkgs; [
+ dbus
+ foot
+ ghostty
+ grim
+ jq
+ sway
+ procps
+ ];
+ env = {
+ LANG = "C.UTF-8";
+ FONTCONFIG_FILE = fonts-conf;
+ WLR_BACKENDS = "headless";
+ WLR_RENDERER = "pixman";
+ LIBGL_ALWAYS_SOFTWARE = "1";
+ WLR_LIBINPUT_NO_DEVICES = "1";
+ };
+ buildCommand = ''
+ export HOME=$(mktemp -d)
+ export XDG_RUNTIME_DIR=$HOME/run
+ mkdir -p $XDG_RUNTIME_DIR
+ export SWAYSOCK=$XDG_RUNTIME_DIR/sway.sock
+ dbus-run-session --config-file ${pkgs.dbus}/share/dbus-1/session.conf sway -c ${sway-conf} &
+ while ! test -S $SWAYSOCK ; do sleep 0.1 ; done
+ export WAYLAND_DISPLAY=wayland-1
+
+ mkdir -p $out
+ for f in ${screenshots-ansi}/* ; do
+ rm -f done
+ foot -c ${foot-conf} -W 120x28 --hold sh -c "echo -ne '\e[H\e[?25l' ; cat $f ; touch done" &
+ foot_pid=$!
+ while ! test -f done ; do sleep 0.1 ; done
+ geometry=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]?) | select(.app_id == "foot").geometry | "\(.x),\(.y) \(.width)x\(.height)"')
+ grim -g "$geometry" $out/$(basename ''${f%.ansi}).png
+ kill -TERM $foot_pid
+ wait $foot_pid || :
+ done
+ '';
+ };
+in
+screenshots
diff --git a/contrib/screenshot-generator/scenes.yaml b/contrib/screenshot-generator/scenes.yaml
new file mode 100644
index 00000000..ae736a26
--- /dev/null
+++ b/contrib/screenshot-generator/scenes.yaml
@@ -0,0 +1,51 @@
+---
+- name: inbox
+ steps:
+ - keys: ["N", "N", "N"]
+
+- name: search-results
+ steps:
+ - keys: ["F"]
+ wait: 'Search all messages'
+ - keys: ["maildir", "Enter"]
+ wait: '\[search-results-mode\]'
+ - keys: ["N", "N", "N"]
+ - keys: ["a", "j", "a", "j", "a", "j", "a", "j", "a", "j", "a", "j", "a", "j", "a", "j", "a", "j", "a", "j", "a", "N", "a", "j", "a", "j", "a", "j", "a", "N", "a", "N", "a", "j", "a", "j", "a", "j", "a", "j", "a", "j", "a", "j", "a"]
+ - keys: ["1", "j", "j", "j"]
+
+- name: thread-view
+ steps:
+ - keys: ["j", "j", "j", "j", "j", "j", "j", "j", "j", "j", "N", "k"]
+ - keys: ["Enter"]
+ wait: '\[thread-view-mode\].*line \d+ of \d+'
+ - keys: ["Enter", "Enter", "Enter", "Enter", "Enter"]
+ - keys: ["K", "K", "K", "K", "K", "Left", "Left"]
+
+- name: reply
+ steps:
+ - keys: ["j", "j", "j", "j", "j", "j", "j"]
+ - keys: ["G"]
+ wait: '\[reply-mode\]'
+ - keys: ["PageDown", "k", "k", "k"]
+
+- name: help
+ steps:
+ - keys: ["?"]
+ wait: '\[help-mode\]'
+
+- name: log
+ steps:
+ - keys: ["F"]
+ wait: "Search all messages"
+ - keys: ["maildir", "Enter"]
+ wait: '\[search-results-mode\]'
+ - keys: ["!", "!"]
+ - keys: [";", "j", "j", "Enter"]
+ wait: '\[log-mode\]'
+
+- name: console
+ steps:
+ - keys: ["~"]
+ wait: '\[console-mode\]'
+ - keys: ['Index.parse_query "is:unread"', "Enter"]
+ - keys: ['Index.num_results_for :label => "supmua"', "Enter"]
diff --git a/contrib/screenshot-generator/shoot.rb b/contrib/screenshot-generator/shoot.rb
new file mode 100755
index 00000000..b44c94c0
--- /dev/null
+++ b/contrib/screenshot-generator/shoot.rb
@@ -0,0 +1,127 @@
+require 'fileutils'
+require 'json'
+require 'open3'
+require 'optparse'
+require 'shellwords'
+require 'tmpdir'
+require 'yaml'
+
+SIZE = "120x28" # terminal grid dimensions
+IDLE = 0.3 # settling time in seconds for the terminal
+
+class Session
+ def initialize command, env
+ ht_command = ["ht", "--size", SIZE,
+ "--subscribe", "init,output,snapshot",
+ "--", Shellwords.join(command)]
+ @stdin, @stdout, @process = Open3.popen2 env, *ht_command
+ @stdin.sync = true
+ raise "ht did not send init event" unless read_event["type"] == "init"
+ end
+
+ def write command
+ @stdin.puts JSON.generate(command)
+ end
+
+ def read_event
+ line = @stdout.gets or return nil
+ JSON.parse line
+ end
+
+ def send_keys keys
+ write :type => "sendKeys", :keys => keys
+ end
+
+ ## Wait until at least IDLE seconds has passed with no more events.
+ def settle
+ loop do
+ return unless IO.select([@stdout], nil, nil, IDLE)
+ return unless read_event
+ end
+ end
+
+ def snapshot
+ write :type => "takeSnapshot"
+ loop do
+ event = read_event
+ return event["data"] if event["type"] == "snapshot"
+ end
+ end
+
+ def expect pattern
+ settle
+ screen = snapshot
+ raise "/#{pattern.source}/ not found" unless screen["text"] =~ pattern
+ screen
+ end
+
+ def dump_screen
+ $stderr.puts "--- screen was ---"
+ $stderr.puts snapshot["text"]
+ $stderr.puts "------------------"
+ rescue
+ $stderr.puts "--- no screen ---"
+ end
+
+ def close
+ @stdin.close unless @stdin.closed?
+ @stdout.read
+ @stdout.close
+ end
+end
+
+options = {}
+OptionParser.new do |parser|
+ parser.on "--sup-base PATH"
+ parser.on "--sup PATH"
+ parser.on "--scenes-yaml PATH"
+ parser.on "--out PATH"
+end.parse! into: options
+
+FileUtils.mkdir_p options[:out]
+
+scenes = YAML.load_file options[:"scenes-yaml"]
+scenes.each do |scene|
+ name = scene["name"]
+ steps = scene["steps"] || []
+
+ ## Make a fresh copy of SUP_BASE for this run of sup.
+ base = Dir.mktmpdir "sup-screenshots-#{name}-"
+ FileUtils.cp_r Dir.glob(File.join(options[:"sup-base"], "*")), base
+ FileUtils.chmod_R "u+w", base
+
+ puts "[#{name}] starting sup"
+ session = nil
+ begin
+ session = Session.new(
+ ["ruby", options[:sup], "--no-threads", "--no-initial-poll"],
+ {"SUP_BASE" => base, "SUP_LOG_LEVEL" => "debug"})
+
+ screen = session.expect /\[inbox-mode\]/
+
+ steps.each do |step|
+ keys = step["keys"]
+ puts "[#{name}] send #{keys.inspect}"
+ session.send_keys keys
+
+ screen = if step["wait"].nil?
+ session.settle
+ session.snapshot
+ else
+ session.expect Regexp.new(step["wait"])
+ end
+ end
+
+ ansi = screen["seq"]
+ ansi = ansi.gsub "\u009b", "\e[" # map CSI emitted by ht to ESC [
+ path = File.join options[:out], "#{name}.ansi"
+ File.write path, ansi
+ puts "[#{name}] wrote #{path}"
+ rescue RuntimeError => e
+ $stderr.puts "[#{name}] #{e.message}"
+ session.dump_screen if session
+ raise
+ ensure
+ session.close if session
+ end
+end
diff --git a/contrib/screenshot-generator/sup-is-plain-text-applied.msg b/contrib/screenshot-generator/sup-is-plain-text-applied.msg
new file mode 100644
index 00000000..78bbc832
--- /dev/null
+++ b/contrib/screenshot-generator/sup-is-plain-text-applied.msg
@@ -0,0 +1,83 @@
+Authentication-Results: mail-a.sr.ht; dkim=pass header.d=ddevault.org header.i=@ddevault.org
+Received: from mx.freebitcoin.gay (mx.freebitcoin.gay [92.65.121.143])
+ by mail-a.sr.ht (Postfix) with ESMTPS id 13F73200E0
+ for <~sircmpwn/public-inbox@lists.sr.ht>; Mon, 20 Apr 2026 07:26:50 +0000 (UTC)
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ddevault.org;
+ s=_bikeshed; t=1776670002;
+ h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
+ to:to:cc:mime-version:mime-version:content-type:content-type:
+ in-reply-to:in-reply-to:references:references;
+ bh=/yTIwruVpbRgzboJc+lUtE3TsCGqQmxSUE8vJiuBYB0=;
+ b=TfqhiwTaygLnt3sbmZNT1qMNIcaPYGPyTMRJpNOsfALmwG5g91xf1RVO8BpnSB4D45LZMP
+ h26PRpF2bBW8oRYRfaSsMwiSl0T2ucPlH08rIWPNBuq4roZAvPH+Ga6RKp9RcNhSsMMvwh
+ 2h9/1KDKFNUA2P/kdRjlifSjaCsnmKc=
+Received: from taiga (mx.freebitcoin.gay [92.65.121.143])
+ by mail.freebitcoin.gay (OpenSMTPD) with ESMTPSA id 7314ef4d (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO);
+ Mon, 20 Apr 2026 09:26:42 +0200 (CEST)
+Received: by taiga (Postfix, from userid 1000)
+ id 9EFA3BA002F; Mon, 20 Apr 2026 09:26:49 +0200 (CEST)
+Mime-Version: 1.0
+Content-Type: multipart/signed;
+ boundary=a036da96ce29d60f01d793f8b11ad804cb7659b0e414c63118649b669cdc;
+ micalg=pgp-sha512; protocol="application/pgp-signature"
+Date: Mon, 20 Apr 2026 09:26:49 +0200
+Message-Id: <DHXSYEQU1SFY.1W0NFHNML13VB@ddevault.org>
+From: "Drew DeVault" <drew@ddevault.org>
+To: "Dan Callaghan" <djc@djc.id.au>, <~sircmpwn/public-inbox@lists.sr.ht>
+Subject: Re: [PATCH] add Sup to the list of plain text certified mail
+ clients
+X-Sourcehut-Patchset-Update: APPLIED
+References: <20260411092525.498926-1-djc@djc.id.au>
+In-Reply-To: <20260411092525.498926-1-djc@djc.id.au>
+
+--a036da96ce29d60f01d793f8b11ad804cb7659b0e414c63118649b669cdc
+Content-Type: multipart/mixed;
+ boundary=1d16b06c6066296315555c6776a0e1d688a41caf8c9cea66a5cdcdcfd42a
+
+--1d16b06c6066296315555c6776a0e1d688a41caf8c9cea66a5cdcdcfd42a
+Content-Type: multipart/alternative;
+ boundary=a95442b43616d7ee1f8d1e2ae129e5a85862edd92378eb2f25ff009758ef
+
+--a95442b43616d7ee1f8d1e2ae129e5a85862edd92378eb2f25ff009758ef
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+Content-Type: text/plain; charset=UTF-8
+
+Thanks!
+
+To git@git.sr.ht:~sircmpwn/useplaintext.email
+ e22de97..70ed7d5 master -> master
+
+--a95442b43616d7ee1f8d1e2ae129e5a85862edd92378eb2f25ff009758ef--
+
+--1d16b06c6066296315555c6776a0e1d688a41caf8c9cea66a5cdcdcfd42a
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename=42F3F1862E3CC4B8.asc
+Content-Type: application/pgp-keys; charset=UTF-8
+
+LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tCgptRE1FWjdZOWt4WUpLd1lCQkFI
+YVJ3OEJBUWRBL3BQeTZYK25OTDVUMlFhSktFTTA4eE4vS3o3d0ZUQVpvSDVZCnJpVjl4MW0wSUVS
+eVpYY2dSR1ZXWVhWc2RDQThaSEpsZDBCa1pHVjJZWFZzZEM1dmNtYytpSk1FRXhZS0FEc0MKR3dN
+RkN3a0lCd0lDSWdJR0ZRb0pDQXNDQkJZQ0F3RUNIZ2NDRjRBV0lRU2Z0ZWMzM0NXeW5ZN3NScEZD
+OC9HRwpManpFdUFVQ1o3WTl3d0FLQ1JCQzgvR0dManpFdU1FRUFQOURIKzFMZ3ZUcVpETFo4YmFi
+QjVDZHA1eTBaVytRClR4NzhtaDFMOGpKZDZnRUFzc21nc0ltY3JadjRhZFAyVVc1UlU1QkhDZTlL
+VWR4MER5VjgzUXdsRkFTNE9BUm4KdGoyVEVnb3JCZ0VFQVpkVkFRVUJBUWRBR0FIOWRsYUNPTm9Y
+cG1RZ0hvUWdZSTJ0UytWTTNtelU4STJQeVZZUQoxR1VEQVFnSGlIZ0VHQllLQUNBQ0d3d1dJUVNm
+dGVjMzNDV3luWTdzUnBGQzgvR0dManpFdUFVQ1o3WTkxZ0FLCkNSQkM4L0dHTGp6RXVIY25BUDR5
+ak9pTTB5cWtTVDZ5WHpEVVd6ZTdCOUltMjRGOEhWeCt3TnFjRGFEdGNBRC8KZktRaHowU0NQaWJs
+TzZsYzdNRlV2bGFPejJ2ODdVcFVZUmh6UGRnUXF3az0KPWVtcmIKLS0tLS1FTkQgUEdQIFBVQkxJ
+QyBLRVkgQkxPQ0stLS0tLQo=
+--1d16b06c6066296315555c6776a0e1d688a41caf8c9cea66a5cdcdcfd42a--
+
+--a036da96ce29d60f01d793f8b11ad804cb7659b0e414c63118649b669cdc
+Content-Type: application/pgp-signature; name="signature.asc"
+
+-----BEGIN PGP SIGNATURE-----
+
+iHUEABYKAB0WIQSftec33CWynY7sRpFC8/GGLjzEuAUCaeXVOQAKCRBC8/GGLjzE
+uJRIAPwOx55M404obNqpVNWkeipGH68mQlprxiQqztCT6jG5qgD+LUPSDChxMpmo
+ogLdO5Rb3UDRet4xWy0fjSAxT34AHgA=
+=tPvL
+-----END PGP SIGNATURE-----
+
+--a036da96ce29d60f01d793f8b11ad804cb7659b0e414c63118649b669cdc--
diff --git a/contrib/screenshot-generator/sup-is-plain-text.msg b/contrib/screenshot-generator/sup-is-plain-text.msg
new file mode 100644
index 00000000..3cb70a81
--- /dev/null
+++ b/contrib/screenshot-generator/sup-is-plain-text.msg
@@ -0,0 +1,78 @@
+Authentication-Results: mail-a.sr.ht; dkim=none
+Received: from smtp02.aussiebb.com.au (unknown [121.200.0.93])
+ by mail-a.sr.ht (Postfix) with ESMTPS id C7D921FFE2
+ for <~sircmpwn/public-inbox@lists.sr.ht>; Sat, 11 Apr 2026 09:26:03 +0000 (UTC)
+Received: from localhost (localhost.localdomain [127.0.0.1])
+ by smtp02.aussiebb.com.au (Postfix) with ESMTP id 3E06E101B25
+ for <~sircmpwn/public-inbox@lists.sr.ht>; Sat, 11 Apr 2026 19:25:55 +1000 (AEST)
+X-Virus-Scanned: Debian amavis at smtp02.aussiebb.com.au
+Received: from smtp02.aussiebb.com.au ([127.0.0.1])
+ by localhost (smtp02.aussiebb.com.au [127.0.0.1]) (amavis, port 10024)
+ with ESMTP id DMHmZ0WHyx_y for <~sircmpwn/public-inbox@lists.sr.ht>;
+ Sat, 11 Apr 2026 19:25:55 +1000 (AEST)
+Received: by smtp02.aussiebb.com.au (Postfix, from userid 116)
+ id 2676A101CFB; Sat, 11 Apr 2026 19:25:55 +1000 (AEST)
+X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on
+ smtp02.aussiebb.com.au
+X-Spam-Level: *
+X-Spam-Status: No, score=2.0 required=10.0 tests=DMARC_PASS,FORGED_SPF_HELO,
+ KHOP_HELO_FCRDNS,SPF_HELO_PASS,URIBL_BLOCKED autolearn=disabled
+ version=4.0.0
+Received: from djc.id.au (honeycomb.djc.id.au [IPv6:2403:5818:89c3::35])
+ (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
+ key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256)
+ (No client certificate requested)
+ by smtp02.aussiebb.com.au (Postfix) with ESMTPS id 2B9AF101B25
+ for <~sircmpwn/public-inbox@lists.sr.ht>; Sat, 11 Apr 2026 19:25:54 +1000 (AEST)
+Received: by djc.id.au (Postfix, from userid 1000)
+ id 9B20A3550383; Sat, 11 Apr 2026 19:25:53 +1000 (AEST)
+From: Dan Callaghan <djc@djc.id.au>
+To: ~sircmpwn/public-inbox@lists.sr.ht
+Cc: Dan Callaghan <djc@djc.id.au>
+Subject: [PATCH] add Sup to the list of plain text certified mail clients
+Date: Sat, 11 Apr 2026 19:25:25 +1000
+Message-ID: <20260411092525.498926-1-djc@djc.id.au>
+X-Mailer: git-send-email 2.51.2
+MIME-Version: 1.0
+Content-Transfer-Encoding: 8bit
+
+Sup is a mature TUI mail client, originally released in 2008 and still
+actively maintained. It favours displaying text/plain parts, and
+outgoing mails are composed in plain text. It uses traditional reply
+quoting style and encourages bottom posting.
+---
+ es/index.html | 3 +++
+ index.html | 3 +++
+ 2 files changed, 6 insertions(+)
+
+diff --git a/es/index.html b/es/index.html
+index 7697315..f42aee3 100644
+--- a/es/index.html
++++ b/es/index.html
+@@ -118,6 +118,9 @@ <h2 id="recommended-clients"><a href="#recommended-clients">
+ <li>
+ <a rel="noopener" href="https://www.squirrelmail.org/">SquirrelMail</a> (Web)
+ </li>
++ <li>
++ <a rel="noopener" href="https://supmua.dev/">Sup</a> (TUI)
++ </li>
+ <li>
+ <a rel="noopener" href="https://github.com/wanderlust/wanderlust">Wanderlust</a> (emacs)
+ </li>
+diff --git a/index.html b/index.html
+index e38cb60..3244b16 100644
+--- a/index.html
++++ b/index.html
+@@ -121,6 +121,9 @@ <h2 id="recommended-clients"><a href="#recommended-clients">
+ <li>
+ <a rel="noopener" href="https://www.squirrelmail.org/">SquirrelMail</a> (Webmail)
+ </li>
++ <li>
++ <a rel="noopener" href="https://supmua.dev/">Sup</a> (TUI)
++ </li>
+ <li>
+ <a rel="noopener" href="https://github.com/wanderlust/wanderlust">Wanderlust</a> (emacs)
+ </li>
+--
+2.51.2
+
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-03 9:31 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-03 9:31 [sup.git] branch develop updated (c20d8fe5 -> 5a12acfc) Dan Callaghan
2026-10-03 9:31 ` [sup.git] 01/03: contrib/nix: bump nixpkgs Dan Callaghan
2026-10-03 9:31 ` [sup.git] 02/03: contrib/nix: bump all gem dependencies to their latest versions Dan Callaghan
2026-10-03 9:31 ` [sup.git] 03/03: add a script to generate screenshots Dan Callaghan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox