diff --git a/Makefile b/Makefile index 7e77c7fd8..a2f1df35f 100644 --- a/Makefile +++ b/Makefile @@ -4,20 +4,20 @@ REGEX_SRC ?= text-regex.c SRC = array.c \ buffer.c \ + event-basic.c \ libutf.c \ main.c \ map.c \ sam.c \ - text.c \ text-common.c \ text-io.c \ text-iterator.c \ text-motions.c \ text-objects.c \ text-util.c \ + text.c \ ui-terminal.c \ view.c \ - vis.c \ vis-lua.c \ vis-marks.c \ vis-modes.c \ @@ -25,8 +25,9 @@ SRC = array.c \ vis-operators.c \ vis-prompt.c \ vis-registers.c \ - vis-text-objects.c \ vis-subprocess.c \ + vis-text-objects.c \ + vis.c \ $(REGEX_SRC) OBJ = $(SRC:%.c=obj/%.o) diff --git a/event-basic.c b/event-basic.c new file mode 100644 index 000000000..d59ef8aa8 --- /dev/null +++ b/event-basic.c @@ -0,0 +1,23 @@ +#include + +#include "vis-core.h" + +#if !CONFIG_LUA +bool vis_event_emit(Vis *vis, enum VisEvents id, ...) { + if (!vis->initialized) { + vis->initialized = true; + ui_init(&vis->ui, vis); + } + + va_list ap; + va_start(ap, id); + + if (id == VIS_EVENT_WIN_STATUS) { + Win *win = va_arg(ap, Win*); + window_status_update(vis, win); + } + + va_end(ap); + return true; +} +#endif diff --git a/main.c b/main.c index 8aa31c6b8..85330cbc5 100644 --- a/main.c +++ b/main.c @@ -10,7 +10,7 @@ #include #include -#include "ui-terminal.h" +#include "ui.h" #include "vis.h" #include "vis-lua.h" #include "text-util.h" @@ -1229,7 +1229,7 @@ static const char *macro_replay(Vis *vis, const char *keys, const Arg *arg) { } static const char *suspend(Vis *vis, const char *keys, const Arg *arg) { - vis_suspend(vis); + ui_terminal_suspend(&vis->ui); return keys; } @@ -1240,7 +1240,7 @@ static const char *repeat(Vis *vis, const char *keys, const Arg *arg) { static const char *selections_new(Vis *vis, const char *keys, const Arg *arg) { View *view = vis_view(vis); - bool anchored = view_selections_anchored(view_selections_primary_get(view)); + bool anchored = view_selections_primary_get(view)->anchored; VisCountIterator it = vis_count_iterator_get(vis, 1); while (vis_count_iterator_next(&it)) { Selection *sel = NULL; @@ -1277,10 +1277,10 @@ static const char *selections_new(Vis *vis, const char *keys, const Arg *arg) { } if (sel_new) { view_selections_primary_set(sel_new); - view_selections_anchor(sel_new, anchored); + sel_new->anchored = anchored; } } - vis_count_set(vis, VIS_COUNT_UNKNOWN); + vis->action.count = VIS_COUNT_UNKNOWN; return keys; } @@ -1289,9 +1289,10 @@ static const char *selections_align(Vis *vis, const char *keys, const Arg *arg) Text *txt = vis_text(vis); int mincol = INT_MAX; for (Selection *s = view_selections(view); s; s = view_selections_next(s)) { - int col = view_cursors_cell_get(s); - if (col >= 0 && col < mincol) - mincol = col; + if (!s->line) + continue; + if (s->col >= 0 && s->col < mincol) + mincol = s->col; } for (Selection *s = view_selections(view); s; s = view_selections_next(s)) { if (view_cursors_cell_set(s, mincol) == -1) { @@ -1348,7 +1349,7 @@ static const char *selections_align_indent(Vis *vis, const char *keys, const Arg static const char *selections_clear(Vis *vis, const char *keys, const Arg *arg) { View *view = vis_view(vis); - if (view_selections_count(view) > 1) + if (view->selection_count > 1) view_selections_dispose_all(view); else view_selection_clear(view_selections_primary_get(view)); @@ -1356,13 +1357,13 @@ static const char *selections_clear(Vis *vis, const char *keys, const Arg *arg) } static Selection *selection_new(View *view, Filerange *r, bool isprimary) { - Text *txt = view_text(view); + Text *txt = view->text; size_t pos = text_char_prev(txt, r->end); Selection *s = view_selections_new(view, pos); if (!s) return NULL; view_selections_set(s, r); - view_selections_anchor(s, true); + s->anchored = true; if (isprimary) view_selections_primary_set(s); return s; @@ -1378,7 +1379,7 @@ static const char *selections_match_next(Vis *vis, const char *keys, const Arg * static bool match_word; - if (view_selections_count(view) == 1) { + if (view->selection_count == 1) { Filerange word = text_object_word(txt, view_cursors_pos(s)); match_word = text_range_equal(&sel, &word); } @@ -1432,17 +1433,17 @@ static const char *selections_match_skip(Vis *vis, const char *keys, const Arg * static const char *selections_remove(Vis *vis, const char *keys, const Arg *arg) { View *view = vis_view(vis); view_selections_dispose(view_selections_primary_get(view)); - view_cursor_to(view, view_cursor_get(view)); + view_cursors_to(view->selection, view_cursor_get(view)); return keys; } static const char *selections_remove_column(Vis *vis, const char *keys, const Arg *arg) { View *view = vis_view(vis); int max = view_selections_column_count(view); - int column = vis_count_get_default(vis, arg->i) - 1; + int column = VIS_COUNT_DEFAULT(vis->action.count, arg->i) - 1; if (column >= max) column = max - 1; - if (view_selections_count(view) == 1) { + if (view->selection_count == 1) { vis_keys_feed(vis, ""); return keys; } @@ -1452,17 +1453,17 @@ static const char *selections_remove_column(Vis *vis, const char *keys, const Ar view_selections_dispose(s); } - vis_count_set(vis, VIS_COUNT_UNKNOWN); + vis->action.count = VIS_COUNT_UNKNOWN; return keys; } static const char *selections_remove_column_except(Vis *vis, const char *keys, const Arg *arg) { View *view = vis_view(vis); int max = view_selections_column_count(view); - int column = vis_count_get_default(vis, arg->i) - 1; + int column = VIS_COUNT_DEFAULT(vis->action.count, arg->i) - 1; if (column >= max) column = max - 1; - if (view_selections_count(view) == 1) { + if (view->selection_count == 1) { vis_redraw(vis); return keys; } @@ -1477,13 +1478,13 @@ static const char *selections_remove_column_except(Vis *vis, const char *keys, c view_selections_dispose(sel); } - vis_count_set(vis, VIS_COUNT_UNKNOWN); + vis->action.count = VIS_COUNT_UNKNOWN; return keys; } static const char *selections_navigate(Vis *vis, const char *keys, const Arg *arg) { View *view = vis_view(vis); - if (view_selections_count(view) == 1) + if (view->selection_count == 1) return wscroll(vis, keys, arg); Selection *s = view_selections_primary_get(view); VisCountIterator it = vis_count_iterator_get(vis, 1); @@ -1502,7 +1503,7 @@ static const char *selections_navigate(Vis *vis, const char *keys, const Arg *ar } } view_selections_primary_set(s); - vis_count_set(vis, VIS_COUNT_UNKNOWN); + vis->action.count = VIS_COUNT_UNKNOWN; return keys; } @@ -1518,8 +1519,8 @@ static const char *selections_rotate(Vis *vis, const char *keys, const Arg *arg) Text *txt = vis_text(vis); View *view = vis_view(vis); int columns = view_selections_column_count(view); - int selections = columns == 1 ? view_selections_count(view) : columns; - int count = vis_count_get_default(vis, 1); + int selections = columns == 1 ? view->selection_count : columns; + int count = VIS_COUNT_DEFAULT(vis->action.count, 1); array_init_sized(&arr, sizeof(Rotate)); if (!array_reserve(&arr, selections)) return keys; @@ -1569,7 +1570,7 @@ static const char *selections_rotate(Vis *vis, const char *keys, const Arg *arg) } array_release(&arr); - vis_count_set(vis, VIS_COUNT_UNKNOWN); + vis->action.count = VIS_COUNT_UNKNOWN; return keys; } @@ -1595,7 +1596,7 @@ static const char *selections_trim(Vis *vis, const char *keys, const Arg *arg) { } static void selections_set(Vis *vis, View *view, Array *sel) { - enum VisMode mode = vis_mode_get(vis); + enum VisMode mode = vis->mode->id; bool anchored = mode == VIS_MODE_VISUAL || mode == VIS_MODE_VISUAL_LINE; view_selections_set_all(view, sel, anchored); if (!anchored) @@ -1603,7 +1604,7 @@ static void selections_set(Vis *vis, View *view, Array *sel) { } static const char *selections_save(Vis *vis, const char *keys, const Arg *arg) { - Win *win = vis_window(vis); + Win *win = vis->win; View *view = vis_view(vis); enum VisMark mark = vis_mark_used(vis); Array sel = view_selections_get_all(view); @@ -1614,7 +1615,7 @@ static const char *selections_save(Vis *vis, const char *keys, const Arg *arg) { } static const char *selections_restore(Vis *vis, const char *keys, const Arg *arg) { - Win *win = vis_window(vis); + Win *win = vis->win; View *view = vis_view(vis); enum VisMark mark = vis_mark_used(vis); Array sel = vis_mark_get(win, mark); @@ -1625,7 +1626,7 @@ static const char *selections_restore(Vis *vis, const char *keys, const Arg *arg } static const char *selections_union(Vis *vis, const char *keys, const Arg *arg) { - Win *win = vis_window(vis); + Win *win = vis->win; View *view = vis_view(vis); enum VisMark mark = vis_mark_used(vis); Array a = vis_mark_get(win, mark); @@ -1692,7 +1693,7 @@ static void intersect(Array *ret, Array *a, Array *b) { } static const char *selections_intersect(Vis *vis, const char *keys, const Arg *arg) { - Win *win = vis_window(vis); + Win *win = vis->win; View *view = vis_view(vis); enum VisMark mark = vis_mark_used(vis); Array a = vis_mark_get(win, mark); @@ -1745,7 +1746,7 @@ static const char *selections_complement(Vis *vis, const char *keys, const Arg * static const char *selections_minus(Vis *vis, const char *keys, const Arg *arg) { Text *txt = vis_text(vis); - Win *win = vis_window(vis); + Win *win = vis->win; View *view = vis_view(vis); enum VisMark mark = vis_mark_used(vis); Array a = view_selections_get_all(view); @@ -1788,25 +1789,25 @@ static const char *replace(Vis *vis, const char *keys, const Arg *arg) { return next; vis_operator(vis, VIS_OP_REPLACE, replacement); - if (vis_mode_get(vis) == VIS_MODE_OPERATOR_PENDING) + if (vis->mode->id == VIS_MODE_OPERATOR_PENDING) vis_motion(vis, VIS_MOVE_CHAR_NEXT); return next; } static const char *count(Vis *vis, const char *keys, const Arg *arg) { int digit = keys[-1] - '0'; - int count = vis_count_get_default(vis, 0); + int count = VIS_COUNT_DEFAULT(vis->action.count, 0); if (0 <= digit && digit <= 9) { if (digit == 0 && count == 0) vis_motion(vis, VIS_MOVE_LINE_BEGIN); else - vis_count_set(vis, count * 10 + digit); + vis->action.count = VIS_COUNT_NORMALIZE(count * 10 + digit); } return keys; } static const char *gotoline(Vis *vis, const char *keys, const Arg *arg) { - if (vis_count_get(vis) != VIS_COUNT_UNKNOWN) + if (vis->action.count != VIS_COUNT_UNKNOWN) vis_motion(vis, VIS_MOVE_LINE); else if (arg->i < 0) vis_motion(vis, VIS_MOVE_FILE_BEGIN); @@ -1877,8 +1878,8 @@ static const char *undo(Vis *vis, const char *keys, const Arg *arg) { size_t pos = text_undo(vis_text(vis)); if (pos != EPOS) { View *view = vis_view(vis); - if (view_selections_count(view) == 1) - view_cursor_to(view, pos); + if (view->selection_count == 1) + view_cursors_to(view->selection, pos); /* redraw all windows in case some display the same file */ vis_draw(vis); } @@ -1889,8 +1890,8 @@ static const char *redo(Vis *vis, const char *keys, const Arg *arg) { size_t pos = text_redo(vis_text(vis)); if (pos != EPOS) { View *view = vis_view(vis); - if (view_selections_count(view) == 1) - view_cursor_to(view, pos); + if (view->selection_count == 1) + view_cursors_to(view->selection, pos); /* redraw all windows in case some display the same file */ vis_draw(vis); } @@ -1903,7 +1904,7 @@ static const char *earlier(Vis *vis, const char *keys, const Arg *arg) { while (vis_count_iterator_next(&it)) pos = text_earlier(vis_text(vis)); if (pos != EPOS) { - view_cursor_to(vis_view(vis), pos); + view_cursors_to(vis_view(vis)->selection, pos); /* redraw all windows in case some display the same file */ vis_draw(vis); } @@ -1916,7 +1917,7 @@ static const char *later(Vis *vis, const char *keys, const Arg *arg) { while (vis_count_iterator_next(&it)) pos = text_later(vis_text(vis)); if (pos != EPOS) { - view_cursor_to(vis_view(vis), pos); + view_cursors_to(vis_view(vis)->selection, pos); /* redraw all windows in case some display the same file */ vis_draw(vis); } @@ -2032,7 +2033,7 @@ static const char *insert_verbatim(Vis *vis, const char *keys, const Arg *arg) { static const char *wscroll(Vis *vis, const char *keys, const Arg *arg) { View *view = vis_view(vis); - int count = vis_count_get(vis); + int count = vis->action.count; switch (arg->i) { case -PAGE: view_scroll_page_up(view); @@ -2055,20 +2056,20 @@ static const char *wscroll(Vis *vis, const char *keys, const Arg *arg) { view_scroll_down(view, count); break; } - vis_count_set(vis, VIS_COUNT_UNKNOWN); + vis->action.count = VIS_COUNT_UNKNOWN; return keys; } static const char *wslide(Vis *vis, const char *keys, const Arg *arg) { View *view = vis_view(vis); - int count = vis_count_get(vis); + int count = vis->action.count; if (count == VIS_COUNT_UNKNOWN) count = arg->i < 0 ? -arg->i : arg->i; if (arg->i >= 0) view_slide_down(view, count); else view_slide_up(view, count); - vis_count_set(vis, VIS_COUNT_UNKNOWN); + vis->action.count = VIS_COUNT_UNKNOWN; return keys; } @@ -2088,7 +2089,7 @@ static const char *openline(Vis *vis, const char *keys, const Arg *arg) { vis_motion(vis, VIS_MOVE_LINE_END); vis_keys_feed(vis, ""); } else { - if (vis_get_autoindent(vis)) { + if (vis->autoindent) { vis_motion(vis, VIS_MOVE_LINE_START); vis_keys_feed(vis, ""); } else { @@ -2101,30 +2102,30 @@ static const char *openline(Vis *vis, const char *keys, const Arg *arg) { } static const char *join(Vis *vis, const char *keys, const Arg *arg) { - bool normal = (vis_mode_get(vis) == VIS_MODE_NORMAL); + bool normal = (vis->mode->id == VIS_MODE_NORMAL); vis_operator(vis, VIS_OP_JOIN, arg->s); if (normal) { - int count = vis_count_get_default(vis, 0); - if (count) - vis_count_set(vis, count-1); + vis->action.count = VIS_COUNT_DEFAULT(vis->action.count, 0); + if (vis->action.count > 0) + vis->action.count -= 1; vis_motion(vis, VIS_MOVE_LINE_NEXT); } return keys; } static const char *normalmode_escape(Vis *vis, const char *keys, const Arg *arg) { - if (vis_count_get(vis) == VIS_COUNT_UNKNOWN) + if (vis->action.count == VIS_COUNT_UNKNOWN) selections_clear(vis, keys, arg); else - vis_count_set(vis, VIS_COUNT_UNKNOWN); + vis->action.count = VIS_COUNT_UNKNOWN; return keys; } static const char *visualmode_escape(Vis *vis, const char *keys, const Arg *arg) { - if (vis_count_get(vis) == VIS_COUNT_UNKNOWN) + if (vis->action.count == VIS_COUNT_UNKNOWN) vis_mode_switch(vis, VIS_MODE_NORMAL); else - vis_count_set(vis, VIS_COUNT_UNKNOWN); + vis->action.count = VIS_COUNT_UNKNOWN; return keys; } @@ -2189,7 +2190,7 @@ static const char *unicode_info(Vis *vis, const char *keys, const Arg *arg) { } static const char *percent(Vis *vis, const char *keys, const Arg *arg) { - if (vis_count_get(vis) == VIS_COUNT_UNKNOWN) + if (vis->action.count == VIS_COUNT_UNKNOWN) vis_motion(vis, VIS_MOVE_BRACKET_MATCH); else vis_motion(vis, VIS_MOVE_PERCENT); @@ -2213,26 +2214,7 @@ static void signal_handler(int signum, siginfo_t *siginfo, void *context) { } int main(int argc, char *argv[]) { - - VisEvent event = { - .init = vis_lua_init, - .start = vis_lua_start, - .quit = vis_lua_quit, - .mode_insert_input = vis_lua_mode_insert_input, - .mode_replace_input = vis_lua_mode_replace_input, - .file_open = vis_lua_file_open, - .file_save_pre = vis_lua_file_save_pre, - .file_save_post = vis_lua_file_save_post, - .file_close = vis_lua_file_close, - .win_open = vis_lua_win_open, - .win_close = vis_lua_win_close, - .win_highlight = vis_lua_win_highlight, - .win_status = vis_lua_win_status, - .term_csi = vis_lua_term_csi, - .ui_draw = vis_lua_ui_draw, - }; - - vis = vis_new(ui_term_new(), &event); + vis = vis_new(); if (!vis) return EXIT_FAILURE; @@ -2342,7 +2324,7 @@ int main(int argc, char *argv[]) { } } - if (!vis_window(vis) && !win_created) { + if (!vis->win && !win_created) { if (!vis_window_new(vis, NULL)) vis_die(vis, "Can not create empty buffer\n"); if (cmd) diff --git a/sam.c b/sam.c index 223bbe268..90d19c297 100644 --- a/sam.c +++ b/sam.c @@ -1232,7 +1232,7 @@ enum SamError sam_cmd(Vis *vis, const char *s) { } bool visual = vis->mode->visual; - size_t primary_pos = vis->win ? view_cursor_get(vis->win->view) : EPOS; + size_t primary_pos = vis->win ? view_cursor_get(&vis->win->view) : EPOS; Filerange range = text_range_empty(); sam_execute(vis, vis->win, cmd, NULL, &range); @@ -1270,7 +1270,7 @@ enum SamError sam_cmd(Vis *vis, const char *s) { if (c->sel) { if (visual) { view_selections_set(c->sel, &r); - view_selections_anchor(c->sel, true); + c->sel->anchored = true; } else { if (memchr(c->data, '\n', c->len)) view_cursors_to(c->sel, r.start); @@ -1278,10 +1278,10 @@ enum SamError sam_cmd(Vis *vis, const char *s) { view_cursors_to(c->sel, r.end); } } else if (visual) { - Selection *sel = view_selections_new(c->win->view, r.start); + Selection *sel = view_selections_new(&c->win->view, r.start); if (sel) { view_selections_set(sel, &r); - view_selections_anchor(sel, true); + sel->anchored = true; } } } @@ -1291,16 +1291,16 @@ enum SamError sam_cmd(Vis *vis, const char *s) { } for (Win *win = vis->windows; win; win = win->next) - view_selections_normalize(win->view); + view_selections_normalize(&win->view); if (vis->win) { - if (primary_pos != EPOS && view_selection_disposed(vis->win->view)) - view_cursor_to(vis->win->view, primary_pos); - view_selections_primary_set(view_selections(vis->win->view)); + if (primary_pos != EPOS && view_selection_disposed(&vis->win->view)) + view_cursors_to(vis->win->view.selection, primary_pos); + view_selections_primary_set(view_selections(&vis->win->view)); vis_jumplist_save(vis); bool completed = true; - for (Selection *s = view_selections(vis->win->view); s; s = view_selections_next(s)) { - if (view_selections_anchored(s)) { + for (Selection *s = view_selections(&vis->win->view); s; s = view_selections_next(s)) { + if (s->anchored) { completed = false; break; } @@ -1507,13 +1507,13 @@ static bool cmd_select(Vis *vis, Win *win, Command *cmd, const char *argv[], Sel if (!win) return sam_execute(vis, NULL, cmd->cmd, NULL, &r); bool ret = true; - View *view = win->view; + View *view = &win->view; Text *txt = win->file->text; - bool multiple_cursors = view_selections_count(view) > 1; + bool multiple_cursors = view->selection_count > 1; Selection *primary = view_selections_primary_get(view); if (vis->mode->visual) - count_init(cmd->cmd, view_selections_count(view)+1); + count_init(cmd->cmd, view->selection_count + 1); for (Selection *s = view_selections(view), *next; s && ret; s = next) { next = view_selections_next(s); @@ -1557,7 +1557,7 @@ static bool cmd_select(Vis *vis, Win *win, Command *cmd, const char *argv[], Sel break; } - if (vis->win && vis->win->view == view && primary != view_selections_primary_get(view)) + if (vis->win && &vis->win->view == view && primary != view_selections_primary_get(view)) view_selections_primary_set(view_selections(view)); return ret; } @@ -1565,14 +1565,13 @@ static bool cmd_select(Vis *vis, Win *win, Command *cmd, const char *argv[], Sel static bool cmd_print(Vis *vis, Win *win, Command *cmd, const char *argv[], Selection *sel, Filerange *range) { if (!win || !text_range_valid(range)) return false; - View *view = win->view; if (!sel) - sel = view_selections_new_force(view, range->start); + sel = view_selections_new_force(&win->view, range->start); if (!sel) return false; if (range->start != range->end) { view_selections_set(sel, range); - view_selections_anchor(sel, true); + sel->anchored = true; } else { view_cursors_to(sel, range->start); view_selection_clear(sel); @@ -1641,7 +1640,7 @@ static bool cmd_write(Vis *vis, Win *win, Command *cmd, const char *argv[], Sele bool visual = vis->mode->visual; - for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) { + for (Selection *s = view_selections(&win->view); s; s = view_selections_next(s)) { Filerange range = visual ? view_selections_get(s) : *r; ssize_t written = text_write_range(text, &range, file->fd); if (written == -1 || (size_t)written != text_range_size(&range)) { @@ -1709,7 +1708,7 @@ static bool cmd_write(Vis *vis, Win *win, Command *cmd, const char *argv[], Sele bool failure = false; bool visual = vis->mode->visual; - for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) { + for (Selection *s = view_selections(&win->view); s; s = view_selections_next(s)) { Filerange range = visual ? view_selections_get(s) : *r; ssize_t written = text_save_write_range(ctx, &range); failure = (written == -1 || (size_t)written != text_range_size(&range)); diff --git a/ui-terminal-curses.c b/ui-terminal-curses.c index b89d9b58f..c3ae06488 100644 --- a/ui-terminal-curses.c +++ b/ui-terminal-curses.c @@ -4,18 +4,6 @@ #define UI_TERMKEY_FLAGS (TERMKEY_FLAG_UTF8|TERMKEY_FLAG_NOTERMIOS) -#define ui_term_backend_init ui_curses_init -#define ui_term_backend_blit ui_curses_blit -#define ui_term_backend_clear ui_curses_clear -#define ui_term_backend_colors ui_curses_colors -#define ui_term_backend_resize ui_curses_resize -#define ui_term_backend_restore ui_curses_restore -#define ui_term_backend_save ui_curses_save -#define ui_term_backend_new ui_curses_new -#define ui_term_backend_resume ui_curses_resume -#define ui_term_backend_suspend ui_curses_suspend -#define ui_term_backend_free ui_curses_free - #define CELL_COLOR_BLACK COLOR_BLACK #define CELL_COLOR_RED COLOR_RED #define CELL_COLOR_GREEN COLOR_GREEN @@ -85,7 +73,7 @@ static void undo_palette(void) } /* Work out the nearest color from the 256 color set, or perhaps exactly. */ -static CellColor color_rgb(UiTerm *ui, uint8_t r, uint8_t g, uint8_t b) +static CellColor color_rgb(Ui *ui, uint8_t r, uint8_t g, uint8_t b) { static short color_clobber_idx = 0; static uint32_t clobbering_colors[MAX_COLOR_CLOBBER]; @@ -163,7 +151,7 @@ static CellColor color_rgb(UiTerm *ui, uint8_t r, uint8_t g, uint8_t b) return i; } -static CellColor color_terminal(UiTerm *ui, uint8_t index) { +static CellColor color_terminal(Ui *ui, uint8_t index) { return index; } @@ -227,7 +215,7 @@ static inline attr_t style_to_attr(CellStyle *style) { return style->attr | COLOR_PAIR(color_pair_get(style->fg, style->bg)); } -static void ui_curses_blit(UiTerm *tui) { +static void ui_term_backend_blit(Ui *tui) { int w = tui->width, h = tui->height; Cell *cell = tui->cells; for (int y = 0; y < h; y++) { @@ -242,16 +230,16 @@ static void ui_curses_blit(UiTerm *tui) { doupdate(); } -static void ui_curses_clear(UiTerm *tui) { +static void ui_term_backend_clear(Ui *tui) { clear(); } -static bool ui_curses_resize(UiTerm *tui, int width, int height) { +static bool ui_term_backend_resize(Ui *tui, int width, int height) { return resizeterm(height, width) == OK && wresize(stdscr, height, width) == OK; } -static void ui_curses_save(UiTerm *tui, bool fscr) { +static void ui_term_backend_save(Ui *tui, bool fscr) { curs_set(1); if (fscr) { def_prog_mode(); @@ -261,17 +249,17 @@ static void ui_curses_save(UiTerm *tui, bool fscr) { } } -static void ui_curses_restore(UiTerm *tui) { +static void ui_term_backend_restore(Ui *tui) { reset_prog_mode(); wclear(stdscr); curs_set(0); } -static int ui_curses_colors(Ui *ui) { +int ui_terminal_colors(void) { return COLORS; } -static bool ui_curses_init(UiTerm *tui, char *term) { +static bool ui_term_backend_init(Ui *tui, char *term) { if (!newterm(term, stderr, stdin)) { snprintf(tui->info, sizeof(tui->info), "Warning: unknown term `%s'", term); if (!newterm(strstr(term, "-256color") ? "xterm-256color" : "xterm", stderr, stdin)) @@ -288,19 +276,19 @@ static bool ui_curses_init(UiTerm *tui, char *term) { return true; } -static UiTerm *ui_curses_new(void) { - return calloc(1, sizeof(UiTerm)); +static bool ui_backend_init(Ui *ui) { + return true; } -static void ui_curses_resume(UiTerm *term) { } +void ui_terminal_resume(Ui *term) { } -static void ui_curses_suspend(UiTerm *term) { +static void ui_term_backend_suspend(Ui *term) { if (change_colors == 1) undo_palette(); } -static void ui_curses_free(UiTerm *term) { - ui_curses_suspend(term); +static void ui_term_backend_free(Ui *term) { + ui_term_backend_suspend(term); endwin(); } diff --git a/ui-terminal-vt100.c b/ui-terminal-vt100.c index 565313f9e..a1c92f35b 100644 --- a/ui-terminal-vt100.c +++ b/ui-terminal-vt100.c @@ -41,18 +41,6 @@ #define UI_TERMKEY_FLAGS TERMKEY_FLAG_UTF8 -#define ui_term_backend_init ui_vt100_init -#define ui_term_backend_blit ui_vt100_blit -#define ui_term_backend_clear ui_vt100_clear -#define ui_term_backend_colors ui_vt100_colors -#define ui_term_backend_resize ui_vt100_resize -#define ui_term_backend_save ui_vt100_save -#define ui_term_backend_restore ui_vt100_restore -#define ui_term_backend_suspend ui_vt100_suspend -#define ui_term_backend_resume ui_vt100_resume -#define ui_term_backend_new ui_vt100_new -#define ui_term_backend_free ui_vt100_free - #define CELL_COLOR_BLACK { .index = 0 } #define CELL_COLOR_RED { .index = 1 } #define CELL_COLOR_GREEN { .index = 2 } @@ -71,22 +59,17 @@ #define CELL_ATTR_ITALIC (1 << 4) #define CELL_ATTR_DIM (1 << 5) -typedef struct { - UiTerm uiterm; - Buffer buf; -} UiVt100; - static inline bool cell_color_equal(CellColor c1, CellColor c2) { if (c1.index != (uint8_t)-1 || c2.index != (uint8_t)-1) return c1.index == c2.index; return c1.r == c2.r && c1.g == c2.g && c1.b == c2.b; } -static CellColor color_rgb(UiTerm *ui, uint8_t r, uint8_t g, uint8_t b) { +static CellColor color_rgb(Ui *ui, uint8_t r, uint8_t g, uint8_t b) { return (CellColor){ .r = r, .g = g, .b = b, .index = (uint8_t)-1 }; } -static CellColor color_terminal(UiTerm *ui, uint8_t index) { +static CellColor color_terminal(Ui *ui, uint8_t index) { return (CellColor){ .r = 0, .g = 0, .b = 0, .index = index }; } @@ -108,8 +91,8 @@ static void cursor_visible(bool visible) { output_literal(visible ? "\x1b[?25h" : "\x1b[?25l"); } -static void ui_vt100_blit(UiTerm *tui) { - Buffer *buf = &((UiVt100*)tui)->buf; +static void ui_term_backend_blit(Ui *tui) { + Buffer *buf = tui->ctx; buffer_clear(buf); CellAttr attr = CELL_ATTR_NORMAL; CellColor fg = CELL_COLOR_DEFAULT, bg = CELL_COLOR_DEFAULT; @@ -174,55 +157,57 @@ static void ui_vt100_blit(UiTerm *tui) { output(buffer_content(buf), buffer_length0(buf)); } -static void ui_vt100_clear(UiTerm *tui) { } +static void ui_term_backend_clear(Ui *tui) { } -static bool ui_vt100_resize(UiTerm *tui, int width, int height) { +static bool ui_term_backend_resize(Ui *tui, int width, int height) { return true; } -static void ui_vt100_save(UiTerm *tui, bool fscr) { +static void ui_term_backend_save(Ui *tui, bool fscr) { cursor_visible(true); } -static void ui_vt100_restore(UiTerm *tui) { +static void ui_term_backend_restore(Ui *tui) { cursor_visible(false); } -static int ui_vt100_colors(Ui *ui) { +int ui_terminal_colors(void) { char *term = getenv("TERM"); return (term && strstr(term, "-256color")) ? 256 : 16; } -static void ui_vt100_suspend(UiTerm *tui) { +static void ui_term_backend_suspend(Ui *tui) { if (!tui->termkey) return; termkey_stop(tui->termkey); cursor_visible(true); screen_alternate(false); } -static void ui_vt100_resume(UiTerm *tui) { +void ui_terminal_resume(Ui *tui) { screen_alternate(true); cursor_visible(false); termkey_start(tui->termkey); } -static bool ui_vt100_init(UiTerm *tui, char *term) { - ui_vt100_resume(tui); +static bool ui_term_backend_init(Ui *tui, char *term) { + ui_terminal_resume(tui); return true; } -static UiTerm *ui_vt100_new(void) { - UiVt100 *vtui = calloc(1, sizeof *vtui); - if (!vtui) - return NULL; - buffer_init(&vtui->buf); - return (UiTerm*)vtui; +static bool ui_backend_init(Ui *ui) { + Buffer *buf = calloc(1, sizeof(Buffer)); + if (!buf) + return false; + buffer_init(buf); + ui->ctx = buf; + return true; } -static void ui_vt100_free(UiTerm *tui) { - UiVt100 *vtui = (UiVt100*)tui; - ui_vt100_suspend(tui); - buffer_release(&vtui->buf); +static void ui_term_backend_free(Ui *tui) { + Buffer *buf = tui->ctx; + ui_term_backend_suspend(tui); + buffer_release(buf); + free(buf); } static bool is_default_color(CellColor c) { diff --git a/ui-terminal.c b/ui-terminal.c index 09e618ea8..d540308eb 100644 --- a/ui-terminal.c +++ b/ui-terminal.c @@ -13,7 +13,6 @@ #include #include -#include "ui-terminal.h" #include "vis.h" #include "vis-core.h" #include "text.h" @@ -30,39 +29,6 @@ #define debug(...) do { } while (0) #endif -#define MAX_WIDTH 1024 -#define MAX_HEIGHT 1024 -typedef struct UiTermWin UiTermWin; - -typedef struct { - Ui ui; /* generic ui interface, has to be the first struct member */ - Vis *vis; /* editor instance to which this ui belongs */ - UiTermWin *windows; /* all windows managed by this ui */ - UiTermWin *selwin; /* the currently selected layout */ - char info[MAX_WIDTH]; /* info message displayed at the bottom of the screen */ - int width, height; /* terminal dimensions available for all windows */ - enum UiLayout layout; /* whether windows are displayed horizontally or vertically */ - TermKey *termkey; /* libtermkey instance to handle keyboard input (stdin or /dev/tty) */ - size_t ids; /* bit mask of in use window ids */ - size_t styles_size; /* #bytes allocated for styles array */ - CellStyle *styles; /* each window has UI_STYLE_MAX different style definitions */ - size_t cells_size; /* #bytes allocated for 2D grid (grows only) */ - Cell *cells; /* 2D grid of cells, at least as large as current terminal size */ - bool doupdate; /* Whether to update the screen after refreshing contents */ -} UiTerm; - -struct UiTermWin { - UiWin uiwin; /* generic interface, has to be the first struct member */ - UiTerm *ui; /* ui which manages this window */ - Win *win; /* editor window being displayed */ - int id; /* unique identifier for this window */ - int width, height; /* window dimension including status bar */ - int x, y; /* window position */ - int sidebar_width; /* width of the sidebar showing line numbers etc. */ - UiTermWin *next, *prev; /* pointers to neighbouring windows */ - enum UiOption options; /* display settings for this window */ -}; - #if CONFIG_CURSES #include "ui-terminal-curses.c" #else @@ -72,37 +38,36 @@ struct UiTermWin { /* helper macro for handling UiTerm.cells */ #define CELL_AT_POS(UI, X, Y) (((UI)->cells) + (X) + ((Y) * (UI)->width)); -__attribute__((noreturn)) static void ui_die(Ui *ui, const char *msg, va_list ap) { - UiTerm *tui = (UiTerm*)ui; - ui_term_backend_free(tui); +void ui_die(Ui *tui, const char *msg, va_list ap) { + ui_terminal_free(tui); if (tui->termkey) termkey_stop(tui->termkey); vfprintf(stderr, msg, ap); exit(EXIT_FAILURE); } -__attribute__((noreturn)) static void ui_die_msg(Ui *ui, const char *msg, ...) { +static void ui_die_msg(Ui *ui, const char *msg, ...) { va_list ap; va_start(ap, msg); ui_die(ui, msg, ap); va_end(ap); } -static void ui_window_resize(UiTermWin *win, int width, int height) { +static void ui_window_resize(UiWin *win, int width, int height) { debug("ui-win-resize[%s]: %dx%d\n", win->win->file->name ? win->win->file->name : "noname", width, height); bool status = win->options & UI_OPTION_STATUSBAR; win->width = width; win->height = height; - view_resize(win->win->view, width - win->sidebar_width, status ? height - 1 : height); + view_resize(&win->win->view, width - win->sidebar_width, status ? height - 1 : height); } -static void ui_window_move(UiTermWin *win, int x, int y) { +static void ui_window_move(UiWin *win, int x, int y) { debug("ui-win-move[%s]: (%d, %d)\n", win->win->file->name ? win->win->file->name : "noname", x, y); win->x = x; win->y = y; } -static bool color_fromstring(UiTerm *ui, CellColor *color, const char *s) +static bool color_fromstring(Ui *ui, CellColor *color, const char *s) { if (!s) return false; @@ -150,9 +115,8 @@ static bool color_fromstring(UiTerm *ui, CellColor *color, const char *s) return false; } -static bool ui_style_define(UiWin *w, int id, const char *style) { - UiTermWin *win = (UiTermWin*)w; - UiTerm *tui = win->ui; +bool ui_style_define(UiWin *win, int id, const char *style) { + Ui *tui = win->ui; if (id >= UI_STYLE_MAX) return false; if (!style) @@ -204,7 +168,7 @@ static bool ui_style_define(UiWin *w, int id, const char *style) { return true; } -static void ui_draw_line(UiTerm *tui, int x, int y, char c, enum UiStyle style_id) { +static void ui_draw_line(Ui *tui, int x, int y, char c, enum UiStyle style_id) { if (x < 0 || x >= tui->width || y < 0 || y >= tui->height) return; CellStyle style = tui->styles[style_id]; @@ -217,7 +181,7 @@ static void ui_draw_line(UiTerm *tui, int x, int y, char c, enum UiStyle style_i } } -static void ui_draw_string(UiTerm *tui, int x, int y, const char *str, UiTermWin *win, enum UiStyle style_id) { +static void ui_draw_string(Ui *tui, int x, int y, const char *str, UiWin *win, enum UiStyle style_id) { debug("draw-string: [%d][%d]\n", y, x); if (x < 0 || x >= tui->width || y < 0 || y >= tui->height) return; @@ -238,12 +202,11 @@ static void ui_draw_string(UiTerm *tui, int x, int y, const char *str, UiTermWin } } -static void ui_window_draw(UiWin *w) { - UiTermWin *win = (UiTermWin*)w; - UiTerm *ui = win->ui; - View *view = win->win->view; +static void ui_window_draw(UiWin *win) { + Ui *ui = win->ui; + View *view = &win->win->view; int width = win->width, height = win->height; - const Line *line = view_lines_first(view); + const Line *line = view->topline; bool status = win->options & UI_OPTION_STATUSBAR; bool nu = win->options & UI_OPTION_LINE_NUMBERS_ABSOLUTE; bool rnu = win->options & UI_OPTION_LINE_NUMBERS_RELATIVE; @@ -254,14 +217,13 @@ static void ui_window_draw(UiWin *w) { win->sidebar_width = sidebar_width; } vis_window_draw(win->win); - line = view_lines_first(view); + line = view->topline; size_t prev_lineno = 0; Selection *sel = view_selections_primary_get(view); - const Line *cursor_line = view_cursors_line_get(sel); - size_t cursor_lineno = cursor_line->lineno; + size_t cursor_lineno = sel->line->lineno; char buf[(sizeof(size_t) * CHAR_BIT + 2) / 3 + 1 + 1]; int x = win->x, y = win->y; - int view_width = view_width_get(view); + int view_width = view->width; Cell *cells = ui->cells + y * ui->width; if (x + sidebar_width + view_width > ui->width) view_width = ui->width - x - sidebar_width; @@ -291,9 +253,8 @@ static void ui_window_draw(UiWin *w) { } } -static void ui_window_style_set(UiWin *w, Cell *cell, enum UiStyle id) { - UiTermWin *win = (UiTermWin*)w; - UiTerm *tui = win->ui; +void ui_window_style_set(UiWin *win, Cell *cell, enum UiStyle id) { + Ui *tui = win->ui; CellStyle set, style = tui->styles[win->id * UI_STYLE_MAX + id]; if (id == UI_STYLE_DEFAULT) { @@ -308,32 +269,29 @@ static void ui_window_style_set(UiWin *w, Cell *cell, enum UiStyle id) { memcpy(&cell->style, &set, sizeof(CellStyle)); } -static bool ui_window_style_set_pos(UiWin *w, int x, int y, enum UiStyle id) { - UiTermWin *win = (UiTermWin*)w; - UiTerm *tui = win->ui; +bool ui_window_style_set_pos(UiWin *win, int x, int y, enum UiStyle id) { + Ui *tui = win->ui; if (x < 0 || y < 0 || y >= win->height || x >= win->width) { return false; } Cell *cell = CELL_AT_POS(tui, win->x + x, win->y + y) - ui_window_style_set(w, cell, id); + ui_window_style_set(win, cell, id); return true; } -static void ui_window_status(UiWin *w, const char *status) { - UiTermWin *win = (UiTermWin*)w; +void ui_window_status(UiWin *win, const char *status) { if (!(win->options & UI_OPTION_STATUSBAR)) return; - UiTerm *ui = win->ui; + Ui *ui = win->ui; enum UiStyle style = ui->selwin == win ? UI_STYLE_STATUS_FOCUSED : UI_STYLE_STATUS; ui_draw_string(ui, win->x, win->y + win->height - 1, status, win, style); } -static void ui_arrange(Ui *ui, enum UiLayout layout) { +void ui_arrange(Ui *tui, enum UiLayout layout) { debug("ui-arrange\n"); - UiTerm *tui = (UiTerm*)ui; tui->layout = layout; int n = 0, m = !!tui->info[0], x = 0, y = 0; - for (UiTermWin *win = tui->windows; win; win = win->next) { + for (UiWin *win = tui->windows; win; win = win->next) { if (win->options & UI_OPTION_ONELINE) m++; else @@ -342,7 +300,7 @@ static void ui_arrange(Ui *ui, enum UiLayout layout) { int max_height = tui->height - m; int width = (tui->width / MAX(1, n)) - 1; int height = max_height / MAX(1, n); - for (UiTermWin *win = tui->windows; win; win = win->next) { + for (UiWin *win = tui->windows; win; win = win->next) { if (win->options & UI_OPTION_ONELINE) continue; n--; @@ -371,7 +329,7 @@ static void ui_arrange(Ui *ui, enum UiLayout layout) { if (layout == UI_LAYOUT_VERTICAL) y = max_height; - for (UiTermWin *win = tui->windows; win; win = win->next) { + for (UiWin *win = tui->windows; win; win = win->next) { if (!(win->options & UI_OPTION_ONELINE)) continue; ui_window_resize(win, tui->width, 1); @@ -379,32 +337,24 @@ static void ui_arrange(Ui *ui, enum UiLayout layout) { } } -static void ui_doupdates(Ui *ui, bool doupdate) { - UiTerm *tui = (UiTerm*)ui; - tui->doupdate = doupdate; -} - -static void ui_draw(Ui *ui) { +void ui_draw(Ui *tui) { debug("ui-draw\n"); - UiTerm *tui = (UiTerm*)ui; - ui_arrange(ui, tui->layout); - for (UiTermWin *win = tui->windows; win; win = win->next) - ui_window_draw((UiWin*)win); + ui_arrange(tui, tui->layout); + for (UiWin *win = tui->windows; win; win = win->next) + ui_window_draw(win); if (tui->info[0]) ui_draw_string(tui, 0, tui->height-1, tui->info, NULL, UI_STYLE_INFO); vis_event_emit(tui->vis, VIS_EVENT_UI_DRAW); ui_term_backend_blit(tui); } -static void ui_redraw(Ui *ui) { - UiTerm *tui = (UiTerm*)ui; +void ui_redraw(Ui *tui) { ui_term_backend_clear(tui); - for (UiTermWin *win = tui->windows; win; win = win->next) - view_invalidate(win->win->view); + for (UiWin *win = tui->windows; win; win = win->next) + win->win->view.need_update = true; } -static void ui_resize(Ui *ui) { - UiTerm *tui = (UiTerm*)ui; +void ui_resize(Ui *tui) { struct winsize ws; int width = 80, height = 24; @@ -415,8 +365,8 @@ static void ui_resize(Ui *ui) { height = ws.ws_row; } - width = MIN(width, MAX_WIDTH); - height = MIN(height, MAX_HEIGHT); + width = MIN(width, UI_MAX_WIDTH); + height = MIN(height, UI_MAX_HEIGHT); if (!ui_term_backend_resize(tui, width, height)) return; @@ -433,11 +383,10 @@ static void ui_resize(Ui *ui) { tui->height = height; } -static void ui_window_free(UiWin *w) { - UiTermWin *win = (UiTermWin*)w; +void ui_window_free(UiWin *win) { if (!win) return; - UiTerm *tui = win->ui; + Ui *tui = win->ui; if (win->prev) win->prev->next = win->next; if (win->next) @@ -451,23 +400,21 @@ static void ui_window_free(UiWin *w) { free(win); } -static void ui_window_focus(UiWin *w) { - UiTermWin *new = (UiTermWin*)w; - UiTermWin *old = new->ui->selwin; +void ui_window_focus(UiWin *new) { + UiWin *old = new->ui->selwin; if (new->options & UI_OPTION_STATUSBAR) new->ui->selwin = new; if (old) - view_invalidate(old->win->view); - view_invalidate(new->win->view); + old->win->view.need_update = true; + new->win->view.need_update = true; } -static void ui_window_options_set(UiWin *w, enum UiOption options) { - UiTermWin *win = (UiTermWin*)w; +void ui_window_options_set(UiWin *win, enum UiOption options) { win->options = options; if (options & UI_OPTION_ONELINE) { /* move the new window to the end of the list */ - UiTerm *tui = win->ui; - UiTermWin *last = tui->windows; + Ui *tui = win->ui; + UiWin *last = tui->windows; while (last->next) last = last->next; if (last != win) { @@ -482,28 +429,14 @@ static void ui_window_options_set(UiWin *w, enum UiOption options) { win->next = NULL; } } - ui_draw((Ui*)win->ui); + ui_draw(win->ui); } -static enum UiOption ui_window_options_get(UiWin *win) { - return ((UiTermWin*)win)->options; -} - -static int ui_window_width(UiWin *win) { - return ((UiTermWin*)win)->width; -} - -static int ui_window_height(UiWin *win) { - return ((UiTermWin*)win)->height; -} - -static void ui_window_swap(UiWin *aw, UiWin *bw) { - UiTermWin *a = (UiTermWin*)aw; - UiTermWin *b = (UiTermWin*)bw; +void ui_window_swap(UiWin *a, UiWin *b) { if (a == b || !a || !b) return; - UiTerm *tui = a->ui; - UiTermWin *tmp = a->next; + Ui *tui = a->ui; + UiWin *tmp = a->next; a->next = b->next; b->next = tmp; if (a->next) @@ -522,13 +455,12 @@ static void ui_window_swap(UiWin *aw, UiWin *bw) { else if (tui->windows == b) tui->windows = a; if (tui->selwin == a) - ui_window_focus(bw); + ui_window_focus(b); else if (tui->selwin == b) - ui_window_focus(aw); + ui_window_focus(a); } -static UiWin *ui_window_new(Ui *ui, Win *w, enum UiOption options) { - UiTerm *tui = (UiTerm*)ui; +UiWin *ui_window_new(Ui *tui, Win *w, enum UiOption options) { /* get rightmost zero bit, i.e. highest available id */ size_t bit = ~tui->ids & (tui->ids + 1); size_t id = 0; @@ -543,21 +475,10 @@ static UiWin *ui_window_new(Ui *ui, Win *w, enum UiOption options) { tui->styles = styles; tui->styles_size = styles_size; } - UiTermWin *win = calloc(1, sizeof(UiTermWin)); + UiWin *win = calloc(1, sizeof(UiWin)); if (!win) return NULL; - win->uiwin = (UiWin) { - .style_set = ui_window_style_set, - .style_set_pos = ui_window_style_set_pos, - .status = ui_window_status, - .options_set = ui_window_options_set, - .options_get = ui_window_options_get, - .style_define = ui_style_define, - .window_width = ui_window_width, - .window_height = ui_window_height, - }; - tui->ids |= bit; win->id = id; win->ui = tui; @@ -579,7 +500,7 @@ static UiWin *ui_window_new(Ui *ui, Win *w, enum UiOption options) { styles[UI_STYLE_STATUS].attr |= CELL_ATTR_REVERSE; styles[UI_STYLE_STATUS_FOCUSED].attr |= CELL_ATTR_REVERSE|CELL_ATTR_BOLD; styles[UI_STYLE_INFO].attr |= CELL_ATTR_BOLD; - view_ui(w->view, &win->uiwin); + w->view.ui = win; if (tui->windows) tui->windows->prev = win; @@ -591,19 +512,17 @@ static UiWin *ui_window_new(Ui *ui, Win *w, enum UiOption options) { options &= ~UI_OPTION_LINE_NUMBERS_ABSOLUTE; } - ui_window_options_set((UiWin*)win, options); + ui_window_options_set(win, options); - return &win->uiwin; + return win; } -static void ui_info(Ui *ui, const char *msg, va_list ap) { - UiTerm *tui = (UiTerm*)ui; +void ui_info_show(Ui *tui, const char *msg, va_list ap) { ui_draw_line(tui, 0, tui->height-1, ' ', UI_STYLE_INFO); vsnprintf(tui->info, sizeof(tui->info), msg, ap); } -static void ui_info_hide(Ui *ui) { - UiTerm *tui = (UiTerm*)ui; +void ui_info_hide(Ui *tui) { if (tui->info[0]) tui->info[0] = '\0'; } @@ -627,31 +546,19 @@ static TermKey *ui_termkey_reopen(Ui *ui, int fd) { return ui_termkey_new(fd); } -static TermKey *ui_termkey_get(Ui *ui) { - UiTerm *tui = (UiTerm*)ui; - return tui->termkey; -} - -static void ui_suspend(Ui *ui) { - UiTerm *tui = (UiTerm*)ui; +void ui_terminal_suspend(Ui *tui) { ui_term_backend_suspend(tui); kill(0, SIGTSTP); } -static void ui_resume(Ui *ui) { - UiTerm *tui = (UiTerm*)ui; - ui_term_backend_resume(tui); -} - -static bool ui_getkey(Ui *ui, TermKeyKey *key) { - UiTerm *tui = (UiTerm*)ui; +bool ui_getkey(Ui *tui, TermKeyKey *key) { TermKeyResult ret = termkey_getkey(tui->termkey, key); if (ret == TERMKEY_RES_EOF) { termkey_destroy(tui->termkey); errno = 0; - if (!(tui->termkey = ui_termkey_reopen(ui, STDIN_FILENO))) - ui_die_msg(ui, "Failed to re-open stdin as /dev/tty: %s\n", errno != 0 ? strerror(errno) : ""); + if (!(tui->termkey = ui_termkey_reopen(tui, STDIN_FILENO))) + ui_die_msg(tui, "Failed to re-open stdin as /dev/tty: %s\n", errno != 0 ? strerror(errno) : ""); return false; } @@ -666,20 +573,17 @@ static bool ui_getkey(Ui *ui, TermKeyKey *key) { return ret == TERMKEY_RES_KEY; } -static void ui_terminal_save(Ui *ui, bool fscr) { - UiTerm *tui = (UiTerm*)ui; +void ui_terminal_save(Ui *tui, bool fscr) { ui_term_backend_save(tui, fscr); termkey_stop(tui->termkey); } -static void ui_terminal_restore(Ui *ui) { - UiTerm *tui = (UiTerm*)ui; +void ui_terminal_restore(Ui *tui) { termkey_start(tui->termkey); ui_term_backend_restore(tui); } -static bool ui_init(Ui *ui, Vis *vis) { - UiTerm *tui = (UiTerm*)ui; +bool ui_init(Ui *tui, Vis *vis) { tui->vis = vis; setlocale(LC_CTYPE, ""); @@ -695,7 +599,7 @@ static bool ui_init(Ui *ui, Vis *vis) { /* work around libtermkey bug which fails if stdin is /dev/null */ if (errno == EBADF) { errno = 0; - if (!(tui->termkey = ui_termkey_reopen(ui, STDIN_FILENO)) && errno == ENXIO) + if (!(tui->termkey = ui_termkey_reopen(tui, STDIN_FILENO)) && errno == ENXIO) tui->termkey = termkey_new_abstract(term, UI_TERMKEY_FLAGS); } if (!tui->termkey) @@ -704,69 +608,36 @@ static bool ui_init(Ui *ui, Vis *vis) { if (!ui_term_backend_init(tui, term)) goto err; - ui_resize(ui); + ui_resize(tui); return true; err: - ui_die_msg(ui, "Failed to start curses interface: %s\n", errno != 0 ? strerror(errno) : ""); + ui_die_msg(tui, "Failed to start curses interface: %s\n", errno != 0 ? strerror(errno) : ""); return false; } -enum UiLayout ui_layout_get(Ui *ui) { - UiTerm *tui = (UiTerm *)ui; - return tui->layout; -} - -Ui *ui_term_new(void) { +bool ui_terminal_init(Ui *tui) { size_t styles_size = UI_STYLE_MAX * sizeof(CellStyle); CellStyle *styles = calloc(1, styles_size); if (!styles) - return NULL; - UiTerm *tui = ui_term_backend_new(); - if (!tui) { + return false; + if (!ui_backend_init(tui)) { free(styles); - return NULL; + return false; } tui->styles_size = styles_size; tui->styles = styles; tui->doupdate = true; - Ui *ui = (Ui*)tui; - *ui = (Ui) { - .init = ui_init, - .free = ui_term_free, - .termkey_get = ui_termkey_get, - .suspend = ui_suspend, - .resume = ui_resume, - .resize = ui_resize, - .window_new = ui_window_new, - .window_free = ui_window_free, - .window_focus = ui_window_focus, - .window_swap = ui_window_swap, - .draw = ui_draw, - .redraw = ui_redraw, - .arrange = ui_arrange, - .doupdates = ui_doupdates, - .die = ui_die, - .info = ui_info, - .info_hide = ui_info_hide, - .getkey = ui_getkey, - .terminal_save = ui_terminal_save, - .terminal_restore = ui_terminal_restore, - .colors = ui_term_backend_colors, - }; - - return ui; + return true; } -void ui_term_free(Ui *ui) { - UiTerm *tui = (UiTerm*)ui; +void ui_terminal_free(Ui *tui) { if (!tui) return; while (tui->windows) - ui_window_free((UiWin*)tui->windows); + ui_window_free(tui->windows); ui_term_backend_free(tui); if (tui->termkey) termkey_destroy(tui->termkey); free(tui->cells); free(tui->styles); - free(tui); } diff --git a/ui-terminal.h b/ui-terminal.h deleted file mode 100644 index 45286abff..000000000 --- a/ui-terminal.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef UI_TERMINAL_H -#define UI_TERMINAL_H - -#include "ui.h" - -Ui *ui_term_new(void); -void ui_term_free(Ui*); - -#endif diff --git a/ui.h b/ui.h index 45b6065eb..c03a7096f 100644 --- a/ui.h +++ b/ui.h @@ -10,8 +10,8 @@ /* enable large file optimization for files containing lines longer than: */ #define UI_LARGE_FILE_LINE_SIZE (1 << 16) -typedef struct Ui Ui; -typedef struct UiWin UiWin; +#define UI_MAX_WIDTH 1024 +#define UI_MAX_HEIGHT 1024 enum UiLayout { UI_LAYOUT_HORIZONTAL, @@ -67,45 +67,84 @@ typedef struct { CellColor fg, bg; } CellStyle; +typedef struct { + char data[16]; /* utf8 encoded character displayed in this cell (might be more than + one Unicode codepoint. might also not be the same as in the + underlying text, for example tabs get expanded */ + size_t len; /* number of bytes the character displayed in this cell uses, for + characters which use more than 1 column to display, their length + is stored in the leftmost cell whereas all following cells + occupied by the same character have a length of 0. */ + int width; /* display width i.e. number of columns occupied by this character */ + CellStyle style; /* colors and attributes used to display this cell */ +} Cell; + +struct Ui; +struct Win; +typedef struct UiWin { + struct Ui *ui; /* ui which manages this window */ + struct Win *win; /* editor window being displayed */ + int id; /* unique identifier for this window */ + int width, height; /* window dimension including status bar */ + int x, y; /* window position */ + int sidebar_width; /* width of the sidebar showing line numbers etc. */ + struct UiWin *next, *prev; /* pointers to neighbouring windows */ + enum UiOption options; /* display settings for this window */ +} UiWin; + +struct Vis; +typedef struct Ui { + struct Vis *vis; /* editor instance to which this ui belongs */ + UiWin *windows; /* all windows managed by this ui */ + UiWin *selwin; /* the currently selected layout */ + char info[UI_MAX_WIDTH]; /* info message displayed at the bottom of the screen */ + int width, height; /* terminal dimensions available for all windows */ + enum UiLayout layout; /* whether windows are displayed horizontally or vertically */ + TermKey *termkey; /* libtermkey instance to handle keyboard input (stdin or /dev/tty) */ + size_t ids; /* bit mask of in use window ids */ + size_t styles_size; /* #bytes allocated for styles array */ + CellStyle *styles; /* each window has UI_STYLE_MAX different style definitions */ + size_t cells_size; /* #bytes allocated for 2D grid (grows only) */ + Cell *cells; /* 2D grid of cells, at least as large as current terminal size */ + bool doupdate; /* Whether to update the screen after refreshing contents */ + void *ctx; /* Any additional data needed by the backend */ +} Ui; + +#include "view.h" #include "vis.h" #include "text.h" -#include "view.h" -struct Ui { - bool (*init)(Ui*, Vis*); - void (*free)(Ui*); - void (*resize)(Ui*); - UiWin* (*window_new)(Ui*, Win*, enum UiOption); - void (*window_free)(UiWin*); - void (*window_focus)(UiWin*); - void (*window_swap)(UiWin*, UiWin*); - void (*die)(Ui*, const char *msg, va_list ap) __attribute__((noreturn)); - void (*info)(Ui*, const char *msg, va_list ap); - void (*info_hide)(Ui*); - void (*arrange)(Ui*, enum UiLayout); - void (*draw)(Ui*); - void (*redraw)(Ui*); - void (*suspend)(Ui*); - void (*resume)(Ui*); - void (*doupdates)(Ui*, bool); - bool (*getkey)(Ui*, TermKeyKey*); - void (*terminal_save)(Ui*, bool fscr); - void (*terminal_restore)(Ui*); - TermKey* (*termkey_get)(Ui*); - int (*colors)(Ui*); -}; +#define UI_OPTIONS_GET(ui) ((ui) ? (ui)->options : 0) -struct UiWin { - void (*style_set)(UiWin*, Cell*, enum UiStyle); - bool (*style_set_pos)(UiWin*, int x, int y, enum UiStyle); - void (*status)(UiWin*, const char *txt); - void (*options_set)(UiWin*, enum UiOption); - enum UiOption (*options_get)(UiWin*); - bool (*style_define)(UiWin*, int id, const char *style); - int (*window_width)(UiWin*); - int (*window_height)(UiWin*); -}; +bool ui_terminal_init(Ui*); +int ui_terminal_colors(void); +void ui_terminal_free(Ui*); +void ui_terminal_restore(Ui*); +void ui_terminal_resume(Ui*); +void ui_terminal_save(Ui*, bool fscr); +void ui_terminal_suspend(Ui*); + +__attribute__((noreturn)) void ui_die(Ui *, const char *, va_list); +bool ui_init(Ui *, Vis *); +void ui_arrange(Ui*, enum UiLayout); +void ui_draw(Ui*); +void ui_info_hide(Ui *); +void ui_info_show(Ui *, const char *, va_list); +void ui_redraw(Ui*); +void ui_resize(Ui*); + +UiWin *ui_window_new(Ui *, Win *, enum UiOption); +void ui_window_focus(UiWin *); +void ui_window_free(UiWin *); +void ui_window_swap(UiWin *, UiWin *); + +bool ui_getkey(Ui *, TermKeyKey *); + +bool ui_style_define(UiWin *win, int id, const char *style); +bool ui_window_style_set_pos(UiWin *win, int x, int y, enum UiStyle id); +void ui_window_style_set(UiWin *win, Cell *cell, enum UiStyle id); -enum UiLayout ui_layout_get(Ui *ui); +void ui_window_options_set(UiWin *win, enum UiOption options); +void ui_window_status(UiWin *win, const char *status); #endif diff --git a/view.c b/view.c index df7906b54..6e67088e9 100644 --- a/view.c +++ b/view.c @@ -1,28 +1,18 @@ -#include -#include -#include #include #include #include +#include +#include +#include +#include + +#include "vis-core.h" #include "view.h" #include "text.h" #include "text-motions.h" #include "text-util.h" #include "util.h" -typedef struct { - char *symbol; -} SyntaxSymbol; - -enum { - SYNTAX_SYMBOL_SPACE, - SYNTAX_SYMBOL_TAB, - SYNTAX_SYMBOL_TAB_FILL, - SYNTAX_SYMBOL_EOL, - SYNTAX_SYMBOL_EOF, - SYNTAX_SYMBOL_LAST, -}; - /* A selection is made up of two marks named cursor and anchor. * While the anchor remains fixed the cursor mark follows cursor motions. * For a selection (indicated by []), the marks (^) are placed as follows: @@ -39,53 +29,6 @@ enum { * the necessary offset for the last character. */ -struct Selection { - Mark cursor; /* other selection endpoint where it changes */ - Mark anchor; /* position where the selection was created */ - bool anchored; /* whether anchor remains fixed */ - size_t pos; /* in bytes from the start of the file */ - int row, col; /* in terms of zero based screen coordinates */ - int lastcol; /* remembered column used when moving across lines */ - Line *line; /* screen line on which cursor currently resides */ - int generation; /* used to filter out newly created cursors during iteration */ - int number; /* how many cursors are located before this one */ - View *view; /* associated view to which this cursor belongs */ - Selection *prev, *next; /* previous/next cursors ordered by location at creation time */ -}; - -struct View { - Text *text; /* underlying text management */ - char *textbuf; /* scratch buffer used for drawing */ - UiWin *ui; /* corresponding ui window */ - Cell cell_blank; /* used for empty/blank cells */ - int width, height; /* size of display area */ - size_t start, end; /* currently displayed area [start, end] in bytes from the start of the file */ - size_t start_last; /* previously used start of visible area, used to update the mark */ - Mark start_mark; /* mark to keep track of the start of the visible area */ - size_t lines_size; /* number of allocated bytes for lines (grows only) */ - Line *lines; /* view->height number of lines representing view content */ - Line *topline; /* top of the view, first line currently shown */ - Line *lastline; /* last currently used line, always <= bottomline */ - Line *bottomline; /* bottom of view, might be unused if lastline < bottomline */ - Selection *selection; /* primary selection, always placed within the visible viewport */ - Selection *selection_latest; /* most recently created cursor */ - Selection *selection_dead; /* primary cursor which was disposed, will be removed when another cursor is created */ - int selection_count; /* how many cursors do currently exist */ - Line *line; /* used while drawing view content, line where next char will be drawn */ - int col; /* used while drawing view content, column where next char will be drawn */ - const SyntaxSymbol *symbols[SYNTAX_SYMBOL_LAST]; /* symbols to use for white spaces etc */ - int tabwidth; /* how many spaces should be used to display a tab character */ - Selection *selections; /* all cursors currently active */ - int selection_generation; /* used to filter out newly created cursors during iteration */ - bool need_update; /* whether view has been redrawn */ - bool large_file; /* optimize for displaying large files */ - int colorcolumn; - char *breakat; /* characters which might cause a word wrap */ - int wrapcolumn; /* wrap lines at minimum of window width and wrapcolumn (if != 0) */ - int wrapcol; /* used while drawing view content, column where word wrap might happen */ - bool prevch_breakat; /* used while drawing view content, previous char is part of breakat */ -}; - static const SyntaxSymbol symbols_none[] = { [SYNTAX_SYMBOL_SPACE] = { " " }, [SYNTAX_SYMBOL_TAB] = { " " }, @@ -107,7 +50,7 @@ static Cell cell_unused; /* move visible viewport n-lines up/down, redraws the view but does not change * cursor position which becomes invalid and should be corrected by calling - * view_cursor_to. the return value indicates whether the visible area changed. + * view_cursors_to. the return value indicates whether the visible area changed. */ static bool view_viewport_up(View *view, int n); static bool view_viewport_down(View *view, int n); @@ -119,6 +62,100 @@ static void selection_free(Selection*); /* set/move current cursor position to a given (line, column) pair */ static size_t cursor_set(Selection*, Line *line, int col); +void window_status_update(Vis *vis, Win *win) { + char left_parts[4][255] = { "", "", "", "" }; + char right_parts[4][32] = { "", "", "", "" }; + char left[sizeof(left_parts)+LENGTH(left_parts)*8]; + char right[sizeof(right_parts)+LENGTH(right_parts)*8]; + char status[sizeof(left)+sizeof(right)+1]; + size_t left_count = 0; + size_t right_count = 0; + + View *view = &win->view; + File *file = win->file; + Text *txt = file->text; + int width = win->ui->width; + enum UiOption options = UI_OPTIONS_GET(view->ui); + bool focused = vis->win == win; + const char *filename = file_name_get(file); + const char *mode = vis->mode->status; + + if (focused && mode) + strcpy(left_parts[left_count++], mode); + + snprintf(left_parts[left_count++], sizeof(left_parts[0]), "%s%s%s", + filename ? filename : "[No Name]", + text_modified(txt) ? " [+]" : "", + vis_macro_recording(vis) ? " @": ""); + + int count = vis->action.count; + const char *keys = buffer_content0(&vis->input_queue); + if (keys && keys[0]) + snprintf(right_parts[right_count++], sizeof(right_parts[0]), "%s", keys); + else if (count != VIS_COUNT_UNKNOWN) + snprintf(right_parts[right_count++], sizeof(right_parts[0]), "%d", count); + + int sel_count = view->selection_count; + if (sel_count > 1) { + Selection *s = view_selections_primary_get(view); + int sel_number = view_selections_number(s) + 1; + snprintf(right_parts[right_count++], sizeof(right_parts[0]), + "%d/%d", sel_number, sel_count); + } + + size_t size = text_size(txt); + size_t pos = view_cursor_get(view); + size_t percent = 0; + if (size > 0) { + double tmp = ((double)pos/(double)size)*100; + percent = (size_t)(tmp+1); + } + snprintf(right_parts[right_count++], sizeof(right_parts[0]), + "%zu%%", percent); + + if (!(options & UI_OPTION_LARGE_FILE)) { + Selection *sel = view_selections_primary_get(&win->view); + size_t line = view_cursors_line(sel); + size_t col = view_cursors_col(sel); + if (col > UI_LARGE_FILE_LINE_SIZE) { + options |= UI_OPTION_LARGE_FILE; + view_options_set(&win->view, options); + } + snprintf(right_parts[right_count++], sizeof(right_parts[0]), + "%zu, %zu", line, col); + } + + int left_len = snprintf(left, sizeof(left), " %s%s%s%s%s%s%s", + left_parts[0], + left_parts[1][0] ? " » " : "", + left_parts[1], + left_parts[2][0] ? " » " : "", + left_parts[2], + left_parts[3][0] ? " » " : "", + left_parts[3]); + + int right_len = snprintf(right, sizeof(right), "%s%s%s%s%s%s%s ", + right_parts[0], + right_parts[1][0] ? " « " : "", + right_parts[1], + right_parts[2][0] ? " « " : "", + right_parts[2], + right_parts[3][0] ? " « " : "", + right_parts[3]); + + if (left_len < 0 || right_len < 0) + return; + int left_width = text_string_width(left, left_len); + int right_width = text_string_width(right, right_len); + + int spaces = width - left_width - right_width; + if (spaces < 1) + spaces = 1; + + snprintf(status, sizeof(status), "%s%*s%s", left, spaces, " ", right); + ui_window_status(win->ui, status); +} + void view_tabwidth_set(View *view, int tabwidth) { if (tabwidth < 1 || tabwidth > 8) return; @@ -126,10 +163,6 @@ void view_tabwidth_set(View *view, int tabwidth) { view_draw(view); } -int view_tabwidth_get(View *view) { - return view->tabwidth; -} - /* reset internal view data structures (cell matrix, line offsets etc.) */ static void view_clear(View *view) { memset(view->lines, 0, view->lines_size); @@ -170,11 +203,7 @@ static void view_clear(View *view) { view->wrapcol = 0; view->prevch_breakat = false; if (view->ui) - view->ui->style_set(view->ui, &view->cell_blank, UI_STYLE_DEFAULT); -} - -Filerange view_viewport_get(View *view) { - return (Filerange){ .start = view->start, .end = view->end }; + ui_window_style_set(view->ui, &view->cell_blank, UI_STYLE_DEFAULT); } static int view_max_text_width(const View *view) { @@ -363,12 +392,6 @@ bool view_coord_get(View *view, size_t pos, Line **retline, int *retrow, int *re return true; } -/* move the cursor to the character at pos bytes from the beginning of the file. - * if pos is not in the current viewport, redraw the view to make it visible */ -void view_cursor_to(View *view, size_t pos) { - view_cursors_to(view->selection, pos); -} - /* redraw the complete with data starting from view->start bytes into the file. * stop once the screen is full, update view->end, view->lastline */ void view_draw(View *view) { @@ -478,10 +501,6 @@ void view_draw(View *view) { view->need_update = true; } -void view_invalidate(View *view) { - view->need_update = true; -} - bool view_update(View *view) { if (!view->need_update) return false; @@ -524,14 +543,6 @@ bool view_resize(View *view, int width, int height) { return true; } -int view_height_get(View *view) { - return view->height; -} - -int view_width_get(View *view) { - return view->width; -} - void view_free(View *view) { if (!view) return; @@ -540,21 +551,17 @@ void view_free(View *view) { free(view->textbuf); free(view->lines); free(view->breakat); - free(view); } void view_reload(View *view, Text *text) { view->text = text; view_selections_clear_all(view); - view_cursor_to(view, 0); + view_cursors_to(view->selection, 0); } -View *view_new(Text *text) { +bool view_init(View *view, Text *text) { if (!text) - return NULL; - View *view = calloc(1, sizeof(View)); - if (!view) - return NULL; + return false; view->text = text; view->tabwidth = 8; @@ -571,16 +578,11 @@ View *view_new(Text *text) { !view_selections_new(view, 0) || !view_resize(view, 1, 1)) { - view_free(view); - return NULL; + return false; } - view_cursor_to(view, 0); - return view; -} - -void view_ui(View *view, UiWin* ui) { - view->ui = ui; + view_cursors_to(view->selection, 0); + return true; } static size_t cursor_set(Selection *sel, Line *line, int col) { @@ -656,7 +658,8 @@ void view_redraw_top(View *view) { for (Line *cur = view->topline; cur && cur != line; cur = cur->next) view->start += cur->len; view_draw(view); - view_cursor_to(view, view->selection->pos); + /* FIXME: does this logic make sense */ + view_cursors_to(view->selection, view->selection->pos); } void view_redraw_center(View *view) { @@ -678,7 +681,7 @@ void view_redraw_center(View *view) { break; } view_draw(view); - view_cursor_to(view, pos); + view_cursors_to(view->selection, pos); } void view_redraw_bottom(View *view) { @@ -694,7 +697,7 @@ size_t view_slide_up(View *view, int lines) { if (sel->line == view->topline) cursor_set(sel, view->topline, sel->col); else - view_cursor_to(view, sel->pos); + view_cursors_to(view->selection, sel->pos); } else { view_screenline_down(sel); } @@ -709,7 +712,7 @@ size_t view_slide_down(View *view, int lines) { if (lastline) cursor_set(sel, view->lastline, col); else - view_cursor_to(view, sel->pos); + view_cursors_to(view->selection, sel->pos); } else { view_screenline_up(sel); } @@ -722,7 +725,7 @@ size_t view_scroll_up(View *view, int lines) { Line *line = sel->line < view->lastline ? sel->line : view->lastline; cursor_set(sel, line, view->selection->col); } else { - view_cursor_to(view, 0); + view_cursors_to(view->selection, 0); } return sel->pos; } @@ -730,9 +733,9 @@ size_t view_scroll_up(View *view, int lines) { size_t view_scroll_page_up(View *view) { Selection *sel = view->selection; if (view->start == 0) { - view_cursor_to(view, 0); + view_cursors_to(view->selection, 0); } else { - view_cursor_to(view, view->start-1); + view_cursors_to(view->selection, view->start-1); view_redraw_bottom(view); view_screenline_begin(sel); } @@ -747,9 +750,9 @@ size_t view_scroll_page_down(View *view) { size_t view_scroll_halfpage_up(View *view) { Selection *sel = view->selection; if (view->start == 0) { - view_cursor_to(view, 0); + view_cursors_to(view->selection, 0); } else { - view_cursor_to(view, view->start-1); + view_cursors_to(view->selection, view->start-1); view_redraw_center(view); view_screenline_begin(sel); } @@ -760,7 +763,7 @@ size_t view_scroll_halfpage_down(View *view) { size_t end = view->end; size_t pos = view_scroll_down(view, view->height/2); if (pos < text_size(view->text)) - view_cursor_to(view, end); + view_cursors_to(view->selection, end); return view->selection->pos; } @@ -770,7 +773,7 @@ size_t view_scroll_down(View *view, int lines) { Line *line = sel->line > view->topline ? sel->line : view->topline; cursor_set(sel, line, sel->col); } else { - view_cursor_to(view, text_size(view->text)); + view_cursors_to(view->selection, text_size(view->text)); } return sel->pos; } @@ -858,18 +861,6 @@ size_t view_cursor_get(View *view) { return view_cursors_pos(view->selection); } -Line *view_lines_first(View *view) { - return view->topline; -} - -Line *view_lines_last(View *view) { - return view->lastline; -} - -Line *view_cursors_line_get(Selection *sel) { - return sel->line; -} - void view_scroll_to(View *view, size_t pos) { view_cursors_scroll_to(view->selection, pos); } @@ -894,29 +885,7 @@ void view_options_set(View *view, enum UiOption options) { view->large_file = (options & UI_OPTION_LARGE_FILE); if (view->ui) - view->ui->options_set(view->ui, options); -} - -enum UiOption view_options_get(View *view) { - return view->ui ? view->ui->options_get(view->ui) : 0; -} - -void view_colorcolumn_set(View *view, int col) { - if (col >= 0) - view->colorcolumn = col; -} - -int view_colorcolumn_get(View *view) { - return view->colorcolumn; -} - -void view_wrapcolumn_set(View *view, int col) { - if (col >= 0) - view->wrapcolumn = col; -} - -int view_wrapcolumn_get(View *view) { - return view->wrapcolumn; + ui_window_options_set(view->ui, options); } bool view_breakat_set(View *view, const char *breakat) { @@ -928,10 +897,6 @@ bool view_breakat_set(View *view, const char *breakat) { return true; } -const char *view_breakat_get(View *view) { - return view->breakat; -} - size_t view_screenline_goto(View *view, int n) { size_t pos = view->start; for (Line *line = view->topline; --n > 0 && line != view->lastline; line = line->next) @@ -1011,10 +976,6 @@ Selection *view_selections_new_force(View *view, size_t pos) { return selections_new(view, pos, true); } -int view_selections_count(View *view) { - return view->selection_count; -} - int view_selections_number(Selection *sel) { return sel->number; } @@ -1174,10 +1135,6 @@ size_t view_cursors_col(Selection *s) { return text_line_char_get(s->view->text, pos) + 1; } -int view_cursors_cell_get(Selection *s) { - return s->line ? s->col : -1; -} - int view_cursors_cell_set(Selection *s, int cell) { if (!s->line || cell < 0) return -1; @@ -1238,10 +1195,6 @@ void view_cursors_place(Selection *s, size_t line, size_t col) { view_cursors_to(s, pos); } -void view_selections_anchor(Selection *s, bool anchored) { - s->anchored = anchored; -} - void view_selection_clear(Selection *s) { s->anchored = false; s->anchor = s->cursor; @@ -1255,10 +1208,6 @@ void view_selections_flip(Selection *s) { view_cursors_to(s, text_mark_get(s->view->text, s->cursor)); } -bool view_selections_anchored(Selection *s) { - return s->anchored; -} - void view_selections_clear_all(View *view) { for (Selection *s = view->selections; s; s = s->next) view_selection_clear(s); @@ -1277,10 +1226,6 @@ void view_selections_dispose_all(View *view) { view_draw(view); } -Filerange view_selection_get(View *view) { - return view_selections_get(view->selection); -} - Filerange view_selections_get(Selection *s) { if (!s) return text_range_empty(); @@ -1361,7 +1306,7 @@ void view_selections_set_all(View *view, Array *arr, bool anchored) { Array view_selections_get_all(View *view) { Array arr; array_init_sized(&arr, sizeof(Filerange)); - if (!array_reserve(&arr, view_selections_count(view))) + if (!array_reserve(&arr, view->selection_count)) return arr; for (Selection *s = view->selections; s; s = s->next) { Filerange r = view_selections_get(s); @@ -1393,18 +1338,10 @@ void view_selections_normalize(View *view) { view_selections_set(prev, &range_prev); } -Text *view_text(View *view) { - return view->text; -} - char *view_symbol_eof_get(View *view) { return view->symbols[SYNTAX_SYMBOL_EOF]->symbol; } -bool view_style_define(View *view, enum UiStyle id, const char *style) { - return view->ui->style_define(view->ui, id, style); -} - void view_style(View *view, enum UiStyle style, size_t start, size_t end) { if (end < view->start || start > view->end) return; @@ -1434,7 +1371,7 @@ void view_style(View *view, enum UiStyle style, size_t start, size_t end) { do { while (pos <= end && col < width) { pos += line->cells[col].len; - view->ui->style_set(view->ui, &line->cells[col++], style); + ui_window_style_set(view->ui, &line->cells[col++], style); } col = 0; } while (pos <= end && (line = line->next)); diff --git a/view.h b/view.h index 68eeb4b9f..b159267e0 100644 --- a/view.h +++ b/view.h @@ -4,31 +4,28 @@ #include #include -typedef struct View View; -typedef struct Selection Selection; -typedef struct Cell Cell; - -#include "text.h" #include "ui.h" +#include "text.h" #include "array.h" +typedef struct { + char *symbol; +} SyntaxSymbol; + +enum { + SYNTAX_SYMBOL_SPACE, + SYNTAX_SYMBOL_TAB, + SYNTAX_SYMBOL_TAB_FILL, + SYNTAX_SYMBOL_EOL, + SYNTAX_SYMBOL_EOF, + SYNTAX_SYMBOL_LAST, +}; + typedef struct { Mark anchor; Mark cursor; } SelectionRegion; -struct Cell { - char data[16]; /* utf8 encoded character displayed in this cell (might be more than - one Unicode codepoint. might also not be the same as in the - underlying text, for example tabs get expanded */ - size_t len; /* number of bytes the character displayed in this cell uses, for - characters which use more than 1 column to display, their length - is stored in the leftmost cell whereas all following cells - occupied by the same character have a length of 0. */ - int width; /* display width i.e. number of columns occupied by this character */ - CellStyle style; /* colors and attributes used to display this cell */ -}; - typedef struct Line Line; struct Line { /* a line on the screen, *not* in the file */ Line *prev, *next; /* pointer to neighbouring screen lines */ @@ -38,14 +35,60 @@ struct Line { /* a line on the screen, *not* in the file */ Cell cells[]; /* win->width cells storing information about the displayed characters */ }; +struct View; +typedef struct Selection { + Mark cursor; /* other selection endpoint where it changes */ + Mark anchor; /* position where the selection was created */ + bool anchored; /* whether anchor remains fixed */ + size_t pos; /* in bytes from the start of the file */ + int row, col; /* in terms of zero based screen coordinates */ + int lastcol; /* remembered column used when moving across lines */ + Line *line; /* screen line on which cursor currently resides */ + int generation; /* used to filter out newly created cursors during iteration */ + int number; /* how many cursors are located before this one */ + struct View *view; /* associated view to which this cursor belongs */ + struct Selection *prev, *next; /* previous/next cursors ordered by location at creation time */ +} Selection; + +typedef struct View { + Text *text; /* underlying text management */ + char *textbuf; /* scratch buffer used for drawing */ + UiWin *ui; /* corresponding ui window */ + Cell cell_blank; /* used for empty/blank cells */ + int width, height; /* size of display area */ + size_t start, end; /* currently displayed area [start, end] in bytes from the start of the file */ + size_t start_last; /* previously used start of visible area, used to update the mark */ + Mark start_mark; /* mark to keep track of the start of the visible area */ + size_t lines_size; /* number of allocated bytes for lines (grows only) */ + Line *lines; /* view->height number of lines representing view content */ + Line *topline; /* top of the view, first line currently shown */ + Line *lastline; /* last currently used line, always <= bottomline */ + Line *bottomline; /* bottom of view, might be unused if lastline < bottomline */ + Selection *selection; /* primary selection, always placed within the visible viewport */ + Selection *selection_latest; /* most recently created cursor */ + Selection *selection_dead; /* primary cursor which was disposed, will be removed when another cursor is created */ + int selection_count; /* how many cursors do currently exist */ + Line *line; /* used while drawing view content, line where next char will be drawn */ + int col; /* used while drawing view content, column where next char will be drawn */ + const SyntaxSymbol *symbols[SYNTAX_SYMBOL_LAST]; /* symbols to use for white spaces etc */ + int tabwidth; /* how many spaces should be used to display a tab character */ + Selection *selections; /* all cursors currently active */ + int selection_generation; /* used to filter out newly created cursors during iteration */ + bool need_update; /* whether view has been redrawn */ + bool large_file; /* optimize for displaying large files */ + int colorcolumn; + char *breakat; /* characters which might cause a word wrap */ + int wrapcolumn; /* wrap lines at minimum of window width and wrapcolumn (if != 0) */ + int wrapcol; /* used while drawing view content, column where word wrap might happen */ + bool prevch_breakat; /* used while drawing view content, previous char is part of breakat */ +} View; + /** * @defgroup view_life * @{ */ -View *view_new(Text*); +bool view_init(View*, Text*); void view_free(View*); -void view_ui(View*, UiWin*); -Text *view_text(View*); void view_reload(View*, Text*); /** * @} @@ -53,7 +96,7 @@ void view_reload(View*, Text*); * @{ */ /** Get the currently displayed text range. */ -Filerange view_viewport_get(View*); +#define VIEW_VIEWPORT_GET(v) (Filerange){ .start = v.start, .end = v.end } /** * Get window coordinate of text position. * @param pos The position to query. @@ -65,10 +108,6 @@ Filerange view_viewport_get(View*); bool view_coord_get(View*, size_t pos, Line **line, int *row, int *col); /** Get position at the start of the ``n``-th window line, counting from 1. */ size_t view_screenline_goto(View*, int n); -/** Get first screen line. */ -Line *view_lines_first(View*); -/** Get last non-empty screen line. */ -Line *view_lines_last(View*); size_t view_slide_up(View*, int lines); size_t view_slide_down(View*, int lines); size_t view_scroll_up(View*, int lines); @@ -87,14 +126,11 @@ void view_scroll_to(View*, size_t pos); * @{ */ bool view_resize(View*, int width, int height); -int view_height_get(View*); -int view_width_get(View*); /** * @} * @defgroup view_draw * @{ */ -void view_invalidate(View*); void view_draw(View*); bool view_update(View*); @@ -113,7 +149,7 @@ bool view_update(View*); Selection *view_selections_new(View*, size_t pos); /** * Create a new selection even if position is already covered by an - * existing selection. + * existing selection. * @rst * .. note:: This should only be used if the old selection is eventually * disposed. @@ -167,13 +203,6 @@ Selection *view_selections(View*); Selection *view_selections_prev(Selection*); /** Get immediate successor of selection. */ Selection *view_selections_next(Selection*); -/** - * Get number of existing selections. - * @rst - * .. note:: Is always at least 1. - * @endrst - */ -int view_selections_count(View*); /** * Get selection index. * @rst @@ -220,19 +249,6 @@ void view_selections_clear_all(View*); * @endrst */ void view_selections_flip(Selection*); -/** - * @} - * @defgroup view_anchor - * @{ - */ -/** - * Anchor selection. - * Further updates will only update the cursor, the anchor will remain fixed. - */ -void view_selections_anchor(Selection*, bool anchored); -/** Check whether selection is anchored. */ -bool view_selections_anchored(Selection*); -/** Get position of selection cursor. */ /** * @} * @defgroup view_props @@ -250,20 +266,6 @@ size_t view_cursors_line(Selection*); * @endrst */ size_t view_cursors_col(Selection*); -/** - * Get screen line of selection cursor. - * @rst - * .. warning: Is `NULL` for non-visible selections. - * @endrst - */ -Line *view_cursors_line_get(Selection*); -/** - * Get zero based index of screen cell on which selection cursor currently resides. - * @rst - * .. warning:: Returns ``-1`` if the selection cursor is currently not visible. - * @endrst - */ -int view_cursors_cell_get(Selection*); /** * @} * @defgroup view_place @@ -276,6 +278,11 @@ int view_cursors_cell_get(Selection*); * will be adjusted to form a singleton selection covering one * character starting at `pos`. Otherwise only the selection * cursor will be changed while the anchor remains fixed. + * + * If primary position was not visible before, we attempt to show + * the surrounding context. The viewport will be adjusted such + * that the line holding the primary cursor is shown in the middle + * of the window. * @endrst */ void view_cursors_to(Selection*, size_t pos); @@ -323,26 +330,8 @@ size_t view_screenline_end(Selection*); * @defgroup view_primary * @{ */ -/** - * Move primary selection cursor to the given position. - * Makes sure that position is visible. - * @rst - * .. note:: If position was not visible before, we attempt to show - * surrounding context. The viewport will be adjusted such - * that the line holding the cursor is shown in the middle - * of the window. - * @endrst - */ -void view_cursor_to(View*, size_t pos); /** Get cursor position of primary selection. */ size_t view_cursor_get(View*); -/** - * Get primary selection. - * @rst - * .. note:: Is always a non-empty range. - * @endrst - */ -Filerange view_selection_get(View*); /** * @} * @defgroup view_save @@ -356,20 +345,10 @@ bool view_regions_save(View*, Filerange*, SelectionRegion*); * @{ */ void view_options_set(View*, enum UiOption options); -enum UiOption view_options_get(View*); -void view_colorcolumn_set(View*, int col); -int view_colorcolumn_get(View*); -void view_wrapcolumn_set(View*, int col); -int view_wrapcolumn_get(View*); bool view_breakat_set(View*, const char *breakat); -const char *view_breakat_get(View*); /** Set how many spaces are used to display a tab `\t` character. */ void view_tabwidth_set(View*, int tabwidth); -/** Get how many spaces are used to display a tab `\t` character. */ -int view_tabwidth_get(View*); -/** Define a display style. */ -bool view_style_define(View*, enum UiStyle, const char *style); /** Apply a style to a text range. */ void view_style(View*, enum UiStyle, size_t start, size_t end); diff --git a/vis-cmds.c b/vis-cmds.c index 2b6428ab6..382a7d795 100644 --- a/vis-cmds.c +++ b/vis-cmds.c @@ -125,10 +125,6 @@ static bool cmd_user(Vis *vis, Win *win, Command *cmd, const char *argv[], Selec return user && user->func(vis, win, user->data, cmd->flags == '!', argv, sel, range); } -static void windows_arrange(Vis *vis, enum UiLayout layout) { - vis->ui->arrange(vis->ui, layout); -} - void vis_shell_set(Vis *vis, const char *new_shell) { char *shell = strdup(new_shell); if (!shell) { @@ -250,8 +246,7 @@ static bool cmd_set(Vis *vis, Win *win, Command *cmd, const char *argv[], Select break; case OPTION_ESCDELAY: { - TermKey *termkey = vis->ui->termkey_get(vis->ui); - termkey_set_waittime(termkey, arg.i); + termkey_set_waittime(vis->ui.termkey, arg.i); break; } case OPTION_EXPANDTAB: @@ -261,7 +256,7 @@ static bool cmd_set(Vis *vis, Win *win, Command *cmd, const char *argv[], Select vis->autoindent = toggle ? !vis->autoindent : arg.b; break; case OPTION_TABWIDTH: - view_tabwidth_set(vis->win->view, arg.i); + view_tabwidth_set(&vis->win->view, arg.i); break; case OPTION_SHOW_SPACES: case OPTION_SHOW_TABS: @@ -276,47 +271,48 @@ static bool cmd_set(Vis *vis, Win *win, Command *cmd, const char *argv[], Select [OPTION_SHOW_EOF] = UI_OPTION_SYMBOL_EOF, [OPTION_STATUSBAR] = UI_OPTION_STATUSBAR, }; - int flags = view_options_get(win->view); + int flags = UI_OPTIONS_GET(win->view.ui); if (arg.b || (toggle && !(flags & values[opt_index]))) flags |= values[opt_index]; else flags &= ~values[opt_index]; - view_options_set(win->view, flags); + view_options_set(&win->view, flags); break; } case OPTION_NUMBER: { - enum UiOption opt = view_options_get(win->view); + enum UiOption opt = UI_OPTIONS_GET(win->view.ui); if (arg.b || (toggle && !(opt & UI_OPTION_LINE_NUMBERS_ABSOLUTE))) { opt &= ~UI_OPTION_LINE_NUMBERS_RELATIVE; opt |= UI_OPTION_LINE_NUMBERS_ABSOLUTE; } else { opt &= ~UI_OPTION_LINE_NUMBERS_ABSOLUTE; } - view_options_set(win->view, opt); + view_options_set(&win->view, opt); break; } case OPTION_NUMBER_RELATIVE: { - enum UiOption opt = view_options_get(win->view); + enum UiOption opt = UI_OPTIONS_GET(win->view.ui); if (arg.b || (toggle && !(opt & UI_OPTION_LINE_NUMBERS_RELATIVE))) { opt &= ~UI_OPTION_LINE_NUMBERS_ABSOLUTE; opt |= UI_OPTION_LINE_NUMBERS_RELATIVE; } else { opt &= ~UI_OPTION_LINE_NUMBERS_RELATIVE; } - view_options_set(win->view, opt); + view_options_set(&win->view, opt); break; } case OPTION_CURSOR_LINE: { - enum UiOption opt = view_options_get(win->view); + enum UiOption opt = UI_OPTIONS_GET(win->view.ui); if (arg.b || (toggle && !(opt & UI_OPTION_CURSOR_LINE))) opt |= UI_OPTION_CURSOR_LINE; else opt &= ~UI_OPTION_CURSOR_LINE; - view_options_set(win->view, opt); + view_options_set(&win->view, opt); break; } case OPTION_COLOR_COLUMN: - view_colorcolumn_set(win->view, arg.i); + if (arg.i >= 0) + win->view.colorcolumn = arg.i; break; case OPTION_SAVE_METHOD: if (strcmp("auto", arg.s) == 0) { @@ -357,20 +353,21 @@ static bool cmd_set(Vis *vis, Win *win, Command *cmd, const char *argv[], Select vis_info_show(vis, "Invalid layout `%s', expected 'h' or 'v'", arg.s); return false; } - windows_arrange(vis, layout); + ui_arrange(&vis->ui, layout); break; } case OPTION_IGNORECASE: vis->ignorecase = toggle ? !vis->ignorecase : arg.b; break; case OPTION_BREAKAT: - if (!view_breakat_set(win->view, arg.s)) { + if (!view_breakat_set(&win->view, arg.s)) { vis_info_show(vis, "Failed to set breakat"); return false; } break; case OPTION_WRAP_COLUMN: - view_wrapcolumn_set(win->view, arg.i); + if (arg.i >= 0) + win->view.wrapcolumn = arg.i; break; default: if (!opt->func) @@ -543,36 +540,36 @@ static bool cmd_qall(Vis *vis, Win *win, Command *cmd, const char *argv[], Selec static bool cmd_split(Vis *vis, Win *win, Command *cmd, const char *argv[], Selection *sel, Filerange *range) { if (!win) return false; - enum UiOption options = view_options_get(win->view); - windows_arrange(vis, UI_LAYOUT_HORIZONTAL); + enum UiOption options = UI_OPTIONS_GET(win->view.ui); + ui_arrange(&vis->ui, UI_LAYOUT_HORIZONTAL); if (!argv[1]) return vis_window_split(win); bool ret = openfiles(vis, &argv[1]); if (ret) - view_options_set(vis->win->view, options); + view_options_set(&vis->win->view, options); return ret; } static bool cmd_vsplit(Vis *vis, Win *win, Command *cmd, const char *argv[], Selection *sel, Filerange *range) { if (!win) return false; - enum UiOption options = view_options_get(win->view); - windows_arrange(vis, UI_LAYOUT_VERTICAL); + enum UiOption options = UI_OPTIONS_GET(win->view.ui); + ui_arrange(&vis->ui, UI_LAYOUT_VERTICAL); if (!argv[1]) return vis_window_split(win); bool ret = openfiles(vis, &argv[1]); if (ret) - view_options_set(vis->win->view, options); + view_options_set(&vis->win->view, options); return ret; } static bool cmd_new(Vis *vis, Win *win, Command *cmd, const char *argv[], Selection *sel, Filerange *range) { - windows_arrange(vis, UI_LAYOUT_HORIZONTAL); + ui_arrange(&vis->ui, UI_LAYOUT_HORIZONTAL); return vis_window_new(vis, NULL); } static bool cmd_vnew(Vis *vis, Win *win, Command *cmd, const char *argv[], Selection *sel, Filerange *range) { - windows_arrange(vis, UI_LAYOUT_VERTICAL); + ui_arrange(&vis->ui, UI_LAYOUT_VERTICAL); return vis_window_new(vis, NULL); } @@ -777,7 +774,7 @@ static void print_symbolic_keys(Vis *vis, Text *txt) { TERMKEY_SYM_KPEQUALS, }; - TermKey *termkey = vis->ui->termkey_get(vis->ui); + TermKey *termkey = vis->ui.termkey; text_appendf(txt, " ␣ (a literal \" \" space symbol must be used to refer to )\n"); for (size_t i = 0; i < LENGTH(keys); i++) { text_appendf(txt, " <%s>\n", termkey_get_keyname(termkey, keys[i])); @@ -874,7 +871,7 @@ static bool cmd_help(Vis *vis, Win *win, Command *cmd, const char *argv[], Selec text_appendf(txt, " %-32s\t%s\n", configs[i].name, configs[i].enabled ? "yes" : "no"); text_save(txt, NULL); - view_cursor_to(vis->win->view, 0); + view_cursors_to(vis->win->view.selection, 0); if (argv[1]) vis_motion(vis, VIS_MOVE_SEARCH_FORWARD, argv[1]); diff --git a/vis-core.h b/vis-core.h index 4f81e4cbd..c66924e9b 100644 --- a/vis-core.h +++ b/vis-core.h @@ -157,7 +157,7 @@ struct Win { Vis *vis; /* editor instance to which this window belongs */ UiWin *ui; /* ui object handling visual appearance of this window */ File *file; /* file being displayed in this window */ - View *view; /* currently displayed part of underlying text */ + View view; /* currently displayed part of underlying text */ bool expandtab; /* whether typed tabs should be converted to spaces in this window*/ MarkList jumplist; /* LRU jump management */ Array saved_selections; /* register used to store selections */ @@ -168,7 +168,6 @@ struct Win { }; struct Vis { - Ui *ui; /* user interface responsible for visual appearance */ File *files; /* all files currently managed by this editor instance */ File *command_file; /* special internal file used to store :-command prompt */ File *search_file; /* special internal file used to store /,? search prompt */ @@ -176,6 +175,7 @@ struct Vis { Win *windows; /* all windows currently managed by this editor instance */ Win *win; /* currently active/focused window */ Win *message_window; /* special window to display multi line messages */ + Ui ui; /* user interface responsible for visual appearance */ Register registers[VIS_REG_INVALID]; /* registers used for text manipulations yank/put etc. and macros */ Macro *recording, *last_recording; /* currently (if non NULL) and least recently recorded macro */ const Macro *replaying; /* macro currently being replayed */ @@ -215,7 +215,6 @@ struct Vis { Array actions_user; /* dynamically allocated editor actions */ lua_State *lua; /* lua context used for syntax highlighting */ enum TextLoadMethod load_method; /* how existing files should be loaded */ - VisEvent *event; Array operators; Array motions; Array textobjects; @@ -268,8 +267,9 @@ Mode *mode_get(Vis*, enum VisMode); void mode_set(Vis *vis, Mode *new_mode); Macro *macro_get(Vis *vis, enum VisRegister); -void window_selection_save(Win *win); Win *window_new_file(Vis*, File*, enum UiOption); +void window_selection_save(Win *win); +void window_status_update(Vis *vis, Win *win); char *absolute_path(const char *path); diff --git a/vis-lua.c b/vis-lua.c index ca36d2d5e..75e2e24c7 100644 --- a/vis-lua.c +++ b/vis-lua.c @@ -54,119 +54,13 @@ #define debug(...) do { } while (0) #endif -static void window_status_update(Vis *vis, Win *win) { - char left_parts[4][255] = { "", "", "", "" }; - char right_parts[4][32] = { "", "", "", "" }; - char left[sizeof(left_parts)+LENGTH(left_parts)*8]; - char right[sizeof(right_parts)+LENGTH(right_parts)*8]; - char status[sizeof(left)+sizeof(right)+1]; - size_t left_count = 0; - size_t right_count = 0; - - View *view = win->view; - File *file = win->file; - Text *txt = file->text; - int width = vis_window_width_get(win); - enum UiOption options = view_options_get(view); - bool focused = vis->win == win; - const char *filename = file_name_get(file); - const char *mode = vis->mode->status; - - if (focused && mode) - strcpy(left_parts[left_count++], mode); - - snprintf(left_parts[left_count++], sizeof(left_parts[0]), "%s%s%s", - filename ? filename : "[No Name]", - text_modified(txt) ? " [+]" : "", - vis_macro_recording(vis) ? " @": ""); - - int count = vis_count_get(vis); - const char *keys = buffer_content0(&vis->input_queue); - if (keys && keys[0]) - snprintf(right_parts[right_count++], sizeof(right_parts[0]), "%s", keys); - else if (count != VIS_COUNT_UNKNOWN) - snprintf(right_parts[right_count++], sizeof(right_parts[0]), "%d", count); - - int sel_count = view_selections_count(view); - if (sel_count > 1) { - Selection *s = view_selections_primary_get(view); - int sel_number = view_selections_number(s) + 1; - snprintf(right_parts[right_count++], sizeof(right_parts[0]), - "%d/%d", sel_number, sel_count); - } - - size_t size = text_size(txt); - size_t pos = view_cursor_get(view); - size_t percent = 0; - if (size > 0) { - double tmp = ((double)pos/(double)size)*100; - percent = (size_t)(tmp+1); - } - snprintf(right_parts[right_count++], sizeof(right_parts[0]), - "%zu%%", percent); - - if (!(options & UI_OPTION_LARGE_FILE)) { - Selection *sel = view_selections_primary_get(win->view); - size_t line = view_cursors_line(sel); - size_t col = view_cursors_col(sel); - if (col > UI_LARGE_FILE_LINE_SIZE) { - options |= UI_OPTION_LARGE_FILE; - view_options_set(win->view, options); - } - snprintf(right_parts[right_count++], sizeof(right_parts[0]), - "%zu, %zu", line, col); - } - - int left_len = snprintf(left, sizeof(left), " %s%s%s%s%s%s%s", - left_parts[0], - left_parts[1][0] ? " » " : "", - left_parts[1], - left_parts[2][0] ? " » " : "", - left_parts[2], - left_parts[3][0] ? " » " : "", - left_parts[3]); - - int right_len = snprintf(right, sizeof(right), "%s%s%s%s%s%s%s ", - right_parts[0], - right_parts[1][0] ? " « " : "", - right_parts[1], - right_parts[2][0] ? " « " : "", - right_parts[2], - right_parts[3][0] ? " « " : "", - right_parts[3]); - - if (left_len < 0 || right_len < 0) - return; - int left_width = text_string_width(left, left_len); - int right_width = text_string_width(right, right_len); - - int spaces = width - left_width - right_width; - if (spaces < 1) - spaces = 1; - - snprintf(status, sizeof(status), "%s%*s%s", left, spaces, " ", right); - vis_window_status(win, status); -} #if !CONFIG_LUA bool vis_lua_path_add(Vis *vis, const char *path) { return true; } bool vis_lua_paths_get(Vis *vis, char **lpath, char **cpath) { return false; } -void vis_lua_init(Vis *vis) { } -void vis_lua_start(Vis *vis) { } -void vis_lua_quit(Vis *vis) { } -void vis_lua_file_open(Vis *vis, File *file) { } -bool vis_lua_file_save_pre(Vis *vis, File *file, const char *path) { return true; } -void vis_lua_file_save_post(Vis *vis, File *file, const char *path) { } -void vis_lua_file_close(Vis *vis, File *file) { } -void vis_lua_win_open(Vis *vis, Win *win) { } -void vis_lua_win_close(Vis *vis, Win *win) { } -void vis_lua_win_highlight(Vis *vis, Win *win) { } -void vis_lua_win_status(Vis *vis, Win *win) { window_status_update(vis, win); } -void vis_lua_term_csi(Vis *vis, const long *csi) { } void vis_lua_process_response(Vis *vis, const char *name, char *buffer, size_t len, ResponseType rtype) { } -void vis_lua_ui_draw(Vis *vis) { } #else @@ -1213,7 +1107,7 @@ static bool command_lua(Vis *vis, Win *win, void *data, bool force, const char * if (!obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW)) return false; if (!sel) - sel = view_selections_primary_get(win->view); + sel = view_selections_primary_get(&win->view); if (!obj_lightref_new(L, sel, VIS_LUA_TYPE_SELECTION)) return false; pushrange(L, range); @@ -1490,7 +1384,7 @@ static int vis_index(lua_State *L) { } if (strcmp(key, "count") == 0) { - int count = vis_count_get(vis); + int count = vis->action.count; if (count == VIS_COUNT_UNKNOWN) lua_pushnil(L); else @@ -1505,7 +1399,7 @@ static int vis_index(lua_State *L) { } if (strcmp(key, "registers") == 0) { - obj_ref_new(L, vis->ui, VIS_LUA_TYPE_REGISTERS); + obj_ref_new(L, &vis->ui, VIS_LUA_TYPE_REGISTERS); return 1; } @@ -1521,7 +1415,7 @@ static int vis_index(lua_State *L) { } if (strcmp(key, "ui") == 0) { - obj_ref_new(L, vis->ui, VIS_LUA_TYPE_UI); + obj_ref_new(L, &vis->ui, VIS_LUA_TYPE_UI); return 1; } } @@ -1535,8 +1429,7 @@ static int vis_options_assign(Vis *vis, lua_State *L, const char *key, int next) } else if (strcmp(key, "changecolors") == 0) { vis->change_colors = lua_toboolean(L, next); } else if (strcmp(key, "escdelay") == 0) { - TermKey *tk = vis->ui->termkey_get(vis->ui); - termkey_set_waittime(tk, luaL_checkint(L, next)); + termkey_set_waittime(vis->ui.termkey, luaL_checkint(L, next)); } else if (strcmp(key, "ignorecase") == 0 || strcmp(key, "ic") == 0) { vis->ignorecase = lua_toboolean(L, next); } else if (strcmp(key, "loadmethod") == 0) { @@ -1573,7 +1466,7 @@ static int vis_newindex(lua_State *L) { count = VIS_COUNT_UNKNOWN; else count = luaL_checkunsigned(L, 3); - vis_count_set(vis, count); + vis->action.count = count; return 0; } @@ -1676,8 +1569,7 @@ static int vis_options_index(lua_State *L) { lua_pushboolean(L, vis->change_colors); return 1; } else if (strcmp(key, "escdelay") == 0) { - TermKey *tk = vis->ui->termkey_get(vis->ui); - lua_pushunsigned(L, termkey_get_waittime(tk)); + lua_pushunsigned(L, termkey_get_waittime(vis->ui.termkey)); return 1; } else if (strcmp(key, "ignorecase") == 0 || strcmp(key, "ic") == 0) { lua_pushboolean(L, vis->ignorecase); @@ -1739,7 +1631,7 @@ static int ui_index(lua_State *L) { const char *key = lua_tostring(L, 2); if (strcmp(key, "layout") == 0) { - lua_pushunsigned(L, ui_layout_get(ui)); + lua_pushunsigned(L, ui->layout); return 1; } } @@ -1754,7 +1646,7 @@ static int ui_newindex(lua_State *L) { const char *key = lua_tostring(L, 2); if (strcmp(key, "layout") == 0) { - ui->arrange(ui, luaL_checkint(L, 3)); + ui_arrange(ui, luaL_checkint(L, 3)); return 0; } } @@ -1872,10 +1764,10 @@ static int window_index(lua_State *L) { const char *key = lua_tostring(L, 2); if (strcmp(key, "viewport") == 0) { - Filerange b = view_viewport_get(win->view); + Filerange b = VIEW_VIEWPORT_GET(win->view); Filerange l; - l.start = view_lines_first(win->view)->lineno; - l.end = view_lines_last(win->view)->lineno; + l.start = win->view.topline->lineno; + l.end = win->view.lastline->lineno; lua_createtable(L, 0, 4); lua_pushstring(L, "bytes"); @@ -1885,21 +1777,21 @@ static int window_index(lua_State *L) { pushrange(L, &l); lua_settable(L, -3); lua_pushstring(L, "width"); - lua_pushunsigned(L, view_width_get(win->view)); + lua_pushunsigned(L, win->view.width); lua_settable(L, -3); lua_pushstring(L, "height"); - lua_pushunsigned(L, view_height_get(win->view)); + lua_pushunsigned(L, win->view.height); lua_settable(L, -3); return 1; } if (strcmp(key, "width") == 0) { - lua_pushunsigned(L, vis_window_width_get(win)); + lua_pushunsigned(L, win->ui->width); return 1; } if (strcmp(key, "height") == 0) { - lua_pushunsigned(L, vis_window_height_get(win)); + lua_pushunsigned(L, win->ui->height); return 1; } @@ -1909,13 +1801,13 @@ static int window_index(lua_State *L) { } if (strcmp(key, "selection") == 0) { - Selection *sel = view_selections_primary_get(win->view); + Selection *sel = view_selections_primary_get(&win->view); obj_lightref_new(L, sel, VIS_LUA_TYPE_SELECTION); return 1; } if (strcmp(key, "selections") == 0) { - obj_ref_new(L, win->view, VIS_LUA_TYPE_SELECTIONS); + obj_ref_new(L, &win->view, VIS_LUA_TYPE_SELECTIONS); return 1; } @@ -1933,64 +1825,64 @@ static int window_index(lua_State *L) { } static int window_options_assign(Win *win, lua_State *L, const char *key, int next) { - enum UiOption flags = view_options_get(win->view); + enum UiOption flags = UI_OPTIONS_GET(win->view.ui); if (strcmp(key, "breakat") == 0 || strcmp(key, "brk") == 0) { if (lua_isstring(L, next)) - view_breakat_set(win->view, lua_tostring(L, next)); + view_breakat_set(&win->view, lua_tostring(L, next)); } else if (strcmp(key, "colorcolumn") == 0 || strcmp(key, "cc") == 0) { - view_colorcolumn_set(win->view, luaL_checkint(L, next)); + win->view.colorcolumn = luaL_checkunsigned(L, next); } else if (strcmp(key, "cursorline") == 0 || strcmp(key, "cul") == 0) { if (lua_toboolean(L, next)) flags |= UI_OPTION_CURSOR_LINE; else flags &= ~UI_OPTION_CURSOR_LINE; - view_options_set(win->view, flags); + view_options_set(&win->view, flags); } else if (strcmp(key, "numbers") == 0 || strcmp(key, "nu") == 0) { if (lua_toboolean(L, next)) flags |= UI_OPTION_LINE_NUMBERS_ABSOLUTE; else flags &= ~UI_OPTION_LINE_NUMBERS_ABSOLUTE; - view_options_set(win->view, flags); + view_options_set(&win->view, flags); } else if (strcmp(key, "relativenumbers") == 0 || strcmp(key, "rnu") == 0) { if (lua_toboolean(L, next)) flags |= UI_OPTION_LINE_NUMBERS_RELATIVE; else flags &= ~UI_OPTION_LINE_NUMBERS_RELATIVE; - view_options_set(win->view, flags); + view_options_set(&win->view, flags); } else if (strcmp(key, "showeof") == 0) { if (lua_toboolean(L, next)) flags |= UI_OPTION_SYMBOL_EOF; else flags &= ~UI_OPTION_SYMBOL_EOF; - view_options_set(win->view, flags); + view_options_set(&win->view, flags); } else if (strcmp(key, "shownewlines") == 0) { if (lua_toboolean(L, next)) flags |= UI_OPTION_SYMBOL_EOL; else flags &= ~UI_OPTION_SYMBOL_EOL; - view_options_set(win->view, flags); + view_options_set(&win->view, flags); } else if (strcmp(key, "showspaces") == 0) { if (lua_toboolean(L, next)) flags |= UI_OPTION_SYMBOL_SPACE; else flags &= ~UI_OPTION_SYMBOL_SPACE; - view_options_set(win->view, flags); + view_options_set(&win->view, flags); } else if (strcmp(key, "showtabs") == 0) { if (lua_toboolean(L, next)) flags |= UI_OPTION_SYMBOL_TAB; else flags &= ~UI_OPTION_SYMBOL_TAB; - view_options_set(win->view, flags); + view_options_set(&win->view, flags); } else if (strcmp(key, "statusbar") == 0) { if (lua_toboolean(L, next)) flags |= UI_OPTION_STATUSBAR; else flags &= ~UI_OPTION_STATUSBAR; - view_options_set(win->view, flags); + view_options_set(&win->view, flags); } else if (strcmp(key, "wrapcolumn") == 0 || strcmp(key, "wc") == 0) { - view_wrapcolumn_set(win->view, luaL_checkint(L, next)); + win->view.wrapcolumn = luaL_checkunsigned(L, next); } else if (strcmp(key, "tabwidth") == 0 || strcmp(key, "tw") == 0) { - view_tabwidth_set(win->view, luaL_checkint(L, next)); + view_tabwidth_set(&win->view, luaL_checkint(L, next)); } else if (strcmp(key, "expandtab") == 0 || strcmp(key, "et") == 0) { win->expandtab = lua_toboolean(L, next); } @@ -2050,7 +1942,7 @@ static int window_selections_iterator_next(lua_State *L) { static int window_selections_iterator(lua_State *L) { Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW); Selection **handle = lua_newuserdata(L, sizeof *handle); - *handle = view_selections(win->view); + *handle = view_selections(&win->view); lua_pushcclosure(L, window_selections_iterator_next, 1); return 1; } @@ -2094,7 +1986,7 @@ static int window_style_define(lua_State *L) { Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW); enum UiStyle id = luaL_checkunsigned(L, 2); const char *style = luaL_checkstring(L, 3); - bool ret = view_style_define(win->view, id, style); + bool ret = ui_style_define(win->view.ui, id, style); lua_pushboolean(L, ret); return 1; } @@ -2116,7 +2008,7 @@ static int window_style(lua_State *L) { enum UiStyle style = luaL_checkunsigned(L, 2); size_t start = checkpos(L, 3); size_t end = checkpos(L, 4); - view_style(win->view, style, start, end); + view_style(&win->view, style, start, end); return 0; } @@ -2141,7 +2033,7 @@ static int window_style_pos(lua_State *L) { enum UiStyle style = luaL_checkunsigned(L, 2); size_t x = checkpos(L, 3); size_t y = checkpos(L, 4); - bool ret = win->ui->style_set_pos(win->ui, (int)x, (int)y, style); + bool ret = ui_window_style_set_pos(win->ui, (int)x, (int)y, style); lua_pushboolean(L, ret); return 1; } @@ -2156,7 +2048,7 @@ static int window_style_pos(lua_State *L) { static int window_status(lua_State *L) { Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW); char status[1024] = ""; - int width = vis_window_width_get(win); + int width = win->ui->width; const char *left = luaL_checkstring(L, 2); const char *right = luaL_optstring(L, 3, ""); int left_width = text_string_width(left, strlen(left)); @@ -2165,7 +2057,7 @@ static int window_status(lua_State *L) { if (spaces < 1) spaces = 1; snprintf(status, sizeof(status)-1, "%s%*s%s", left, spaces, " ", right); - vis_window_status(win, status); + ui_window_status(win->ui, status); return 0; } @@ -2176,7 +2068,7 @@ static int window_status(lua_State *L) { */ static int window_draw(lua_State *L) { Win *win = obj_ref_check(L, 1, VIS_LUA_TYPE_WINDOW); - view_draw(win->view); + view_draw(&win->view); return 0; } @@ -2248,43 +2140,43 @@ static int window_options_index(lua_State *L) { if (lua_isstring(L, 2)) { const char *key = lua_tostring(L, 2); if (strcmp(key, "breakat") == 0 || strcmp(key, "brk") == 0) { - lua_pushstring(L, view_breakat_get(win->view)); + lua_pushstring(L, win->view.breakat); return 1; } else if (strcmp(key, "colorcolumn") == 0 || strcmp(key, "cc") == 0) { - lua_pushunsigned(L, view_colorcolumn_get(win->view)); + lua_pushunsigned(L, win->view.colorcolumn); return 1; } else if (strcmp(key, "cursorline") == 0 || strcmp(key, "cul") == 0) { - lua_pushboolean(L, view_options_get(win->view) & UI_OPTION_CURSOR_LINE); + lua_pushboolean(L, UI_OPTIONS_GET(win->view.ui) & UI_OPTION_CURSOR_LINE); return 1; } else if (strcmp(key, "expandtab") == 0 || strcmp(key, "et") == 0) { lua_pushboolean(L, win->expandtab); return 1; } else if (strcmp(key, "numbers") == 0 || strcmp(key, "nu") == 0) { - lua_pushboolean(L, view_options_get(win->view) & UI_OPTION_LINE_NUMBERS_ABSOLUTE); + lua_pushboolean(L, UI_OPTIONS_GET(win->view.ui) & UI_OPTION_LINE_NUMBERS_ABSOLUTE); return 1; } else if (strcmp(key, "relativenumbers") == 0 || strcmp(key, "rnu") == 0) { - lua_pushboolean(L, view_options_get(win->view) & UI_OPTION_LINE_NUMBERS_RELATIVE); + lua_pushboolean(L, UI_OPTIONS_GET(win->view.ui) & UI_OPTION_LINE_NUMBERS_RELATIVE); return 1; } else if (strcmp(key, "showeof") == 0) { - lua_pushboolean(L, view_options_get(win->view) & UI_OPTION_SYMBOL_EOF); + lua_pushboolean(L, UI_OPTIONS_GET(win->view.ui) & UI_OPTION_SYMBOL_EOF); return 1; } else if (strcmp(key, "shownewlines") == 0) { - lua_pushboolean(L, view_options_get(win->view) & UI_OPTION_SYMBOL_EOL); + lua_pushboolean(L, UI_OPTIONS_GET(win->view.ui) & UI_OPTION_SYMBOL_EOL); return 1; } else if (strcmp(key, "showspaces") == 0) { - lua_pushboolean(L, view_options_get(win->view) & UI_OPTION_SYMBOL_SPACE); + lua_pushboolean(L, UI_OPTIONS_GET(win->view.ui) & UI_OPTION_SYMBOL_SPACE); return 1; } else if (strcmp(key, "showtabs") == 0) { - lua_pushboolean(L, view_options_get(win->view) & UI_OPTION_SYMBOL_TAB); + lua_pushboolean(L, UI_OPTIONS_GET(win->view.ui) & UI_OPTION_SYMBOL_TAB); return 1; } else if (strcmp(key, "statusbar") == 0) { - lua_pushboolean(L, view_options_get(win->view) & UI_OPTION_STATUSBAR); + lua_pushboolean(L, UI_OPTIONS_GET(win->view.ui) & UI_OPTION_STATUSBAR); return 1; } else if (strcmp(key, "tabwidth") == 0 || strcmp(key, "tw") == 0) { - lua_pushinteger(L, view_tabwidth_get(win->view)); + lua_pushinteger(L, win->view.tabwidth); return 1; } else if (strcmp(key, "wrapcolumn") == 0 || strcmp(key, "wc") == 0) { - lua_pushunsigned(L, view_wrapcolumn_get(win->view)); + lua_pushunsigned(L, win->view.wrapcolumn); return 1; } } @@ -2309,7 +2201,7 @@ static const struct luaL_Reg window_option_funcs[] = { static int window_selections_index(lua_State *L) { View *view = obj_ref_check(L, 1, VIS_LUA_TYPE_SELECTIONS); size_t index = luaL_checkunsigned(L, 2); - size_t count = view_selections_count(view); + size_t count = view->selection_count; if (index == 0 || index > count) goto err; for (Selection *s = view_selections(view); s; s = view_selections_next(s)) { @@ -2325,7 +2217,7 @@ static int window_selections_index(lua_State *L) { static int window_selections_len(lua_State *L) { View *view = obj_ref_check(L, 1, VIS_LUA_TYPE_SELECTIONS); - lua_pushunsigned(L, view_selections_count(view)); + lua_pushunsigned(L, view->selection_count); return 1; } @@ -2469,7 +2361,7 @@ static int window_selection_index(lua_State *L) { } if (strcmp(key, "anchored") == 0) { - lua_pushboolean(L, view_selections_anchored(sel)); + lua_pushboolean(L, sel->anchored); return 1; } @@ -2494,7 +2386,7 @@ static int window_selection_newindex(lua_State *L) { Filerange range = getrange(L, 3); if (text_range_valid(&range)) { view_selections_set(sel, &range); - view_selections_anchor(sel, true); + sel->anchored = true; } else { view_selection_clear(sel); } @@ -2502,7 +2394,7 @@ static int window_selection_newindex(lua_State *L) { } if (strcmp(key, "anchored") == 0) { - view_selections_anchor(sel, lua_toboolean(L, 3)); + sel->anchored = lua_toboolean(L, 3); return 0; } } @@ -3213,7 +3105,7 @@ static void *alloc_lua(void *ud, void *ptr, size_t osize, size_t nsize) { * Can be used to set *global* configuration options. * @function init */ -void vis_lua_init(Vis *vis) { +static void vis_lua_init(Vis *vis) { lua_State *L = lua_newstate(alloc_lua, vis); if (!L) return; @@ -3366,7 +3258,7 @@ void vis_lua_init(Vis *vis) { obj_type_new(L, VIS_LUA_TYPE_UI); luaL_setfuncs(L, ui_funcs, 0); - lua_pushunsigned(L, vis->ui->colors(vis->ui)); + lua_pushunsigned(L, ui_terminal_colors()); lua_setfield(L, -2, "colors"); lua_newtable(L); static const struct { @@ -3432,7 +3324,7 @@ void vis_lua_init(Vis *vis) { * We are about to process interactive keyboard input. * @function start */ -void vis_lua_start(Vis *vis) { +static void vis_lua_start(Vis *vis) { vis_lua_event_call(vis, "start"); } @@ -3440,7 +3332,7 @@ void vis_lua_start(Vis *vis) { * Editor is about to terminate. * @function quit */ -void vis_lua_quit(Vis *vis) { +static void vis_lua_quit(Vis *vis) { if (!vis->lua) return; vis_lua_event_call(vis, "quit"); @@ -3471,12 +3363,12 @@ static bool vis_lua_input(Vis *vis, const char *key, size_t len) { return ret; } -void vis_lua_mode_insert_input(Vis *vis, const char *key, size_t len) { +void vis_event_mode_insert_input(Vis *vis, const char *key, size_t len) { if (!vis_lua_input(vis, key, len)) vis_insert_key(vis, key, len); } -void vis_lua_mode_replace_input(Vis *vis, const char *key, size_t len) { +void vis_event_mode_replace_input(Vis *vis, const char *key, size_t len) { if (!vis_lua_input(vis, key, len)) vis_replace_key(vis, key, len); } @@ -3486,7 +3378,7 @@ void vis_lua_mode_replace_input(Vis *vis, const char *key, size_t len) { * @function file_open * @tparam File file the file to be opened */ -void vis_lua_file_open(Vis *vis, File *file) { +static void vis_lua_file_open(Vis *vis, File *file) { debug("event: file-open: %s %p %p\n", file->name ? file->name : "unnamed", (void*)file, (void*)file->text); lua_State *L = vis->lua; if (!L) @@ -3507,7 +3399,7 @@ void vis_lua_file_open(Vis *vis, File *file) { * @tparam string path the absolute path to which the file will be written, `nil` if standard output * @treturn bool whether the write operation should be proceeded */ -bool vis_lua_file_save_pre(Vis *vis, File *file, const char *path) { +static bool vis_lua_file_save_pre(Vis *vis, File *file, const char *path) { lua_State *L = vis->lua; if (!L) return true; @@ -3530,7 +3422,7 @@ bool vis_lua_file_save_pre(Vis *vis, File *file, const char *path) { * @tparam File file the file which was written * @tparam string path the absolute path to which it was written, `nil` if standard output */ -void vis_lua_file_save_post(Vis *vis, File *file, const char *path) { +static void vis_lua_file_save_post(Vis *vis, File *file, const char *path) { lua_State *L = vis->lua; if (!L) return; @@ -3549,7 +3441,7 @@ void vis_lua_file_save_post(Vis *vis, File *file, const char *path) { * @function file_close * @tparam File file the file being closed */ -void vis_lua_file_close(Vis *vis, File *file) { +static void vis_lua_file_close(Vis *vis, File *file) { debug("event: file-close: %s %p %p\n", file->name ? file->name : "unnamed", (void*)file, (void*)file->text); lua_State *L = vis->lua; if (!L) @@ -3571,7 +3463,7 @@ void vis_lua_file_close(Vis *vis, File *file) { * @function win_open * @tparam Window win the window being opened */ -void vis_lua_win_open(Vis *vis, Win *win) { +static void vis_lua_win_open(Vis *vis, Win *win) { debug("event: win-open: %s %p %p\n", win->file->name ? win->file->name : "unnamed", (void*)win, (void*)win->view); lua_State *L = vis->lua; if (!L) @@ -3590,7 +3482,7 @@ void vis_lua_win_open(Vis *vis, Win *win) { * @function win_close * @tparam Window win the window being closed */ -void vis_lua_win_close(Vis *vis, Win *win) { +static void vis_lua_win_close(Vis *vis, Win *win) { debug("event: win-close: %s %p %p\n", win->file->name ? win->file->name : "unnamed", (void*)win, (void*)win->view); lua_State *L = vis->lua; if (!L) @@ -3600,7 +3492,7 @@ void vis_lua_win_close(Vis *vis, Win *win) { obj_ref_new(L, win, VIS_LUA_TYPE_WINDOW); pcall(vis, L, 1, 0); } - obj_ref_free(L, win->view); + obj_ref_free(L, &win->view); obj_ref_free(L, win); lua_pop(L, 1); } @@ -3612,7 +3504,7 @@ void vis_lua_win_close(Vis *vis, Win *win) { * @tparam Window win the window being redrawn * @see style */ -void vis_lua_win_highlight(Vis *vis, Win *win) { +static void vis_lua_win_highlight(Vis *vis, Win *win) { lua_State *L = vis->lua; if (!L) return; @@ -3630,7 +3522,7 @@ void vis_lua_win_highlight(Vis *vis, Win *win) { * @tparam Window win the affected window * @see status */ -void vis_lua_win_status(Vis *vis, Win *win) { +static void vis_lua_win_status(Vis *vis, Win *win) { lua_State *L = vis->lua; if (!L || win->file->internal) { window_status_update(vis, win); @@ -3651,7 +3543,7 @@ void vis_lua_win_status(Vis *vis, Win *win) { * @function term_csi * @param List of CSI parameters */ -void vis_lua_term_csi(Vis *vis, const long *csi) { +static void vis_lua_term_csi(Vis *vis, const long *csi) { lua_State *L = vis->lua; if (!L) return; @@ -3711,8 +3603,80 @@ void vis_lua_process_response(Vis *vis, const char *name, * Use sparingly and check for `nil` values! * @function ui_draw */ -void vis_lua_ui_draw(Vis *vis) { +static void vis_lua_ui_draw(Vis *vis) { vis_lua_event_call(vis, "ui_draw"); } +bool vis_event_emit(Vis *vis, enum VisEvents id, ...) { + if (!vis->initialized) { + vis->initialized = true; + ui_init(&vis->ui, vis); + vis_lua_init(vis); + } + + va_list ap; + va_start(ap, id); + bool ret = true; + + switch (id) { + case VIS_EVENT_INIT: + break; + case VIS_EVENT_START: + vis_lua_start(vis); + break; + case VIS_EVENT_FILE_OPEN: + case VIS_EVENT_FILE_SAVE_PRE: + case VIS_EVENT_FILE_SAVE_POST: + case VIS_EVENT_FILE_CLOSE: + { + File *file = va_arg(ap, File*); + if (file->internal) + break; + if (id == VIS_EVENT_FILE_OPEN) { + vis_lua_file_open(vis, file); + } else if (id == VIS_EVENT_FILE_SAVE_PRE) { + const char *path = va_arg(ap, const char*); + ret = vis_lua_file_save_pre(vis, file, path); + } else if (id == VIS_EVENT_FILE_SAVE_POST) { + const char *path = va_arg(ap, const char*); + vis_lua_file_save_post(vis, file, path); + } else if (id == VIS_EVENT_FILE_CLOSE) { + vis_lua_file_close(vis, file); + } + break; + } + case VIS_EVENT_WIN_OPEN: + case VIS_EVENT_WIN_CLOSE: + case VIS_EVENT_WIN_HIGHLIGHT: + case VIS_EVENT_WIN_STATUS: + { + Win *win = va_arg(ap, Win*); + if (win->file->internal && id != VIS_EVENT_WIN_STATUS) + break; + if (id == VIS_EVENT_WIN_OPEN) { + vis_lua_win_open(vis, win); + } else if (id == VIS_EVENT_WIN_CLOSE) { + vis_lua_win_close(vis, win); + } else if (id == VIS_EVENT_WIN_HIGHLIGHT) { + vis_lua_win_highlight(vis, win); + } else if (id == VIS_EVENT_WIN_STATUS) { + vis_lua_win_status(vis, win); + } + break; + } + case VIS_EVENT_QUIT: + vis_lua_quit(vis); + break; + case VIS_EVENT_TERM_CSI: + vis_lua_term_csi(vis, va_arg(ap, const long *)); + break; + case VIS_EVENT_UI_DRAW: + vis_lua_ui_draw(vis); + break; + } + + va_end(ap); + return ret; +} + #endif diff --git a/vis-lua.h b/vis-lua.h index b4f3f51bb..76e7029ff 100644 --- a/vis-lua.h +++ b/vis-lua.h @@ -22,26 +22,13 @@ bool vis_lua_path_add(Vis*, const char *path); bool vis_lua_paths_get(Vis*, char **lpath, char **cpath); /* various event handlers, triggered by the vis core */ -void vis_lua_init(Vis*); -void vis_lua_start(Vis*); -void vis_lua_quit(Vis*); #if !CONFIG_LUA -#define vis_lua_mode_insert_input vis_insert_key -#define vis_lua_mode_replace_input vis_replace_key +#define vis_event_mode_insert_input vis_insert_key +#define vis_event_mode_replace_input vis_replace_key #else -void vis_lua_mode_insert_input(Vis*, const char *key, size_t len); -void vis_lua_mode_replace_input(Vis*, const char *key, size_t len); +void vis_event_mode_insert_input(Vis*, const char *key, size_t len); +void vis_event_mode_replace_input(Vis*, const char *key, size_t len); #endif -void vis_lua_file_open(Vis*, File*); -bool vis_lua_file_save_pre(Vis*, File*, const char *path); -void vis_lua_file_save_post(Vis*, File*, const char *path); -void vis_lua_file_close(Vis*, File*); -void vis_lua_win_open(Vis*, Win*); -void vis_lua_win_close(Vis*, Win*); -void vis_lua_win_highlight(Vis*, Win*); -void vis_lua_win_status(Vis*, Win*); -void vis_lua_term_csi(Vis*, const long *); void vis_lua_process_response(Vis *, const char *, char *, size_t, ResponseType); -void vis_lua_ui_draw(Vis*); #endif diff --git a/vis-marks.c b/vis-marks.c index 8ae97ac2f..48c065cdb 100644 --- a/vis-marks.c +++ b/vis-marks.c @@ -72,12 +72,11 @@ static Array mark_get(Win *win, Array *mark) { array_init_sized(&sel, sizeof(Filerange)); if (!mark) return sel; - View *view = win->view; size_t len = array_length(mark); array_reserve(&sel, len); for (size_t i = 0; i < len; i++) { SelectionRegion *sr = array_get(mark, i); - Filerange r = view_regions_restore(view, sr); + Filerange r = view_regions_restore(&win->view, sr); if (text_range_valid(&r)) array_add(&sel, &r); } @@ -93,11 +92,10 @@ static void mark_set(Win *win, Array *mark, Array *sel) { if (!mark) return; array_clear(mark); - View *view = win->view; for (size_t i = 0, len = array_length(sel); i < len; i++) { SelectionRegion ss; Filerange *r = array_get(sel, i); - if (view_regions_save(view, r, &ss)) + if (view_regions_save(&win->view, r, &ss)) array_add(mark, &ss); } } @@ -150,18 +148,17 @@ static bool marklist_push(Win *win, MarkList *list, Array *sel) { } bool vis_jumplist_save(Vis *vis) { - View *view = vis->win->view; - Array sel = view_selections_get_all(view); + Array sel = view_selections_get_all(&vis->win->view); bool ret = marklist_push(vis->win, &vis->win->jumplist, &sel); array_release(&sel); return ret; } static bool marklist_prev(Win *win, MarkList *list) { - View *view = win->view; + View *view = &win->view; bool restore = false; Array cur = view_selections_get_all(view); - bool anchored = view_selections_anchored(view_selections_primary_get(view)); + bool anchored = view_selections_primary_get(view)->anchored; Array *top = array_peek(&list->prev); if (!top) goto out; @@ -191,8 +188,8 @@ static bool marklist_prev(Win *win, MarkList *list) { } static bool marklist_next(Win *win, MarkList *list) { - View *view = win->view; - bool anchored = view_selections_anchored(view_selections_primary_get(view)); + View *view = &win->view; + bool anchored = view_selections_primary_get(view)->anchored; for (;;) { Array *next = array_pop(&list->next); if (!next) diff --git a/vis-modes.c b/vis-modes.c index 2e120aab3..f6d2b267a 100644 --- a/vis-modes.c +++ b/vis-modes.c @@ -148,7 +148,7 @@ static void vis_mode_normal_enter(Vis *vis, Mode *old) { return; if (vis->autoindent && strcmp(vis->key_prev, "") == 0) { Text *txt = win->file->text; - for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) { + for (Selection *s = view_selections(&win->view); s; s = view_selections_next(s)) { size_t pos = view_cursors_pos(s); size_t start = text_line_start(txt, pos); size_t end = text_line_end(txt, pos); @@ -189,16 +189,16 @@ static void vis_mode_operator_input(Vis *vis, const char *str, size_t len) { static void vis_mode_visual_enter(Vis *vis, Mode *old) { Win *win = vis->win; if (!old->visual && win) { - for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) - view_selections_anchor(s, true); + for (Selection *s = view_selections(&win->view); s; s = view_selections_next(s)) + s->anchored = true; } } static void vis_mode_visual_line_enter(Vis *vis, Mode *old) { Win *win = vis->win; if (!old->visual && win) { - for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) - view_selections_anchor(s, true); + for (Selection *s = view_selections(&win->view); s; s = view_selections_next(s)) + s->anchored = true; } if (!vis->action.op) vis_motion(vis, VIS_MOVE_NOP); @@ -211,9 +211,9 @@ static void vis_mode_visual_line_leave(Vis *vis, Mode *new) { if (!new->visual) { if (!vis->action.op) window_selection_save(win); - view_selections_clear_all(win->view); + view_selections_clear_all(&win->view); } else { - view_cursor_to(win->view, view_cursor_get(win->view)); + view_cursors_to(win->view.selection, view_cursor_get(&win->view)); } } @@ -222,7 +222,7 @@ static void vis_mode_visual_leave(Vis *vis, Mode *new) { if (!new->visual && win) { if (!vis->action.op) window_selection_save(win); - view_selections_clear_all(win->view); + view_selections_clear_all(&win->view); } } diff --git a/vis-motions.c b/vis-motions.c index 6178f5a3e..1d3f49a23 100644 --- a/vis-motions.c +++ b/vis-motions.c @@ -69,7 +69,7 @@ static size_t common_word_next(Vis *vis, Text *txt, size_t pos, if (!text_iterator_byte_get(&it, &c)) return pos; const Movement *motion = NULL; - int count = vis_count_get_default(vis, 1); + int count = VIS_COUNT_DEFAULT(vis->action.count, 1); if (isspace((unsigned char)c)) { motion = &vis_motions[start_next]; } else if (!isboundary((unsigned char)c) && text_iterator_char_next(&it, &c) && isboundary((unsigned char)c)) { @@ -175,7 +175,7 @@ static size_t firstline(Text *txt, size_t pos) { } static size_t line(Vis *vis, Text *txt, size_t pos) { - int count = vis_count_get_default(vis, 1); + int count = VIS_COUNT_DEFAULT(vis->action.count, 1); return text_line_start(txt, text_pos_by_lineno(txt, count)); } @@ -185,21 +185,21 @@ static size_t lastline(Text *txt, size_t pos) { } static size_t column(Vis *vis, Text *txt, size_t pos) { - return text_line_offset(txt, pos, vis_count_get_default(vis, 0)); + return text_line_offset(txt, pos, VIS_COUNT_DEFAULT(vis->action.count, 0)); } static size_t view_lines_top(Vis *vis, View *view) { - return view_screenline_goto(view, vis_count_get_default(vis, 1)); + return view_screenline_goto(view, VIS_COUNT_DEFAULT(vis->action.count, 1)); } static size_t view_lines_middle(Vis *vis, View *view) { - int h = view_height_get(view); + int h = view->height; return view_screenline_goto(view, h/2); } static size_t view_lines_bottom(Vis *vis, View *view) { - int h = view_height_get(vis->win->view); - return view_screenline_goto(vis->win->view, h - vis_count_get_default(vis, 0)); + int h = view->height; + return view_screenline_goto(view, h - VIS_COUNT_DEFAULT(vis->action.count, 0)); } static size_t window_nop(Vis *vis, Win *win, size_t pos) { @@ -233,25 +233,25 @@ static size_t bracket_match(Text *txt, size_t pos) { } static size_t percent(Vis *vis, Text *txt, size_t pos) { - int ratio = vis_count_get_default(vis, 0); + int ratio = VIS_COUNT_DEFAULT(vis->action.count, 0); if (ratio > 100) ratio = 100; return text_size(txt) * ratio / 100; } static size_t byte(Vis *vis, Text *txt, size_t pos) { - pos = vis_count_get_default(vis, 0); + pos = VIS_COUNT_DEFAULT(vis->action.count, 0); size_t max = text_size(txt); return pos <= max ? pos : max; } static size_t byte_left(Vis *vis, Text *txt, size_t pos) { - size_t off = vis_count_get_default(vis, 1); + size_t off = VIS_COUNT_DEFAULT(vis->action.count, 1); return off <= pos ? pos-off : 0; } static size_t byte_right(Vis *vis, Text *txt, size_t pos) { - size_t off = vis_count_get_default(vis, 1); + size_t off = VIS_COUNT_DEFAULT(vis->action.count, 1); size_t new = pos + off; size_t max = text_size(txt); return new <= max && new > pos ? new : max; diff --git a/vis-operators.c b/vis-operators.c index 0e4f8b4d1..59abcf6bb 100644 --- a/vis-operators.c +++ b/vis-operators.c @@ -102,7 +102,7 @@ static size_t op_put(Vis *vis, Text *txt, OperatorContext *c) { static size_t op_shift_right(Vis *vis, Text *txt, OperatorContext *c) { char spaces[9] = " "; - spaces[MIN(view_tabwidth_get(vis->win->view), LENGTH(spaces) - 1)] = '\0'; + spaces[MIN(vis->win->view.tabwidth, LENGTH(spaces) - 1)] = '\0'; const char *tab = vis->win->expandtab ? spaces : "\t"; size_t tablen = strlen(tab); size_t pos = text_line_begin(txt, c->range.end), prev_pos; @@ -127,7 +127,7 @@ static size_t op_shift_right(Vis *vis, Text *txt, OperatorContext *c) { static size_t op_shift_left(Vis *vis, Text *txt, OperatorContext *c) { size_t pos = text_line_begin(txt, c->range.end), prev_pos; - size_t tabwidth = view_tabwidth_get(vis->win->view), tablen; + size_t tabwidth = vis->win->view.tabwidth, tablen; size_t newpos = c->pos; /* if range ends at the begin of a line, skip line break */ @@ -161,7 +161,6 @@ static size_t op_shift_left(Vis *vis, Text *txt, OperatorContext *c) { } static size_t op_cursor(Vis *vis, Text *txt, OperatorContext *c) { - View *view = vis->win->view; Filerange r = text_range_linewise(txt, &c->range); for (size_t line = text_range_line_first(txt, &r); line != EPOS; line = text_range_line_next(txt, &r, line)) { size_t pos; @@ -169,7 +168,7 @@ static size_t op_cursor(Vis *vis, Text *txt, OperatorContext *c) { pos = text_line_finish(txt, line); else pos = text_line_start(txt, line); - view_selections_new_force(view, pos); + view_selections_new_force(&vis->win->view, pos); } return EPOS; } @@ -272,7 +271,7 @@ bool vis_operator(Vis *vis, enum VisOperator id, ...) { } case VIS_OP_DELETE: { - enum VisMode mode = vis_mode_get(vis); + enum VisMode mode = vis->mode->id; enum VisRegister reg = vis_register_used(vis); if (reg == VIS_REG_DEFAULT && (mode == VIS_MODE_INSERT || mode == VIS_MODE_REPLACE)) vis_register(vis, VIS_REG_BLACKHOLE); diff --git a/vis-prompt.c b/vis-prompt.c index 1add11afe..86699f22a 100644 --- a/vis-prompt.c +++ b/vis-prompt.c @@ -49,12 +49,12 @@ static void prompt_restore(Win *win) { static const char *prompt_enter(Vis *vis, const char *keys, const Arg *arg) { Win *prompt = vis->win; - View *view = prompt->view; + View *view = &prompt->view; Text *txt = prompt->file->text; Win *win = prompt->parent; char *cmd = NULL; - Filerange range = view_selection_get(view); + Filerange range = view_selections_get(view->selection); if (!vis->mode->visual) { const char *pattern = NULL; Regex *regex = text_regex_new(); @@ -114,8 +114,8 @@ static const char *prompt_enter(Vis *vis, const char *keys, const Arg *arg) { static const char *prompt_esc(Vis *vis, const char *keys, const Arg *arg) { Win *prompt = vis->win; - if (view_selections_count(prompt->view) > 1) { - view_selections_dispose_all(prompt->view); + if (prompt->view.selection_count > 1) { + view_selections_dispose_all(&prompt->view); } else { prompt_restore(prompt); prompt_hide(prompt); @@ -126,7 +126,7 @@ static const char *prompt_esc(Vis *vis, const char *keys, const Arg *arg) { static const char *prompt_up(Vis *vis, const char *keys, const Arg *arg) { vis_motion(vis, VIS_MOVE_LINE_UP); vis_window_mode_unmap(vis->win, VIS_MODE_INSERT, ""); - view_options_set(vis->win->view, UI_OPTION_SYMBOL_EOF); + view_options_set(&vis->win->view, UI_OPTION_SYMBOL_EOF); return keys; } @@ -164,7 +164,7 @@ void vis_prompt_show(Vis *vis, const char *title) { return; Text *txt = prompt->file->text; text_appendf(txt, "%s\n", title); - Selection *sel = view_selections_primary_get(prompt->view); + Selection *sel = view_selections_primary_get(&prompt->view); view_cursors_scroll_to(sel, text_size(txt)-1); prompt->parent = active; prompt->parent_mode = vis->mode; @@ -182,14 +182,10 @@ void vis_prompt_show(Vis *vis, const char *title) { void vis_info_show(Vis *vis, const char *msg, ...) { va_list ap; va_start(ap, msg); - vis->ui->info(vis->ui, msg, ap); + ui_info_show(&vis->ui, msg, ap); va_end(ap); } -void vis_info_hide(Vis *vis) { - vis->ui->info_hide(vis->ui); -} - void vis_message_show(Vis *vis, const char *msg) { if (!msg) return; @@ -202,6 +198,6 @@ void vis_message_show(Vis *vis, const char *msg) { size_t pos = text_size(txt); text_appendf(txt, "%s\n", msg); text_save(txt, NULL); - view_cursor_to(win->view, pos); + view_cursors_to(win->view.selection, pos); vis_window_focus(win); } diff --git a/vis-registers.c b/vis-registers.c index 1875da95d..6e21a5840 100644 --- a/vis-registers.c +++ b/vis-registers.c @@ -188,7 +188,7 @@ bool register_put_range(Vis *vis, Register *reg, Text *txt, Filerange *range) { size_t vis_register_count(Vis *vis, Register *reg) { if (reg->type == REGISTER_NUMBER) - return vis->win ? view_selections_count(vis->win->view) : 0; + return vis->win ? vis->win->view.selection_count : 0; return array_length(®->values); } diff --git a/vis.c b/vis.c index cabad6780..4a025f9a2 100644 --- a/vis.c +++ b/vis.c @@ -35,86 +35,6 @@ static void macro_replay(Vis *vis, const Macro *macro); static void macro_replay_internal(Vis *vis, const Macro *macro); static void vis_keys_push(Vis *vis, const char *input, size_t pos, bool record); -bool vis_event_emit(Vis *vis, enum VisEvents id, ...) { - if (!vis->event) - return true; - - if (!vis->initialized) { - vis->initialized = true; - vis->ui->init(vis->ui, vis); - if (vis->event->init) - vis->event->init(vis); - } - - va_list ap; - va_start(ap, id); - bool ret = true; - - switch (id) { - case VIS_EVENT_INIT: - break; - case VIS_EVENT_START: - if (vis->event->start) - vis->event->start(vis); - break; - case VIS_EVENT_FILE_OPEN: - case VIS_EVENT_FILE_SAVE_PRE: - case VIS_EVENT_FILE_SAVE_POST: - case VIS_EVENT_FILE_CLOSE: - { - File *file = va_arg(ap, File*); - if (file->internal) - break; - if (id == VIS_EVENT_FILE_OPEN && vis->event->file_open) { - vis->event->file_open(vis, file); - } else if (id == VIS_EVENT_FILE_SAVE_PRE && vis->event->file_save_pre) { - const char *path = va_arg(ap, const char*); - ret = vis->event->file_save_pre(vis, file, path); - } else if (id == VIS_EVENT_FILE_SAVE_POST && vis->event->file_save_post) { - const char *path = va_arg(ap, const char*); - vis->event->file_save_post(vis, file, path); - } else if (id == VIS_EVENT_FILE_CLOSE && vis->event->file_close) { - vis->event->file_close(vis, file); - } - break; - } - case VIS_EVENT_WIN_OPEN: - case VIS_EVENT_WIN_CLOSE: - case VIS_EVENT_WIN_HIGHLIGHT: - case VIS_EVENT_WIN_STATUS: - { - Win *win = va_arg(ap, Win*); - if (win->file->internal && id != VIS_EVENT_WIN_STATUS) - break; - if (vis->event->win_open && id == VIS_EVENT_WIN_OPEN) { - vis->event->win_open(vis, win); - } else if (vis->event->win_close && id == VIS_EVENT_WIN_CLOSE) { - vis->event->win_close(vis, win); - } else if (vis->event->win_highlight && id == VIS_EVENT_WIN_HIGHLIGHT) { - vis->event->win_highlight(vis, win); - } else if (vis->event->win_status && id == VIS_EVENT_WIN_STATUS) { - vis->event->win_status(vis, win); - } - break; - } - case VIS_EVENT_QUIT: - if (vis->event->quit) - vis->event->quit(vis); - break; - case VIS_EVENT_TERM_CSI: - if (vis->event->term_csi) - vis->event->term_csi(vis, va_arg(ap, const long *)); - break; - case VIS_EVENT_UI_DRAW: - if (vis->event->ui_draw) - vis->event->ui_draw(vis); - break; - } - - va_end(ap); - return ret; -} - /** window / file handling */ static void file_free(Vis *vis, File *file) { @@ -182,7 +102,7 @@ char *absolute_path(const char *name) { return path_normalized[0] ? strdup(path_normalized) : NULL; } -static File *file_new(Vis *vis, const char *name) { +static File *file_new(Vis *vis, const char *name, bool internal) { char *name_absolute = NULL; bool cmp_names = 0; struct stat new; @@ -225,7 +145,9 @@ static File *file_new(Vis *vis, const char *name) { if (!(file = file_new_text(vis, text))) goto err; file->name = name_absolute; - vis_event_emit(vis, VIS_EVENT_FILE_OPEN, file); + file->internal = internal; + if (!internal) + vis_event_emit(vis, VIS_EVENT_FILE_OPEN, file); return file; err: free(name_absolute); @@ -235,11 +157,9 @@ static File *file_new(Vis *vis, const char *name) { } static File *file_new_internal(Vis *vis, const char *filename) { - File *file = file_new(vis, filename); - if (file) { + File *file = file_new(vis, filename, true); + if (file) file->refcount = 1; - file->internal = true; - } return file; } @@ -264,14 +184,9 @@ const char *file_name_get(File *file) { return file->name[cwdlen] == '/' ? file->name+cwdlen+1 : file->name; } -void vis_window_status(Win *win, const char *status) { - win->ui->status(win->ui, status); -} - void window_selection_save(Win *win) { Vis *vis = win->vis; - View *view = win->view; - Array sel = view_selections_get_all(view); + Array sel = view_selections_get_all(&win->view); vis_mark_set(win, VIS_MARK_SELECTION, &sel); array_release(&sel); vis_jumplist_save(vis); @@ -286,9 +201,8 @@ static void window_free(Win *win) { if (other->parent == win) other->parent = NULL; } - if (vis->ui) - vis->ui->window_free(win->ui); - view_free(win->view); + ui_window_free(win->ui); + view_free(&win->view); for (size_t i = 0; i < LENGTH(win->modes); i++) map_free(win->modes[i].bindings); marklist_release(&win->jumplist); @@ -297,16 +211,15 @@ static void window_free(Win *win) { } static void window_draw_colorcolumn(Win *win) { - View *view = win->view; - int cc = view_colorcolumn_get(view); + int cc = win->view.colorcolumn; if (cc <= 0) return; size_t lineno = 0; int line_cols = 0; /* Track the number of columns we've passed on each line */ bool line_cc_set = false; /* Has the colorcolumn attribute been set for this line yet */ - int width = view_width_get(view); + int width = win->view.width; - for (Line *l = view_lines_first(view); l; l = l->next) { + for (Line *l = win->view.topline; l; l = l->next) { if (l->lineno != lineno) { line_cols = 0; line_cc_set = false; @@ -318,7 +231,7 @@ static void window_draw_colorcolumn(Win *win) { /* This screen line contains the cell we want to highlight */ if (cc <= line_cols + width) { - win->ui->style_set(win->ui, &l->cells[cc - 1 - line_cols], UI_STYLE_COLOR_COLUMN); + ui_window_style_set(win->ui, &l->cells[cc - 1 - line_cols], UI_STYLE_COLOR_COLUMN); line_cc_set = true; } else { line_cols += width; @@ -328,22 +241,21 @@ static void window_draw_colorcolumn(Win *win) { static void window_draw_cursorline(Win *win) { Vis *vis = win->vis; - View *view = win->view; - enum UiOption options = view_options_get(view); + enum UiOption options = UI_OPTIONS_GET(win->view.ui); if (!(options & UI_OPTION_CURSOR_LINE)) return; if (vis->mode->visual || vis->win != win) return; - if (view_selections_count(view) > 1) + if (win->view.selection_count > 1) return; - int width = view_width_get(view); - Selection *sel = view_selections_primary_get(view); - size_t lineno = view_cursors_line_get(sel)->lineno; - for (Line *l = view_lines_first(view); l; l = l->next) { + int width = win->view.width; + Selection *sel = view_selections_primary_get(&win->view); + size_t lineno = sel->line->lineno; + for (Line *l = win->view.topline; l; l = l->next) { if (l->lineno == lineno) { for (int x = 0; x < width; x++) - win->ui->style_set(win->ui, &l->cells[x], UI_STYLE_CURSOR_LINE); + ui_window_style_set(win->ui, &l->cells[x], UI_STYLE_CURSOR_LINE); } else if (l->lineno > lineno) { break; } @@ -351,7 +263,7 @@ static void window_draw_cursorline(Win *win) { } static void window_draw_selection(Win *win, Selection *cur) { - View *view = win->view; + View *view = &win->view; Filerange sel = view_selections_get(cur); if (!text_range_valid(&sel)) return; @@ -362,18 +274,18 @@ static void window_draw_selection(Win *win, Selection *cur) { if (!start_line && !end_line) return; if (!start_line) { - start_line = view_lines_first(view); + start_line = view->topline; start_col = 0; } if (!end_line) { - end_line = view_lines_last(view); + end_line = view->lastline; end_col = end_line->width; } for (Line *l = start_line; l != end_line->next; l = l->next) { int col = (l == start_line) ? start_col : 0; int end = (l == end_line) ? end_col : l->width; while (col < end) - win->ui->style_set(win->ui, &l->cells[col++], UI_STYLE_SELECTION); + ui_window_style_set(win->ui, &l->cells[col++], UI_STYLE_SELECTION); } } @@ -382,32 +294,30 @@ static void window_draw_cursor_matching(Win *win, Selection *cur) { return; Line *line_match; int col_match; size_t pos = view_cursors_pos(cur); - Filerange limits = view_viewport_get(win->view); + Filerange limits = VIEW_VIEWPORT_GET(win->view); size_t pos_match = text_bracket_match_symbol(win->file->text, pos, "(){}[]\"'`", &limits); if (pos == pos_match) return; - if (!view_coord_get(win->view, pos_match, &line_match, NULL, &col_match)) + if (!view_coord_get(&win->view, pos_match, &line_match, NULL, &col_match)) return; - win->ui->style_set(win->ui, &line_match->cells[col_match], UI_STYLE_SELECTION); + ui_window_style_set(win->ui, &line_match->cells[col_match], UI_STYLE_SELECTION); } static void window_draw_cursor(Win *win, Selection *cur) { if (win->vis->win != win) return; - Line *line = view_cursors_line_get(cur); - int col = view_cursors_cell_get(cur); - if (!line || col == -1) + Line *line = cur->line; + if (!line) return; - Selection *primary = view_selections_primary_get(win->view); - win->ui->style_set(win->ui, &line->cells[col], primary == cur ? UI_STYLE_CURSOR_PRIMARY : UI_STYLE_CURSOR); + Selection *primary = view_selections_primary_get(&win->view); + ui_window_style_set(win->ui, &line->cells[cur->col], primary == cur ? UI_STYLE_CURSOR_PRIMARY : UI_STYLE_CURSOR); window_draw_cursor_matching(win, cur); return; } static void window_draw_selections(Win *win) { - View *view = win->view; - Filerange viewport = view_viewport_get(view); - Selection *sel = view_selections_primary_get(view); + Filerange viewport = VIEW_VIEWPORT_GET(win->view); + Selection *sel = view_selections_primary_get(&win->view); for (Selection *s = view_selections_prev(sel); s; s = view_selections_prev(s)) { window_draw_selection(win, s); size_t pos = view_cursors_pos(s); @@ -427,17 +337,17 @@ static void window_draw_selections(Win *win) { } static void window_draw_eof(Win *win) { - View *view = win->view; - if (view_width_get(view) == 0) + View *view = &win->view; + if (view->width == 0) return; - for (Line *l = view_lines_last(view)->next; l; l = l->next) { + for (Line *l = view->lastline->next; l; l = l->next) { strncpy(l->cells[0].data, view_symbol_eof_get(view), sizeof(l->cells[0].data)-1); - win->ui->style_set(win->ui, &l->cells[0], UI_STYLE_EOF); + ui_window_style_set(win->ui, &l->cells[0], UI_STYLE_EOF); } } void vis_window_draw(Win *win) { - if (!win->ui || !view_update(win->view)) + if (!win->ui || !view_update(&win->view)) return; Vis *vis = win->vis; vis_event_emit(vis, VIS_EVENT_WIN_HIGHLIGHT, win); @@ -455,7 +365,7 @@ void vis_window_draw(Win *win) { void vis_window_invalidate(Win *win) { for (Win *w = win->vis->windows; w; w = w->next) { if (w->file == win->file) - view_draw(w->view); + view_draw(&w->view); } } @@ -465,24 +375,27 @@ Win *window_new_file(Vis *vis, File *file, enum UiOption options) { return NULL; win->vis = vis; win->file = file; - win->view = view_new(file->text); + if (!view_init(&win->view, file->text)) { + free(win); + return NULL; + } win->expandtab = false; - win->ui = vis->ui->window_new(vis->ui, win, options); - if (!win->view || !win->ui) { + win->ui = ui_window_new(&vis->ui, win, options); + if (!win->ui) { window_free(win); return NULL; } marklist_init(&win->jumplist, 32); mark_init(&win->saved_selections); file->refcount++; - view_options_set(win->view, view_options_get(win->view)); + view_options_set(&win->view, UI_OPTIONS_GET(win->view.ui)); if (vis->windows) vis->windows->prev = win; win->next = vis->windows; vis->windows = win; vis->win = win; - vis->ui->window_focus(win->ui); + ui_window_focus(win->ui); for (size_t i = 0; i < LENGTH(win->modes); i++) win->modes[i].parent = &vis_modes[i]; vis_event_emit(vis, VIS_EVENT_WIN_OPEN, win); @@ -495,31 +408,31 @@ bool vis_window_reload(Win *win) { return false; /* can't reload unsaved file */ /* temporarily unset file name, otherwise file_new returns the same File */ win->file->name = NULL; - File *file = file_new(win->vis, name); + File *file = file_new(win->vis, name, false); win->file->name = name; if (!file) return false; file_free(win->vis, win->file); file->refcount = 1; win->file = file; - view_reload(win->view, file->text); + view_reload(&win->view, file->text); return true; } bool vis_window_change_file(Win *win, const char* filename) { - File *file = file_new(win->vis, filename); + File *file = file_new(win->vis, filename, false); if (!file) return false; file->refcount++; if (win->file) file_free(win->vis, win->file); win->file = file; - view_reload(win->view, file->text); + view_reload(&win->view, file->text); return true; } bool vis_window_split(Win *original) { - vis_doupdates(original->vis, false); + original->vis->ui.doupdate = false; Win *win = window_new_file(original->vis, original->file, UI_OPTION_STATUSBAR); if (!win) return false; @@ -530,9 +443,9 @@ bool vis_window_split(Win *original) { map_copy(win->modes[i].bindings, original->modes[i].bindings); } win->file = original->file; - view_options_set(win->view, view_options_get(original->view)); - view_cursor_to(win->view, view_cursor_get(original->view)); - vis_doupdates(win->vis, true); + view_options_set(&win->view, UI_OPTIONS_GET(original->view.ui)); + view_cursors_to(win->view.selection, view_cursor_get(&original->view)); + win->vis->ui.doupdate = true; return true; } @@ -541,7 +454,7 @@ void vis_window_focus(Win *win) { return; Vis *vis = win->vis; vis->win = win; - vis->ui->window_focus(win->ui); + ui_window_focus(win->ui); } void vis_window_next(Vis *vis) { @@ -561,51 +474,27 @@ void vis_window_prev(Vis *vis) { vis_window_focus(sel); } -int vis_window_width_get(const Win *win) { - return win->ui->window_width(win->ui); -} - -int vis_window_height_get(const Win *win) { - return win->ui->window_height(win->ui); -} - void vis_draw(Vis *vis) { for (Win *win = vis->windows; win; win = win->next) - view_draw(win->view); + view_draw(&win->view); } void vis_redraw(Vis *vis) { - vis->ui->redraw(vis->ui); - vis_update(vis); -} - -void vis_update(Vis *vis) { - vis->ui->draw(vis->ui); -} - -void vis_suspend(Vis *vis) { - vis->ui->suspend(vis->ui); -} - -void vis_resume(Vis *vis) { - vis->ui->resume(vis->ui); -} - -void vis_doupdates(Vis *vis, bool doupdate) { - vis->ui->doupdates(vis->ui, doupdate); + ui_redraw(&vis->ui); + ui_draw(&vis->ui); } bool vis_window_new(Vis *vis, const char *filename) { - File *file = file_new(vis, filename); + File *file = file_new(vis, filename, false); if (!file) return false; - vis_doupdates(vis, false); + vis->ui.doupdate = false; Win *win = window_new_file(vis, file, UI_OPTION_STATUSBAR|UI_OPTION_SYMBOL_EOF); if (!win) { file_free(vis, file); return false; } - vis_doupdates(vis, true); + vis->ui.doupdate = true; return true; } @@ -647,7 +536,7 @@ void vis_window_swap(Win *a, Win *b) { vis->windows = b; else if (vis->windows == b) vis->windows = a; - vis->ui->window_swap(a->ui, b->ui); + ui_window_swap(a->ui, b->ui); if (vis->win == a) vis_window_focus(b); else if (vis->win == b) @@ -672,18 +561,19 @@ void vis_window_close(Win *win) { vis->message_window = NULL; window_free(win); if (vis->win) - vis->ui->window_focus(vis->win->ui); + ui_window_focus(vis->win->ui); vis_draw(vis); } -Vis *vis_new(Ui *ui, VisEvent *event) { - if (!ui) - return NULL; +Vis *vis_new(void) { Vis *vis = calloc(1, sizeof(Vis)); if (!vis) return NULL; vis->exit_status = -1; - vis->ui = ui; + if (!ui_terminal_init(&vis->ui)) { + free(vis); + return NULL; + } vis->change_colors = true; for (size_t i = 0; i < LENGTH(vis->registers); i++) register_init(&vis->registers[i]); @@ -719,13 +609,8 @@ Vis *vis_new(Ui *ui, VisEvent *event) { if (!(vis->shell = strdup(shell))) goto err; vis->mode_prev = vis->mode = &vis_modes[VIS_MODE_NORMAL]; - vis->event = event; - if (event) { - if (event->mode_insert_input) - vis_modes[VIS_MODE_INSERT].input = event->mode_insert_input; - if (event->mode_replace_input) - vis_modes[VIS_MODE_REPLACE].input = event->mode_replace_input; - } + vis_modes[VIS_MODE_INSERT].input = vis_event_mode_insert_input; + vis_modes[VIS_MODE_REPLACE].input = vis_event_mode_replace_input; return vis; err: vis_free(vis); @@ -735,16 +620,15 @@ Vis *vis_new(Ui *ui, VisEvent *event) { void vis_free(Vis *vis) { if (!vis) return; - vis_event_emit(vis, VIS_EVENT_QUIT); - vis->event = NULL; while (vis->windows) vis_window_close(vis->windows); + vis_event_emit(vis, VIS_EVENT_QUIT); file_free(vis, vis->command_file); file_free(vis, vis->search_file); file_free(vis, vis->error_file); for (int i = 0; i < LENGTH(vis->registers); i++) register_release(&vis->registers[i]); - vis->ui->free(vis->ui); + ui_terminal_free(&vis->ui); if (vis->usercmds) { const char *name; while (map_first(vis->usercmds, &name) && vis_cmd_unregister(vis, name)); @@ -786,7 +670,7 @@ void vis_insert_key(Vis *vis, const char *data, size_t len) { Win *win = vis->win; if (!win) return; - for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) { + for (Selection *s = view_selections(&win->view); s; s = view_selections_next(s)) { size_t pos = view_cursors_pos(s); vis_insert(vis, pos, data, len); view_cursors_scroll_to(s, pos + len); @@ -811,7 +695,7 @@ void vis_replace_key(Vis *vis, const char *data, size_t len) { Win *win = vis->win; if (!win) return; - for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) { + for (Selection *s = view_selections(&win->view); s; s = view_selections_next(s)) { size_t pos = view_cursors_pos(s); vis_replace(vis, pos, data, len); view_cursors_scroll_to(s, pos + len); @@ -852,14 +736,14 @@ void vis_do(Vis *vis) { return; File *file = win->file; Text *txt = file->text; - View *view = win->view; + View *view = &win->view; Action *a = &vis->action; int count = MAX(a->count, 1); if (a->op == &vis_operators[VIS_OP_MODESWITCH]) count = 1; /* count should apply to inserted text not motion */ bool repeatable = a->op && !vis->macro_operator && !vis->win->parent; - bool multiple_cursors = view_selections_count(view) > 1; + bool multiple_cursors = view->selection_count > 1; bool linewise = !(a->type & CHARWISE) && ( a->type & LINEWISE || (a->movement && a->movement->type & LINEWISE) || @@ -1004,7 +888,7 @@ void vis_do(Vis *vis) { c.range = text_range_linewise(txt, &c.range); if (vis->mode->visual) { view_selections_set(sel, &c.range); - view_selections_anchor(sel, true); + sel->anchored = true; } if (a->op) { @@ -1075,7 +959,7 @@ void vis_cancel(Vis *vis) { void vis_die(Vis *vis, const char *msg, ...) { va_list ap; va_start(ap, msg); - vis->ui->die(vis->ui, msg, ap); + ui_die(&vis->ui, msg, ap); va_end(ap); } @@ -1083,7 +967,7 @@ const char *vis_keys_next(Vis *vis, const char *keys) { if (!keys || !*keys) return NULL; TermKeyKey key; - TermKey *termkey = vis->ui->termkey_get(vis->ui); + TermKey *termkey = vis->ui.termkey; const char *next = NULL; /* first try to parse a special key of the form */ if (*keys == '<' && keys[1] && (next = termkey_strpkey(termkey, keys+1, &key, TERMKEY_FORMAT_VIM)) && *next == '>') @@ -1111,7 +995,7 @@ long vis_keys_codepoint(Vis *vis, const char *keys) { long codepoint = -1; const char *next; TermKeyKey key; - TermKey *termkey = vis->ui->termkey_get(vis->ui); + TermKey *termkey = vis->ui.termkey; if (!keys[0]) return -1; @@ -1304,9 +1188,9 @@ static void vis_keys_push(Vis *vis, const char *input, size_t pos, bool record) static const char *getkey(Vis *vis) { TermKeyKey key = { 0 }; - if (!vis->ui->getkey(vis->ui, &key)) + if (!ui_getkey(&vis->ui, &key)) return NULL; - vis_info_hide(vis); + ui_info_hide(&vis->ui); bool use_keymap = vis->mode->id != VIS_MODE_INSERT && vis->mode->id != VIS_MODE_REPLACE && !vis->keymap_disabled; @@ -1320,7 +1204,7 @@ static const char *getkey(Vis *vis) { } } - TermKey *termkey = vis->ui->termkey_get(vis->ui); + TermKey *termkey = vis->ui.termkey; if (key.type == TERMKEY_TYPE_UNKNOWN_CSI) { long args[18]; size_t nargs; @@ -1414,16 +1298,16 @@ int vis_run(Vis *vis) { } if (vis->resume) { - vis_resume(vis); + ui_terminal_resume(&vis->ui); vis->resume = false; } if (vis->need_resize) { - vis->ui->resize(vis->ui); + ui_resize(&vis->ui); vis->need_resize = false; } - vis_update(vis); + ui_draw(&vis->ui); idle.tv_sec = vis->mode->idle_timeout; int r = pselect(vis_process_before_tick(&fds) + 1, &fds, NULL, NULL, timeout, &emptyset); @@ -1443,8 +1327,7 @@ int vis_run(Vis *vis) { continue; } - TermKey *termkey = vis->ui->termkey_get(vis->ui); - termkey_advisereadable(termkey); + termkey_advisereadable(vis->ui.termkey); const char *key; while ((key = getkey(vis))) @@ -1547,7 +1430,7 @@ bool vis_macro_replay(Vis *vis, enum VisRegister id) { Macro *macro = macro_get(vis, id); if (!macro || macro == vis->recording) return false; - int count = vis_count_get_default(vis, 1); + int count = VIS_COUNT_DEFAULT(vis->action.count, 1); vis_cancel(vis); for (int i = 0; i < count; i++) macro_replay(vis, macro); @@ -1588,25 +1471,11 @@ void vis_repeat(Vis *vis) { vis_file_snapshot(vis, win->file); } -int vis_count_get(Vis *vis) { - return vis->action.count; -} - -int vis_count_get_default(Vis *vis, int def) { - if (vis->action.count == VIS_COUNT_UNKNOWN) - return def; - return vis->action.count; -} - -void vis_count_set(Vis *vis, int count) { - vis->action.count = (count >= 0 ? count : VIS_COUNT_UNKNOWN); -} - VisCountIterator vis_count_iterator_get(Vis *vis, int def) { return (VisCountIterator) { .vis = vis, .iteration = 0, - .count = vis_count_get_default(vis, def), + .count = VIS_COUNT_DEFAULT(vis->action.count, def), }; } @@ -1638,8 +1507,8 @@ void vis_insert_tab(Vis *vis) { return; } char spaces[9]; - int tabwidth = MIN(view_tabwidth_get(vis->win->view), LENGTH(spaces) - 1); - for (Selection *s = view_selections(win->view); s; s = view_selections_next(s)) { + int tabwidth = MIN(vis->win->view.tabwidth, LENGTH(spaces) - 1); + for (Selection *s = view_selections(&win->view); s; s = view_selections_next(s)) { size_t pos = view_cursors_pos(s); int width = text_line_width_get(win->file->text, pos); int count = tabwidth - (width % tabwidth); @@ -1694,9 +1563,8 @@ void vis_insert_nl(Vis *vis) { Win *win = vis->win; if (!win) return; - View *view = win->view; Text *txt = win->file->text; - for (Selection *s = view_selections(view); s; s = view_selections_next(s)) { + for (Selection *s = view_selections(&win->view); s; s = view_selections_next(s)) { size_t pos = view_cursors_pos(s); size_t newpos = vis_text_insert_nl(vis, txt, pos); /* This is a bit of a hack to fix cursor positioning when @@ -1753,7 +1621,7 @@ int vis_pipe(Vis *vis, File *file, Filerange *range, const char *argv[], return -1; } - vis->ui->terminal_save(vis->ui, fullscreen); + ui_terminal_save(&vis->ui, fullscreen); pid_t pid = fork(); if (pid == -1) { @@ -1947,7 +1815,7 @@ int vis_pipe(Vis *vis, File *file, Filerange *range, const char *argv[], sigaction(SIGTERM, &sigterm_old, NULL); vis->interrupted = false; - vis->ui->terminal_restore(vis->ui); + ui_terminal_restore(&vis->ui); if (WIFEXITED(status)) return WEXITSTATUS(status); @@ -2012,13 +1880,5 @@ Text *vis_text(Vis *vis) { View *vis_view(Vis *vis) { Win *win = vis->win; - return win ? win->view : NULL; -} - -Win *vis_window(Vis *vis) { - return vis->win; -} - -bool vis_get_autoindent(const Vis *vis) { - return vis->autoindent; + return win ? &win->view : NULL; } diff --git a/vis.h b/vis.h index fcc1e055d..eb8ec92d1 100644 --- a/vis.h +++ b/vis.h @@ -40,27 +40,6 @@ typedef struct Win Win; /* maximum bytes needed for string representation of a (pseudo) key */ #define VIS_KEY_LENGTH_MAX 64 -/** - * Editor event handlers. - */ -typedef struct { - void (*init)(Vis*); - void (*start)(Vis*); - void (*quit)(Vis*); - void (*mode_insert_input)(Vis*, const char *key, size_t len); - void (*mode_replace_input)(Vis*, const char *key, size_t len); - void (*file_open)(Vis*, File*); - bool (*file_save_pre)(Vis*, File*, const char *path); - void (*file_save_post)(Vis*, File*, const char *path); - void (*file_close)(Vis*, File*); - void (*win_open)(Vis*, Win*); - void (*win_close)(Vis*, Win*); - void (*win_highlight)(Vis*, Win*); - void (*win_status)(Vis*, Win*); - void (*term_csi)(Vis*, const long *); - void (*ui_draw)(Vis*); -} VisEvent; - /** Union used to pass arguments to key action functions. */ typedef union { bool b; @@ -111,8 +90,8 @@ typedef struct { * @defgroup vis_lifecycle * @{ */ -/** Create a new editor instance using the given user interface and event handlers. */ -Vis *vis_new(Ui*, VisEvent*); +/** Create a new editor instance. */ +Vis *vis_new(void); /** Free all resources associated with this editor instance, terminates UI. */ void vis_free(Vis*); /** @@ -130,27 +109,6 @@ void vis_exit(Vis*, int status); */ void vis_die(Vis*, const char *msg, ...) __attribute__((noreturn,format(printf, 2, 3))); -/** - * Temporarily suspend the editor process. - * @rst - * .. note:: This function will generate a ``SIGTSTP`` signal. - * @endrst - **/ -void vis_suspend(Vis*); -/** - * Resume editor process. - * @rst - * .. note:: This function is usually called in response to a ``SIGCONT`` signal. - * @endrst - */ -void vis_resume(Vis*); -/** - * Set doupdate flag. - * @rst - * .. note:: Prevent flickering in curses by delaying window updates. - * @endrst - */ -void vis_doupdates(Vis*, bool); /** * Inform the editor core that a signal occurred. * @return Whether the signal was handled. @@ -183,8 +141,6 @@ bool vis_interrupt_requested(Vis*); void vis_draw(Vis*); /** Completely redraw user interface. */ void vis_redraw(Vis*); -/** Blit user interface state to output device. */ -void vis_update(Vis*); /** * @} * @defgroup vis_windows @@ -217,8 +173,6 @@ bool vis_window_closable(Win*); void vis_window_close(Win*); /** Split the window, shares the underlying file object. */ bool vis_window_split(Win*); -/** Change status message of this window. */ -void vis_window_status(Win*, const char *status); void vis_window_draw(Win*); void vis_window_invalidate(Win*); /** Focus next window. */ @@ -229,10 +183,6 @@ void vis_window_prev(Vis*); void vis_window_focus(Win*); /** Swap location of two windows. */ void vis_window_swap(Win*, Win*); -/** Query window width. */ -int vis_window_width_get(const Win*); -/** Query window height. */ -int vis_window_height_get(const Win*); /** * @} * @defgroup vis_info @@ -253,8 +203,6 @@ void vis_prompt_show(Vis*, const char *title); * @endrst */ void vis_info_show(Vis*, const char *msg, ...) __attribute__((format(printf, 2, 3))); -/** Hide informational message. */ -void vis_info_hide(Vis*); /** Display arbitrary long message in a dedicated window. */ void vis_message_show(Vis*, const char *msg); @@ -315,8 +263,6 @@ enum VisMode { * @endrst */ void vis_mode_switch(Vis*, enum VisMode); -/** Get currently active mode. */ -enum VisMode vis_mode_get(Vis*); /** Translate human readable mode name to constant. */ enum VisMode vis_mode_from(Vis*, const char *name); @@ -581,14 +527,8 @@ int vis_motion_register(Vis*, void *context, VisMotionFunction*); */ /** No count was specified. */ #define VIS_COUNT_UNKNOWN (-1) -/** Get count, might return `VIS_COUNT_UNKNOWN`. */ -int vis_count_get(Vis*); -/** Get count, if none was specified, return ``def``. */ -int vis_count_get_default(Vis*, int def); -/** Set a count. */ -void vis_count_set(Vis*, int count); -/** Set the tabwidth */ -void vis_tabwidth_set(Vis*, int tw); +#define VIS_COUNT_DEFAULT(count, def) ((count) == VIS_COUNT_UNKNOWN ? (def) : (count)) +#define VIS_COUNT_NORMALIZE(count) ((count) < 0 ? VIS_COUNT_UNKNOWN : (count)) /** Set the shell */ void vis_shell_set(Vis*, const char *new_shell); @@ -995,9 +935,5 @@ void vis_file_snapshot(Vis*, File*); /* TODO: expose proper API to iterate through files etc */ Text *vis_text(Vis*); View *vis_view(Vis*); -Win *vis_window(Vis*); - -/* Get value of autoindent */ -bool vis_get_autoindent(const Vis*); #endif