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
******************************************************************************/
#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
int CLR_Ruler = 1; // Ruler color
int CLR_Cursor = 7; // Cursor color
+int LineNumbers = 1;
+
#undef INCLUDE_DEFS
#endif
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 */
buf->undo = NULL;
buf->redo = NULL;
buf->errfn = errfn;
+ buf->nlines = 0;
assert(buf->bufstart);
}
}
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);
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++)
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);
}
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;
}
*beg = opbeg, *end = opend;
}
-/*****************************************************************************/
-
size_t buf_setln(Buf* buf, size_t line) {
size_t off = 0;
while (line > 1 && off < buf_end(buf))
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) {
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);
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);
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;
}
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));
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);
}
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) {
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;
view_redo(win_view(EDIT));
}
+static void tag_lnnum(void) {
+ LineNumbers = !LineNumbers;
+}
+
static void search(void) {
char* str;
SearchDir *= (x11_keymodsset(ModShift) ? UP : DOWN);
{ .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 }
};