- May need to support sending XOFF/XON to control speed, if too fast it
still jump scrolls, because the next scroll operation is requested before
the smooth scrolling offset animation expires.
+ So far nice with a tool like: | sleepycat -s0 -l144 -w80
+ Where 150 is how many ms to delay per line and 80 is the width where
+ sleeping also occurs despite the lack of a newline. 144 was chosen since
+ it's a multiple of 8, the font's height.
- When the cursor is down and a command is typed then the whole screen
quickly refreshed, the scroll jump is a bit strange, similarly to a
vertically desynched TV. Unsure if some control flow somewhere or timer
works when it's configured to put its status bar at the top rather than at
the bottom, but a strange refresh artefact at the top happens. tmux(1)
just redisplays its bar after scrolling.
+ - Smooth scrolling within a scroll region where the bottom is not the end of
+ the terminal would work, considering that the rendering is actually drawn
+ per scanline. The cursor drawing code would also need to take this into
+ account.
- Various latin characters look strange and could be improved.
- Links appears to enter DEC Special Graphics for some reason and to not exit
it. This does not happen under tmux(1).
--- /dev/null
+/*
+ * A slowed down cat for ascii animation. Also useful for rate-limiting
+ * a transfer over a narrow channel, e.g., sending data over a dialup
+ * link so as to not overly interfere with interactive use.
+ *
+ * bsy@cs.cmu.edu
+ *
+ * Adapted by Matthew Mondor in 2022 to support line/width based timer, for
+ * use with AnalogTerm's smooth scrolling. The original source was found
+ * here:
+ * https://github.com/bennetyee/TekGraphics
+ * To compile, use:
+ * $ cc -o sleepycat sleepycat.c
+ * Example usage for AnalogTerm:
+ * $ tail -F <logfile> | sleepycat -s0 -l144 -w80
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void usage(void) {
+ fprintf(stderr,"Usage: sleepycat [-c skip] [-s ms] [-l ms] [-w width] [files]...\n");
+}
+
+static void sleepycat(FILE *fp, long c, long s, long ls, long w) {
+ int ch;
+ long i, wi, left;
+
+ i = 0;
+ wi = 0;
+ s *= 1000;
+ if (s < 0 || s > 1000000) {
+ fprintf(stderr, "sleepycat: truncating character timer\n");
+ s = 1000000;
+ }
+ ls *= 1000;
+ if (ls < 0) {
+ fprintf(stderr, "sleepycat: truncating line timer\n");
+ ls = 1000000;
+ }
+ while ((ch = getc(fp)) != EOF) {
+ int s_p = 0;
+
+ if (ls != 0) {
+ if (ch == '\n') {
+ wi = 0;
+ s_p = 1;
+ }
+ if (w != 0 && wi == w) {
+ wi = 0;
+ s_p = 1;
+ }
+ }
+ if (s_p) {
+ fflush(stdout);
+ for (left = ls; left > 0; ) {
+ long t;
+
+ t = left;
+ if (t >= 1000000) t = 999999;
+ usleep(t);
+ left -= t;
+ }
+ }
+ putchar(ch);
+ if (w != 0)
+ wi++;
+ if (++i == c) {
+ fflush(stdout);
+ if (s != 0)
+ usleep(s);
+ i = 0;
+ }
+ }
+}
+
+int main(int ac, char **av) {
+ long snooze, lsnooze, count, width;
+ int ch;
+ extern char *optarg;
+ extern int optind, getopt();
+ FILE *fp, *fopen();
+
+ count = 1;
+ snooze = 1;
+ lsnooze = 0;
+ width = 0;
+ while ((ch = getopt(ac,av,"c:s:l:w:")) != EOF) switch (ch) {
+ case 'c': count = atol(optarg); break;
+ case 's': snooze = atol(optarg); break;
+ case 'l': lsnooze = atol(optarg); break;
+ case 'w': width = atol(optarg); break;
+ default: usage(); exit(1);
+ }
+ if (count <= 0) {
+ fprintf(stderr,"sleepycat: bogus skip count!\n");
+ count = 1;
+ }
+ if (snooze < 0 || lsnooze < 0) {
+ fprintf(stderr,"sleepycat: bogus timer!\n");
+ snooze = 1;
+ lsnooze = 0;
+ }
+ if (width < 0) {
+ fprintf(stderr,"sleepycat: bogus width!\n");
+ width = 0;
+ }
+ if (optind == ac) sleepycat(stdin,count,snooze,lsnooze,width);
+ else for (; optind < ac; optind++) {
+ if ((fp = fopen(av[optind],"r"))) {
+ sleepycat(fp,count,snooze,lsnooze,width);
+ (void) fclose(fp);
+ } else {
+ perror("sleepycat");
+ fprintf(stderr,"sleepycat: can not open %s\n",av[optind]);
+ }
+ }
+
+ exit(EXIT_SUCCESS);
+}