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; /* tracks number of lines in the buffer */
} Buf;
/* cursor/selection representation */
} UGlyph;
typedef struct {
- size_t line; /* the line number of the data in the row */
size_t off; /* offset of the first rune in the row */
size_t rlen; /* number of runes displayed in the row */
size_t len; /* number of screen columns taken up by row */
int clrnor, clrsel; /* text color pairs for normal and selected text */
bool sync_needed; /* whether the view needs to be synced with cursor */
bool sync_center; /* cursor should be centered on screen if possible */
- bool sync_lines; /* whether the line numbers should be recalculated */
} View;
enum {
extern char TagString[], FontString[];
extern int Palette[16];
extern int WinWidth, WinHeight, LineSpacing, RulerPos, Timeout, TabWidth, ScrollBy,
- ClickTime, MaxScanDist, LineNums, Syntax, CopyIndent, TrimOnSave, ExpandTabs;
+ ClickTime, MaxScanDist, Syntax, CopyIndent, TrimOnSave, ExpandTabs;
extern CPair Colors[28];
enum { /* Color Variables */
void win_save(char* path);
void win_loop(void);
void win_settext(WinRegion id, char* text);
-void win_setlinenums(bool enable);
-bool win_getlinenums(void);
void win_setruler(size_t ruler);
Rune win_getkey(void);
void win_setkeys(KeyBinding* bindings, void (*inputfn)(Rune));
buf->undo = NULL;
buf->redo = NULL;
buf->errfn = errfn;
- buf->nlines = 0;
assert(buf->bufstart);
}
static void delete(Buf* buf, size_t off) {
Rune rune = buf_get(buf, off);
- if (rune == RUNE_CRLF || rune == '\n')
- buf->nlines--;
syncgap(buf, off);
buf->gapend++;
}
static size_t insert(Buf* buf, size_t off, Rune rune) {
size_t rcount = 1;
syncgap(buf, off);
- if (rune == '\n' || rune == RUNE_CRLF) buf->nlines++;
if (buf->crlf && rune == '\n' && buf_get(buf, off-1) == '\r') {
rcount = 0;
*(buf->gapstart-1) = RUNE_CRLF;
ScrollBy = 4,
ClickTime = 500,
MaxScanDist = 0,
- LineNums = ON,
Syntax = ON,
CopyIndent = ON,
TrimOnSave = ON,
[ClrEditRul] = { .bg = 0, .fg = 1 },
[ClrBorders] = { .bg = 3, .fg = 3 },
/* Syntax Colors */
- [SynNormal] = { .bg = 0, .fg = 5 },
- [SynComment] = { .bg = 0, .fg = 3 },
- [SynConstant] = { .bg = 0, .fg = 14 },
- [SynNumber] = { .bg = 0, .fg = 14 },
- [SynBoolean] = { .bg = 0, .fg = 14 },
- [SynFloat] = { .bg = 0, .fg = 14 },
- [SynString] = { .bg = 0, .fg = 10 },
- [SynChar] = { .bg = 0, .fg = 10 },
- [SynPreProc] = { .bg = 0, .fg = 8 },
- [SynType] = { .bg = 0, .fg = 13 },
- [SynKeyword] = { .bg = 0, .fg = 8 },
- [SynStatement] = { .bg = 0, .fg = 15 },
- [SynFunction] = { .bg = 0, .fg = 13 },
- [SynVariable] = { .bg = 0, .fg = 8 },
- [SynSpecial] = { .bg = 0, .fg = 15 },
- [SynOperator] = { .bg = 0, .fg = 12 },
+ [SynNormal] = { .fg = 5 },
+ [SynComment] = { .fg = 3 },
+ [SynConstant] = { .fg = 14 },
+ [SynNumber] = { .fg = 14 },
+ [SynBoolean] = { .fg = 14 },
+ [SynFloat] = { .fg = 14 },
+ [SynString] = { .fg = 10 },
+ [SynChar] = { .fg = 10 },
+ [SynPreProc] = { .fg = 8 },
+ [SynType] = { .fg = 13 },
+ [SynKeyword] = { .fg = 8 },
+ [SynStatement] = { .fg = 15 },
+ [SynFunction] = { .fg = 13 },
+ [SynVariable] = { .fg = 8 },
+ [SynSpecial] = { .fg = 15 },
+ [SynOperator] = { .fg = 12 },
};
static void find_cursor(View* view, size_t* csrx, size_t* csry);
static void clearrow(View* view, size_t row);
static size_t setcell(View* view, size_t row, size_t col, uint32_t attr, Rune r);
-static size_t fill_row(View* view, unsigned row, size_t pos, size_t* line);
+static size_t fill_row(View* view, unsigned row, size_t pos);
static unsigned prev_screen_line(View* view, unsigned bol, unsigned off);
static unsigned scroll_up(View* view);
static unsigned scroll_dn(View* view);
view->selection = (Sel){ 0 };
view->sync_needed = true;
view->sync_center = true;
- view->sync_lines = true;
view->prev_csr = 0;
/* load the file and jump to the address returned from the load function */
buf_init(&(view->buffer), errfn);
view->clrnor = clrnor, view->clrsel = clrsel;
size_t csr = view->selection.end;
/* scroll the view and reflow the screen lines */
- size_t pos = view->rows[0]->off, line = view->rows[0]->line;
- if (!line || view->sync_lines) {
- line = buf_getln(&(view->buffer), buf_bol(&(view->buffer), pos));
- view->sync_lines = false;
- }
+ size_t pos = view->rows[0]->off;
/* fill the view and scroll if needed */
for (size_t y = 0; y < view->nrows; y++)
- pos = fill_row(view, y, pos, &line);
+ pos = fill_row(view, y, pos);
if (view->sync_needed)
view_scrollto(view, csr);
/* locate the cursor if visible */
view->prev_csr = view->selection.end;
buf_undo(&(view->buffer), &(view->selection));
view->sync_needed = true;
- view->sync_lines = true;
view->sync_center = !selection_visible(view);
}
view->prev_csr = view->selection.end;
buf_redo(&(view->buffer), &(view->selection));
view->sync_needed = true;
- view->sync_lines = true;
view->sync_center = !selection_visible(view);
}
return ncols;
}
-static size_t fill_row(View* view, unsigned row, size_t pos, size_t* line) {
+static size_t fill_row(View* view, unsigned row, size_t pos) {
view_getrow(view, row)->off = pos;
- if (line) {
- if (pos > buf_end(&(view->buffer)))
- *line = 0;
- view_getrow(view, row)->line = *line;
- }
clearrow(view, row);
for (size_t x = 0; x < view->ncols;) {
uint32_t attr = (in_selection(view->selection, pos) ? view->clrsel : view->clrnor);
Rune r = buf_get(&(view->buffer), pos++);
x += setcell(view, row, x, attr, r);
if (buf_iseol(&(view->buffer), pos-1)) {
- if (line) *line += 1;
break;
}
}
size_t first = view->rows[0]->off;
size_t bol = buf_bol(&(view->buffer), first);
size_t prevln = (first == bol ? buf_byline(&(view->buffer), bol, UP) : bol);
- size_t linenum = (prevln < bol ? view->rows[0]->line-1 : view->rows[0]->line);
if (!first) return first;
prevln = prev_screen_line(view, prevln, first);
/* delete the last row and shift the others */
memmove(&view->rows[1], &view->rows[0], sizeof(Row*) * (view->nrows-1));
view->rows[0] = calloc(1, sizeof(Row) + (view->ncols * sizeof(UGlyph)));
view->rows[0]->off = prevln;
- view->rows[0]->line = linenum;
/* fill in row content */
- fill_row(view, 0, view->rows[0]->off, NULL);
+ fill_row(view, 0, view->rows[0]->off);
return view->rows[0]->off;
}
static unsigned scroll_dn(View* view) {
size_t last = view->rows[view->nrows-1]->off + view->rows[view->nrows-1]->rlen - 1;
- size_t line = view->rows[view->nrows-1]->line;
if (last >= buf_end(&(view->buffer))) return last;
/* delete the first row and shift the others */
if (view->nrows > 1) {
view->rows[view->nrows-1] = calloc(1, sizeof(Row) + (view->ncols * sizeof(UGlyph)));
view->rows[view->nrows-1]->off = (view->rows[view->nrows-2]->off + view->rows[view->nrows-2]->rlen);
/* fill in row content */
- fill_row(view, view->nrows-1, view->rows[view->nrows-1]->off, NULL);
+ fill_row(view, view->nrows-1, view->rows[view->nrows-1]->off);
} else {
view->rows[0]->off += view->rows[0]->rlen;
- fill_row(view, 0, view->rows[0]->off, NULL);
+ fill_row(view, 0, view->rows[0]->off);
}
- view->rows[view->nrows-1]->line = (buf_iseol(&(view->buffer), last) ? line+1 : line);
return view->rows[view->nrows-1]->off + view->rows[view->nrows-1]->rlen - 1;
}
static void sync_line_numbers(View* view, size_t newpos) {
if (!view->nrows || newpos <= view->rows[0]->off) {
- view->sync_lines = true;
if (view->nrows)
view->rows[0]->off = buf_bol(&(view->buffer), newpos);
}
static Rune LastKey;
static KeyBinding* Keys = NULL;
static void (*InputFunc)(Rune);
-static bool ShowLineNumbers = false;
static void win_init(void (*errfn)(char*)) {
for (int i = 0; i < SCROLL; i++)
buf_logclear(&(view->buffer));
}
-void win_setlinenums(bool enable) {
- ShowLineNumbers = enable;
-}
-
-bool win_getlinenums(void) {
- return ShowLineNumbers;
-}
-
void win_setruler(size_t ruler) {
Ruler = ruler;
}
ScrollVisible = visible;
}
-static size_t gutter_cols(void) {
- size_t len = 0, lines = win_buf(EDIT)->nlines + 1;
- while (ShowLineNumbers && lines)
- lines /= 10, len++;
- return len;
-}
-
-static size_t gutter_size(void) {
- return (gutter_cols() * x11_font_width(Font)) + (ShowLineNumbers ? 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 + gutter_size();
+ Regions[EDIT].x = 3 + Regions[SCROLL].width;
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;
- view_resize(editview, Regions[EDIT].height / fheight, Regions[EDIT].width / fwidth - gutter_cols());
+ view_resize(editview, Regions[EDIT].height / fheight, Regions[EDIT].width / fwidth);
}
static void onredraw(int width, int height) {
x11_draw_rect(clr_hbor, 0, Regions[i].y - 3, width, 1);
if (i == EDIT) {
- size_t gsz = gutter_size();
if (Ruler)
- x11_draw_rect( Colors[ClrEditRul].bg,
- ((Ruler+2) * fwidth) + gsz,
+ x11_draw_rect( Colors[ClrEditRul].fg,
+ ((Ruler+2) * fwidth),
Regions[i].y-2,
1,
Regions[i].height+7 );
- if (ShowLineNumbers)
- x11_draw_rect( Colors[ClrGutterNor].bg,
- Regions[SCROLL].width,
- Regions[SCROLL].y-2,
- gsz,
- Regions[SCROLL].height+7 );
}
- size_t gcols = gutter_cols();
for (size_t line = 0, y = 0; y < view->nrows; y++) {
Row* row = view_getrow(view, y);
- draw_line_num( (y == Regions[i].csry),
- Regions[i].x - (gcols * fwidth) - 5,
- Regions[i].y + ((y+1) * fheight),
- gcols,
- (line != row->line ? row->line : 0) );
draw_glyphs(Regions[i].x, Regions[i].y + ((y+1) * fheight), row->cols, row->rlen, row->len);
- line = row->line;
}
}
return changed;
}
-static void draw_line_num(bool current, size_t x, size_t y, size_t gcols, size_t num) {
- int color = (Colors[ClrGutterNor].bg << 8 | Colors[ClrGutterNor].fg);
- if (!gcols) return;
- if (current) {
- color = (Colors[ClrGutterSel].bg << 8 | Colors[ClrGutterSel].fg);
- size_t fheight = x11_font_height(Font);
- x11_draw_rect(Colors[ClrGutterSel].bg, x-3, y-fheight, gutter_size(), fheight);
- }
- UGlyph glyphs[gcols];
- for (int i = gcols-1; i >= 0; i--) {
- glyphs[i].attr = color;
- 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) {
- win_setlinenums(!win_getlinenums());
-}
-
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 }
+ { .tag = NULL, .action.noarg = NULL }
};
static KeyBinding Bindings[] = {
/* now create the window and start the event loop */
win_settext(TAGS, TagString);
win_setruler(RulerPos);
- win_setlinenums(LineNums);
win_setkeys(Bindings, oninput);
win_loop();
return 0;