📄 terminal.c
字号:
#include "links.h"int hard_write(int fd, unsigned char *p, int l){ int w = 1; int t = 0; while (l > 0 && w) { if ((w = write(fd, p, l)) < 0) { if (errno == EINTR) continue; return -1; } t += w; p += w; l -= w; } return t;}int hard_read(int fd, unsigned char *p, int l){ int r = 1; int t = 0; while (l > 0 && r) { if ((r = read(fd, p, l)) < 0) { if (errno == EINTR) continue; return -1; } /*{int ww;for(ww=0;ww<r;ww++)fprintf(stderr," %02x",(int)p[ww]);fflush(stderr);}*/ t += r; p += r; l -= r; } return t;}unsigned char *get_cwd(){ int bufsize = 128; unsigned char *buf; while (1) { buf = mem_alloc(bufsize); if (getcwd(buf, bufsize)) return buf; mem_free(buf); if (errno == EINTR) continue; if (errno != ERANGE) return NULL; if ((unsigned)bufsize > MAXINT - 128) overalloc(); bufsize += 128; } return NULL;}void set_cwd(unsigned char *path){ if (path) while (chdir(path) && errno == EINTR) ;}struct list_head terminals = {&terminals, &terminals};void alloc_term_screen(struct terminal *term, int x, int y){ unsigned *s, *t; if (x && (unsigned)x * (unsigned)y / (unsigned)x != (unsigned)y) overalloc(); if ((unsigned)x * (unsigned)y > MAXINT / sizeof(unsigned)) overalloc(); s = mem_realloc(term->screen, x * y * sizeof(unsigned)); t = mem_realloc(term->last_screen, x * y * sizeof(unsigned)); memset(t, -1, x * y * sizeof(unsigned)); term->x = x; term->y = y; term->last_screen = t; memset(s, 0, x * y * sizeof(unsigned)); term->screen = s; term->dirty = 1;}void in_term(struct terminal *);void destroy_terminal(struct terminal *);void check_if_no_terminal();void clear_terminal(struct terminal *term){ fill_area(term, 0, 0, term->x, term->y, ' '); set_cursor(term, 0, 0, 0, 0);}void redraw_terminal_ev(struct terminal *term, int e){ struct window *win; struct event ev = {0, 0, 0, 0}; ev.ev = e; ev.x = term->x; ev.y = term->y; clear_terminal(term); term->redrawing = 2; foreachback(win, term->windows) win->handler(win, &ev, 0); term->redrawing = 0;}void redraw_terminal(struct terminal *term){ redraw_terminal_ev(term, EV_REDRAW);}void redraw_terminal_all(struct terminal *term){ redraw_terminal_ev(term, EV_RESIZE);}void erase_screen(struct terminal *term){ if (!term->master || !is_blocked()) { if (term->master) want_draw(); hard_write(term->fdout, "\033[2J\033[1;1H", 10); if (term->master) done_draw(); }}void redraw_terminal_cls(struct terminal *term){ erase_screen(term); alloc_term_screen(term, term->x, term->y); redraw_terminal_all(term);}void cls_redraw_all_terminals(){ struct terminal *term; foreach(term, terminals) redraw_terminal_cls(term);}void redraw_from_window(struct window *win){ struct terminal *term = win->term; struct window *end = (void *)&term->windows; struct event ev = {EV_REDRAW, 0, 0, 0}; ev.x = term->x; ev.y = term->y; if (term->redrawing) return; term->redrawing = 1; for (win = win->prev; win != end; win = win->prev) { win->handler(win, &ev, 0); } term->redrawing = 0;}void redraw_below_window(struct window *win){ int tr; struct terminal *term = win->term; struct window *end = win; struct event ev = {EV_REDRAW, 0, 0, 0}; ev.x = term->x; ev.y = term->y; if (term->redrawing >= 2) return; tr = term->redrawing; win->term->redrawing = 2; for (win = term->windows.prev; win != end; win = win->prev) { win->handler(win, &ev, 0); } term->redrawing = tr;}void add_window_at_pos(struct terminal *term, void (*handler)(struct window *, struct event *, int), void *data, struct window *at){ struct event ev = {EV_INIT, 0, 0, 0}; struct window *win; ev.x = term->x; ev.y = term->y; win = mem_alloc(sizeof (struct window)); win->handler = handler; win->data = data; win->term = term; win->xp = win->yp = 0; add_at_pos(at, win); win->handler(win, &ev, 0);}void add_window(struct terminal *term, void (*handler)(struct window *, struct event *, int), void *data){ add_window_at_pos(term, handler, data, (struct window *)(void *)&term->windows);}void delete_window(struct window *win){ struct event ev = {EV_ABORT, 0, 0, 0}; win->handler(win, &ev, 1); del_from_list(win); if (win->data) mem_free(win->data); redraw_terminal(win->term); mem_free(win);}void delete_window_ev(struct window *win, struct event *ev){ struct window *w = win->next; if ((void *)w == &win->term->windows) w = NULL; delete_window(win); if (ev && w && w->next != w) w->handler(w, ev, 1);}void set_window_ptr(struct window *win, int x, int y){ win->xp = x; win->yp = y;}void get_parent_ptr(struct window *win, int *x, int *y){ if ((void *)win->next != &win->term->windows) { *x = win->next->xp; *y = win->next->yp; } else { *x = *y = 0; }}struct window *get_root_window(struct terminal *term){ if (list_empty(term->windows)) { internal("terminal has no windows"); return NULL; } return (struct window *)term->windows.prev;}struct ewd { void (*fn)(void *); void *data; int b;};void empty_window_handler(struct window *win, struct event *ev, int fwd){ struct window *n; struct ewd *ewd = win->data; int x, y; void (*fn)(void *) = ewd->fn; void *data = ewd->data; if (ewd->b) return; switch (ev->ev) { case EV_INIT: case EV_RESIZE: case EV_REDRAW: get_parent_ptr(win, &x, &y); set_window_ptr(win, x, y); return; case EV_ABORT: fn(data); return; } ewd->b = 1; n = win->next; delete_window(win); fn(data); if (n->next != n) n->handler(n, ev, fwd);}void add_empty_window(struct terminal *term, void (*fn)(void *), void *data){ struct ewd *ewd; ewd = mem_alloc(sizeof(struct ewd)); ewd->fn = fn; ewd->data = data; ewd->b = 0; add_window(term, empty_window_handler, ewd);}void free_term_specs(){ free_list(term_specs);}struct list_head term_specs = {&term_specs, &term_specs};struct term_spec dumb_term = { NULL, NULL, "", 0, 1, 0, 0, 0, 0 };struct term_spec *get_term_spec(unsigned char *term){ struct term_spec *t; foreach(t, term_specs) if (!strcasecmp(t->term, term)) return t; return &dumb_term;}struct term_spec *new_term_spec(unsigned char *term){ struct term_spec *t; foreach(t, term_specs) if (!strcasecmp(t->term, term)) return t; t = mem_alloc(sizeof(struct term_spec)); memcpy(t, &dumb_term, sizeof(struct term_spec)); if (strlen(term) < MAX_TERM_LEN) strcpy(t->term, term); else memcpy(t->term, term, MAX_TERM_LEN - 1), t->term[MAX_TERM_LEN - 1] = 0; add_to_list(term_specs, t); sync_term_specs(); return t;}void sync_term_specs(){ struct terminal *term; foreach (term, terminals) term->spec = get_term_spec(term->term);}struct terminal *init_term(int fdin, int fdout, void (*root_window)(struct window *, struct event *, int)){ struct terminal *term; struct window *win; term = mem_alloc(sizeof (struct terminal)); memset(term, 0, sizeof(struct terminal)); term->fdin = fdin; term->fdout = fdout; term->master = term->fdout == get_output_handle(); /*term->x = 0; term->y = 0; term->cx = 0; term->cy = 0;*/ term->lcx = -1; term->lcy = -1; term->dirty = 1; term->redrawing = 0; term->blocked = -1; term->screen = DUMMY; term->last_screen = DUMMY; term->spec = &dumb_term; term->term[0] = 0; term->cwd[0] = 0; term->input_queue = DUMMY; term->qlen = 0; init_list(term->windows); win = mem_alloc(sizeof (struct window)); win->handler = root_window; win->data = NULL; win->term = term; add_to_list(term->windows, win); /*alloc_term_screen(term, 80, 25);*/ add_to_list(terminals, term); set_handlers(fdin, (void (*)(void *))in_term, NULL, (void (*)(void *))destroy_terminal, term); return term;}void in_term(struct terminal *term){ struct event *ev; int r; unsigned char *iq; if ((unsigned)term->qlen + ALLOC_GR > MAXINT) overalloc(); iq = mem_realloc(term->input_queue, term->qlen + ALLOC_GR); term->input_queue = iq; if ((r = read(term->fdin, iq + term->qlen, ALLOC_GR)) <= 0) { if (r == -1 && errno != ECONNRESET) error("ERROR: error %d on terminal: could not read event", errno); destroy_terminal(term); return; } term->qlen += r; test_queue: if ((size_t)term->qlen < sizeof(struct event)) return; ev = (struct event *)iq; r = sizeof(struct event); if (ev->ev != EV_INIT && ev->ev != EV_RESIZE && ev->ev != EV_REDRAW && ev->ev != EV_KBD && ev->ev != EV_MOUSE && ev->ev != EV_ABORT) { error("ERROR: error on terminal: bad event %d", ev->ev); goto mm; } if (ev->ev == EV_INIT) { int init_len; if ((size_t)term->qlen < sizeof(struct event) + MAX_TERM_LEN + MAX_CWD_LEN + 2 * sizeof(int)) return; init_len = *(int *)(iq + sizeof(struct event) + MAX_TERM_LEN + MAX_CWD_LEN + sizeof(int)); if ((size_t)term->qlen < sizeof(struct event) + MAX_TERM_LEN + MAX_CWD_LEN + 2 * sizeof(int) + init_len) return; memcpy(term->term, iq + sizeof(struct event), MAX_TERM_LEN); term->term[MAX_TERM_LEN - 1] = 0; memcpy(term->cwd, iq + sizeof(struct event) + MAX_TERM_LEN, MAX_CWD_LEN); term->cwd[MAX_CWD_LEN - 1] = 0; term->environment = *(int *)(iq + sizeof(struct event) + MAX_TERM_LEN + MAX_CWD_LEN); ev->b = (long)(iq + sizeof(struct event) + MAX_TERM_LEN + MAX_CWD_LEN + sizeof(int)); r = sizeof(struct event) + MAX_TERM_LEN + MAX_CWD_LEN + 2 * sizeof(int) + init_len; sync_term_specs(); } if (ev->ev == EV_REDRAW || ev->ev == EV_RESIZE || ev->ev == EV_INIT) { struct window *win; send_redraw: if (ev->x < 0 || ev->y < 0) { error("ERROR: bad terminal size: %d, %d", (int)ev->x, (int)ev->y); goto mm; } alloc_term_screen(term, ev->x, ev->y); clear_terminal(term); erase_screen(term); term->redrawing = 1; foreachback(win, term->windows) win->handler(win, ev, 0); term->redrawing = 0; } if (ev->ev == EV_KBD || ev->ev == EV_MOUSE) { if (ev->ev == EV_KBD && upcase(ev->x) == 'L' && ev->y == KBD_CTRL) { ev->ev = EV_REDRAW; ev->x = term->x; ev->y = term->y; goto send_redraw; } else if (ev->ev == EV_KBD && ev->x == KBD_CTRL_C) ((struct window *)(void *)&term->windows)->prev->handler(term->windows.prev, ev, 0); else ((struct window *)(void *)&term->windows)->next->handler(term->windows.next, ev, 0); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -