static const char *prompt_enter(Vis *vis, const char *keys, const Arg *arg) { Win *prompt = vis->win; View *view = prompt->view; Text *txt = prompt->file->text; Win *win = prompt->parent; char *cmd = NULL; Filerange range = view_selection_get(view); if (!text_range_valid(&range)) range = text_object_line(txt, view_cursor_get(view)); if (text_range_valid(&range)) cmd = text_bytes_alloc0(txt, range.start, text_range_size(&range)); if (!win || !cmd) { vis_info_show(vis, "Prompt window invalid\n"); prompt_restore(prompt); prompt_hide(prompt); free(cmd); return keys; } size_t len = strlen(cmd); if (len > 0 && cmd[len-1] == '\n') cmd[len-1] = '\0'; bool lastline = (range.end == text_size(txt)); prompt_restore(prompt); if (vis_prompt_cmd(vis, cmd)) { prompt_hide(prompt); if (!lastline) { text_delete(txt, range.start, text_range_size(&range)); text_appendf(txt, "%s\n", cmd); } } else { vis->win = prompt; vis->mode = &vis_modes[VIS_MODE_INSERT]; } free(cmd); vis_draw(vis); return keys; }
/* 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) { view_clear(view); /* current absolute file position */ size_t pos = view->start; /* number of bytes to read in one go */ size_t text_len = view->width * view->height; /* current buffer to work with */ char text[text_len+1]; /* remaining bytes to process in buffer*/ size_t rem = text_bytes_get(view->text, pos, text_len, text); /* NUL terminate because regex(3) function expect it */ text[rem] = '\0'; /* current position into buffer from which to interpret a character */ char *cur = text; /* current selection */ Filerange sel = view_selection_get(view); /* syntax definition to use */ Syntax *syntax = view->syntax; /* matched tokens for each syntax rule */ regmatch_t match[syntax ? LENGTH(syntax->rules) : 1][1], *matched = NULL; memset(match, 0, sizeof match); /* default and current curses attributes to use */ int default_attrs = COLOR_PAIR(0) | A_NORMAL, attrs = default_attrs; while (rem > 0) { /* current 'parsed' character' */ wchar_t wchar; Cell cell; memset(&cell, 0, sizeof cell); if (syntax) { if (matched && cur >= text + matched->rm_eo) { /* end of current match */ matched = NULL; attrs = default_attrs; for (int i = 0; i < LENGTH(syntax->rules); i++) { if (match[i][0].rm_so == -1) continue; /* no match on whole text */ /* reset matches which overlap with matched */ if (text + match[i][0].rm_so <= cur && cur < text + match[i][0].rm_eo) { match[i][0].rm_so = 0; match[i][0].rm_eo = 0; } } } if (!matched) { size_t off = cur - text; /* number of already processed bytes */ for (int i = 0; i < LENGTH(syntax->rules); i++) { SyntaxRule *rule = &syntax->rules[i]; if (!rule->rule) break; if (match[i][0].rm_so == -1) continue; /* no match on whole text */ if (off >= (size_t)match[i][0].rm_eo) { /* past match, continue search from current position */ if (regexec(&rule->regex, cur, 1, match[i], 0) || match[i][0].rm_so == match[i][0].rm_eo) { match[i][0].rm_so = -1; match[i][0].rm_eo = -1; continue; } match[i][0].rm_so += off; match[i][0].rm_eo += off; } if (text + match[i][0].rm_so <= cur && cur < text + match[i][0].rm_eo) { /* within matched expression */ matched = &match[i][0]; attrs = rule->color->attr; break; /* first match views */ } } } } size_t len = mbrtowc(&wchar, cur, rem, NULL); if (len == (size_t)-1 && errno == EILSEQ) { /* ok, we encountered an invalid multibyte sequence, * replace it with the Unicode Replacement Character * (FFFD) and skip until the start of the next utf8 char */ for (len = 1; rem > len && !ISUTF8(cur[len]); len++); cell = (Cell){ .data = "\xEF\xBF\xBD", .len = len, .width = 1, .istab = false }; } else if (len == (size_t)-2) { /* not enough bytes available to convert to a * wide character. advance file position and read * another junk into buffer. */ rem = text_bytes_get(view->text, pos, text_len, text); text[rem] = '\0'; cur = text; continue; } else if (len == 0) { /* NUL byte encountered, store it and continue */ cell = (Cell){ .data = "\x00", .len = 1, .width = 0, .istab = false }; } else { for (size_t i = 0; i < len; i++) cell.data[i] = cur[i]; cell.data[len] = '\0'; cell.istab = false; cell.len = len; cell.width = wcwidth(wchar); if (cell.width == -1) cell.width = 1; } if (cur[0] == '\r' && rem > 1 && cur[1] == '\n') { /* convert views style newline \r\n into a single char with len = 2 */ cell = (Cell){ .data = "\n", .len = 2, .width = 1, .istab = false }; } cell.attr = attrs; if (sel.start <= pos && pos < sel.end) cell.attr |= A_REVERSE; if (!view_addch(view, &cell)) break; rem -= cell.len; cur += cell.len; pos += cell.len; }
static void ui_window_draw(UiWin *w) { UiCursesWin *win = (UiCursesWin*)w; if (!ui_window_draw_sidebar(win)) return; debug("ui-win-draw[%s]\n", win->file->name ? win->file->name : "noname"); wbkgd(win->win, style_to_attr(&win->styles[UI_STYLE_DEFAULT])); wmove(win->win, 0, 0); int width = view_width_get(win->view); CellStyle *prev_style = NULL; size_t cursor_lineno = -1; if (win->options & UI_OPTION_CURSOR_LINE && win->ui->selwin == win) { Filerange selection = view_selection_get(win->view); if (!view_cursors_multiple(win->view) && !text_range_valid(&selection)) { const Line *line = view_line_get(win->view); cursor_lineno = line->lineno; } } short selection_bg = win->styles[UI_STYLE_SELECTION].bg; short cursor_line_bg = win->styles[UI_STYLE_CURSOR_LINE].bg; bool multiple_cursors = view_cursors_multiple(win->view); attr_t attr = A_NORMAL; for (const Line *l = view_lines_get(win->view); l; l = l->next) { bool cursor_line = l->lineno == cursor_lineno; for (int x = 0; x < width; x++) { enum UiStyle style_id = l->cells[x].style; if (style_id == 0) style_id = UI_STYLE_DEFAULT; CellStyle *style = &win->styles[style_id]; if (l->cells[x].cursor && win->ui->selwin == win) { if (multiple_cursors && l->cells[x].cursor_primary) attr = style_to_attr(&win->styles[UI_STYLE_CURSOR_PRIMARY]); else attr = style_to_attr(&win->styles[UI_STYLE_CURSOR]); prev_style = NULL; } else if (l->cells[x].selected) { if (style->fg == selection_bg) attr |= A_REVERSE; else attr = style->attr | COLOR_PAIR(color_pair_get(style->fg, selection_bg)); prev_style = NULL; } else if (cursor_line) { attr = style->attr | COLOR_PAIR(color_pair_get(style->fg, cursor_line_bg)); prev_style = NULL; } else if (style != prev_style) { attr = style_to_attr(style); prev_style = style; } wattrset(win->win, attr); waddstr(win->win, l->cells[x].data); } /* try to fixup display issues, in theory we should always output a full line */ int x, y; getyx(win->win, y, x); (void)y; wattrset(win->win, A_NORMAL); for (; 0 < x && x < width; x++) waddstr(win->win, " "); } wclrtobot(win->win); }