Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package ttyplot for openSUSE:Factory checked 
in at 2026-07-15 16:40:43
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ttyplot (Old)
 and      /work/SRC/openSUSE:Factory/.ttyplot.new.1991 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ttyplot"

Wed Jul 15 16:40:43 2026 rev:5 rq:1365683 version:1.7.6

Changes:
--------
--- /work/SRC/openSUSE:Factory/ttyplot/ttyplot.changes  2026-06-25 
10:58:37.652318506 +0200
+++ /work/SRC/openSUSE:Factory/.ttyplot.new.1991/ttyplot.changes        
2026-07-15 17:00:09.212160689 +0200
@@ -1,0 +2,16 @@
+Tue Jul 14 13:23:25 UTC 2026 - Martin Hauke <[email protected]>
+
+- Update to version 1.7.6
+  New rendering modes
+  * braille line mode (-b) — high-resolution 2×4 dot plotting; two
+    lines distinguished by color.
+  * block / quadrant mode (-B) — 2×2 block-element plotting,
+    like -b
+  * fill (-f) — fill the area under the line in braille/block mode
+    (line 1).
+  * aalib ASCII-art mode (-A) — experimental smooth ASCII line
+    rendering, opt-in (make AA=1, requires aalib).
+  * updated dark color scheme.
+- Build with support for aalib.
+
+-------------------------------------------------------------------

Old:
----
  ttyplot-1.7.5.tar.gz

New:
----
  ttyplot-1.7.6.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ttyplot.spec ++++++
--- /var/tmp/diff_new_pack.sU7ICQ/_old  2026-07-15 17:00:09.896183886 +0200
+++ /var/tmp/diff_new_pack.sU7ICQ/_new  2026-07-15 17:00:09.896183886 +0200
@@ -18,12 +18,13 @@
 
 
 Name:           ttyplot
-Version:        1.7.5
+Version:        1.7.6
 Release:        0
 Summary:        Realtime plotting utility for terminals
 License:        Apache-2.0
 URL:            https://github.com/tenox7/ttyplot
 Source:         
https://github.com/tenox7/ttyplot/archive/refs/tags/%{version}.tar.gz#/%{name}-%{version}.tar.gz
+BuildRequires:  aalib-devel
 BuildRequires:  pkgconfig
 BuildRequires:  pkgconfig(ncurses)
 
@@ -37,7 +38,7 @@
 %autosetup -p1
 
 %build
-%make_build CFLAGS="%{optflags} $(pkg-config --cflags --libs ncursesw)"
+%make_build CFLAGS="%{optflags} $(pkg-config --cflags --libs ncursesw)" AA=1
 
 %install
 %make_install DESTDIR=%{buildroot} PREFIX=%{_prefix} MANPREFIX=%{_mandir}

++++++ ttyplot-1.7.5.tar.gz -> ttyplot-1.7.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ttyplot-1.7.5/Makefile new/ttyplot-1.7.6/Makefile
--- old/ttyplot-1.7.5/Makefile  2026-06-22 04:17:25.000000000 +0200
+++ new/ttyplot-1.7.6/Makefile  2026-07-14 05:38:07.000000000 +0200
@@ -1,4 +1,4 @@
-VERSION    = 1.7.5
+VERSION    = 1.7.6
 DESTDIR   ?=
 PREFIX    ?= /usr/local
 MANPREFIX ?= $(PREFIX)/man
@@ -7,6 +7,14 @@
 CFLAGS += `pkg-config --cflags ncursesw`
 LDLIBS += `pkg-config --libs ncursesw` -lm
 
+# Experimental, opt-in ASCII-art rendering backend (aalib). Off by default;
+# build with `make AA=1` (requires aalib and its aalib-config helper).
+# Written without GNU-only `ifdef` so this file also parses under BSD make 
(bmake).
+AALIB_CPPFLAGS_1 = -DAALIB `aalib-config --cflags`
+AALIB_LDLIBS_1   = `aalib-config --libs`
+CPPFLAGS += $(AALIB_CPPFLAGS_$(AA))
+LDLIBS   += $(AALIB_LDLIBS_$(AA))
+
 all: ttyplot stresstest
 
 install: ttyplot ttyplot.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ttyplot-1.7.5/README.md new/ttyplot-1.7.6/README.md
--- old/ttyplot-1.7.5/README.md 2026-06-22 04:17:25.000000000 +0200
+++ new/ttyplot-1.7.6/README.md 2026-07-14 05:38:07.000000000 +0200
@@ -17,6 +17,14 @@
 &nbsp;
 &nbsp;
 
+experimental braille and block element support:
+
+![braille support](braille.png)
+
+&nbsp;
+&nbsp;
+
+
 ## get
 
 <a href="https://repology.org/project/ttyplot/versions";>
@@ -88,7 +96,7 @@
 ### memory usage on macOS
 
 ```
-vm_stat 1 | awk '{ print int($2)*4096/1024^3; fflush(); }' | ttyplot -t "MacOS 
Memory Usage" -u GB
+vm_stat 1 | awk '{ print int($2)/2^18; fflush(); }' | ttyplot -t "MacOS Memory 
Usage" -u GB
 ```
 
 ### number of processes in running and io blocked state
@@ -133,7 +141,7 @@
 
 ### memory usage from rrdtool and collectd using awk
 ```
-{ while true; do rrdtool lastupdate 
/var/lib/collectd/rrd/$(hostname)/memory/memory-used.rrd | awk 'END { print 
($NF)/1024/1024 }'; sleep 1; done } | ttyplot -m $(awk '/MemTotal/ { print 
($2)/1024 }' /proc/meminfo) -t "Memoru Used" -u MB
+{ while true; do rrdtool lastupdate 
/var/lib/collectd/rrd/$(hostname)/memory/memory-used.rrd | awk 'END { print 
($NF)/1024/1024 }'; sleep 1; done } | ttyplot -m $(awk '/MemTotal/ { print 
($2)/1024 }' /proc/meminfo) -t "Memory Used" -u MB
 ```
 
 ### bitcoin price chart using curl and jq
@@ -141,9 +149,10 @@
 { while true; do curl -sL https://api.coindesk.com/v1/bpi/currentprice.json  | 
jq .bpi.USD.rate_float; sleep 600; done } | ttyplot -t "bitcoin price" -u usd
 ```
 
-### stock quote chart
+### stock price chart using curl and jq
+
 ```
-{ while true; do curl -sL https://api.iextrading.com/1.0/stock/googl/price; 
echo; sleep 600; done } | ttyplot -t "google stock price" -u usd
+{ while true; do curl -s 
"https://query1.finance.yahoo.com/v8/finance/chart/SPY"; -H "User-Agent: 
Mozilla/5.0" | jq '.chart.result[0].meta.regularMarketPrice'; sleep 60; done } 
| ttyplot -t "SPY stock price" -u usd
 ```
 
 ### prometheus load average via node_exporter
@@ -223,11 +232,15 @@
 ## flags
 
 ```
-  ttyplot [-2] [-r] [-c plotchar] [-s scale] [-m max] [-M min] [-t title] [-u 
unit]
+  ttyplot [-2] [-b] [-B] [-f] [-r] [-c plotchar] [-s scale] [-m max] [-M min] 
[-t title] [-u unit]
   ttyplot -h
   ttyplot -v
 
   -2 read two values and draw two plots, the second one is in reverse video
+  -b (experimental) braille line drawing mode, two lines in color
+  -B (experimental) block elements drawing mode (quadrants), like -b
+  -f (experimental) fill area under braille/block line 1
+  -A (experimental) aalib ASCII-art line mode, two lines in color (only if 
built with AA=1)
   -r rate of a counter (divide value by measured sample interval)
   -c character to use for plot line, eg @ # % . etc
   -e character to use for error line when value exceeds hardmax (default: e)
@@ -246,8 +259,8 @@
      Sixth value: min error indicator color (optional)
      Example: -C 1,2,3,4,5,6 or -C 1,2 or -C 1
      Predefined color schemes:
-       -C dark1    Blue-cyan-yellow scheme for dark terminals
-       -C dark2    Purple-yellow-green scheme for dark terminals
+       -C dark1    Red-green lines for dark terminals
+       -C dark2    Blue-yellow lines for dark terminals
        -C light1   Green-blue-red scheme for light terminals
        -C light2   Blue-green-yellow scheme for light terminals
      Colors: 0=black, 1=red, 2=green, 3=yellow, 4=blue, 5=magenta, 6=cyan, 
7=white
@@ -256,6 +269,33 @@
 ```
 
 &nbsp;
+&nbsp;
+
+
+## experimental: braille / block line drawing
+
+> **experimental** — this feature and its flags may still change
+
+`-b` draws **braille** lines instead of block / reverse-video bars; `-B` does 
the same with **quadrant block elements** (`▖▗▘▙▚▛▜▝▞▟`). with `-2`: line 1 
green, line 2 blue (no reverse video); `-f` fills under line 1; `-C n` sets 
line 1, `-C n/m` sets both. needs a UTF-8 locale and a capable font, else falls 
back.
+
+```
+ping 8.8.8.8 | sed -u 's/^.*time=//g; s/ ms//g' | ttyplot -b -t "ping to 
8.8.8.8" -u ms
+vmstat -n 1 | perl -lane 'BEGIN{$|=1} print "@F[0,1]"' | ttyplot -b -2 -f -t 
"procs in R and D"
+```
+
+
+## experimental: aalib ASCII-art rendering
+
+> **very experimental / throwaway** — off by default, opt-in at build time
+
+`-A` draws smooth **7-bit ASCII** lines via 
[aalib](https://aa-project.sourceforge.net/aalib/) (think `aafire`), for dumb 
terminals that can't do braille/Unicode. same two-line color and `-f` fill as 
braille. not built by default: `make AA=1` (needs aalib + `aalib-config`, adds 
`-DAALIB -laa`). smoothest in a C locale (`LC_ALL=C`); UTF-8 folds down to 
approximate ASCII.
+
+```
+make AA=1
+vmstat -n 1 | perl -lane 'BEGIN{$|=1} print "@F[0,1]"' | LC_ALL=C ttyplot -A 
-2 -f -t "procs in R and D"
+```
+
+&nbsp;
 &nbsp;
 
 
Binary files old/ttyplot-1.7.5/braille.png and new/ttyplot-1.7.6/braille.png 
differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ttyplot-1.7.5/snap/snapcraft.yaml 
new/ttyplot-1.7.6/snap/snapcraft.yaml
--- old/ttyplot-1.7.5/snap/snapcraft.yaml       2026-06-22 04:17:25.000000000 
+0200
+++ new/ttyplot-1.7.6/snap/snapcraft.yaml       2026-07-14 05:38:07.000000000 
+0200
@@ -1,5 +1,5 @@
 name: ttyplot
-version: 1.6.2
+version: '1.7.6'
 summary: realtime plotting utility for terminal/console with data input from 
stdin
 description: |
   takes data from standard input / unix pipeline,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ttyplot-1.7.5/stresstest.c 
new/ttyplot-1.7.6/stresstest.c
--- old/ttyplot-1.7.5/stresstest.c      2026-06-22 04:17:25.000000000 +0200
+++ new/ttyplot-1.7.6/stresstest.c      2026-07-14 05:38:07.000000000 +0200
@@ -20,18 +20,44 @@
 
 const char help[] =
     "Usage:\n"
-    "  stresstest [-2] [-c] [-g] [-n] [-r rate]\n"
+    "  stresstest [-2] [-c] [-g] [-m] [-n] [-R] [-r rate]\n"
     "  stresstest -h\n"
     "\n"
     "  -h       print this help message and exit\n"
     "  -2       output two waves\n"
     "  -c       randomly chunk the output\n"
     "  -g       occasionally output garbage\n"
+    "  -m       output realistic metrics (CPU/bandwidth-like, random spikes)\n"
     "  -n       output negative values\n"
+    "  -R       output uniformly random values across the full range\n"
     "  -r rate  sample rate in samples/s (default: 100)\n"
     "  -s seed  set random seed\n";
 
-const char optstring[] = "h2cgnr:s:";
+const char optstring[] = "h2cgmnRr:s:";
+
+// Return a uniformly random value in [lo, hi].
+static double rand_range(double lo, double hi) {
+    return lo + ((double)rand() / RAND_MAX) * (hi - lo);
+}
+
+// Generate one realistic metrics sample. Models a mean-reverting baseline
+// (Ornstein-Uhlenbeck-style random walk) with occasional sharp spikes that
+// rise instantly and decay exponentially -- resembling CPU/bandwidth load.
+// State is carried in *level and *spike so multiple series stay independent.
+static double metric_sample(double *level, double *spike) {
+    const double target = 20.0;  // baseline the walk reverts toward
+    const double theta = 0.02;   // reversion strength
+    const double sigma = 1.5;    // baseline jitter amplitude
+    const double decay = 0.85;   // spike decay per sample (~6 samples to 1/e)
+
+    double noise = ((double)rand() / RAND_MAX) * 2.0 - 1.0;  // -1..1
+    *level += theta * (target - *level) + sigma * noise;
+    *spike *= decay;
+    if (rand() < RAND_MAX / 100)         // ~1% chance of a new spike
+        *spike += 30.0 + (rand() % 50);  // magnitude 30..79
+    double value = *level + *spike;
+    return value < 0 ? 0 : value;  // load is never negative
+}
 
 int main(int argc, char *argv[]) {
     char buffer[1024];
@@ -40,6 +66,8 @@
     bool two_waves = false;
     bool chunked = false;
     bool add_garbage = false;
+    bool metrics = false;
+    bool super_random = false;
     bool output_negative = false;
     double rate = 100;
     unsigned int seed = time(NULL);
@@ -59,9 +87,15 @@
             case 'g':
                 add_garbage = true;
                 break;
+            case 'm':
+                metrics = true;
+                break;
             case 'n':
                 output_negative = true;
                 break;
+            case 'R':
+                super_random = true;
+                break;
             case 'r':
                 rate = atof(optarg);
                 break;
@@ -81,15 +115,31 @@
     const useconds_t delay = 1e6 / rate;
     srand(seed);
 
+    double level1 = 20.0, spike1 = 0.0;                  // metrics state, 
series 1
+    double level2 = 20.0, spike2 = 0.0;                  // metrics state, 
series 2
+    const double rmin = output_negative ? -100.0 : 0.0;  // -R range
+    const double rmax = 100.0;
+
     for (unsigned int n = 0;; n += 5) {
-        buffer_pos += sprintf(buffer + buffer_pos, "%.1f\n",
-                              (sin(n * M_PI / 180) * 5) + (output_negative ? 0 
: 5));
+        double wave1;
+        if (metrics)
+            wave1 = metric_sample(&level1, &spike1);
+        else if (super_random)
+            wave1 = rand_range(rmin, rmax);
+        else
+            wave1 = (sin(n * M_PI / 180) * 5) + (output_negative ? 0 : 5);
+        buffer_pos += sprintf(buffer + buffer_pos, "%.1f\n", wave1);
         if (add_garbage && rand() <= RAND_MAX / 5)
             buffer_pos += sprintf(buffer + buffer_pos, "garbage ");
         if (two_waves) {
-            buffer_pos +=
-                sprintf(buffer + buffer_pos, "%.1f\n",
-                        (cos(n * M_PI / 180) * 5) + (output_negative ? 0 : 5));
+            double wave2;
+            if (metrics)
+                wave2 = metric_sample(&level2, &spike2);
+            else if (super_random)
+                wave2 = rand_range(rmin, rmax);
+            else
+                wave2 = (cos(n * M_PI / 180) * 5) + (output_negative ? 0 : 5);
+            buffer_pos += sprintf(buffer + buffer_pos, "%.1f\n", wave2);
             if (add_garbage && rand() <= RAND_MAX / 5)
                 buffer_pos += sprintf(buffer + buffer_pos, "garbage ");
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ttyplot-1.7.5/ttyplot.1 new/ttyplot-1.7.6/ttyplot.1
--- old/ttyplot-1.7.5/ttyplot.1 2026-06-22 04:17:25.000000000 +0200
+++ new/ttyplot-1.7.6/ttyplot.1 2026-07-14 05:38:07.000000000 +0200
@@ -1,4 +1,4 @@
-.Dd January 20, 2024
+.Dd June 23, 2026
 .Dt TTYPLOT 1
 .Os
 .Sh NAME
@@ -6,11 +6,21 @@
 .Nd realtime terminal plotting utility
 .Sh SYNOPSIS
 .Nm
-.Op Ar options
+.Op Fl 2bBfr
+.Op Fl c Ar plotchar
+.Op Fl e Ar errcharmax
+.Op Fl E Ar errcharmin
+.Op Fl s Ar softmax
+.Op Fl S Ar softmin
+.Op Fl m Ar hardmax
+.Op Fl M Ar hardmin
+.Op Fl t Ar title
+.Op Fl u Ar unit
+.Op Fl C Ar colorspec
 .Nm
--v
+.Fl v
 .Nm
--h
+.Fl h
 .Sh DESCRIPTION
 .Nm
 takes data from standard input,
@@ -25,12 +35,43 @@
 and plots in text mode on a terminal in real time.
 .Pp
 Supports rate calculation for counters and up to two graphs
-on a single display using reverse video for second line.
+on a single display, using reverse video for the second line
+or, experimentally, braille or block element line drawing in color.
 .Pp
 The following options are supported:
 .Bl -tag -width Ds
 .It Fl 2
 Read two values and draw two plots, the second in reverse video.
+.It Fl b
+.Pq Experimental
+Use braille line drawing instead of block/reverse-video bars.
+With
+.Fl 2 ,
+the two lines are distinguished by color rather than reverse video.
+Requires a UTF-8 locale and a capable font, otherwise falls back.
+.It Fl B
+.Pq Experimental
+Use block element (quadrant) line drawing, like
+.Fl b .
+.It Fl f
+.Pq Experimental
+Fill the area under the line in braille or block mode
+.Pq line 1 .
+.It Fl A
+.Pq Experimental
+Render the plot as
+.Xr aalib 3
+ASCII art: smooth lines in plain 7-bit ASCII, for dumb terminals that cannot
+display braille or block glyphs.
+Like braille or block mode it draws up to two lines distinguished by color, and
+.Fl f
+fills the area under line 1.
+aalib emits its native 7-bit ramp in a C locale; in a UTF-8 locale it is forced
+to 8-bit glyphs which are folded back to ASCII, so for the smoothest output run
+with
+.Ev LC_ALL Ns = Ns Cm C .
+Available only when compiled with aalib support
+.Pq Cm make Ar AA Ns = Ns Ar 1 .
 .It Fl r
 Calculate counter rate and divide by measured sample interval.
 .It Fl c Ar plotchar
@@ -55,6 +96,10 @@
 Use
 .Ar softmax
 as the initial maximum value but allow it to grow with input.
+.It Fl S Ar softmin
+Use
+.Ar softmin
+as the initial minimum value but allow it to shrink with input.
 .It Fl m Ar hardmax
 Use
 .Ar hardmax
@@ -78,6 +123,56 @@
 .It Fl u Ar unit
 Label the vertical axis
 .Ar unit .
+.It Fl C Ar colorspec
+Set colors for plot elements.
+.Ar colorspec
+is either a predefined scheme name or a comma-separated list of
+color numbers
+.Pq Ar 0-7 :
+.Ar plotchar Ns Op / Ns Ar line2 ,
+.Ar axes ,
+.Ar text ,
+.Ar title ,
+.Ar max_err ,
+.Ar min_err .
+Only the first value, the plot line color, is required; the rest
+are optional.
+The optional
+.Ar line2
+sets the second line color in braille or block mode.
+For example
+.Ql Fl C Ar 1,2,3,4,5,6 ,
+.Ql Fl C Ar 1,2
+or
+.Ql Fl C Ar 1 .
+The color numbers are
+.Ar 0
+black,
+.Ar 1
+red,
+.Ar 2
+green,
+.Ar 3
+yellow,
+.Ar 4
+blue,
+.Ar 5
+magenta,
+.Ar 6
+cyan and
+.Ar 7
+white.
+Alternatively,
+.Ar colorspec
+may name a predefined scheme:
+.Ar dark1
+or
+.Ar dark2
+for dark terminals,
+.Ar light1
+or
+.Ar light2
+for light terminals.
 .It Fl v
 Print the current version and exit.
 .It Fl h
@@ -92,6 +187,13 @@
 Quit.
 .It Ic r
 Toggle "rate mode" on and off.
+.It Ic Ctrl-L
+Full screen redraw.
+.El
+.Pp
+These commands do not work when standard input is a terminal;
+in that case quit with
+.Ql Ctrl-C .
 .Sh EXAMPLES
 CPU usage from
 .Xr vmstat 8
@@ -149,6 +251,23 @@
  | ttyplot -t "ping to 8.8.8.8" -u ms
 .Ed
 .Pp
+The same ping plot, drawn with braille
+.Pq see Fl b :
+.Bd -literal -offset indent
+ping 8.8.8.8 \\
+ | sed -u 's/^.*time=//g; s/ ms//g' \\
+ | ttyplot -b -t "ping to 8.8.8.8" -u ms
+.Ed
+.Pp
+The same ping plot, with custom colors for the line, axes, text
+and title
+.Pq see Fl C :
+.Bd -literal -offset indent
+ping 8.8.8.8 \\
+ | sed -u 's/^.*time=//g; s/ ms//g' \\
+ | ttyplot -t "ping to 8.8.8.8" -u ms -C 2,3,4,5
+.Ed
+.Pp
 WiFi signal level in -dBM (higher is worse) using
 .Xr iwconfig 8 :
 .Bd -literal -offset indent
@@ -310,19 +429,21 @@
 Its readme was converted into this manual page by
 .An Sijmen J. Mulder Aq Mt [email protected] .
 .Sh BUGS
-By default in standard in- and output are is buffered.
+By default standard input and output are buffered.
 This can be worked around in various
 .Lk http://www.perkin.org.uk/posts/how-to-fix-stdio-buffering.html ways .
 .Pp
+When there is no more data,
 .Nm
-quits and erases the screen when there is no more data.
-This is by design and can be worked around by adding
-.Xr sleep 1
-or
-.Xr read 1 ,
-for example:
+prints
+.Dq input stream closed
+and waits rather than quitting
+.Pq prior to version 1.5 it quit .
+The screen is normally erased on exit because of the terminal's
+.Lk https://invisible-island.net/xterm/xterm.faq.html#xterm_tite "alternate 
screen" ;
+this can be worked around, for example:
 .Pp
-.Dl { echo "1 2 3"; sleep 1000; } | ttyplot
+.Dl echo 1 2 3 | TERM=vt100 ttyplot
 .Pp
 When running interactively and non-numeric data is entered
 .Pq e.g. some key
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ttyplot-1.7.5/ttyplot.c new/ttyplot-1.7.6/ttyplot.c
--- old/ttyplot-1.7.5/ttyplot.c 2026-06-22 04:17:25.000000000 +0200
+++ new/ttyplot-1.7.6/ttyplot.c 2026-07-14 05:38:07.000000000 +0200
@@ -41,6 +41,14 @@
 #include <err.h>
 #endif
 
+// Experimental, opt-in ASCII-art rendering backend (build with -DAALIB -laa).
+#ifdef AALIB
+#include <aalib.h>
+#define AA_OPT "A"
+#else
+#define AA_OPT ""
+#endif
+
 #define T_RARR '>'
 #define T_UARR '^'
 #ifdef NOACS
@@ -71,6 +79,9 @@
 #define C_CYAN 6
 #define C_WHITE 7
 
+#define PAIR_BR1 8
+#define PAIR_BR2 9
+
 // Define color element indices
 enum ColorElement {
     LINE_COLOR = 0,
@@ -101,10 +112,15 @@
 static int width = 0, height = 0, n = -1, v = 0, c = 0, rate = 0, two = 0,
            plotwidth = WIDTH_MIN - WIDTH_MARGIN, plotheight = 0;
 static bool fake_clock = false;
+static int braille = 0;
+static int braille_fill = 0;
+static int block = 0;
+static int aa = 0;  // only settable when compiled with -DAALIB (see optstring)
 static char *errstr = NULL;
 static bool redraw_needed = false;
 // Array of colors for different elements, -1 means no color specified
 static int colors[NUM_COLOR_ELEMENTS] = {-1, -1, -1, -1, -1, -1};
+static int line2color = -1;
 static const char *verstring = "https://github.com/tenox7/ttyplot " 
VERSION_STR;
 
 static void usage(void) {
@@ -116,6 +132,13 @@
         "  ttyplot -v\n"
         "\n"
         "  -2 read two values and draw two plots, the second one is in reverse 
video\n"
+        "  -b braille line drawing mode (two lines distinguished by color)\n"
+        "  -B block elements drawing mode (quadrants), like -b\n"
+        "  -f fill area under the line in braille/block mode (line 1)\n"
+#ifdef AALIB
+        "  -A (experimental) aalib ASCII-art line mode, two lines in color (-f 
fills "
+        "line 1)\n"
+#endif
         "  -r rate of a counter (divide value by measured sample interval)\n"
         "  -c character to use for plot line, eg @ # %% . etc\n"
         "  -e character to use for error line when value exceeds hardmax 
(default: e)\n"
@@ -129,7 +152,7 @@
         "lower-limit of the plot scale is fixed\n"
         "  -t title of the plot\n"
         "  -u unit displayed beside vertical bar\n"
-        "  -C color[,axes,text,title,max_err,min_err]  set colors (0-7) for 
elements:\n"
+        "  -C color[/line2][,axes,text,title,max_err,min_err]  set colors 
(0-7):\n"
         "     First value: plot line color\n"
         "     Second value: axes color (optional)\n"
         "     Third value: text color (optional)\n"
@@ -138,8 +161,8 @@
         "     Sixth value: min error indicator color (optional)\n"
         "     Example: -C 1,2,3,4,5,6 or -C 1,2 or -C 1\n"
         "     Predefined color schemes:\n"
-        "       -C dark1    Blue-cyan-yellow scheme for dark terminals\n"
-        "       -C dark2    Purple-yellow-green scheme for dark terminals\n"
+        "       -C dark1    Red-green lines for dark terminals\n"
+        "       -C dark2    Blue-yellow lines for dark terminals\n"
         "       -C light1   Green-blue-red scheme for light terminals\n"
         "       -C light2   Blue-green-yellow scheme for light terminals\n"
         "  -v print the current version and exit\n"
@@ -158,21 +181,23 @@
 // Set a predefined color scheme
 static void set_color_scheme(const char *scheme_name) {
     if (strcmp(scheme_name, "dark1") == 0) {
-        // Blue-cyan-yellow scheme for dark terminals
-        colors[LINE_COLOR] = C_BLUE;        // Blue for plot line
+        // Red-green lines for dark terminals
+        colors[LINE_COLOR] = C_RED;         // Red for plot line
+        line2color = C_GREEN;               // Green for second plot line
         colors[AXES_COLOR] = C_CYAN;        // Cyan for axes
         colors[TEXT_COLOR] = C_WHITE;       // White for text
         colors[TITLE_COLOR] = C_YELLOW;     // Yellow for title
         colors[MAX_ERROR_COLOR] = C_RED;    // Red for max error
         colors[MIN_ERROR_COLOR] = C_GREEN;  // Green for min error
     } else if (strcmp(scheme_name, "dark2") == 0) {
-        // Purple-yellow-green scheme for dark terminals
-        colors[LINE_COLOR] = C_MAGENTA;    // Magenta for plot line
-        colors[AXES_COLOR] = C_YELLOW;     // Yellow for axes
-        colors[TEXT_COLOR] = C_CYAN;       // Cyan for text
-        colors[TITLE_COLOR] = C_GREEN;     // Green for title
-        colors[MAX_ERROR_COLOR] = C_RED;   // Red for max error
-        colors[MIN_ERROR_COLOR] = C_BLUE;  // Blue for min error
+        // Blue-yellow lines for dark terminals
+        colors[LINE_COLOR] = C_BLUE;          // Blue for plot line
+        line2color = C_YELLOW;                // Yellow for second plot line
+        colors[AXES_COLOR] = C_CYAN;          // Cyan for axes
+        colors[TEXT_COLOR] = C_WHITE;         // White for text
+        colors[TITLE_COLOR] = C_GREEN;        // Green for title
+        colors[MAX_ERROR_COLOR] = C_RED;      // Red for max error
+        colors[MIN_ERROR_COLOR] = C_MAGENTA;  // Magenta for min error
     } else if (strcmp(scheme_name, "light1") == 0) {
         // Green-blue-red scheme for light terminals
         colors[LINE_COLOR] = C_GREEN;         // Green for plot line
@@ -477,6 +502,209 @@
         attroff(COLOR_PAIR(LINE_COLOR + 1));
 }
 
+// braille (2x4) bits indexed [(y%4)*2 + (x&1)]; quadrant (2x2) bits indexed 
[(y%2)*2 +
+// (x&1)]
+static const unsigned char braille_bits[8] = {0x01, 0x08, 0x02, 0x10,
+                                              0x04, 0x20, 0x40, 0x80};
+static const unsigned char quad_bits[4] = {1, 2, 4, 8};
+static const wchar_t quad_glyphs[16] = {L' ',   0x2598, 0x259D, 0x2580, 
0x2596, 0x258C,
+                                        0x259E, 0x259B, 0x2597, 0x259A, 
0x2590, 0x259C,
+                                        0x2584, 0x2599, 0x259F, 0x2588};
+
+// Render v1/v2 onto a sub-cell pixel grid (sub vertical pixels per cell, 2 
horizontal).
+// glyphs==NULL selects braille (U+2800+bits); otherwise a 16-entry quadrant 
table.
+static void plot_dots(int ph, int pw, double *v1, double *v2, double max, 
double min,
+                      int n, int sub, const unsigned char *bits,
+                      const wchar_t *glyphs) {
+    const int first_col = 3;
+    const int dh = ph * sub, dw = pw * 2;
+
+    if (ph <= 0 || pw <= 0)
+        return;
+
+    double range = max - min;
+    if (range <= 0)
+        range = 1;
+
+    unsigned char *canvas = calloc((size_t)ph * pw, 1);
+    unsigned char *owner = calloc((size_t)ph * pw, 1);
+    if (! canvas || ! owner) {
+        free(canvas);
+        free(owner);
+        return;
+    }
+
+    for (int pass = 0; pass < 2; pass++) {
+        double *vals = (pass == 0) ? v1 : v2;
+        unsigned char who = (pass == 0) ? 1 : 2;
+        int do_fill = (pass == 0) ? braille_fill : 0;
+        if (! vals)
+            continue;
+
+        int prev_y = 0;
+        bool prev_valid = false;
+        for (int x = 0; x < dw; x++) {
+            int a = x / 2;
+            double va = vals[(n + 1 + a) % pw];
+            if (isnan(va)) {
+                prev_valid = false;
+                continue;
+            }
+            double v = va;
+            if ((x & 1) && a + 1 < pw) {
+                double vb = vals[(n + 1 + a + 1) % pw];
+                if (! isnan(vb))
+                    v = (va + vb) / 2;
+            }
+            double frac = (v - min) / range;
+            if (frac < 0)
+                frac = 0;
+            if (frac > 1)
+                frac = 1;
+            int y = (dh - 1) - (int)lrint(frac * (dh - 1));
+
+            int lo = y, hi = y;
+            if (do_fill) {
+                hi = dh - 1;
+            } else if (prev_valid) {
+                lo = (prev_y < y) ? prev_y : y;
+                hi = (prev_y < y) ? y : prev_y;
+            }
+            for (int yy = lo; yy <= hi; yy++) {
+                int idx = (yy / sub) * pw + a;
+                canvas[idx] |= bits[(yy % sub) * 2 + (x & 1)];
+                owner[idx] = who;
+            }
+            prev_y = y;
+            prev_valid = true;
+        }
+    }
+
+    for (int r = 0; r < ph; r++) {
+        for (int c = 0; c < pw; c++) {
+            unsigned char b = canvas[r * pw + c];
+            if (! b)
+                continue;
+            wchar_t ws[2] = {glyphs ? glyphs[b] : (wchar_t)(0x2800 + b), 0};
+            cchar_t cc;
+            short pair = (owner[r * pw + c] == 2) ? PAIR_BR2 : PAIR_BR1;
+            setcchar(&cc, ws, A_NORMAL, pair, NULL);
+            mvadd_wch(1 + r, first_col + c, &cc);
+        }
+    }
+
+    free(canvas);
+    free(owner);
+}
+
+#ifdef AALIB
+// aa is the "dumb terminal" tier: smooth lines in plain 7-bit ASCII. In a 
C/POSIX
+// locale aalib natively emits its 7-bit glyph ramp, which we pass through 
untouched.
+// In a UTF-8 locale it insists on 8-bit CP437 glyphs instead (a load-time 
decision we
+// can't override in-process), so we fold those high bytes down to a 7-bit 
ASCII
+// approximation by shape. For the authentic smooth ramp, run with LC_ALL=C.
+static char aa_ascii(unsigned char b) {
+    if (b >= 0x20 && b < 0x7f)  // includes aalib's own 7-bit ramp
+        return (char)b;
+    switch (b) {
+        case 0xDB:  // full block
+        case 0xB2:
+            return '#';  // dark shade
+        case 0xB1:
+            return '+';  // medium shade
+        case 0xB0:
+            return ':';  // light shade
+        case 0xDF:
+            return '"';  // upper half
+        case 0xDC:
+            return '.';  // lower half
+        case 0xDD:
+            return '[';  // left half
+        case 0xDE:
+            return ']';  // right half
+        case 0xCC:       // diagonal quadrants
+        case 0xA5:
+            return 'x';
+    }
+    return b ? '*' : ' ';
+}
+
+// Experimental: render up to two series as aalib 7-bit ASCII-art, one pass 
each so the
+// two lines can be colored independently (like braille/block mode: line 1 
PAIR_BR1,
+// line 2 PAIR_BR2). Without -f each series is a connected line; with -f, line 
1's area
+// is filled. The aalib context is recreated every paint so it tracks resizes 
for free.
+static void plot_aa(int ph, int pw, double *v1, double *v2, double max, double 
min,
+                    int n) {
+    const int first_col = 3;
+    if (ph <= 0 || pw <= 0)
+        return;
+
+    double range = max - min;
+    if (range <= 0)
+        range = 1;
+
+    struct aa_hardware_params hp = aa_defparams;
+    hp.width = pw;
+    hp.height = ph;
+    aa_context *c = aa_init(&mem_d, &hp, NULL);
+    if (! c)
+        return;
+
+    const int iw = aa_imgwidth(c), ih = aa_imgheight(c);
+
+    for (int pass = 0; pass < 2; pass++) {
+        double *vals = (pass == 0) ? v1 : v2;
+        int do_fill = (pass == 0) ? braille_fill : 0;  // -f fills line 1 only
+        short pair = (pass == 0) ? PAIR_BR1 : PAIR_BR2;
+        if (! vals)
+            continue;
+
+        memset(aa_image(c), 0, (size_t)iw * ih);
+
+        int prev_y = 0;
+        bool prev_valid = false;
+        for (int x = 0; x < iw; x++) {
+            int a = x * pw / iw;  // image column -> data column
+            double va = vals[(n + 1 + a) % pw];
+            if (isnan(va)) {
+                prev_valid = false;
+                continue;
+            }
+            double frac = (va - min) / range;
+            if (frac < 0)
+                frac = 0;
+            if (frac > 1)
+                frac = 1;
+            int y = (ih - 1) - (int)lrint(frac * (ih - 1));
+
+            int lo = y, hi = y;
+            if (do_fill) {
+                hi = ih - 1;
+            } else if (prev_valid) {
+                lo = (prev_y < y) ? prev_y : y;
+                hi = (prev_y < y) ? y : prev_y;
+            }
+            for (int yy = lo; yy <= hi; yy++)
+                aa_putpixel(c, x, yy, 255);
+            prev_y = y;
+            prev_valid = true;
+        }
+
+        aa_render(c, &aa_defrenderparams, 0, 0, pw, ph);
+        unsigned char *text = aa_text(c);
+        for (int r = 0; r < ph; r++)
+            for (int col = 0; col < pw; col++) {
+                unsigned char b = text[r * pw + col];
+                if (b == 0 || b == ' ')
+                    continue;
+                mvaddch(1 + r, first_col + col, (chtype)aa_ascii(b) | 
COLOR_PAIR(pair));
+            }
+    }
+
+    aa_close(c);
+}
+#endif
+
 static void show_all_centered(const char *message) {
     const size_t message_len = strlen(message);
     const int x = ((int)message_len > width) ? 0 : (width / 2 - 
(int)message_len / 2);
@@ -554,7 +782,16 @@
     if (colors[TEXT_COLOR] != -1)
         attron(COLOR_PAIR(TEXT_COLOR + 1));
 
-    mvvline_set(height - 2, 5, &plotchar, 1);
+    if (braille || block) {
+        wchar_t iw[2] = {braille ? 0x28FF : 0x2588, 0};
+        cchar_t ind;
+        setcchar(&ind, iw, A_NORMAL, PAIR_BR1, NULL);
+        mvadd_wch(height - 2, 5, &ind);
+    } else if (aa) {
+        mvaddch(height - 2, 5, '#' | COLOR_PAIR(PAIR_BR1));
+    } else {
+        mvvline_set(height - 2, 5, &plotchar, 1);
+    }
     if (v > 0) {
         mvprintw(height - 2, 7, "last=%.1f min=%.1f max=%.1f avg=%.1f %s ", 
values1[n],
                  min1, max1, avg1, unit);
@@ -562,7 +799,16 @@
             printw(" interval=%.3gs", td);
     }
     if (two) {
-        mvaddch(height - 1, 5, ' ' | A_REVERSE);
+        if (braille || block) {
+            wchar_t iw[2] = {braille ? 0x28FF : 0x2588, 0};
+            cchar_t ind;
+            setcchar(&ind, iw, A_NORMAL, PAIR_BR2, NULL);
+            mvadd_wch(height - 1, 5, &ind);
+        } else if (aa) {
+            mvaddch(height - 1, 5, '#' | COLOR_PAIR(PAIR_BR2));
+        } else {
+            mvaddch(height - 1, 5, ' ' | A_REVERSE);
+        }
         if (v > 0) {
             mvprintw(height - 1, 7, "last=%.1f min=%.1f max=%.1f avg=%.1f %s   
",
                      values2[n], min2, max2, avg2, unit);
@@ -572,8 +818,19 @@
     if (colors[TEXT_COLOR] != -1)
         attroff(COLOR_PAIR(TEXT_COLOR + 1));
 
-    plot_values(plotheight, plotwidth, values1, two ? values2 : NULL, max, 
min, n,
-                &plotchar, &max_errchar, &min_errchar, hardmax, hardmin);
+    if (braille)
+        plot_dots(plotheight, plotwidth, values1, two ? values2 : NULL, max, 
min, n, 4,
+                  braille_bits, NULL);
+    else if (block)
+        plot_dots(plotheight, plotwidth, values1, two ? values2 : NULL, max, 
min, n, 2,
+                  quad_bits, quad_glyphs);
+#ifdef AALIB
+    else if (aa)
+        plot_aa(plotheight, plotwidth, values1, two ? values2 : NULL, max, 
min, n);
+#endif
+    else
+        plot_values(plotheight, plotwidth, values1, two ? values2 : NULL, max, 
min, n,
+                    &plotchar, &max_errchar, &min_errchar, hardmax, hardmin);
 
     draw_axes(height, plotheight, plotwidth, max, min, unit);
 
@@ -819,7 +1076,7 @@
     int i;
     bool stdin_is_open = true;
     int cached_opterr;
-    const char *optstring = "2rc:e:E:s:S:m:M:t:u:vhC:";
+    const char *optstring = "2bBf" AA_OPT "rc:e:E:s:S:m:M:t:u:vhC:";
     int show_ver;
     int show_usage;
 
@@ -892,6 +1149,20 @@
             case '2':
                 two = 1;
                 break;
+            case 'b':
+                braille = 1;
+                break;
+            case 'B':
+                block = 1;
+                break;
+#ifdef AALIB
+            case 'A':
+                aa = 1;
+                break;
+#endif
+            case 'f':
+                braille_fill = 1;
+                break;
             case 'c':
                 mbtowc(&plotchar.chars[0], optarg, MB_CUR_MAX);
                 break;
@@ -913,7 +1184,16 @@
                     int color_idx = 0;
 
                     while (token != NULL && color_idx < NUM_COLOR_ELEMENTS) {
-                        colors[color_idx++] = atoi(token);
+                        if (color_idx == 0) {
+                            char *slash = strchr(token, '/');
+                            if (slash) {
+                                *slash = '\0';
+                                line2color = atoi(slash + 1);
+                            }
+                        }
+                        if (*token)
+                            colors[color_idx] = atoi(token);
+                        color_idx++;
                         token = strtok(NULL, ",");
                     }
 
@@ -949,6 +1229,10 @@
     if (hardmax <= hardmin)
         hardmax = FLT_MAX;
 
+    // braille/block need wide glyphs; aa is 7-bit ASCII so it works on dumb 
terminals.
+    if (MB_CUR_MAX <= 1)
+        braille = block = 0;
+
     if (initscr() == NULL) {
         fprintf(stderr, "Error: failed to initialize ncurses\n");
         exit(1);
@@ -968,7 +1252,7 @@
         }
     }
 
-    if (has_colors) {
+    if (has_colors || braille || block || aa) {
         start_color();
         use_default_colors();
 
@@ -986,6 +1270,15 @@
                 init_pair(i + 1, colors[i], -1);  // -1 for default background
             }
         }
+
+        if (braille || block || aa) {
+            int br1 = (colors[LINE_COLOR] != -1) ? colors[LINE_COLOR] : 
C_GREEN;
+            int br2 = (line2color != -1) ? line2color
+                      : (br1 == C_BLUE)  ? C_GREEN
+                                         : C_BLUE;
+            init_pair(PAIR_BR1, br1, -1);
+            init_pair(PAIR_BR2, br2, -1);
+        }
     }
 
     gettimeofday(&now, NULL);

Reply via email to