From c985bbe0cd75803ad25a6565e312e08be085b0e8 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Fri, 2 Jun 2017 22:00:53 -0400 Subject: [PATCH] Added a gutter and logic for displaying line numbers. Next step is to calculate and track them... --- config.h | 10 +++++++--- inc/edit.h | 1 + lib/buf.c | 12 ++++++++---- lib/view.c | 4 +++- lib/win.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++--- tide.c | 5 +++++ 6 files changed, 77 insertions(+), 11 deletions(-) diff --git a/config.h b/config.h index f48a0f1..6589ee2 100644 --- a/config.h +++ b/config.h @@ -2,9 +2,10 @@ extern char *FontString, *DefaultTags; extern unsigned int ColorPalette[16]; extern char *ShellCmd[], *SedCmd[], *PickFileCmd[], *PickTagCmd[], *OpenCmd[]; -extern int CLR_NormalText, CLR_SelectedText, CLR_TagsBkg, CLR_EditBkg, - CLR_HorBorder, CLR_VerBorder, CLR_Ruler, CLR_ScrollBkg, CLR_ThumbBkg, - CLR_Cursor; +extern int CLR_NormalText, CLR_GutterText, CLR_SelectedText, CLR_TagsBkg, + CLR_EditBkg, CLR_HorBorder, CLR_VerBorder, CLR_Ruler, CLR_ScrollBkg, + CLR_ThumbBkg, CLR_Cursor; +extern int LineNumbers; /* OS-Specific Config ******************************************************************************/ @@ -81,6 +82,7 @@ unsigned int ColorPalette[16] = { #define COLOR_PAIR(bg, fg) (((bg) << 8) | (fg)) int CLR_NormalText = COLOR_PAIR(0,4); +int CLR_GutterText = COLOR_PAIR(0,3); int CLR_SelectedText = COLOR_PAIR(4,0); int CLR_TagsBkg = 1; // Background color for the tags region int CLR_EditBkg = 0; // Background color for the edit region @@ -91,5 +93,7 @@ int CLR_VerBorder = 2; // Vertical border color int CLR_Ruler = 1; // Ruler color int CLR_Cursor = 7; // Cursor color +int LineNumbers = 1; + #undef INCLUDE_DEFS #endif diff --git a/inc/edit.h b/inc/edit.h index 65e2f2b..4bdfc1c 100644 --- a/inc/edit.h +++ b/inc/edit.h @@ -58,6 +58,7 @@ typedef struct buf { bool copy_indent; /* copy the indent level from the previous line on new lines */ uint transid; /* tracks the last used transaction id for log entries */ void (*errfn)(char*); /* callback for error messages */ + size_t nlines; } Buf; /* cursor/selection representation */ diff --git a/lib/buf.c b/lib/buf.c index 35737b0..cfd20fa 100644 --- a/lib/buf.c +++ b/lib/buf.c @@ -45,6 +45,7 @@ void buf_init(Buf* buf, void (*errfn)(char*)) { buf->undo = NULL; buf->redo = NULL; buf->errfn = errfn; + buf->nlines = 0; assert(buf->bufstart); } @@ -143,7 +144,9 @@ size_t buf_end(Buf* buf) { } size_t buf_insert(Buf* buf, bool fmt, size_t off, Rune rune) { + bool is_eol = (rune == '\n' || rune == RUNE_CRLF); buf->modified = true; + if (is_eol) buf->nlines++; if (fmt && buf->expand_tabs && rune == '\t') { size_t n = (TabWidth - ((off - buf_bol(buf, off)) % TabWidth)); log_insert(buf, &(buf->undo), off, off+n); @@ -155,7 +158,7 @@ size_t buf_insert(Buf* buf, bool fmt, size_t off, Rune rune) { off += n; } } - if (fmt && buf->copy_indent && (rune == '\n' || rune == RUNE_CRLF)) { + if (fmt && buf->copy_indent && is_eol) { size_t beg = buf_bol(buf, off-1), end = beg; for (; end < buf_end(buf) && (' ' == buf_get(buf, end) || '\t' == buf_get(buf, end)); end++); for (; beg < end; beg++) @@ -170,6 +173,8 @@ size_t buf_delete(Buf* buf, size_t beg, size_t end) { log_clear(&(buf->redo)); for (size_t i = end-beg; i > 0; i--) { Rune r = buf_get(buf, beg); + bool is_eol = (r == '\n' || r == RUNE_CRLF); + if (is_eol) buf->nlines--; log_delete(buf, &(buf->undo), beg, &r, 1); delete(buf, beg); } @@ -298,12 +303,13 @@ void buf_getblock(Buf* buf, Rune first, Rune last, Sel* sel) { size_t buf_byrune(Buf* buf, size_t pos, int count) { int move = (count < 0 ? -1 : 1); count *= move; // remove the sign if there is one - for (; count > 0; count--) + for (; count > 0; count--) { if (move < 0) { if (pos > 0) pos--; } else { if (pos < buf_end(buf)) pos++; } + } return pos; } @@ -404,8 +410,6 @@ void buf_lastins(Buf* buf, size_t* beg, size_t* end) { *beg = opbeg, *end = opend; } -/*****************************************************************************/ - size_t buf_setln(Buf* buf, size_t line) { size_t off = 0; while (line > 1 && off < buf_end(buf)) diff --git a/lib/view.c b/lib/view.c index e8cd06f..1c86c58 100644 --- a/lib/view.c +++ b/lib/view.c @@ -434,7 +434,9 @@ static void move_selection(View* view, bool extsel, Sel* sel, int move, movefn_t sel->end = buf_setcol(&(view->buffer), sel->end, sel->col); if (!extsel) sel->beg = sel->end; } - sel->col = buf_getcol(&(view->buffer), sel->end); + /* only update column if not moving vertically */ + if (bything != buf_byline) + sel->col = buf_getcol(&(view->buffer), sel->end); } static void select_context(View* view, bool (*isword)(Rune), Sel* sel) { diff --git a/lib/win.c b/lib/win.c index 8b9fe69..484f89b 100644 --- a/lib/win.c +++ b/lib/win.c @@ -12,6 +12,7 @@ static void onmousedrag(int state, int x, int y); static void onmousebtn(int btn, bool pressed, int x, int y); static void onwheelup(WinRegion id, bool pressed, size_t row, size_t col); static void onwheeldn(WinRegion id, bool pressed, size_t row, size_t col); +static void draw_line_num(size_t x, size_t y, size_t gcols, size_t num); static void draw_glyphs(size_t x, size_t y, UGlyph* glyphs, size_t rlen, size_t ncols); static WinRegion getregion(size_t x, size_t y); @@ -141,6 +142,18 @@ void win_setscroll(double offset, double visible) { ScrollVisible = visible; } +static size_t gutter_cols(void) { + size_t len = 1, lines = win_buf(EDIT)->nlines; + while (LineNumbers && lines > 9) + lines /= 10, len++; + return len; +} + +static size_t gutter_size(void) { + if (!LineNumbers) return 0; + return (gutter_cols() * x11_font_width(Font)) + (LineNumbers ? 5 : 0); +} + static void layout(int width, int height) { size_t fheight = x11_font_height(Font); size_t fwidth = x11_font_width(Font); @@ -176,7 +189,7 @@ static void layout(int width, int height) { Regions[SCROLL].width = 5 + fwidth; /* Place the edit region relative to tags */ - Regions[EDIT].x = 3 + Regions[SCROLL].width; + Regions[EDIT].x = 3 + Regions[SCROLL].width + gutter_size(); Regions[EDIT].y = 5 + Regions[TAGS].y + Regions[TAGS].height; Regions[EDIT].height = (height - Regions[EDIT].y - 5); Regions[EDIT].width = width - Regions[SCROLL].width - 5; @@ -184,9 +197,12 @@ static void layout(int width, int height) { } static void onredraw(int width, int height) { + static uint64_t maxtime = 0; size_t fheight = x11_font_height(Font); size_t fwidth = x11_font_width(Font); + uint64_t start = getmillis(); + layout(width, height); onupdate(); // Let the user program update the status and other content view_update(win_view(STATUS), &(Regions[STATUS].csrx), &(Regions[STATUS].csry)); @@ -199,9 +215,17 @@ static void onredraw(int width, int height) { x11_draw_rect((i == TAGS ? CLR_TagsBkg : CLR_EditBkg), 0, Regions[i].y - 3, width, Regions[i].height + 8); x11_draw_rect(CLR_HorBorder, 0, Regions[i].y - 3, width, 1); - if ((i == EDIT) && (Ruler != 0)) - x11_draw_rect(CLR_Ruler, (Ruler+2) * fwidth, Regions[i].y-2, 1, Regions[i].height+7); + + if (i == EDIT) { + if (Ruler) + x11_draw_rect(CLR_Ruler, (Ruler+2) * fwidth, Regions[i].y-2, 1, Regions[i].height+7); + if (LineNumbers) + x11_draw_rect(CLR_Ruler, Regions[SCROLL].width, Regions[SCROLL].y-2, gutter_size(), Regions[SCROLL].height+7); + } + + size_t gcols = gutter_cols(); for (size_t y = 0; y < view->nrows; y++) { + draw_line_num(Regions[i].x - (gcols * fwidth) - 5, Regions[i].y + ((y+1) * fheight), gcols, (y % 2 ? 123 : 45)); Row* row = view_getrow(view, y); draw_glyphs(Regions[i].x, Regions[i].y + ((y+1) * fheight), row->cols, row->rlen, row->len); } @@ -231,6 +255,15 @@ static void onredraw(int width, int height) { size_t y = Regions[Focused].y + (Regions[Focused].csry * fheight) + (fheight/2); x11_mouse_set(x, y); } + + printf("lines: %llu\n", win_buf(EDIT)->nlines); + + uint64_t stop = getmillis(); + uint64_t elapsed = stop-start; + if (elapsed > maxtime) { + printf("%llu\n", elapsed); + maxtime = elapsed; + } } static void oninput(int mods, Rune key) { @@ -323,6 +356,23 @@ static void onwheeldn(WinRegion id, bool pressed, size_t row, size_t col) { view_scroll(win_view(id), +ScrollLines); } +static void draw_line_num(size_t x, size_t y, size_t gcols, size_t num) { + UGlyph glyphs[gcols]; + if (LineNumbers) { + printf("cols: %lu\n", gcols); + for (int i = gcols-1; i >= 0; i--) { + glyphs[i].attr = CLR_GutterText; + if (num > 0) { + glyphs[i].rune = ((num % 10) + '0'); + num /= 10; + } else { + glyphs[i].rune = ' '; + } + } + draw_glyphs(x, y, glyphs, gcols, gcols); + } +} + static void draw_glyphs(size_t x, size_t y, UGlyph* glyphs, size_t rlen, size_t ncols) { XGlyphSpec specs[rlen]; size_t i = 0; diff --git a/tide.c b/tide.c index 061f16c..71c6553 100644 --- a/tide.c +++ b/tide.c @@ -237,6 +237,10 @@ static void tag_redo(void) { view_redo(win_view(EDIT)); } +static void tag_lnnum(void) { + LineNumbers = !LineNumbers; +} + static void search(void) { char* str; SearchDir *= (x11_keymodsset(ModShift) ? UP : DOWN); @@ -413,6 +417,7 @@ static Tag Builtins[] = { { .tag = "SaveAs", .action.arg = saveas }, { .tag = "Tabs", .action.noarg = tabs }, { .tag = "Undo", .action.noarg = tag_undo }, + { .tag = "LineNums", .action.noarg = tag_lnnum }, { .tag = NULL, .action.noarg = NULL } }; -- 2.49.0