From: Michael D. Lowis Date: Sat, 10 Jun 2017 00:41:40 +0000 (-0400) Subject: optimized color scanning so that large files still perform reasonably X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=7d0166d45c0d27f5853f979d82afb298533fa257;p=projs%2Ftide.git optimized color scanning so that large files still perform reasonably --- diff --git a/inc/edit.h b/inc/edit.h index 1c699be..a6d959b 100644 --- a/inc/edit.h +++ b/inc/edit.h @@ -141,7 +141,8 @@ typedef struct SyntaxSpan { } SyntaxSpan; SyntaxDef* colors_find(char* path); -SyntaxSpan* colors_scan(SyntaxDef* syntax, Buf* buf); +SyntaxSpan* colors_scan(SyntaxDef* syntax, SyntaxSpan* spans, Buf* buf, size_t beg, size_t end); +SyntaxSpan* colors_rewind(SyntaxSpan* spans, size_t first); /* Screen management functions *****************************************************************************/ diff --git a/lib/colors.c b/lib/colors.c index 5f77de0..8fb27bf 100644 --- a/lib/colors.c +++ b/lib/colors.c @@ -65,11 +65,10 @@ static SyntaxSpan* mkspan(size_t beg, size_t end, size_t clr, SyntaxSpan* span) return newspan; } -SyntaxSpan* colors_scan(SyntaxDef* syntax, Buf* buf) { - SyntaxSpan* firstspan = NULL; - SyntaxSpan* spans = NULL; - if (!syntax) return spans; - for (size_t end = buf_end(buf), off = 0; off < end; off++) { +SyntaxSpan* colors_scan(SyntaxDef* syntax, SyntaxSpan* spans, Buf* buf, size_t beg, size_t end) { + SyntaxSpan* firstspan = spans; + if (!syntax) return firstspan; + for (size_t off = beg; off < end; off++) { size_t start = off; if (matches(buf, &off, syntax->comments.line_beg)) for (; off < end && !buf_iseol(buf, off); off++); @@ -82,3 +81,27 @@ SyntaxSpan* colors_scan(SyntaxDef* syntax, Buf* buf) { } return firstspan; } + +SyntaxSpan* colors_rewind(SyntaxSpan* spans, size_t first) { + /* rewind to the first span that start before visible space */ + while (spans && spans->beg >= first && spans->prev) + spans = spans->prev; + + /* if we're on the first one, setup to return NULL, otherwise return the + previous one because we're about to regenerate the current one and + everything after it */ + SyntaxSpan* ret = (spans ? spans->prev : NULL); + + /* ok now free the rest of the list */ + while (spans) { + SyntaxSpan* dead = spans; + spans = dead->next; + free(dead); + } + + /* make sure we clear out the next link */ + if (ret) ret->next = NULL; + + return ret; +} + diff --git a/lib/view.c b/lib/view.c index ee1e91d..5ee56bf 100644 --- a/lib/view.c +++ b/lib/view.c @@ -23,6 +23,7 @@ static unsigned scroll_dn(View* view); static void sync_center(View* view, size_t csr); static size_t getoffset(View* view, size_t row, size_t col); static void sync_line_numbers(View* view); +static void apply_colors(View* view); void view_init(View* view, char* file, void (*errfn)(char*)) { if (view->nrows) { @@ -95,40 +96,21 @@ void view_update(View* view, size_t* csrx, size_t* csry) { line = buf_getln(&(view->buffer), buf_bol(&(view->buffer), pos)); view->sync_lines = false; } - + /* fill the view and scroll if needed */ for (size_t y = 0; y < view->nrows; y++) pos = fill_row(view, y, pos, &line); if (view->sync_needed) view_scrollto(view, csr); /* locate the cursor if visible */ find_cursor(view, csrx, csry); - - view->spans = colors_scan(view->syntax, &(view->buffer)); - SyntaxSpan* curr = view->spans; - for (size_t r = 0; curr && r < view->nrows; r++) { - Row* row = view->rows[r]; - size_t off = row->off, col = 0; - while (col < row->len) { - /* skip irrelevant highlight regions */ - for (; curr && curr->end < off; curr = curr->next); - if (!curr) { r = -1; break; } // Break both loops if we're done - - /* check if we're in the current region */ - if (curr->beg <= off && off <= curr->end && !(row->cols[col].attr & 0xFF00)) { - uint32_t attr = row->cols[col].attr; - row->cols[col].attr = (row->cols[col].attr & 0xFF00) | curr->color; - } - off++, col++; - while (col < row->len && row->cols[col].rune == '\0') - col++; - } - } - - while (view->spans) { - SyntaxSpan* deadite = view->spans; - view->spans = deadite->next; - free(deadite); - } + /* synchronize, scan for, and apply highlighted regions */ + size_t first = (view->nrows ? view->rows[0]->off : 0), + last = buf_end(&(view->buffer)); + if (view->nrows) + last = view->rows[view->nrows-1]->off + view->rows[view->nrows-1]->rlen; + view->spans = colors_rewind(view->spans, first); + view->spans = colors_scan(view->syntax, view->spans, &(view->buffer), first, last+1); + apply_colors(view); } Row* view_getrow(View* view, size_t row) { @@ -690,3 +672,26 @@ static void sync_line_numbers(View* view) { view->selection.end <= view->rows[0]->off) view->sync_lines = true; } + +static void apply_colors(View* view) { + SyntaxSpan* curr = view->spans; + for (size_t r = 0; curr && r < view->nrows; r++) { + Row* row = view->rows[r]; + size_t off = row->off, col = 0; + while (col < row->len) { + /* skip irrelevant highlight regions */ + for (; curr && curr->end < off; curr = curr->next); + if (!curr) { r = -1; break; } // Break both loops if we're done + + /* check if we're in the current region */ + if (curr->beg <= off && off <= curr->end && !(row->cols[col].attr & 0xFF00)) { + uint32_t attr = row->cols[col].attr; + row->cols[col].attr = (row->cols[col].attr & 0xFF00) | curr->color; + } + off++, col++; + while (col < row->len && row->cols[col].rune == '\0') + col++; + } + } + +}