tAdd rudimentary support for extra line spacing - ledit - Text editor (WIP) | |
git clone git://lumidify.org/ledit.git (fast, but not encrypted) | |
git clone https://lumidify.org/git/ledit.git (encrypted, but very slow) | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit a3b601c93fde71dd598f855980897a1e3ead492e | |
parent 7a93ac1c6f53c9464eb548bef555f22da0d9bbac | |
Author: lumidify <[email protected]> | |
Date: Mon, 2 Oct 2023 10:49:08 +0200 | |
Add rudimentary support for extra line spacing | |
Diffstat: | |
M configparser.c | 16 ++++++++++++++-- | |
M configparser.h | 1 + | |
M keys_basic.c | 5 ++--- | |
M leditrc.5 | 7 ++++++- | |
M leditrc.example | 1 + | |
M theme_config.h | 3 +++ | |
M view.c | 48 +++++++++++++++++------------… | |
7 files changed, 54 insertions(+), 27 deletions(-) | |
--- | |
diff --git a/configparser.c b/configparser.c | |
t@@ -32,7 +32,7 @@ struct config { | |
char **langs; | |
size_t num_langs; | |
size_t alloc_langs; | |
-} config = {NULL}; | |
+} config = {NULL, NULL, NULL, NULL, NULL, 0, 0}; | |
enum toktype { | |
STRING, | |
t@@ -576,6 +576,7 @@ load_destroy_theme(ledit_common *common, ast_list *theme_l… | |
{"text-size", &theme->text_size, &parse_theme_number, &destroy… | |
{"scrollbar-width", &theme->scrollbar_width, &parse_theme_numb… | |
{"scrollbar-step", &theme->scrollbar_step, &parse_theme_number… | |
+ {"extra-line-spacing", &theme->extra_line_spacing, &parse_them… | |
{"text-fg", &theme->text_fg, &parse_theme_color, &destroy_them… | |
{"text-bg", &theme->text_bg, &parse_theme_color, &destroy_them… | |
{"cursor-fg", &theme->cursor_fg, &parse_theme_color, &destroy_… | |
t@@ -664,6 +665,17 @@ load_destroy_theme(ledit_common *common, ast_list *theme_… | |
} | |
} | |
+ /* FIXME: make this check part of the generic handling above (also, < … | |
+ /* FIXME: 100 is completely arbitrary */ | |
+ if (theme->extra_line_spacing < 0 || theme->extra_line_spacing > 100) { | |
+ *errstr = print_fmt( | |
+ "%s: Invalid value '%d' for theme setting 'extra-line-spac… | |
+ "(allowed values are 0-100)", | |
+ filename, theme->extra_line_spacing | |
+ ); | |
+ goto cleanup; | |
+ } | |
+ | |
return theme; | |
cleanup: | |
for (size_t i = 0; i < LENGTH(settings); i++) { | |
t@@ -1658,7 +1670,7 @@ config_loadfile(ledit_common *common, char *filename, ch… | |
clock_gettime(CLOCK_MONOTONIC, &last); | |
#endif | |
- struct config cfg = {NULL}; | |
+ struct config cfg = {NULL, NULL, NULL, NULL, NULL, 0, 0}; | |
int theme_init = 0, bindings_init = 0, mappings_init = 0; | |
ast_assignment *assignment; | |
for (size_t i = 0; i < list.len; i++) { | |
diff --git a/configparser.h b/configparser.h | |
t@@ -11,6 +11,7 @@ typedef struct { | |
int scrollbar_step; | |
int text_size; | |
int highlight_search; | |
+ int extra_line_spacing; | |
XftColor text_fg; | |
XftColor text_bg; | |
XftColor cursor_fg; | |
diff --git a/keys_basic.c b/keys_basic.c | |
t@@ -714,10 +714,9 @@ static void | |
push_undo_empty_insert(ledit_view *view, size_t line, size_t index, int start_… | |
/* WARNING: Don't abuse txtbuf like this unless you're stupid like me.… | |
txtbuf ins_buf = {.text = "", .len = 0, .cap = 0}; | |
- ledit_range ins_range = {.line1 = line, .byte1 = index, .line2 = line,… | |
- ledit_range cur_range = {.line1 = line, .byte1 = index, .line2 = line,… | |
+ ledit_range range = {.line1 = line, .byte1 = index, .line2 = line, .by… | |
undo_push_insert( | |
- view->buffer->undo, &ins_buf, ins_range, cur_range, start_group, v… | |
+ view->buffer->undo, &ins_buf, range, range, start_group, view->mode | |
); | |
} | |
diff --git a/leditrc.5 b/leditrc.5 | |
t@@ -1,4 +1,4 @@ | |
-.Dd October 22, 2022 | |
+.Dd October 2, 2023 | |
.Dt LEDITRC 5 | |
.Os | |
.Sh NAME | |
t@@ -175,6 +175,11 @@ Note that the mode is automatically switched to visual wh… | |
This is a bit weird, but in order to keep everything a bit more consistent, se… | |
only allowed in visual mode. | |
Default: true | |
+.It Ar extra-line-spacing | |
+Extra space between each line (in pixels). | |
+Note that this is very rudimentary at the moment. | |
+In particular, selections covering multiple lines do not highlight the extra s… | |
+Default: 0 | |
.El | |
.Sh BINDINGS | |
The key bindings may be configured by assigning | |
diff --git a/leditrc.example b/leditrc.example | |
t@@ -19,6 +19,7 @@ theme = { | |
scrollbar-bg = CCCCCC | |
scrollbar-fg = 000000 | |
highlight-search = true | |
+ extra-line-spacing = 0 | |
} | |
bindings = { | |
diff --git a/theme_config.h b/theme_config.h | |
t@@ -49,4 +49,7 @@ static const char *SCROLLBAR_FG = "#000000"; | |
/* FIXME: this should maybe be in a separate "general config" section */ | |
static const char *HIGHLIGHT_SEARCH = "true"; | |
+/* extra space between lines (in pixels) */ | |
+static const char *EXTRA_LINE_SPACING = "0"; | |
+ | |
#endif /* _THEME_CONFIG_H_ */ | |
diff --git a/view.c b/view.c | |
t@@ -492,6 +492,7 @@ invalidate_layout_line_helper(void *data, size_t line) { | |
void | |
view_recalc_line(ledit_view *view, size_t line) { | |
+ ledit_theme *theme = config_get_theme(); | |
ledit_view_line *l = view_get_line(view, line); | |
if (l->text_dirty) | |
set_pango_text_and_highlight(view, line); | |
t@@ -503,13 +504,13 @@ view_recalc_line(ledit_view *view, size_t line) { | |
if (l->h_dirty) { | |
l->h_dirty = 0; | |
/* FIXME: maybe also check overflow for offset? */ | |
- long off = l->y_offset + l->h; | |
+ long off = l->y_offset + l->h + theme->extra_line_spacing; | |
for (size_t i = line + 1; i < view->lines_num; i++) { | |
l = view_get_line(view, i); | |
l->y_offset = off; | |
- off += l->h; | |
+ off += l->h + theme->extra_line_spacing; | |
} | |
- view->total_height = off; | |
+ view->total_height = off - theme->extra_line_spacing; | |
if (l->y_offset < view->display_offset + text_h) | |
view->redraw = 1; | |
} | |
t@@ -524,6 +525,7 @@ view_recalc_line(ledit_view *view, size_t line) { | |
void | |
view_recalc_from_line(ledit_view *view, size_t line) { | |
+ ledit_theme *theme = config_get_theme(); | |
ledit_view_line *l = view_get_line(view, line); | |
/* force first line to offset 0 */ | |
if (line == 0) | |
t@@ -539,9 +541,9 @@ view_recalc_from_line(ledit_view *view, size_t line) { | |
set_pango_text_and_highlight(view, i); | |
l->h_dirty = 0; | |
l->y_offset = off; | |
- off += l->h; | |
+ off += l->h + theme->extra_line_spacing; | |
} | |
- view->total_height = off; | |
+ view->total_height = off - theme->extra_line_spacing; | |
window_set_scroll_max(view->window, view->total_height); | |
view_scroll(view, view->display_offset); | |
} | |
t@@ -1071,6 +1073,7 @@ ledit_line_word_boundaries(ledit_line *line, int byte, i… | |
static void | |
set_pango_text_and_highlight(ledit_view *view, size_t line) { | |
cache_layout *cl; | |
+ ledit_theme *theme = config_get_theme(); | |
ledit_line *ll = buffer_get_line(view->buffer, line); | |
ledit_view_line *vl = view_get_line(view, line); | |
char old_valid = vl->cache_layout_valid; | |
t@@ -1087,6 +1090,7 @@ set_pango_text_and_highlight(ledit_view *view, size_t li… | |
cl->layout = pango_layout_new(view->window->context); | |
pango_layout_set_font_description(cl->layout, view->window->fo… | |
pango_layout_set_wrap(cl->layout, PANGO_WRAP_WORD_CHAR); | |
+ pango_layout_set_spacing(cl->layout, theme->extra_line_spacing… | |
} | |
if (vl->text_dirty || !old_valid) { | |
buffer_normalize_line(ll); | |
t@@ -1512,6 +1516,7 @@ view_delete_range_base( | |
/* FIXME: any way to make this more efficient? */ | |
void | |
view_resize_textview(void *data) { | |
+ ledit_theme *theme = config_get_theme(); | |
ledit_view *view = (ledit_view *)data; | |
view->total_height = 0; | |
int text_w, text_h; | |
t@@ -1524,8 +1529,9 @@ view_resize_textview(void *data) { | |
line->y_offset = view->total_height; | |
line->dirty = 1; | |
line->h_dirty = 0; | |
- view->total_height += line->h; | |
+ view->total_height += line->h + theme->extra_line_spacing; | |
} | |
+ view->total_height -= theme->extra_line_spacing; | |
window_set_scroll_max(view->window, view->total_height); | |
if (view->display_offset > 0 && | |
view->display_offset + text_h > view->total_height) { | |
t@@ -1547,6 +1553,7 @@ view_scroll(ledit_view *view, long new_offset) { | |
/* FIXME: there's gotta be a better/more efficient way to do this... */ | |
/* FIXME: make sure h_dirty is not set here */ | |
+/* FIXME: this might cause weird effects when used together with extra-line-sp… | |
void | |
view_get_nearest_legal_pos( | |
ledit_view *view, | |
t@@ -1648,19 +1655,19 @@ view_get_nearest_legal_pos( | |
void | |
view_xy_to_line_byte(ledit_view *view, int x, int y, int snap_to_nearest, size… | |
- /* FIXME: store current line offset to speed this up */ | |
- /* FIXME: use y_offset in lines */ | |
- long h = 0; | |
+ ledit_theme *theme = config_get_theme(); | |
long pos = view->display_offset + y; | |
for (size_t i = 0; i < view->lines_num; i++) { | |
ledit_view_line *vline = view_get_line(view, i); | |
- if ((h <= pos && h + vline->h > pos) || i == view->lines_num -… | |
+ long y1 = vline->y_offset - (i == 0 ? 0 : theme->extra_line_sp… | |
+ long y2 = vline->y_offset + vline->h + theme->extra_line_spaci… | |
+ if ((y1 <= pos && y2 > pos) || i == view->lines_num - 1) { | |
int index, trailing; | |
PangoLayout *layout = get_pango_layout(view, i); | |
/* FIXME: what if i == view->lines_num - 1 but pos - h… | |
pango_layout_xy_to_index( | |
layout, | |
- x * PANGO_SCALE, (int)(pos - h) * PANGO_SCALE, | |
+ x * PANGO_SCALE, (int)(pos - y1) * PANGO_SCALE, | |
&index, &trailing | |
); | |
*byte_ret = (size_t)index; | |
t@@ -1674,7 +1681,6 @@ view_xy_to_line_byte(ledit_view *view, int x, int y, int… | |
*line_ret = i; | |
return; | |
} | |
- h += vline->h; | |
} | |
*line_ret = 0; | |
*byte_ret = 0; | |
t@@ -1894,15 +1900,16 @@ view_button_handler(void *data, XEvent *event) { | |
static void | |
view_redraw_text(ledit_view *view) { | |
ledit_theme *theme = config_get_theme(); | |
- int h = 0; | |
int cur_line_y = 0; | |
int cursor_displayed = 0; | |
int text_w, text_h; | |
window_get_textview_size(view->window, &text_w, &text_h); | |
/* FIXME: use binary search here */ | |
+ /* FIXME: draw extra highlight when extra-line-spacing set | |
+ (also between soft lines because pango doesn't do that) */ | |
for (size_t i = 0; i < view->lines_num; i++) { | |
ledit_view_line *vline = view_get_line(view, i); | |
- if (h + vline->h > view->display_offset) { | |
+ if (vline->y_offset + vline->h > view->display_offset) { | |
/* FIXME: vline->text_dirty should not happen here */ | |
if (vline->text_dirty || vline->highlight_dirty) | |
set_pango_text_and_highlight(view, i); | |
t@@ -1910,12 +1917,12 @@ view_redraw_text(ledit_view *view) { | |
render_line(view, i); | |
} | |
int final_y = 0; | |
- int dest_y = h - view->display_offset; | |
+ int dest_y = vline->y_offset - view->display_offset; | |
int final_h = vline->h; | |
- if (h < view->display_offset) { | |
+ if (vline->y_offset < view->display_offset) { | |
dest_y = 0; | |
- final_y = view->display_offset - h; | |
- final_h -= view->display_offset - h; | |
+ final_y = view->display_offset - vline->y_offs… | |
+ final_h -= view->display_offset - vline->y_off… | |
} | |
if (dest_y + final_h > text_h) { | |
final_h -= final_y + final_h - | |
t@@ -1930,13 +1937,12 @@ view_redraw_text(ledit_view *view) { | |
0, final_y, vline->w, final_h, 0, dest_y | |
); | |
if (i == view->cur_line) { | |
- cur_line_y = h - view->display_offset; | |
+ cur_line_y = vline->y_offset - view->display_o… | |
cursor_displayed = 1; | |
} | |
- if (h + vline->h >= view->display_offset + text_h) | |
+ if (vline->y_offset + vline->h >= view->display_offset… | |
break; | |
} | |
- h += vline->h; | |
} | |
XSetForeground(view->buffer->common->dpy, view->window->gc, theme->cur… |