commit - a00b4c97e6dd47ac8ada094890b515cfe6744607
commit + 2b2d2872b6aacc66cdcc7af08ab684c12616c33d
blob - 3bf75054ea85c4d6faa82c75cc2d7bde823157b1
blob + c8dfd1f1aff18357ca810bf4fef758d08050cfa4
--- Makefile.am
+++ Makefile.am
bin_PROGRAMS = telescope
-telescope_SOURCES = cmd.h \
+telescope_SOURCES = cmd.c \
+ cmd.h \
cmd.gen.h \
compat.h \
compat/*.[ch] \
blob - /dev/null
blob + 13a09a1ddd29c5bb8469aca4f7fe0280cf245ddd (mode 644)
--- /dev/null
+++ cmd.c
+/*
+ * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "telescope.h"
+#include "cmd.gen.h"
+
+#define message ui_notify
+
+void
+cmd_previous_line(struct buffer *buffer)
+{
+ struct vline *vl;
+
+ if (buffer->current_line == NULL
+ || (vl = TAILQ_PREV(buffer->current_line, vhead, vlines)) == NULL)
+ return;
+
+ if (--buffer->curs_y < 0) {
+ buffer->curs_y = 0;
+ cmd_scroll_line_up(buffer);
+ return;
+ }
+
+ buffer->current_line = vl;
+ restore_cursor(buffer);
+}
+
+void
+cmd_next_line(struct buffer *buffer)
+{
+ struct vline *vl;
+
+ if (buffer->current_line == NULL
+ || (vl = TAILQ_NEXT(buffer->current_line, vlines)) == NULL)
+ return;
+
+ if (++buffer->curs_y > body_lines-1) {
+ buffer->curs_y = body_lines-1;
+ cmd_scroll_line_down(buffer);
+ return;
+ }
+
+ buffer->current_line = vl;
+ restore_cursor(buffer);
+}
+
+void
+cmd_backward_char(struct buffer *buffer)
+{
+ if (buffer->cpoff != 0)
+ buffer->cpoff--;
+ restore_cursor(buffer);
+}
+
+void
+cmd_forward_char(struct buffer *buffer)
+{
+ size_t len = 0;
+
+ if (buffer->current_line->line != NULL)
+ len = utf8_cplen(buffer->current_line->line);
+ if (++buffer->cpoff > len)
+ buffer->cpoff = len;
+ restore_cursor(buffer);
+}
+
+void
+cmd_backward_paragraph(struct buffer *buffer)
+{
+ do {
+ if (buffer->current_line == NULL ||
+ buffer->current_line == TAILQ_FIRST(&buffer->head)) {
+ message("No previous paragraph");
+ return;
+ }
+ cmd_previous_line(buffer);
+ } while (buffer->current_line->line != NULL ||
+ buffer->current_line->parent->type != LINE_TEXT);
+}
+
+void
+cmd_forward_paragraph(struct buffer *buffer)
+{
+ do {
+ if (buffer->current_line == NULL ||
+ buffer->current_line == TAILQ_LAST(&buffer->head, vhead)) {
+ message("No next paragraph");
+ return;
+ }
+ cmd_next_line(buffer);
+ } while (buffer->current_line->line != NULL ||
+ buffer->current_line->parent->type != LINE_TEXT);
+}
+
+void
+cmd_move_beginning_of_line(struct buffer *buffer)
+{
+ buffer->cpoff = 0;
+ restore_cursor(buffer);
+}
+
+void
+cmd_move_end_of_line(struct buffer *buffer)
+{
+ struct vline *vl;
+
+ vl = buffer->current_line;
+ if (vl->line == NULL)
+ return;
+ buffer->cpoff = utf8_cplen(vl->line);
+ restore_cursor(buffer);
+}
+
+void
+cmd_redraw(struct buffer *buffer)
+{
+ ui_schedule_redraw();
+}
+
+void
+cmd_scroll_line_up(struct buffer *buffer)
+{
+ struct vline *vl;
+
+ if (buffer->current_line == NULL)
+ return;
+
+ if ((vl = TAILQ_PREV(buffer->current_line, vhead, vlines)) == NULL)
+ return;
+
+ buffer->current_line = vl;
+ buffer->line_off--;
+ restore_cursor(buffer);
+}
+
+void
+cmd_scroll_line_down(struct buffer *buffer)
+{
+ struct vline *vl;
+
+ if (buffer->current_line == NULL)
+ return;
+
+ if ((vl = TAILQ_NEXT(buffer->current_line, vlines)) == NULL)
+ return;
+
+ buffer->current_line = vl;
+ buffer->line_off++;
+ restore_cursor(buffer);
+}
+
+void
+cmd_scroll_up(struct buffer *buffer)
+{
+ size_t off;
+
+ off = body_lines-1;
+
+ for (; off > 0; --off)
+ cmd_scroll_line_up(buffer);
+}
+
+void
+cmd_scroll_down(struct buffer *buffer)
+{
+ size_t off;
+
+ off = body_lines-1;
+
+ for (; off > 0; --off)
+ cmd_scroll_line_down(buffer);
+}
+
+void
+cmd_beginning_of_buffer(struct buffer *buffer)
+{
+ buffer->current_line = TAILQ_FIRST(&buffer->head);
+ buffer->line_off = 0;
+ buffer->curs_y = 0;
+ buffer->cpoff = 0;
+ restore_cursor(buffer);
+}
+
+void
+cmd_end_of_buffer(struct buffer *buffer)
+{
+ ssize_t off;
+
+ off = buffer->line_max - body_lines;
+ off = MAX(0, off);
+
+ buffer->line_off = off;
+ buffer->curs_y = MIN((size_t)body_lines, buffer->line_max-1);
+
+ buffer->current_line = TAILQ_LAST(&buffer->head, vhead);
+ buffer->cpoff = body_cols;
+ restore_cursor(buffer);
+}
+
+void
+cmd_kill_telescope(struct buffer *buffer)
+{
+ save_session();
+ event_loopbreak();
+}
+
+void
+cmd_push_button(struct buffer *buffer)
+{
+ struct vline *vl;
+
+ vl = buffer->current_line;
+ if (vl->parent->type != LINE_LINK)
+ return;
+
+ load_url_in_tab(current_tab(), vl->parent->alt);
+}
+
+void
+cmd_push_button_new_tab(struct buffer *buffer)
+{
+ struct vline *vl;
+
+ vl = buffer->current_line;
+ if (vl->parent->type != LINE_LINK)
+ return;
+
+ new_tab(vl->parent->alt);
+}
+
+void
+cmd_previous_button(struct buffer *buffer)
+{
+ do {
+ if (buffer->current_line == NULL ||
+ buffer->current_line == TAILQ_FIRST(&buffer->head)) {
+ message("No previous link");
+ return;
+ }
+ cmd_previous_line(buffer);
+ } while (buffer->current_line->parent->type != LINE_LINK);
+}
+
+void
+cmd_next_button(struct buffer *buffer)
+{
+ do {
+ if (buffer->current_line == NULL ||
+ buffer->current_line == TAILQ_LAST(&buffer->head, vhead)) {
+ message("No next link");
+ return;
+ }
+ cmd_next_line(buffer);
+ } while (buffer->current_line->parent->type != LINE_LINK);
+}
+
+void
+cmd_previous_page(struct buffer *buffer)
+{
+ struct tab *tab = current_tab();
+
+ if (!load_previous_page(tab))
+ message("No previous page");
+ else
+ start_loading_anim(tab);
+}
+
+void
+cmd_next_page(struct buffer *buffer)
+{
+ struct tab *tab = current_tab();
+
+ if (!load_next_page(tab))
+ message("No next page");
+ else
+ start_loading_anim(tab);
+}
+
+void
+cmd_clear_minibuf(struct buffer *buffer)
+{
+ message(NULL);
+}
+
+void
+cmd_execute_extended_command(struct buffer *buffer)
+{
+ size_t len;
+
+ if (in_minibuffer) {
+ message("We don't have enable-recursive-minibuffers");
+ return;
+ }
+
+ enter_minibuffer(eecmd_self_insert, eecmd_select, exit_minibuffer,
+ &eecmd_history);
+
+ len = sizeof(ministate.prompt);
+ strlcpy(ministate.prompt, "", len);
+
+ if (thiskey.meta)
+ strlcat(ministate.prompt, "M-", len);
+
+ strlcat(ministate.prompt, ui_keyname(thiskey.key), len);
+
+ if (thiskey.meta)
+ strlcat(ministate.prompt, " ", len);
+}
+
+void
+cmd_tab_close(struct buffer *buffer)
+{
+ struct tab *tab, *t;
+
+ tab = current_tab();
+ if (TAILQ_PREV(tab, tabshead, tabs) == NULL &&
+ TAILQ_NEXT(tab, tabs) == NULL) {
+ message("Can't close the only tab.");
+ return;
+ }
+
+ if (evtimer_pending(&tab->loadingev, NULL))
+ evtimer_del(&tab->loadingev);
+
+ stop_tab(tab);
+
+ if ((t = TAILQ_PREV(tab, tabshead, tabs)) == NULL)
+ t = TAILQ_NEXT(tab, tabs);
+ TAILQ_REMOVE(&tabshead, tab, tabs);
+ free(tab);
+
+ switch_to_tab(t);
+}
+
+void
+cmd_tab_close_other(struct buffer *buffer)
+{
+ struct tab *t, *i;
+
+ TAILQ_FOREACH_SAFE(t, &tabshead, tabs, i) {
+ if (t->flags & TAB_CURRENT)
+ continue;
+
+ stop_tab(t);
+ TAILQ_REMOVE(&tabshead, t, tabs);
+ free(t);
+ }
+}
+
+void
+cmd_tab_new(struct buffer *buffer)
+{
+ const char *url;
+
+ if ((url = new_tab_url) == NULL)
+ url = NEW_TAB_URL;
+
+ new_tab(url);
+}
+
+void
+cmd_tab_next(struct buffer *buffer)
+{
+ struct tab *tab, *t;
+
+ tab = current_tab();
+ tab->flags &= ~TAB_CURRENT;
+
+ if ((t = TAILQ_NEXT(tab, tabs)) == NULL)
+ t = TAILQ_FIRST(&tabshead);
+ t->flags |= TAB_CURRENT;
+ t->flags &= ~TAB_URGENT;
+}
+
+void
+cmd_tab_previous(struct buffer *buffer)
+{
+ struct tab *tab, *t;
+
+ tab = current_tab();
+ tab->flags &= ~TAB_CURRENT;
+
+ if ((t = TAILQ_PREV(tab, tabshead, tabs)) == NULL)
+ t = TAILQ_LAST(&tabshead, tabshead);
+ t->flags |= TAB_CURRENT;
+ t->flags &= ~TAB_URGENT;
+}
+
+void
+cmd_tab_move(struct buffer *buffer)
+{
+ struct tab *tab, *t;
+
+ tab = current_tab();
+ t = TAILQ_NEXT(tab, tabs);
+ TAILQ_REMOVE(&tabshead, tab, tabs);
+
+ if (t == NULL)
+ TAILQ_INSERT_HEAD(&tabshead, tab, tabs);
+ else
+ TAILQ_INSERT_AFTER(&tabshead, t, tab, tabs);
+}
+
+void
+cmd_tab_move_to(struct buffer *buffer)
+{
+ struct tab *tab, *t;
+
+ tab = current_tab();
+ t = TAILQ_PREV(tab, tabshead, tabs);
+ TAILQ_REMOVE(&tabshead, tab, tabs);
+
+ if (t == NULL) {
+ if (TAILQ_EMPTY(&tabshead))
+ TAILQ_INSERT_HEAD(&tabshead, tab, tabs);
+ else
+ TAILQ_INSERT_TAIL(&tabshead, tab, tabs);
+ } else
+ TAILQ_INSERT_BEFORE(t, tab, tabs);
+}
+
+void
+cmd_load_url(struct buffer *buffer)
+{
+ if (in_minibuffer) {
+ message("We don't have enable-recursive-minibuffers");
+ return;
+ }
+
+ enter_minibuffer(lu_self_insert, lu_select, exit_minibuffer,
+ &lu_history);
+ strlcpy(ministate.prompt, "Load URL: ", sizeof(ministate.prompt));
+ strlcpy(ministate.buf, "gemini://", sizeof(ministate.buf));
+ cmd_move_end_of_line(&ministate.buffer);
+}
+
+void
+cmd_load_current_url(struct buffer *buffer)
+{
+ struct tab *tab = current_tab();
+
+ if (in_minibuffer) {
+ message("We don't have enable-recursive-minibuffers");
+ return;
+ }
+
+ enter_minibuffer(lu_self_insert, lu_select, exit_minibuffer,
+ &lu_history);
+ strlcpy(ministate.prompt, "Load URL: ", sizeof(ministate.prompt));
+ strlcpy(ministate.buf, tab->hist_cur->h, sizeof(ministate.buf));
+ ministate.buffer.cpoff = utf8_cplen(ministate.buf);
+}
+
+void
+cmd_bookmark_page(struct buffer *buffer)
+{
+ struct tab *tab = current_tab();
+
+ enter_minibuffer(lu_self_insert, bp_select, exit_minibuffer, NULL);
+ strlcpy(ministate.prompt, "Bookmark URL: ", sizeof(ministate.prompt));
+ strlcpy(ministate.buf, tab->hist_cur->h, sizeof(ministate.buf));
+ ministate.buffer.cpoff = utf8_cplen(ministate.buf);
+}
+
+void
+cmd_list_bookmarks(struct buffer *buffer)
+{
+ load_url_in_tab(current_tab(), "about:bookmarks");
+}
+
+void
+cmd_toggle_help(struct buffer *buffer)
+{
+ ui_toggle_side_window();
+ ui_schedule_redraw();
+}
+
+void
+cmd_olivetti_mode(struct buffer *buffer)
+{
+ olivetti_mode = !olivetti_mode;
+ if (olivetti_mode)
+ message("olivetti-mode enabled");
+ else
+ message("olivetti-mode disabled");
+
+ ui_schedule_redraw();
+}
+
+void
+cmd_mini_delete_char(struct buffer *buffer)
+{
+ char *c, *n;
+
+ if (!in_minibuffer) {
+ message("text is read-only");
+ return;
+ }
+
+ minibuffer_taint_hist();
+
+ c = utf8_nth(buffer->current_line->line, buffer->cpoff);
+ if (*c == '\0')
+ return;
+ n = utf8_next_cp(c);
+
+ memmove(c, n, strlen(n)+1);
+}
+
+void
+cmd_mini_delete_backward_char(struct buffer *buffer)
+{
+ char *c, *p, *start;
+
+ if (!in_minibuffer) {
+ message("text is read-only");
+ return;
+ }
+
+ minibuffer_taint_hist();
+
+ c = utf8_nth(buffer->current_line->line, buffer->cpoff);
+ start = buffer->current_line->line;
+ if (c == start)
+ return;
+ p = utf8_prev_cp(c-1, start);
+
+ memmove(p, c, strlen(c)+1);
+ buffer->cpoff--;
+}
+
+void
+cmd_mini_kill_line(struct buffer *buffer)
+{
+ char *c;
+
+ if (!in_minibuffer) {
+ message("text is read-only");
+ return;
+ }
+
+ minibuffer_taint_hist();
+ c = utf8_nth(buffer->current_line->line, buffer->cpoff);
+ *c = '\0';
+}
+
+void
+cmd_mini_abort(struct buffer *buffer)
+{
+ if (!in_minibuffer)
+ return;
+
+ ministate.abortfn();
+}
+
+void
+cmd_mini_complete_and_exit(struct buffer *buffer)
+{
+ if (!in_minibuffer)
+ return;
+
+ minibuffer_taint_hist();
+ ministate.donefn();
+}
+
+void
+cmd_mini_previous_history_element(struct buffer *buffer)
+{
+ if (ministate.history == NULL) {
+ message("No history");
+ return;
+ }
+
+ if (ministate.hist_cur == NULL ||
+ (ministate.hist_cur = TAILQ_PREV(ministate.hist_cur, mhisthead, entries)) == NULL) {
+ ministate.hist_cur = TAILQ_LAST(&ministate.history->head, mhisthead);
+ ministate.hist_off = ministate.history->len - 1;
+ if (ministate.hist_cur == NULL)
+ message("No prev item");
+ } else {
+ ministate.hist_off--;
+ }
+
+ if (ministate.hist_cur != NULL)
+ buffer->current_line->line = ministate.hist_cur->h;
+}
+
+void
+cmd_mini_next_history_element(struct buffer *buffer)
+{
+ if (ministate.history == NULL) {
+ message("No history");
+ return;
+ }
+
+ if (ministate.hist_cur == NULL ||
+ (ministate.hist_cur = TAILQ_NEXT(ministate.hist_cur, entries)) == NULL) {
+ ministate.hist_cur = TAILQ_FIRST(&ministate.history->head);
+ ministate.hist_off = 0;
+ if (ministate.hist_cur == NULL)
+ message("No next item");
+ } else {
+ ministate.hist_off++;
+ }
+
+ if (ministate.hist_cur != NULL)
+ buffer->current_line->line = ministate.hist_cur->h;
+}
blob - ae84fd1733a499d1c4f7f3d5002172687c81fde2
blob + f6f9fc1db5be5a52a95bb4725e7ba43ed15fd45f
--- telescope.h
+++ telescope.h
TAILQ_HEAD(vhead, vline) head;
};
+
+#define TAB_CURRENT 0x1
+#define TAB_URGENT 0x2
+
+#define NEW_TAB_URL "about:new"
+
extern TAILQ_HEAD(tabshead, tab) tabshead;
struct tab {
TAILQ_ENTRY(tab) tabs;
void tofu_update(struct ohash*, struct tofu_entry*);
/* ui.c */
+extern int body_lines;
+extern int body_cols;
+extern int in_minibuffer;
+
+struct thiskey {
+ short meta;
+ int key;
+ uint32_t cp;
+};
+extern struct thiskey thiskey;
+
+extern struct histhead eecmd_history,
+ ir_history,
+ lu_history,
+ read_history;
+
+struct ministate {
+ char *curmesg;
+
+ char prompt[64];
+ void (*donefn)(void);
+ void (*abortfn)(void);
+
+ char buf[1025];
+ struct line line;
+ struct vline vline;
+ struct buffer buffer;
+
+ struct histhead *history;
+ struct hist *hist_cur;
+ size_t hist_off;
+};
+extern struct ministate ministate;
+
+void restore_cursor(struct buffer *);
+void minibuffer_taint_hist(void);
+void eecmd_self_insert(void);
+void eecmd_select(void);
+void ir_self_insert(void);
+void ir_select(void);
+void lu_self_insert(void);
+void lu_select(void);
+void bp_select(void);
+void start_loading_anim(struct tab *tab);
+void load_url_in_tab(struct tab *, const char *);
+void enter_minibuffer(void(*)(void), void(*)(void), void(*)(void), struct histhead *);
+void exit_minibuffer(void);
+void switch_to_tab(struct tab *);
+struct tab *current_tab(void);
+struct tab *new_tab(const char *);
unsigned int tab_new_id(void);
int ui_init(int, char * const*);
void ui_on_tab_loaded(struct tab*);
void ui_on_tab_refresh(struct tab*);
+const char *ui_keyname(int);
+void ui_toggle_side_window(void);
+void ui_schedule_redraw(void);
void ui_require_input(struct tab*, int);
void ui_read(const char*, void(*)(const char*, unsigned int), unsigned int);
void ui_yornp(const char*, void (*)(int, unsigned int), unsigned int);
blob - 82a0fedd736cd241035a1e18f08fabc0f32e5a95
blob + 867e350f864d47b60e15ec7ac4d51321c54c334a
--- ui.c
+++ ui.c
#include <string.h>
#include <unistd.h>
-#define TAB_CURRENT 0x1
-#define TAB_URGENT 0x2
-
-#define NEW_TAB_URL "about:new"
-
static struct event stdioev, winchev;
static void load_default_keys(void);
-static void restore_cursor(struct buffer*);
static void global_key_unbound(void);
static void minibuffer_hist_save_entry(void);
-static void minibuffer_taint_hist(void);
static void minibuffer_self_insert(void);
-static void eecmd_self_insert(void);
-static void eecmd_select(void);
-static void ir_self_insert(void);
-static void ir_select(void);
-static void lu_self_insert(void);
-static void lu_select(void);
-static void bp_select(void);
static void yornp_self_insert(void);
static void yornp_abort(void);
static void read_self_insert(void);
static void read_select(void);
static struct vline *nth_line(struct buffer*, size_t);
-static struct tab *current_tab(void);
static struct buffer *current_buffer(void);
static int readkey(void);
static void dispatch_stdio(int, short, void*);
static void recompute_help(void);
static void vmessage(const char*, va_list);
static void message(const char*, ...) __attribute__((format(printf, 1, 2)));
-static void start_loading_anim(struct tab*);
static void update_loading_anim(int, short, void*);
static void stop_loading_anim(struct tab*);
-static void load_url_in_tab(struct tab*, const char*);
-static void enter_minibuffer(void(*)(void), void(*)(void), void(*)(void), struct histhead*);
-static void exit_minibuffer(void);
-static void switch_to_tab(struct tab*);
-static struct tab *new_tab(const char*);
static void session_new_tab_cb(const char*);
static void usage(void);
static int x_offset;
-static struct { short meta; int key; uint32_t cp; } thiskey;
+struct thiskey thiskey;
static struct event resizeev;
static struct timeval resize_timer = { 0, 250000 };
static WINDOW *tabline, *body, *modeline, *minibuf;
-static int body_lines, body_cols;
+int body_lines, body_cols;
+
static WINDOW *help;
static struct buffer helpwin;
static int help_lines, help_cols;
*current_map,
*base_map;
-static struct histhead eecmd_history,
+struct histhead eecmd_history,
ir_history,
lu_history,
read_history;
-static int in_minibuffer;
+int in_minibuffer;
-static struct {
- char *curmesg;
-
- char prompt[64];
- void (*donefn)(void);
- void (*abortfn)(void);
-
- char buf[1025];
- struct line line;
- struct vline vline;
- struct buffer buffer;
-
- struct histhead *history;
- struct hist *hist_cur;
- size_t hist_off;
-} ministate;
+struct ministate ministate;
static inline void
update_x_offset()
minibuffer_set_key("<down>", cmd_mini_next_history_element);
}
-static void
+void
restore_cursor(struct buffer *buffer)
{
struct vline *vl;
if (vl != NULL) {
prfx = line_prefixes[vl->parent->type].prfx1;
buffer->curs_x += utf8_swidth(prfx);
- }
-}
-
-void
-cmd_previous_line(struct buffer *buffer)
-{
- struct vline *vl;
-
- if (buffer->current_line == NULL
- || (vl = TAILQ_PREV(buffer->current_line, vhead, vlines)) == NULL)
- return;
-
- if (--buffer->curs_y < 0) {
- buffer->curs_y = 0;
- cmd_scroll_line_up(buffer);
- return;
- }
-
- buffer->current_line = vl;
- restore_cursor(buffer);
-}
-
-void
-cmd_next_line(struct buffer *buffer)
-{
- struct vline *vl;
-
- if (buffer->current_line == NULL
- || (vl = TAILQ_NEXT(buffer->current_line, vlines)) == NULL)
- return;
-
- if (++buffer->curs_y > body_lines-1) {
- buffer->curs_y = body_lines-1;
- cmd_scroll_line_down(buffer);
- return;
- }
-
- buffer->current_line = vl;
- restore_cursor(buffer);
-}
-
-void
-cmd_backward_char(struct buffer *buffer)
-{
- if (buffer->cpoff != 0)
- buffer->cpoff--;
- restore_cursor(buffer);
-}
-
-void
-cmd_forward_char(struct buffer *buffer)
-{
- size_t len = 0;
-
- if (buffer->current_line->line != NULL)
- len = utf8_cplen(buffer->current_line->line);
- if (++buffer->cpoff > len)
- buffer->cpoff = len;
- restore_cursor(buffer);
-}
-
-void
-cmd_backward_paragraph(struct buffer *buffer)
-{
- do {
- if (buffer->current_line == NULL ||
- buffer->current_line == TAILQ_FIRST(&buffer->head)) {
- message("No previous paragraph");
- return;
- }
- cmd_previous_line(buffer);
- } while (buffer->current_line->line != NULL ||
- buffer->current_line->parent->type != LINE_TEXT);
-}
-
-void
-cmd_forward_paragraph(struct buffer *buffer)
-{
- do {
- if (buffer->current_line == NULL ||
- buffer->current_line == TAILQ_LAST(&buffer->head, vhead)) {
- message("No next paragraph");
- return;
- }
- cmd_next_line(buffer);
- } while (buffer->current_line->line != NULL ||
- buffer->current_line->parent->type != LINE_TEXT);
-}
-
-void
-cmd_move_beginning_of_line(struct buffer *buffer)
-{
- buffer->cpoff = 0;
- restore_cursor(buffer);
-}
-
-void
-cmd_move_end_of_line(struct buffer *buffer)
-{
- struct vline *vl;
-
- vl = buffer->current_line;
- if (vl->line == NULL)
- return;
- buffer->cpoff = utf8_cplen(vl->line);
- restore_cursor(buffer);
-}
-
-void
-cmd_redraw(struct buffer *buffer)
-{
- handle_resize(0, 0, NULL);
-}
-
-void
-cmd_scroll_line_up(struct buffer *buffer)
-{
- struct vline *vl;
-
- if (buffer->current_line == NULL)
- return;
-
- if ((vl = TAILQ_PREV(buffer->current_line, vhead, vlines)) == NULL)
- return;
-
- buffer->current_line = vl;
- buffer->line_off--;
- restore_cursor(buffer);
-}
-
-void
-cmd_scroll_line_down(struct buffer *buffer)
-{
- struct vline *vl;
-
- if (buffer->current_line == NULL)
- return;
-
- if ((vl = TAILQ_NEXT(buffer->current_line, vlines)) == NULL)
- return;
-
- buffer->current_line = vl;
- buffer->line_off++;
- restore_cursor(buffer);
-}
-
-void
-cmd_scroll_up(struct buffer *buffer)
-{
- size_t off;
-
- off = body_lines-1;
-
- for (; off > 0; --off)
- cmd_scroll_line_up(buffer);
-}
-
-void
-cmd_scroll_down(struct buffer *buffer)
-{
- size_t off;
-
- off = body_lines-1;
-
- for (; off > 0; --off)
- cmd_scroll_line_down(buffer);
-}
-
-void
-cmd_beginning_of_buffer(struct buffer *buffer)
-{
- buffer->current_line = TAILQ_FIRST(&buffer->head);
- buffer->line_off = 0;
- buffer->curs_y = 0;
- buffer->cpoff = 0;
- restore_cursor(buffer);
-}
-
-void
-cmd_end_of_buffer(struct buffer *buffer)
-{
- ssize_t off;
-
- off = buffer->line_max - body_lines;
- off = MAX(0, off);
-
- buffer->line_off = off;
- buffer->curs_y = MIN((size_t)body_lines, buffer->line_max-1);
-
- buffer->current_line = TAILQ_LAST(&buffer->head, vhead);
- buffer->cpoff = body_cols;
- restore_cursor(buffer);
-}
-
-void
-cmd_kill_telescope(struct buffer *buffer)
-{
- save_session();
- event_loopbreak();
-}
-
-void
-cmd_push_button(struct buffer *buffer)
-{
- struct vline *vl;
- size_t nth;
-
- nth = buffer->line_off + buffer->curs_y;
- if (nth >= buffer->line_max)
- return;
- vl = nth_line(buffer, nth);
- if (vl->parent->type != LINE_LINK)
- return;
-
- load_url_in_tab(current_tab(), vl->parent->alt);
-}
-
-void
-cmd_push_button_new_tab(struct buffer *buffer)
-{
- struct vline *vl;
- size_t nth;
-
- nth = buffer->line_off + buffer->curs_y;
- if (nth > buffer->line_max)
- return;
- vl = nth_line(buffer, nth);
- if (vl->parent->type != LINE_LINK)
- return;
-
- new_tab(vl->parent->alt);
-}
-
-void
-cmd_previous_button(struct buffer *buffer)
-{
- do {
- if (buffer->current_line == NULL ||
- buffer->current_line == TAILQ_FIRST(&buffer->head)) {
- message("No previous link");
- return;
- }
- cmd_previous_line(buffer);
- } while (buffer->current_line->parent->type != LINE_LINK);
-}
-
-void
-cmd_next_button(struct buffer *buffer)
-{
- do {
- if (buffer->current_line == NULL ||
- buffer->current_line == TAILQ_LAST(&buffer->head, vhead)) {
- message("No next link");
- return;
- }
- cmd_next_line(buffer);
- } while (buffer->current_line->parent->type != LINE_LINK);
-}
-
-void
-cmd_previous_page(struct buffer *buffer)
-{
- struct tab *tab = current_tab();
-
- if (!load_previous_page(tab))
- message("No previous page");
- else
- start_loading_anim(tab);
-}
-
-void
-cmd_next_page(struct buffer *buffer)
-{
- struct tab *tab = current_tab();
-
- if (!load_next_page(tab))
- message("No next page");
- else
- start_loading_anim(tab);
-}
-
-void
-cmd_clear_minibuf(struct buffer *buffer)
-{
- handle_clear_minibuf(0, 0, NULL);
-}
-
-void
-cmd_execute_extended_command(struct buffer *buffer)
-{
- size_t len;
-
- if (in_minibuffer) {
- message("We don't have enable-recursive-minibuffers");
- return;
}
-
- enter_minibuffer(eecmd_self_insert, eecmd_select, exit_minibuffer,
- &eecmd_history);
-
- len = sizeof(ministate.prompt);
- strlcpy(ministate.prompt, "", len);
-
- if (thiskey.meta)
- strlcat(ministate.prompt, "M-", len);
-
- strlcat(ministate.prompt, keyname(thiskey.key), len);
-
- if (thiskey.meta)
- strlcat(ministate.prompt, " ", len);
}
-void
-cmd_tab_close(struct buffer *buffer)
-{
- struct tab *tab, *t;
-
- tab = current_tab();
- if (TAILQ_PREV(tab, tabshead, tabs) == NULL &&
- TAILQ_NEXT(tab, tabs) == NULL) {
- message("Can't close the only tab.");
- return;
- }
-
- if (evtimer_pending(&tab->loadingev, NULL))
- evtimer_del(&tab->loadingev);
-
- stop_tab(tab);
-
- if ((t = TAILQ_PREV(tab, tabshead, tabs)) == NULL)
- t = TAILQ_NEXT(tab, tabs);
- TAILQ_REMOVE(&tabshead, tab, tabs);
- free(tab);
-
- switch_to_tab(t);
-}
-
-void
-cmd_tab_close_other(struct buffer *buffer)
-{
- struct tab *t, *i;
-
- TAILQ_FOREACH_SAFE(t, &tabshead, tabs, i) {
- if (t->flags & TAB_CURRENT)
- continue;
-
- stop_tab(t);
- TAILQ_REMOVE(&tabshead, t, tabs);
- free(t);
- }
-}
-
-void
-cmd_tab_new(struct buffer *buffer)
-{
- const char *url;
-
- if ((url = new_tab_url) == NULL)
- url = NEW_TAB_URL;
-
- new_tab(url);
-}
-
-void
-cmd_tab_next(struct buffer *buffer)
-{
- struct tab *tab, *t;
-
- tab = current_tab();
- tab->flags &= ~TAB_CURRENT;
-
- if ((t = TAILQ_NEXT(tab, tabs)) == NULL)
- t = TAILQ_FIRST(&tabshead);
- t->flags |= TAB_CURRENT;
- t->flags &= ~TAB_URGENT;
-}
-
-void
-cmd_tab_previous(struct buffer *buffer)
-{
- struct tab *tab, *t;
-
- tab = current_tab();
- tab->flags &= ~TAB_CURRENT;
-
- if ((t = TAILQ_PREV(tab, tabshead, tabs)) == NULL)
- t = TAILQ_LAST(&tabshead, tabshead);
- t->flags |= TAB_CURRENT;
- t->flags &= ~TAB_URGENT;
-}
-
-void
-cmd_tab_move(struct buffer *buffer)
-{
- struct tab *tab, *t;
-
- tab = current_tab();
- t = TAILQ_NEXT(tab, tabs);
- TAILQ_REMOVE(&tabshead, tab, tabs);
-
- if (t == NULL)
- TAILQ_INSERT_HEAD(&tabshead, tab, tabs);
- else
- TAILQ_INSERT_AFTER(&tabshead, t, tab, tabs);
-}
-
-void
-cmd_tab_move_to(struct buffer *buffer)
-{
- struct tab *tab, *t;
-
- tab = current_tab();
- t = TAILQ_PREV(tab, tabshead, tabs);
- TAILQ_REMOVE(&tabshead, tab, tabs);
-
- if (t == NULL) {
- if (TAILQ_EMPTY(&tabshead))
- TAILQ_INSERT_HEAD(&tabshead, tab, tabs);
- else
- TAILQ_INSERT_TAIL(&tabshead, tab, tabs);
- } else
- TAILQ_INSERT_BEFORE(t, tab, tabs);
-}
-
-void
-cmd_load_url(struct buffer *buffer)
-{
- if (in_minibuffer) {
- message("We don't have enable-recursive-minibuffers");
- return;
- }
-
- enter_minibuffer(lu_self_insert, lu_select, exit_minibuffer,
- &lu_history);
- strlcpy(ministate.prompt, "Load URL: ", sizeof(ministate.prompt));
- strlcpy(ministate.buf, "gemini://", sizeof(ministate.buf));
- cmd_move_end_of_line(&ministate.buffer);
-}
-
-void
-cmd_load_current_url(struct buffer *buffer)
-{
- struct tab *tab = current_tab();
-
- if (in_minibuffer) {
- message("We don't have enable-recursive-minibuffers");
- return;
- }
-
- enter_minibuffer(lu_self_insert, lu_select, exit_minibuffer,
- &lu_history);
- strlcpy(ministate.prompt, "Load URL: ", sizeof(ministate.prompt));
- strlcpy(ministate.buf, tab->hist_cur->h, sizeof(ministate.buf));
- ministate.buffer.cpoff = utf8_cplen(ministate.buf);
-}
-
-void
-cmd_bookmark_page(struct buffer *buffer)
-{
- struct tab *tab = current_tab();
-
- enter_minibuffer(lu_self_insert, bp_select, exit_minibuffer, NULL);
- strlcpy(ministate.prompt, "Bookmark URL: ", sizeof(ministate.prompt));
- strlcpy(ministate.buf, tab->hist_cur->h, sizeof(ministate.buf));
- ministate.buffer.cpoff = utf8_cplen(ministate.buf);
-}
-
-void
-cmd_list_bookmarks(struct buffer *buffer)
-{
- load_url_in_tab(current_tab(), "about:bookmarks");
-}
-
-void
-cmd_toggle_help(struct buffer *buffer)
-{
- side_window = !side_window;
- if (side_window)
- recompute_help();
-
- /*
- * ugly hack, but otherwise the window doesn't get updated
- * until I call handle_resize a second time (i.e. C-l). I
- * will be happy to know why something like this is needed.
- */
- handle_resize_nodelay(0, 0, NULL);
- handle_resize_nodelay(0, 0, NULL);
-}
-
-void
-cmd_olivetti_mode(struct buffer *buffer)
-{
- olivetti_mode = !olivetti_mode;
- if (olivetti_mode)
- message("olivetti-mode enabled");
- else
- message("olivetti-mode disabled");
-
- handle_resize_nodelay(0, 0, NULL);
-}
-
-void
-cmd_mini_delete_char(struct buffer *buffer)
-{
- char *c, *n;
-
- if (!in_minibuffer) {
- message("text is read-only");
- return;
- }
-
- minibuffer_taint_hist();
-
- c = utf8_nth(buffer->current_line->line, buffer->cpoff);
- if (*c == '\0')
- return;
- n = utf8_next_cp(c);
-
- memmove(c, n, strlen(n)+1);
-}
-
-void
-cmd_mini_delete_backward_char(struct buffer *buffer)
-{
- char *c, *p, *start;
-
- if (!in_minibuffer) {
- message("text is read-only");
- return;
- }
-
- minibuffer_taint_hist();
-
- c = utf8_nth(buffer->current_line->line, buffer->cpoff);
- start = buffer->current_line->line;
- if (c == start)
- return;
- p = utf8_prev_cp(c-1, start);
-
- memmove(p, c, strlen(c)+1);
- buffer->cpoff--;
-}
-
-void
-cmd_mini_kill_line(struct buffer *buffer)
-{
- char *c;
-
- if (!in_minibuffer) {
- message("text is read-only");
- return;
- }
-
- minibuffer_taint_hist();
- c = utf8_nth(buffer->current_line->line, buffer->cpoff);
- *c = '\0';
-}
-
-void
-cmd_mini_abort(struct buffer *buffer)
-{
- if (!in_minibuffer)
- return;
-
- ministate.abortfn();
-}
-
-void
-cmd_mini_complete_and_exit(struct buffer *buffer)
-{
- if (!in_minibuffer)
- return;
-
- minibuffer_taint_hist();
- ministate.donefn();
-}
-
-void
-cmd_mini_previous_history_element(struct buffer *buffer)
-{
- if (ministate.history == NULL) {
- message("No history");
- return;
- }
-
- if (ministate.hist_cur == NULL ||
- (ministate.hist_cur = TAILQ_PREV(ministate.hist_cur, mhisthead, entries)) == NULL) {
- ministate.hist_cur = TAILQ_LAST(&ministate.history->head, mhisthead);
- ministate.hist_off = ministate.history->len - 1;
- if (ministate.hist_cur == NULL)
- message("No prev item");
- } else {
- ministate.hist_off--;
- }
-
- if (ministate.hist_cur != NULL)
- buffer->current_line->line = ministate.hist_cur->h;
-}
-
-void
-cmd_mini_next_history_element(struct buffer *buffer)
-{
- if (ministate.history == NULL) {
- message("No history");
- return;
- }
-
- if (ministate.hist_cur == NULL ||
- (ministate.hist_cur = TAILQ_NEXT(ministate.hist_cur, entries)) == NULL) {
- ministate.hist_cur = TAILQ_FIRST(&ministate.history->head);
- ministate.hist_off = 0;
- if (ministate.hist_cur == NULL)
- message("No next item");
- } else {
- ministate.hist_off++;
- }
-
- if (ministate.hist_cur != NULL)
- buffer->current_line->line = ministate.hist_cur->h;
-}
-
static void
global_key_unbound(void)
{
* element, copy that to the current buf and reset the "history
* navigation" thing.
*/
-static void
+void
minibuffer_taint_hist(void)
{
if (ministate.hist_cur == NULL)
ministate.buffer.cpoff++;
}
-static void
+void
eecmd_self_insert(void)
{
if (thiskey.meta || unicode_isspace(thiskey.cp) ||
minibuffer_self_insert();
}
-static void
+void
eecmd_select(void)
{
struct cmds *cmd;
message("No match");
}
-static void
+void
ir_self_insert(void)
{
minibuffer_self_insert();
}
-static void
+void
ir_select(void)
{
char buf[1025] = {0};
load_url_in_tab(tab, buf);
}
-static void
+void
lu_self_insert(void)
{
if (thiskey.meta || unicode_isspace(thiskey.key) ||
minibuffer_self_insert();
}
-static void
+void
lu_select(void)
{
exit_minibuffer();
load_url_in_tab(current_tab(), ministate.buf);
}
-static void
+void
bp_select(void)
{
exit_minibuffer();
abort();
}
-static struct tab *
+struct tab *
current_tab(void)
{
struct tab *t;
abort();
}
-static struct buffer *
+struct buffer *
current_buffer(void)
{
if (in_minibuffer)
{
if (evtimer_pending(&clminibufev, NULL))
evtimer_del(&clminibufev);
- evtimer_set(&clminibufev, handle_clear_minibuf, NULL);
- evtimer_add(&clminibufev, &clminibufev_timer);
free(ministate.curmesg);
+ ministate.curmesg = NULL;
- /* TODO: what to do if the allocation fails here? */
- if (vasprintf(&ministate.curmesg, fmt, ap) == -1)
- ministate.curmesg = NULL;
+ if (fmt != NULL) {
+ evtimer_set(&clminibufev, handle_clear_minibuf, NULL);
+ evtimer_add(&clminibufev, &clminibufev_timer);
+ /* TODO: what to do if the allocation fails here? */
+ if (vasprintf(&ministate.curmesg, fmt, ap) == -1)
+ ministate.curmesg = NULL;
+ }
+
redraw_minibuffer();
if (in_minibuffer) {
wrefresh(body);
va_end(ap);
}
-static void
+void
start_loading_anim(struct tab *tab)
{
if (tab->loading_anim)
wrefresh(minibuf);
}
-static void
+void
load_url_in_tab(struct tab *tab, const char *url)
{
message("Loading %s...", url);
redraw_tab(tab);
}
-static void
+void
enter_minibuffer(void (*self_insert_fn)(void), void (*donefn)(void),
void (*abortfn)(void), struct histhead *hist)
{
ministate.hist_off = 0;
}
-static void
+void
exit_minibuffer(void)
{
werase(minibuf);
current_map = &global_map;
}
-static void
+void
switch_to_tab(struct tab *tab)
{
struct tab *t;
return tab_counter++;
}
-static struct tab *
+struct tab *
new_tab(const char *url)
{
struct tab *tab;
tab->flags |= TAB_URGENT;
}
+const char *
+ui_keyname(int k)
+{
+ return keyname(k);
+}
+
void
+ui_toggle_side_window(void)
+{
+ side_window = !side_window;
+ if (side_window)
+ recompute_help();
+}
+
+void
+ui_schedule_redraw(void)
+{
+ handle_resize_nodelay(0, 0, NULL);
+}
+
+void
ui_require_input(struct tab *tab, int hide)
{
/* TODO: hard-switching to another tab is ugly */