From 5a207b62cebb4673eb3422001e8d9435fca9f545 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Wed, 3 Feb 2021 18:48:26 -0500 Subject: line numbering! --- buffer.c | 68 ++++++++++++++++++++++++++++++++++++++++++------------------- colors.h | 7 ++++++- config.c | 1 + keywords.h | 2 ++ keywords.py | 3 +++ main.c | 3 ++- math.c | 8 ++++++++ ted.cfg | 6 +++++- ted.h | 1 + 9 files changed, 75 insertions(+), 24 deletions(-) diff --git a/buffer.c b/buffer.c index 53d8201..9df8b65 100644 --- a/buffer.c +++ b/buffer.c @@ -1898,8 +1898,8 @@ void buffer_render(TextBuffer *buffer, Rect r) { Ted *ted = buffer->ted; Settings const *settings = buffer_settings(buffer); u32 const *colors = settings->colors; - - float border_thickness = settings->border_thickness; + float const padding = settings->padding; + float const border_thickness = settings->border_thickness; u32 border_color = colors[COLOR_BORDER]; // color of border around buffer @@ -1914,19 +1914,46 @@ void buffer_render(TextBuffer *buffer, Rect r) { x2 -= border_thickness * 0.5f; y2 -= border_thickness * 0.5f; + u32 start_line = (u32)buffer->scroll_y; // line to start rendering from + float render_start_y = y1 - (float)(buffer->scroll_y - start_line) * char_height; // where the 1st line is rendered + + // line numbering + if (!buffer->is_line_buffer && settings->line_numbers) { + float line_number_width = ndigits_u64(buffer->nlines) * char_width + padding; + + TextRenderState text_state = text_render_state_default; + text_state.min_y = y1; + text_state.max_y = y2; + + float y = render_start_y; + text_chars_begin(font); + gl_color_rgba(colors[COLOR_LINE_NUMBERS]); + for (u32 line = start_line; line < buffer->nlines; ++line) { + char str[32] = {0}; + strbuf_printf(str, U32_FMT, line + 1); // convert line number to string + float x = x1 + line_number_width - (float)strlen(str) * char_width; // right justify + text_render_with_state(font, &text_state, str, x, y); + y += char_height; + if (y > y2) break; + } + text_chars_end(font); + + x1 += line_number_width; + x1 += 2; // a little bit of padding + // line separating line numbers from text + glBegin(GL_LINES); + gl_color_rgba(colors[COLOR_LINE_NUMBERS_SEPARATOR]); + glVertex2f(x1, y1); + glVertex2f(x1, y2); + glEnd(); + x1 += padding; + } // get screen coordinates of cursor v2 cursor_display_pos = buffer_pos_to_pixels(buffer, buffer->cursor_pos); // the rectangle that the cursor is rendered as Rect cursor_rect = rect(cursor_display_pos, V2(settings->cursor_width, char_height)); - TextRenderState text_state = { - .x = 0, .y = 0, - .min_x = x1, .min_y = y1, - .max_x = x2, .max_y = y2, - .render = true - }; - buffer->x1 = x1; buffer->y1 = y1; buffer->x2 = x2; buffer->y2 = y2; @@ -1945,7 +1972,6 @@ void buffer_render(TextBuffer *buffer, Rect r) { float render_start_x = x1 - (float)buffer->scroll_x * char_width; u32 column = 0; - u32 start_line = (u32)buffer->scroll_y; // line to start rendering from if (buffer->selection) { // draw selection glBegin(GL_QUADS); @@ -1992,17 +2018,6 @@ void buffer_render(TextBuffer *buffer, Rect r) { } - text_chars_begin(font); - - text_state = (TextRenderState){ - .x = render_start_x, .y = y1, - .min_x = x1, .min_y = y1, - .max_x = x2, .max_y = y2, - .render = true - }; - - text_state.y -= (float)(buffer->scroll_y - start_line) * char_height; - Language language = buffer_language(buffer); // dynamic array of character types, to be filled by syntax_highlight SyntaxCharType *char_types = NULL; @@ -2035,6 +2050,17 @@ void buffer_render(TextBuffer *buffer, Rect r) { buffer->longest_line_on_screen = 0; + + text_chars_begin(font); + + TextRenderState text_state = text_render_state_default; + text_state.x = render_start_x; + text_state.y = render_start_y; + text_state.min_x = x1; + text_state.min_y = y1; + text_state.max_x = x2; + text_state.max_y = y2; + for (u32 line_idx = start_line; line_idx < nlines; ++line_idx) { Line *line = &lines[line_idx]; buffer->longest_line_on_screen = max_u32(buffer->longest_line_on_screen, line->len); diff --git a/colors.h b/colors.h index 28f9951..374d652 100644 --- a/colors.h +++ b/colors.h @@ -31,6 +31,9 @@ ENUM_U16 { COLOR_CHARACTER, COLOR_CONSTANT, + COLOR_LINE_NUMBERS, + COLOR_LINE_NUMBERS_SEPARATOR, + COLOR_COUNT } ENUM_U16_END(ColorSetting); @@ -67,7 +70,9 @@ static ColorName const color_names[COLOR_COUNT] = { {COLOR_CONSTANT, "constant"}, {COLOR_YES, "yes"}, {COLOR_NO, "no"}, - {COLOR_CANCEL, "cancel"} + {COLOR_CANCEL, "cancel"}, + {COLOR_LINE_NUMBERS, "line-numbers"}, + {COLOR_LINE_NUMBERS_SEPARATOR, "line-numbers-separator"}, }; static ColorSetting color_setting_from_str(char const *str) { diff --git a/config.c b/config.c index 15b787d..b389867 100644 --- a/config.c +++ b/config.c @@ -175,6 +175,7 @@ void config_read(Ted *ted, char const *filename) { {"auto-indent", &settings->auto_indent}, {"auto-add-newline", &settings->auto_add_newline}, {"syntax-highlighting", &settings->syntax_highlighting}, + {"line-numbers", &settings->line_numbers}, }; OptionU8 const options_u8[] = { {"tab-width", &settings->tab_width, 1, 100}, diff --git a/keywords.h b/keywords.h index 56417c4..5906c6f 100644 --- a/keywords.h +++ b/keywords.h @@ -1,3 +1,5 @@ +// keywords for all languages ted supports +// This file was auto-generated by keywords.py typedef struct { char const *str; SyntaxCharType type; diff --git a/keywords.py b/keywords.py index cbe704e..951f3b2 100755 --- a/keywords.py +++ b/keywords.py @@ -217,6 +217,9 @@ builtins_python = ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseE ] file = open('keywords.h', 'w') +file.write('''// keywords for all languages ted supports +// This file was auto-generated by keywords.py +''') file.write('''typedef struct { char const *str; SyntaxCharType type; diff --git a/main.c b/main.c index 3ad3786..2a7fc1a 100644 --- a/main.c +++ b/main.c @@ -1,9 +1,10 @@ // @TODO: -// - line numbering // - popup to reload files and config on change +// - shouldn't be possible to open the same file twice // - find & replace (with regex) // - split // - completion +// - view-only // - Windows installation #include "base.h" no_warn_start diff --git a/math.c b/math.c index c177eef..1443267 100644 --- a/math.c +++ b/math.c @@ -70,6 +70,14 @@ static inline u32 clamp_u32(u32 x, u32 a, u32 b) { return x; } +static inline u8 ndigits_u64(u64 x) { + u8 ndigits = 1; + while (x > 9) { + x /= 10; + ++ndigits; + } + return ndigits; +} // remap x from the interval [from_a, from_b] to the interval [to_a, to_b], NOT clamping if x is outside the "from" interval. static inline float remapf(float x, float from_a, float from_b, float to_a, float to_b) { diff --git a/ted.cfg b/ted.cfg index 6091a47..325c444 100644 --- a/ted.cfg +++ b/ted.cfg @@ -20,6 +20,7 @@ auto-indent = on # automatically add a newline at the end of the file on save auto-add-newline = on syntax-highlighting = on +line-numbers = on [keyboard] # motion and selection @@ -140,8 +141,11 @@ builtin = #a7f comment = #999 constant = #8ff +line-numbers = #779 +line-numbers-separator = #fff3 + [extensions] C = .c, .h C++ = .cpp, .hpp, .C, .H, .cxx, .hxx, .cc, .hh Rust = .rs -Python = .py \ No newline at end of file +Python = .py diff --git a/ted.h b/ted.h index 646da6d..b0e6f6a 100644 --- a/ted.h +++ b/ted.h @@ -70,6 +70,7 @@ typedef struct { bool auto_indent; bool auto_add_newline; bool syntax_highlighting; + bool line_numbers; u8 tab_width; u8 cursor_width; u8 undo_save_time; -- cgit v1.2.3