2 * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <telescope.h>
26 #define TAB_CURRENT 0x1
28 #define CTRL(x) ((x)&0x1F)
30 static struct event stdioev, winchev;
32 static struct tab *current_tab(void);
33 static void dispatch_stdio(int, short, void*);
34 static void handle_resize(int, short, void*);
35 static int word_bourdaries(const char*, const char*, const char**, const char**);
36 static void wrap_text(const char*, const char*, const char*, const char*);
37 static void redraw_tab(struct tab*);
44 TAILQ_FOREACH(t, &tabshead, tabs) {
45 if (t->flags & TAB_CURRENT)
54 dispatch_stdio(int fd, short ev, void *d)
70 redraw_tab(current_tab());
74 printw("You typed %c\n", c);
79 handle_resize(int sig, short ev, void *d)
85 redraw_tab(current_tab());
89 * Helper function for wrap_text. Find the end of the current word
90 * and the end of the separator after the word.
93 word_boundaries(const char *s, const char *sep, const char **endword, const char **endspc)
101 /* find the end of the current world */
102 for (; *s != '\0'; ++s) {
103 if (strchr(sep, *s) != NULL)
109 /* find the end of the separator */
110 for (; *s != '\0'; ++s) {
111 if (strchr(sep, *s) == NULL)
121 emitline(const char *prfx, size_t zero, size_t *off)
123 printw("\n%s", prfx);
128 emitstr(const char **s, size_t len, size_t *off)
132 /* printw("%*s", ...) doesn't seem to respect the precision, so... */
133 for (i = 0; i < len; ++i)
140 * Wrap the text, prefixing the first line with prfx1 and the
141 * following with prfx2, and breaking on characters in the breakon set.
142 * The idea is pretty simple: if there is enough space, write the next
143 * word; if we are at the start of a line and there's not enough
144 * space, hard-split it.
146 * TODO: it considers each byte one cell on the screen!
147 * TODO: assume strlen(prfx1) == strlen(prfx2)
150 wrap_text(const char *prfx1, const char *prfx2, const char *line, const char *breakon)
152 size_t zero, off, len, split;
153 const char *endword, *endspc;
156 zero = strlen(prfx1);
159 while (word_boundaries(line, breakon, &endword, &endspc)) {
160 len = endword - line;
161 if (off + len < COLS) {
162 emitstr(&line, len, &off);
164 emitline(prfx2, zero, &off);
165 while (len >= COLS) {
167 printw("%*s", COLS-1, line);
168 emitline(prfx2, zero, &off);
174 emitstr(&line, len, &off);
177 /* print the spaces iff not at bol */
178 len = endspc - endword;
181 if (off + len >= COLS)
182 emitline(prfx2, zero, &off);
184 emitstr(&line, len, &off);
194 redraw_tab(struct tab *tab)
197 const char *sep = " \t";
201 TAILQ_FOREACH(l, &tab->page.head, lines) {
204 wrap_text("", "", l->line, sep);
207 wrap_text("=> ", " ", l->line, sep);
210 wrap_text("# ", " ", l->line, sep);
213 wrap_text("## ", " ", l->line, sep);
216 wrap_text("### ", " ", l->line, sep);
219 wrap_text("* ", " ", l->line, sep);
222 wrap_text("> ", "> ", l->line, sep);
228 case LINE_PRE_CONTENT:
229 printw("%s\n", l->line);
240 setlocale(LC_ALL, "");
247 intrflush(stdscr, FALSE);
248 keypad(stdscr, TRUE);
250 /* non-blocking input */
255 event_set(&stdioev, 0, EV_READ | EV_PERSIST, dispatch_stdio, NULL);
256 event_add(&stdioev, NULL);
258 signal_set(&winchev, SIGWINCH, handle_resize, NULL);
259 signal_add(&winchev, NULL);
265 ui_on_new_tab(struct tab *tab)
269 TAILQ_FOREACH(t, &tabshead, tabs) {
270 t->flags &= ~TAB_CURRENT;
273 tab->flags = TAB_CURRENT;
275 /* TODO: redraw the tab list */
279 ui_on_tab_refresh(struct tab *tab)
281 if (!(tab->flags & TAB_CURRENT))