/* 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; }
int viewglut_key(viewglut *P, int k, int d) { double s = 5; int mine = 1; assert(P); if (d) { /* Interpret a key press. */ switch (tolower(k)) { case 27: exit(EXIT_SUCCESS); break; case 7: viewglut_grab(); break; case 6: viewglut_fwd(P); break; case 2: viewglut_rev(P); break; case 16: view_prev(P->V); break; case 14: view_next(P->V); break; case 8: view_home(P->V); break; case 10: view_jump(P->V); break; case 19: view_save(P->V, VIEW_DAT); break; case 12: view_load(P->V, VIEW_DAT); break; case 18: view_remove(P->V); break; case 9: view_insert(P->V); break; case 3: view_clear (P->V); break; case 'd': case 'e': P->d[0] += s; break; case 'a': P->d[0] -= s; break; case 'r': case 'p': P->d[1] += s; break; case 'f': case 'u': P->d[1] -= s; break; case 's': case 'o': P->d[2] += s; break; case 'w': case ',': P->d[2] -= s; break; default: mine = 0; /* Not a viewglut key */ } } else { /* Interpret a key release. */ switch (tolower(k)) { case 'd': case 'e': P->d[0] -= s; break; case 'a': P->d[0] += s; break; case 'r': case 'p': P->d[1] -= s; break; case 'f': case 'u': P->d[1] += s; break; case 's': case 'o': P->d[2] -= s; break; case 'w': case ',': P->d[2] += s; break; default: mine = 0; /* Not a viewglut key */ } } if (mine) { view_move(P->V, P->d); glutPostRedisplay(); } return mine; }