git.y1.nz

lwl

Less with links.
download: http://git.y1.nz/archives/lwl.tar.gz
README | Files | Log | Refs

commit 68b15e23ecfc8b2e718be3620a28d8e2d74eca89
Author: Emma Weaver <emma@y1.nz>
Date:   Mon, 22 Jun 2026 11:41:50 -0500

Initial less-like work, everything up to searching works

Diffstat:
A.gitignore2++
AMakefile19+++++++++++++++++++
AREADME32++++++++++++++++++++++++++++++++
ATODO23+++++++++++++++++++++++
Aconfig.h5+++++
Aconfig.mk4++++
Ainput.c54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainput.h14++++++++++++++
Amain.c333+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amarkup.c22++++++++++++++++++++++
Amarkup.h16++++++++++++++++
Aterm.c79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aterm.h1+
Atest/173+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/23+++
Atest/34++++
Atest/478++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/53+++
18 files changed, 765 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,2 @@ +*.o +lwl diff --git a/Makefile b/Makefile @@ -0,0 +1,19 @@ +include config.mk + +all: lwl + +lwl: main.c term.o markup.o config.h + $(CC) main.c markup.o term.o -o lwl + +install: lwl + cp -f lwl $(PREFIX)/lwl + echo "TODO: copy man page also" + +clean: + rm -f term.o markup.o lwl + +term.o: term.c term.h + $(CC) term.c -c -o term.o + +markup.o: markup.c markup.h + $(CC) markup.c -c -o markup.o diff --git a/README b/README @@ -0,0 +1,32 @@ +LWL: less with links + +The goal is for this to eventually become a text-only web-browser, +like lynx or w3m but smaller, more focused, and more modular. + +So far it is just a tiny reimplementation of less. + +Controls: + Basic Navigation (DONE*): + q - exit + jk - scroll up/down + hl - scroll right/left + gG - jump to top/bottom of file + /? - search forwards or backwards + del - delete char or exit search if no chars + enter - search (*TODO) + (highlight matches while active, instead of links) + nN - walk through search results + (these are just a subset of less.) + + Web Navigation (TODO): + (selected link is highlighted) + (*KEY FOR PREVIEWING FULL LINK?) + (or just always preview it? maybe there need to be top bar(s)...) + (if the selected link goes off screen...) + (when scrolling up, select earliest visible link) + (when scrolling down, select latest visible link) + tab - go to next visible link (+shift for backwards) + enter - follow the selected link (*HOW exactly?) + shift+enter - run script (*HOW exactly?) with the link + + - running arbitrary commands with them (Ex. cat $link >> my-bookmarks) diff --git a/TODO b/TODO @@ -0,0 +1,23 @@ + +BUGS +[x] Fix test/4 output (splits a line weirdly in the "authors" section) + (there were backspace chars. Solution: display weird chars in hex) +[x] Figure out how to match less' lack of flicker + - to reproduce issue: less or lwl on test/1, then press Gjjjjjj(etc) + (Solution: DON'T flush output until rendering is over. Kinda obv lol..) + +PLANNED FEATURES +[x] Add make target "install" +[ ] Separate into modules / clean up the code +[ ] Load file in 1d array instead of 2d screen-width-dependent one +[ ] Add searching +[ ] Add usage: + cat test/1 | lwl + echo -e "a\nb\nc\n\ndef" | lwl + (less achieves this by reading input from tty) +[ ] Add links + colors !! +[ ] Write man page + +NOT THAT IMPORTANT +[ ] Add support for Very Large Files +[ ] Optimize it? at least reduce flickering... diff --git a/config.h b/config.h @@ -0,0 +1,5 @@ + +#define MAX_SCREEN_WIDTH 3000 +#define MAX_SCREEN_HEIGHT 2000 + +#define MAX_INPUT_LENGTH 300 diff --git a/config.mk b/config.mk @@ -0,0 +1,4 @@ +# edit this to match your environment & preference + +PREFIX = /usr/local +CC = cc -Wpedantic diff --git a/input.c b/input.c @@ -0,0 +1,54 @@ + +const char *hex_letters = "0123456789ABCDEF"; + +// TODO clean this up and put the input parsing into its own method... +// TODO also, buffer the input into a linear array in addition to the lines table +#define PUT_TO_LINES(ch) {\ + if (x >= screen_width) { \ + total_lines++; \ + x = 0; \ + y++; \ + } \ + \ + lines[y][x] = ch; \ + lines[y][x+1] = '\0'; \ + x++; \ +} +void +read_contents(char **lines, FILE *fin) +{ + char c; + + total_lines = 1; + int x = 0, y = 0; + for (;;) { + c = fgetc(fin); + if (c == EOF) break; + + if (c == '\n') { + total_lines++; + x = 0; + y++; + continue; + } + + if (isprint(c) || c == '\t') { + PUT_TO_LINES(c) + } else { + int x0 = x, y0 = y; + /* for weird characters, just display them in hex: */ + /* be super obvious and transparent when it happens, */ + /* to encourage users to think about what their input is doing. */ + PUT_TO_LINES('#'); + PUT_TO_LINES(hex_letters[((unsigned int) c / 16) % 16]); + PUT_TO_LINES(hex_letters[(unsigned int) c % 16]); + + // TODO add a highlight + Markup *highlight = alloc_markup(x0, y0, 3); + highlight->prefix = "\033[41m"; + highlight->suffix = "\033[40m"; + markups[markup_count++] = highlight; + } + } +} + diff --git a/input.h b/input.h @@ -0,0 +1,14 @@ + +typedef struct _fc { + /* the input, loaded into memory */ + char *buffer; + + /* indices in buffer */ + int *newlines; + int newline_count; +} FileContents; + +typedef struct _state { + int line_offset; + int *line_starts; +} ScreenState; diff --git a/main.c b/main.c @@ -0,0 +1,333 @@ +#include <stdio.h> /* printf, stdin/out/err, etc */ +#include <termios.h> /* termios struct, tsetattr */ +#include <stdlib.h> /* exit */ +#include <ctype.h> /* isprint */ + +#include "config.h" +#include "term.h" +#include "markup.h" + +/* CONSTANTS */ +#define MODE_GROUND 0 +#define MODE_SEARCH 1 +#define MODE_USE_LINK 2 +const char *mode_indicators = ":/>"; + +/* GLOBAL VARS (sowwy,, ill cwean dis up l8r >w<) */ +struct termios termios0; +char lines[MAX_SCREEN_HEIGHT][MAX_SCREEN_WIDTH]; +int total_lines; +int line_offset = 0; +int screen_width, screen_height; + +int mode = MODE_GROUND; +char input_buffer[MAX_INPUT_LENGTH]; +int input_length = 0; +const char *message = NULL; +const char *filename = NULL; + +/* "intrinsic" markups, like highlighting for special chars */ +Markup *markups[10000]; +int markup_count = 0; + +void +set_termios_raw(FILE *fd) +{ + struct termios termios1; + tcgetattr(fileno(fd), &termios0); + tcgetattr(fileno(fd), &termios1); + cfmakeraw(&termios1); + tcsetattr(fileno(fd), TCSANOW, &termios1); +} + +const char *hex_letters = "0123456789ABCDEF!!!!!!"; + +// TODO clean this up and put the input parsing into its own method... +// TODO also, buffer the input into a linear array in addition to the lines table +#define PUT_TO_LINES(ch) {\ + if (x >= screen_width) { \ + total_lines++; \ + x = 0; \ + y++; \ + } \ + \ + lines[y][x] = ch; \ + lines[y][x+1] = '\0'; \ + x++; \ +} +void +read_contents(FILE *fin) +{ + char c; + + total_lines = 1; + int x = 0, y = 0; + for (;;) { + c = fgetc(fin); + if (c == EOF) break; + + if (c == '\n') { + total_lines++; + x = 0; + y++; + continue; + } + + if (isprint(c) || c == '\t') { + PUT_TO_LINES(c) + } else { + int x0 = x, y0 = y; + /* for weird characters, just display them in hex: */ + /* be super obvious and transparent when it happens, */ + /* to encourage users to think about what their input is doing. */ + PUT_TO_LINES('x'); + PUT_TO_LINES(hex_letters[((unsigned int) c / 16) % 16]); + PUT_TO_LINES(hex_letters[(unsigned int) c % 16]); + + // TODO add a highlight + Markup *highlight = alloc_markup(x0, y0, 3); + highlight->prefix = "\033[41m"; + highlight->suffix = "\033[40m"; + markups[markup_count++] = highlight; + } + } +} + +void +draw_status_line() +{ + // TODO or other message, like "No matches found" or etc + if (message != NULL) + printf("\033[30;47m" "%s" "\033[0m", message); + else printf("%c", mode_indicators[mode]); + + if (mode == MODE_SEARCH) { + for (int i = 0; i < input_length; i++) + putchar(input_buffer[i]); + } + + // TODO render command input +} + +void +draw_markups() +{ + Markup *m; + for (int i = 0; i < markup_count; i++) { + m = markups[i]; + + // TODO generalize out onscreen-checking... + // TODO handle markups starting offscreen? (OR NOT IF ITS TOO COMPLEX) + if ( + m->y0 - line_offset < 0 || + m->y0 - line_offset >= screen_height + ) continue; + + printf("\033[%d;%dH", m->y0 + 1 - line_offset, m->x0 + 1); + printf("%s", m->prefix); + + int x = m->x0, y = m->y0; + char ch; + for (int j = 0; j < m->w; j++) { + /* if we've moved offscreen, STOP and dont mess up scroll */ + if ( + m->y0 - line_offset < 0 || + m->y0 - line_offset >= screen_height + ) break; + + ch = lines[y][x]; + if (ch == '\0') { + x = 0; + y++; + printf("\n\r"); + j--; + continue; + } + + putchar(ch); + x++; + } + printf("%s", m->suffix); + } + + /* go down and left and clear line */ + printf("\033[9999B" "\033[9999D" "\033[2K"); +} + +void +redraw() +{ + int y; + // printf("\033[2J" "\033[1;1H"); + printf("\033[1;1H"); + for (int i = 0; i < screen_height; i++) { + y = line_offset+i; + + if (y < 0) printf("!!!"); + else if (y >= total_lines) printf("~"); + else printf("\033[2K" "%s", lines[y]); + + printf("\n\r"); + } + draw_markups(); + draw_status_line(); + fflush(stdout); + + /* always reset message after rendering */ + message = NULL; +} + +void +scroll_to(int offset) +{ + line_offset = offset; + + /* the +1 shows one overflow tilde. */ + if (line_offset+screen_height > total_lines+1) + line_offset = total_lines+1 - screen_height; + + /* this ordering shows short files at top-of-screen */ + if (line_offset < 0) line_offset = 0; + + if (line_offset >= total_lines - screen_height) + message = "(END)"; + + if (line_offset == 0) + message = filename; +} + +int +handle_ground_input(char ch) +{ + if (ch == 'q') return 1; + + /* ctrl-C */ + if (ch == 0x03) return 1; + + /* enter */ + if (ch == 0x0D) scroll_to(line_offset + 1); + + if (ch == 'g') scroll_to(0); + if (ch == 'G') scroll_to(total_lines+1 - screen_height); + if (ch == 'j') scroll_to(line_offset + 1); + if (ch == 'k') scroll_to(line_offset - 1); + if (ch == ' ') scroll_to(line_offset + screen_height); + + if (ch == '/') { + message = "Yet unimplemented D:"; + return 0; + mode = MODE_SEARCH; + input_length = 0; + input_buffer[0] = '\0'; + } + + if (ch == '?') message = "Use / instead"; + if (ch == '<') message = "Use g instead"; + if (ch == '>') message = "Use G instead"; + + return 0; +} + +int +handle_search_input(char ch) +{ + /* ctrl-C */ + if (ch == 0x03) return 1; + + /* backspace */ + if (ch == 0x7F) { + input_buffer[input_length] = '\0'; + input_length--; + if (input_length < 0) { + mode = MODE_GROUND; + input_length = 0; + } + return 0; + } + + /* enter */ + if (ch == 0x0D) { + mode = MODE_GROUND; + message = "No matches found (actually unimplemented SHHH)"; + return 0; + } + + if (input_length+1 >= screen_width) + return 0; + + input_buffer[input_length] = ch; + input_buffer[input_length+1] = '\0'; + input_length++; + + return 0; +} + +int +handle_input(char ch) +{ + switch (mode) { + case MODE_GROUND: return handle_ground_input(ch); + case MODE_SEARCH: return handle_search_input(ch); + } +} + +int +main(int argc, const char *argv[]) +{ + FILE *fin; + int line_index; + int result; + + input_buffer[0] = '\0'; + + // TODO more properly read in options and/or filename + if (argc == 1) { + printf("TODO: piping input" "\n"); + exit(1); + fin = tmpfile(); + char c; + for (;;) { + c = fgetc(stdin); + if (c == EOF) break; + fputc(c, fin); + fputc(c, stdout); + } + if (fin == NULL) { + printf("Error opening tmp file :(" "\n"); + exit(1); + } + } else if (argc != 2) { + printf("Usage: %s FILENAME" "\n", argv[0]); + exit(1); + } + + result = get_root_size(stdin, stdout, &screen_width, &screen_height); + screen_height--; /* accounts for status line */ + if (!result) { + printf("Failed to measure terminal :(" "\n"); + exit(1); + } + + fin = fopen(argv[1], "r"); + message = filename = argv[1]; + read_contents(fin); + fclose(fin); + + set_termios_raw(stdin); + redraw(); + + char ch; + for (;;) { + ch = fgetc(stdin); + result = handle_input(ch); + if (result > 0) break; + redraw(); + } + + tcsetattr(fileno(stdin), TCSANOW, &termios0); + for (int i = 0; i < markup_count; i++) + free_markup(markups[i]); + + /* clear the line and move cursor to left */ + printf("\033[2K" "\033[9999D"); +} diff --git a/markup.c b/markup.c @@ -0,0 +1,22 @@ +#include <stdlib.h> /* malloc & free */ + +#include "markup.h" + +Markup * +alloc_markup(int x0, int y0, int width) +{ + Markup *ret = (Markup *) malloc(sizeof(Markup)); + ret->x0 = x0; + ret->y0 = y0; + ret->w = width; + ret->prefix = ""; + ret->suffix = ""; + ret->data = ""; + return ret; +} + +void +free_markup(Markup *m) +{ + free(m); +} diff --git a/markup.h b/markup.h @@ -0,0 +1,16 @@ + +typedef struct _markup { + /* position and size of marked text */ + int x0, y0, w; + + /* set/reset fg/bg colors surrounding the marked text */ + /* must not move cursor or print to display! */ + const char *prefix; + const char *suffix; + + // TODO metadata/contents (Ex. <a> hrefs, <img> src, annotations? etc) + const char *data; +} Markup; + +Markup *alloc_markup(int x0, int y0, int width); +void free_markup(Markup *m); diff --git a/term.c b/term.c @@ -0,0 +1,79 @@ + +#include <stdio.h> +#include <termios.h> +#include <unistd.h> +#include <ctype.h> +#include <stdlib.h> /* exit */ + +#define RESPONSE_SIZE 10 + +int +query_cursor_position(FILE *tin, FILE *tout, int *x, int *y) +{ + int ch = 0; + int result; + struct termios original, changed; + char response[RESPONSE_SIZE] = ""; + int index = 0; + + /* set termios to avoid hanging for response */ + result = tcgetattr(fileno(tin), &original); + if (result < 0) { + printf("Error getting termios" "\n"); + exit(1); + } + changed = original; + changed.c_lflag &= ~(ICANON | ECHO); + changed.c_cc[VMIN] = 1; + changed.c_cc[VTIME] = 0; + result = tcsetattr(fileno(tin), TCSANOW, &changed); + if (result < 0) { + printf("Error getting termios" "\n"); + exit(1); + } + + /* query cursor position */ + fprintf(tout, "\033[6n"); + fflush(tout); + + for (;;) { + ch = fgetc(tin); + if (ch == 'R' || ch == EOF || index >= RESPONSE_SIZE) break; + if (!isprint(ch)) continue; + response[index++] = ch; + } + response[index] = '\0'; + + /* no R at the end of the format */ + result = sscanf(response, "[%d;%d", y, x); + + result = tcsetattr(fileno(tin), TCSANOW, &original); + if (result < 0) { + printf("Error reset termios" "\n"); + exit(1); + } + return true; // result == 2; +} + +int +get_root_size(FILE *tin, FILE *tout, int *x, int *y) +{ + int x0, y0; + int result; + result = query_cursor_position(tin, tout, &x0, &y0); + if (!result) { + fprintf(stderr, "FAILURE!!" "\n"); + return 0; + } + + /* move down/right until end of screen */ + fprintf(tout, "\033[9999B" "\033[9999C"); + fflush(tout); + result = query_cursor_position(tin, tout, x, y); + + /* move cursor back to original position */ + fprintf(tout, "\033[%d;%dH", y0, x0); + fflush(tout); + + return result; +} diff --git a/term.h b/term.h @@ -0,0 +1 @@ +int get_root_size(FILE *tin, FILE *tout, int *x, int *y); diff --git a/test/1 b/test/1 @@ -0,0 +1,73 @@ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(end) +dddddddddd + +test + + aaaaaaaaaaaaaaa + +... aaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + cccccccccccccccccccccccccccccccccccccccccccccc(end) + dddddddddddddddddddddddddddddddddddddd(end) + eeeeeeeeeeeeeeeeeeeeeeeeeeeeee(ned) +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(end) +dddddddddd + +test + + aaaaaaaaaaaaaaa + +... aaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + cccccccccccccccccccccccccccccccccccccccccccccc(end) + dddddddddddddddddddddddddddddddddddddd(end) + eeeeeeeeeeeeeeeeeeeeeeeeeeeeee(ned) +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(end) +dddddddddd + +test + + aaaaaaaaaaaaaaa + +... aaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +. +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +. +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +. +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +. +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +. +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + cccccccccccccccccccccccccccccccccccccccccccccc(end) + dddddddddddddddddddddddddddddddddddddd(end) + eeeeeeeeeeeeeeeeeeeeeeeeeeeeee(ned) +. +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + cccccccccccccccccccccccccccccccccccccccccccccc(end) + dddddddddddddddddddddddddddddddddddddd(end) + eeeeeeeeeeeeeeeeeeeeeeeeeeeeee(ned) +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + cccccccccccccccccccccccccccccccccccccccccccccc(end) + dddddddddddddddddddddddddddddddddddddd(end) + eeeeeeeeeeeeeeeeeeeeeeeeeeeeee(ned) +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + cccccccccccccccccccccccccccccccccccccccccccccc(end) + dddddddddddddddddddddddddddddddddddddd(end) + eeeeeeeeeeeeeeeeeeeeeeeeeeeeee(ned) +. +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + cccccccccccccccccccccccccccccccccccccccccccccc(end) + dddddddddddddddddddddddddddddddddddddd(end) + eeeeeeeeeeeeeeeeeeeeeeeeeeeeee(ned) diff --git a/test/2 b/test/2 @@ -0,0 +1,3 @@ +the quick brown fox jumped over the lazy dog. the quick brown fox jumped over the lazy dog. the quick brown fox jumped over the lazy dog. the quick brown fox jumped over the lazy dog. the quick brown fox jumped over the lazy dog. the quick brown fox jumped over the lazy dog. the quick brown fox jumped over the lazy dog. the quick brown fox jumped over the lazy dog. +Line 2 +Line 3 diff --git a/test/3 b/test/3 @@ -0,0 +1,4 @@ +\033[35mpurple purple purple purple mmmmmpurple hehe abc abc abc 123 123 123 def def def ghi hi ghi +one two three four five six seven eight + +\033[0mreset reset reset diff --git a/test/4 b/test/4 @@ -0,0 +1,78 @@ +SGW(1) General Commands Manual SGW(1) + +NNAAMMEE + ssggww – static git webpage generator + +SSYYNNOOPPSSIISS + ssggww [--ii] [--pp] [--oo _o_u_t_d_i_r] [--bb _b_a_s_e_u_r_l] _r_e_p_o [_r_e_p_o_2 [...]] + +DDEESSCCRRIIPPTTIIOONN + ssggww writes a webpage consisting of index and repository pages for bare + repositories located at _r_e_p_o, _r_e_p_o_2, etc. Non-bare repositories can also + be used, but will be labelled as "untitled" wherever their name would + have appeared. Its options are as follows: + + --ii If present, generate an index page. The exact file this page is + saved to is defined by config.h at compile time. + + --pp If present, generate the specified repositories' pages. + + --oo _o_u_t_d_i_r + Write all output files under the _o_u_t_d_i_r directory. The exact + destinations of the files are determined by the paths specified + in config.h at compile time. + + --bb _b_a_s_e_u_r_l + Links within the generated webpages include this path, to allow + the webpage to be served from the _b_a_s_e_u_r_l subdirectory. + + The program will return with a failing status if neither of --ii and --pp are + specified, or if no repositories are selected. + + ssggww will do nothing to attempt to clean up the output it has produced if + it fails after writing files. + + It does not remove any files from its output directories and does not + make changes to any of the input repositories. + + It will not, however, indicate any kind of warning before overwriting the + files it has been configured to write its output into. + +EEXXIITT SSTTAATTUUSS + The ssggww utility exits 0 on success, and >0 if an error occurs. + +SSEEEE AALLSSOO + git(1) + +AAUUTTHHOORRSS + Emma Weaver <_e_m_m_a_@_y_1_._n_z> + Based heavily on work by Hiltjo Posthuma <_h_i_l_t_j_o_@_c_o_d_e_m_a_d_n_e_s_s_._o_r_g> + +Linux 6.18.33-0-lts August 2, 2021 Linux 6.18.33-0-lts +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 Extra Lines! :) diff --git a/test/5 b/test/5 @@ -0,0 +1,2 @@ +abc defra babaskubba + doop +

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.