чување 8b6662d7a94f3114542dc1ca40824aa0cb2da23f
родитељ 3c86365a3ce4610d63d4d58eda98ce3fc31bffe7
Аутор: Страхиња Радић <sr@strahinja.org>
Датум: Wed, 10 Jul 2024 23:51:42 +0200
Dynamically compute max line number width at runtime
Diffstat:
измењених датотека: 5, додавања: 78(+), брисања: 29(-)
diff --git a/TODO b/TODO
@@ -6,7 +6,7 @@ TODO
[ ] Add shortcut key which toggles showing line numbers at runtime
(default state still configured in config.h)
-[ ] (vis-like:) Dynamically compute max line number at runtime (number
+[x] (vis-like:) Dynamically compute max line number at runtime (number
of digits in the number of the last line drawn on screen)
[~] Code optimization (struct coord...)
diff --git a/config.def.h b/config.def.h
@@ -54,7 +54,6 @@ const char* backup_suffix = "~";
const int create_backups = 1;
const int enable_wrap = 1;
const int line_numbers = 0; /* draw line numbers? */
-const int line_numbers_width = 6; /* number of glyphs for line numbers */
/* - ideally, wrap_width + line_numbers_width <= 80 */
/* - wrap width of 72 is recommended on https://useplaintext.email/ */
const int wrap_width = 72;
diff --git a/draw.c b/draw.c
@@ -75,6 +75,18 @@ const char* actions[] = {
[ACT_READING] = "Reading...",
[ACT_WRAPPING] = "Wrapping..."
};
+const struct {
+ ssize_t boundary;
+ int width;
+} number_widths[] = {
+ { .boundary = 9999999, .width = 8 },
+ { .boundary = 999999, .width = 7 },
+ { .boundary = 99999, .width = 6 },
+ { .boundary = 9999, .width = 5 },
+ { .boundary = 999, .width = 4 },
+ { .boundary = 99, .width = 3 },
+ { .boundary = 9, .width = 2 }
+};
const char* go_to_dialog_title = "Go to line";
const char* replace_dialog_title = "Replace with";
const char* search_dialog_title = "Search text";
@@ -130,6 +142,23 @@ calculate_input_dialog_width(const struct DrawState* state)
: state->maxx - 2;
}
+int
+calculate_line_numbers_width(const struct DrawState* state)
+{
+ ssize_t last_row;
+ int i;
+ last_row = MIN(state->rows_count,
+ state->first_shown.row + state->maxy - 1);
+ i = 0;
+ while ((size_t)i < LEN(number_widths))
+ {
+ if (last_row > number_widths[i].boundary)
+ return number_widths[i].width;
+ i++;
+ }
+ return 1;
+}
+
/* Calculates display length of a buffer line.
* max_index = the buffer index up to which the length is calculated
*/
@@ -292,6 +321,25 @@ draw_input_dialog(const struct DrawState* state)
}
void
+draw_line_number(const struct DrawState* state, const int i, const int cy)
+{
+ char numbuf[LINE_DEFAULT];
+ char* numbuf_end = NULL;
+ char* pnumbuf = NULL;
+ snprintf(numbuf, LINE_DEFAULT, "%d", i + 1);
+ numbuf_end = strchr(numbuf, 0);
+ if (numbuf_end)
+ {
+ pnumbuf = numbuf_end - numbuf > state->line_numbers_width
+ ? numbuf_end - state->line_numbers_width
+ : numbuf;
+ draw_string(0, cy, LINENO_FG, LINENO_BG, pnumbuf,
+ numbuf_end - numbuf + 1, state->line_numbers_width, 0,
+ 0, RIGHT, 0, 1, NULL, 0, 0, 0, 0, 0, 0);
+ }
+}
+
+void
draw_rect(const int startx, const int endx, const int starty, const int endy,
const uint16_t fg, const uint16_t bg)
{
@@ -323,7 +371,7 @@ draw_screen(const struct DrawState* state)
maxx = state->maxx;
if (line_numbers)
- maxx -= line_numbers_width;
+ maxx -= state->line_numbers_width;
if (state->rows_count == 0)
return 0;
@@ -357,29 +405,12 @@ draw_screen(const struct DrawState* state)
sei = sec;
}
}
-
if (line_numbers)
- {
- char numbuf[LINE_DEFAULT];
- char* numbuf_end = NULL;
- char* pnumbuf = NULL;
- snprintf(numbuf, LINE_DEFAULT, "%d", i + 1);
- numbuf_end = strchr(numbuf, 0);
- if (numbuf_end)
- {
- pnumbuf = numbuf_end - numbuf
- > line_numbers_width
- ? numbuf_end - line_numbers_width
- : numbuf;
- draw_string(0, cy, LINENO_FG, LINENO_BG,
- pnumbuf, numbuf_end - numbuf + 1,
- line_numbers_width, 0, 0, RIGHT, 0, 1,
- NULL, 0, 0, 0, 0, 0, 0);
- }
- }
+ draw_line_number(state, i, cy);
if (current->text)
- u32_draw_string(line_numbers ? line_numbers_width + 2
- : 0,
+ u32_draw_string(line_numbers
+ ? state->line_numbers_width + 2
+ : 0,
cy, TEXT_FG, TEXT_BG, current->text, maxx, maxx,
0, 0, CENTER, state->first_shown.col, 0,
state->search, SEARCH_FG, SEARCH_BG, ssi, sei,
@@ -389,7 +420,7 @@ draw_screen(const struct DrawState* state)
}
tb_set_cursor(line_numbers
- ? line_numbers_width + 2 + state->display_column
+ ? state->line_numbers_width + 2 + state->display_column
- state->first_shown.col
: state->display_column - state->first_shown.col,
state->coord.row - state->first_shown.row);
@@ -683,12 +714,19 @@ init_drawstate(struct DrawState* state, char* error, char* action,
}
void
+recalculate_line_numbers(struct DrawState* state)
+{
+ state->line_numbers_width = calculate_line_numbers_width(state);
+}
+
+void
recalculate_size(struct DrawState* state)
{
state->maxx = tb_width();
state->help_width = calculate_help_width(state);
state->input_dialog_width = calculate_input_dialog_width(state);
state->maxy = tb_height();
+ recalculate_line_numbers(state);
}
void
diff --git a/draw.h b/draw.h
@@ -77,6 +77,7 @@ struct DrawState {
int saved_column; /* display coordinate */
int help_width; /* display parameter */
int input_dialog_width; /* display parameter */
+ int line_numbers_width;
struct BufferLine* paste;
ssize_t paste_count;
ssize_t paste_size;
@@ -119,6 +120,7 @@ void draw_box(const int startx, const int endx, const int starty,
const int endy, const uint16_t fg, const uint16_t bg);
int draw_help(const struct DrawState* state);
int draw_input_dialog(const struct DrawState* state);
+void draw_line_numbers(const struct DrawState* state);
void draw_rect(const int startx, const int endx, const int starty,
const int endy, const uint16_t fg, const uint16_t bg);
int draw_screen(const struct DrawState* state);
@@ -143,6 +145,7 @@ void init_coord(struct Coord* c, const int col, const int row);
void init_drawstate(struct DrawState* state, char* error, char* action,
char* filename, char* prompt, const int skip_paste_and_mode_init,
const int skip_filenames_init);
+void recalculate_line_numbers(struct DrawState* state);
void recalculate_size(struct DrawState* state);
void redraw_status(struct DrawState* state);
void u32_draw_string(const int x, const int y, const uint16_t fg,
diff --git a/sled.c b/sled.c
@@ -189,8 +189,9 @@ create_file(struct DrawState* state)
state->buffer = newchunk;
state->buffer_size = ALLOC_DELTA;
state->rows_count = 1;
- state->coord.row = 0;
- state->dirty = 1;
+ recalculate_line_numbers(state);
+ state->coord.row = 0;
+ state->dirty = 1;
return LOAD_ERR_NONE;
}
@@ -431,6 +432,7 @@ erase_line(struct DrawState* state)
position_to(state, state->coord.row, 0);
state->rows_count--;
state->dirty = 1;
+ recalculate_line_numbers(state);
return 0;
erase_line_error:
@@ -515,6 +517,7 @@ erase_selection(struct DrawState* state)
state->buffer[row].length = 0;
}
state->rows_count -= ser - ssr;
+ recalculate_line_numbers(state);
}
free(buf);
state->dirty = 1;
@@ -1330,6 +1333,7 @@ load_file(struct DrawState* state)
state->rows_count++;
free(input_line);
+ recalculate_line_numbers(state);
return LOAD_ERR_NONE;
load_file_alloc_error:
@@ -1675,7 +1679,8 @@ static void
position_to(struct DrawState* state, const int row, const int column)
{
ssize_t dlen;
-
+ int old_first_shown_row;
+ old_first_shown_row = state->first_shown.row;
if (row != state->coord.row)
{
state->coord.row = row;
@@ -1746,6 +1751,8 @@ position_to(struct DrawState* state, const int row, const int column)
if (state->first_shown.col + (state->maxx - 1) < state->display_column)
state->first_shown.col
= state->display_column - (state->maxx - 1);
+ if (old_first_shown_row != state->first_shown.row)
+ recalculate_line_numbers(state);
if (IN(state->mode, M_SELECTION))
assign_coord(&state->sel_end, state->coord);
@@ -2263,6 +2270,7 @@ simple_insert_line(struct DrawState* state)
state->buffer[state->coord.row].length = state->coord.col;
state->dirty = 1;
+ recalculate_line_numbers(state);
return;
simple_insert_line_error:
@@ -2302,6 +2310,7 @@ simple_join_lines(struct DrawState* state)
free_bufferline(&state->buffer[state->rows_count - 1]);
state->rows_count--;
state->dirty = 1;
+ recalculate_line_numbers(state);
return;
simple_join_lines_error:
@@ -2688,6 +2697,7 @@ wrap_not_enabled:
MEMCCPY(state->error, errors[ERR_NOT_IMP], LINE_DEFAULT, temp);
wrap_success:
+ recalculate_line_numbers(state);
return 0;
wrap_alloc_error:
@@ -2805,7 +2815,6 @@ main(int argc, char** argv)
printf(" enable_wrap:\t\t%s\n", enable_wrap ? "set" : "unset");
printf(" line_numbers:\t\t%s\n",
line_numbers ? "set" : "unset");
- printf(" line_numbers_width:\t%d\n", line_numbers_width);
printf(" wrap_width:\t\t%d\n", wrap_width);
return 0;
}