mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
4effa23528
- POSIX regular expressions for Lua - Improved protocol parsing and encoding - Additional APIs for ZIP storage retrieval - Fix st_mode issue on NT for regular files - Generalized APIs for URL and Host handling - Worked out the kinks in resource resolution - Allow for custom error pages like /404.html
175 lines
5.1 KiB
C
175 lines
5.1 KiB
C
#if 0
|
|
/*─────────────────────────────────────────────────────────────────╗
|
|
│ To the extent possible under law, Justine Tunney has waived │
|
|
│ all copyright and related or neighboring rights to this file, │
|
|
│ as it is written in the following disclaimers: │
|
|
│ • http://unlicense.org/ │
|
|
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
|
╚─────────────────────────────────────────────────────────────────*/
|
|
#endif
|
|
#include "libc/calls/calls.h"
|
|
#include "libc/calls/ioctl.h"
|
|
#include "libc/calls/struct/sigaction.h"
|
|
#include "libc/calls/struct/termios.h"
|
|
#include "libc/calls/struct/winsize.h"
|
|
#include "libc/log/check.h"
|
|
#include "libc/log/gdb.h"
|
|
#include "libc/log/log.h"
|
|
#include "libc/macros.internal.h"
|
|
#include "libc/runtime/gc.internal.h"
|
|
#include "libc/runtime/runtime.h"
|
|
#include "libc/str/str.h"
|
|
#include "libc/sysv/consts/sa.h"
|
|
#include "libc/sysv/consts/sig.h"
|
|
#include "libc/sysv/consts/termios.h"
|
|
#include "libc/x/x.h"
|
|
#include "tool/build/lib/panel.h"
|
|
|
|
/**
|
|
* @fileoverview Cosmopolitan Paneling Demo.
|
|
*
|
|
* This is useful for creating terminal user interfaces. We take the
|
|
* simplest approach possible. The main thing we abstract is like,
|
|
* truncating the lines that overflow within a panel. In order to do
|
|
* that, we abstract the ANSI parsing and the implementation is able to
|
|
* tell how many cells wide each UNICODE character is.
|
|
*
|
|
* There are smarter ways for Cosmopolitan to do this. For example, it'd
|
|
* be great to have automatic flex boxes. It'd also be nice to be able
|
|
* to use dynamic programming for low bandwidth display updates, like
|
|
* Emacs does, but that's less of an issue these days and can actually
|
|
* make things slower, since for heavy workloads like printing videos,
|
|
* having ANSI codes bouncing around the display actually goes slower.
|
|
*
|
|
* Beyond basic paneling, a message box widget is also provided, which
|
|
* makes it easier to do modal dialogs.
|
|
*/
|
|
|
|
struct Panels {
|
|
union {
|
|
struct {
|
|
struct Panel left;
|
|
struct Panel right;
|
|
};
|
|
struct Panel p[2];
|
|
};
|
|
} pan;
|
|
|
|
long tyn;
|
|
long txn;
|
|
char key[8];
|
|
bool shutdown;
|
|
bool invalidated;
|
|
struct termios oldterm;
|
|
|
|
void OnShutdown(int sig) {
|
|
shutdown = true;
|
|
}
|
|
|
|
void OnInvalidate(int sig) {
|
|
invalidated = true;
|
|
}
|
|
|
|
void GetTtySize(void) {
|
|
struct winsize wsize;
|
|
wsize.ws_row = tyn;
|
|
wsize.ws_col = txn;
|
|
getttysize(1, &wsize);
|
|
tyn = wsize.ws_row;
|
|
txn = wsize.ws_col;
|
|
}
|
|
|
|
int Write(const char *s) {
|
|
return write(1, s, strlen(s));
|
|
}
|
|
|
|
void Setup(void) {
|
|
CHECK_NE(-1, ioctl(1, TCGETS, &oldterm));
|
|
}
|
|
|
|
void Enter(void) {
|
|
struct termios term;
|
|
memcpy(&term, &oldterm, sizeof(term));
|
|
term.c_cc[VMIN] = 1;
|
|
term.c_cc[VTIME] = 1;
|
|
term.c_iflag &= ~(INPCK | ISTRIP | PARMRK | INLCR | IGNCR | ICRNL | IXON);
|
|
term.c_lflag &= ~(IEXTEN | ICANON | ECHO | ECHONL);
|
|
term.c_cflag &= ~(CSIZE | PARENB);
|
|
term.c_cflag |= CS8;
|
|
term.c_iflag |= IUTF8;
|
|
CHECK_NE(-1, ioctl(1, TCSETS, &term));
|
|
Write("\e[?25l");
|
|
}
|
|
|
|
void Leave(void) {
|
|
Write(gc(xasprintf("\e[?25h\e[%d;%dH\e[S\r\n", tyn, txn)));
|
|
ioctl(1, TCSETS, &oldterm);
|
|
}
|
|
|
|
void Clear(void) {
|
|
long i, j;
|
|
for (i = 0; i < ARRAYLEN(pan.p); ++i) {
|
|
for (j = 0; j < pan.p[i].n; ++j) {
|
|
free(pan.p[i].lines[j].p);
|
|
}
|
|
free(pan.p[i].lines);
|
|
pan.p[i].lines = 0;
|
|
pan.p[i].n = 0;
|
|
}
|
|
}
|
|
|
|
void Layout(void) {
|
|
long i, j;
|
|
i = txn >> 1;
|
|
pan.left.top = 0;
|
|
pan.left.left = 0;
|
|
pan.left.bottom = tyn;
|
|
pan.left.right = i;
|
|
pan.right.top = 0;
|
|
pan.right.left = i + 1;
|
|
pan.right.bottom = tyn;
|
|
pan.right.right = txn;
|
|
pan.left.n = pan.left.bottom - pan.left.top;
|
|
pan.left.lines = xcalloc(pan.left.n, sizeof(*pan.left.lines));
|
|
pan.right.n = pan.right.bottom - pan.right.top;
|
|
pan.right.lines = xcalloc(pan.right.n, sizeof(*pan.right.lines));
|
|
}
|
|
|
|
void Append(struct Panel *p, int i, const char *s) {
|
|
if (i >= p->n) return;
|
|
AppendStr(p->lines + i, s);
|
|
}
|
|
|
|
void Draw(void) {
|
|
Append(&pan.left, 0, gc(xasprintf("you typed %`'s", key)));
|
|
Append(&pan.left, ((tyn + 1) >> 1) + 0, "hello left 1 𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷");
|
|
Append(&pan.left, ((tyn + 1) >> 1) + 1, "hello left 2 (╯°□°)╯");
|
|
Append(&pan.right, ((tyn + 1) >> 1) + 0, "hello right 1");
|
|
Append(&pan.right, ((tyn + 1) >> 1) + 1, "hello right 2");
|
|
PrintPanels(1, ARRAYLEN(pan.p), pan.p, tyn, txn);
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
struct sigaction sa[2] = {{.sa_handler = OnShutdown},
|
|
{.sa_handler = OnInvalidate}};
|
|
showcrashreports();
|
|
Setup();
|
|
Enter();
|
|
GetTtySize();
|
|
sigaction(SIGINT, &sa[0], 0);
|
|
sigaction(SIGCONT, &sa[1], 0);
|
|
sigaction(SIGWINCH, &sa[1], 0);
|
|
atexit(Leave);
|
|
do {
|
|
Clear();
|
|
Layout();
|
|
Draw();
|
|
if (invalidated) {
|
|
Enter();
|
|
GetTtySize();
|
|
invalidated = false;
|
|
} else {
|
|
readansi(0, key, sizeof(key));
|
|
}
|
|
} while (!shutdown);
|
|
}
|