tImplement switching between hard line and soft line mode - ledit - Text editor… | |
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 f9064673e6ced9b9d8a2c1461c108170c15a96bc | |
parent f46f28e4d372daa0353489d65a29078e69fe0376 | |
Author: lumidify <[email protected]> | |
Date: Sun, 14 Nov 2021 21:50:14 +0100 | |
Implement switching between hard line and soft line mode | |
But it's all really ugly and buggy. | |
Diffstat: | |
M buffer.c | 85 +++++++++++++++++++++++++++++… | |
M buffer.h | 10 ++++++++-- | |
M keys_basic.c | 291 ++++++++++++++++++++---------… | |
M keys_basic.h | 1 + | |
M keys_basic_config.h | 3 +++ | |
M ledit.c | 1 + | |
M memory.c | 17 +++++++++++++++++ | |
M memory.h | 1 + | |
M window.c | 21 +++++++++++++++++---- | |
M window.h | 2 ++ | |
10 files changed, 322 insertions(+), 110 deletions(-) | |
--- | |
diff --git a/buffer.c b/buffer.c | |
t@@ -1,5 +1,6 @@ | |
/* FIXME: shrink buffers when text length less than a fourth of the size */ | |
/* FIXME: also cache PangoLayouts since keeping them around isn't really of mu… | |
+/* FIXME: handle all undo within buffer to keep it consistent */ | |
#include <stdio.h> | |
#include <errno.h> | |
t@@ -1404,13 +1405,13 @@ ledit_buffer_get_legal_normal_pos(ledit_buffer *buffer… | |
void | |
ledit_buffer_delete_range( | |
- ledit_buffer *buffer, int line_based, | |
+ ledit_buffer *buffer, enum delete_mode delmode, | |
int line_index1, int byte_index1, | |
int line_index2, int byte_index2, | |
int *new_line_ret, int *new_byte_ret, | |
ledit_range *final_range_ret, txtbuf *text_ret) { | |
ledit_buffer_delete_range_base( | |
- buffer, line_based, | |
+ buffer, delmode, | |
line_index1, byte_index1, | |
line_index2, byte_index2, | |
new_line_ret, new_byte_ret, | |
t@@ -1423,10 +1424,15 @@ ledit_buffer_delete_range( | |
} | |
/* Note: line_index* and byte_index* don't need to be sorted */ | |
+/* line_index1, byte_index1 are used as the cursor position in order | |
+ to determine the new cursor position */ | |
/* FIXME: use at least somewhat sensible variable names */ | |
+/* FIXME: I once noticed a bug where using 'dG' to delete to the end of | |
+ the file caused a line index way larger than buffer->lines_num to be | |
+ given, but I couldn't reproduce this bug */ | |
void | |
ledit_buffer_delete_range_base( | |
- ledit_buffer *buffer, int line_based, | |
+ ledit_buffer *buffer, enum delete_mode delmode, | |
int line_index1, int byte_index1, | |
int line_index2, int byte_index2, | |
int *new_line_ret, int *new_byte_ret, | |
t@@ -1435,9 +1441,80 @@ ledit_buffer_delete_range_base( | |
/* range line x, range byte x */ | |
int rgl1 = 0, rgb1 = 0, rgl2 = 0, rgb2 = 0; | |
int new_line = 0, new_byte = 0; | |
+ assert(line_index1 >= 0); | |
+ assert(line_index2 >= 0); | |
+ assert(line_index1 < buffer->lines_num); | |
+ assert(line_index2 < buffer->lines_num); | |
/* FIXME: could this be simplified by just calculating the range and t… | |
the non-line-based version? */ | |
- if (line_based) { | |
+ if (delmode == DELETE_HARDLINE) { | |
+ int x, sl_useless; | |
+ int l1 = line_index1, l2 = line_index2; | |
+ if (line_index1 > line_index2) { | |
+ l1 = line_index2; | |
+ l2 = line_index1; | |
+ } | |
+ int dell1 = l1, dell2 = l2; | |
+ ledit_line *ll = ledit_buffer_get_line(buffer, line_index1); | |
+ ledit_pos_to_x_softline(ll, byte_index1, &x, &sl_useless); | |
+ if (l1 > 0 && l2 < buffer->lines_num - 1) { | |
+ rgl1 = l1; | |
+ rgb1 = 0; | |
+ rgl2 = l2 + 1; | |
+ rgb2 = 0; | |
+ } else if (l1 > 0) { | |
+ rgl1 = l1 - 1; | |
+ ll = ledit_buffer_get_line(buffer, rgl1); | |
+ rgb1 = ll->len; | |
+ rgl2 = l2; | |
+ ll = ledit_buffer_get_line(buffer, rgl2); | |
+ rgb2 = ll->len; | |
+ } else if (l2 < buffer->lines_num - 1) { | |
+ rgl1 = l1; | |
+ rgb1 = 0; | |
+ rgl2 = l2 + 1; | |
+ rgb2 = 0; | |
+ } else { | |
+ rgl1 = l1; | |
+ rgb1 = 0; | |
+ rgl2 = l2; | |
+ ll = ledit_buffer_get_line(buffer, rgl2); | |
+ rgb2 = ll->len; | |
+ } | |
+ if (text_ret) { | |
+ ledit_buffer_copy_text_to_txtbuf( | |
+ buffer, text_ret, | |
+ rgl1, rgb1, rgl2, rgb2 | |
+ ); | |
+ } | |
+ /* default is dell1 = l1, dell2 = l2 */ | |
+ if (l2 < buffer->lines_num - 1) { | |
+ new_line = l1; | |
+ ledit_x_softline_to_pos( | |
+ ledit_buffer_get_line(buffer, l2 + 1), | |
+ x, 0, &new_byte | |
+ ); | |
+ } else if (l1 > 0) { | |
+ new_line = l1 - 1; | |
+ ledit_x_softline_to_pos( | |
+ ledit_buffer_get_line(buffer, l1 - 1), | |
+ x, 0, &new_byte | |
+ ); | |
+ } else { | |
+ dell1 = l1 + 1; | |
+ dell2 = l2; | |
+ new_line = l1; | |
+ new_byte = 0; | |
+ /* happens when all lines are deleted, so one line has… | |
+ ll = ledit_buffer_get_line(buffer, l1); | |
+ delete_line_section_base( | |
+ buffer, l1, 0, ll->len | |
+ ); | |
+ } | |
+ if (dell1 <= dell2) { | |
+ ledit_buffer_delete_line_entries_base(buffer, dell1, d… | |
+ } | |
+ } else if (delmode == DELETE_SOFTLINE) { | |
int x, softline1, softline2; | |
ledit_line *line1 = ledit_buffer_get_line(buffer, line_index1); | |
normalize_and_set_pango_text(line1); | |
diff --git a/buffer.h b/buffer.h | |
t@@ -53,6 +53,12 @@ struct ledit_buffer { | |
ledit_buffer_marklist *marklist; | |
}; | |
+enum delete_mode { | |
+ DELETE_CHAR, | |
+ DELETE_SOFTLINE, | |
+ DELETE_HARDLINE | |
+}; | |
+ | |
ledit_buffer *ledit_buffer_create(ledit_common *common, ledit_theme *theme, le… | |
int ledit_buffer_load_file(ledit_buffer *buffer, char *filename, int line, cha… | |
int ledit_buffer_write_to_file(ledit_buffer *buffer, char *filename, char **er… | |
t@@ -110,7 +116,7 @@ void ledit_buffer_delete_line_entries_base(ledit_buffer *b… | |
void ledit_buffer_delete_line_entry_base(ledit_buffer *buffer, int index); | |
int ledit_buffer_delete_unicode_char_base(ledit_buffer *buffer, int line_index… | |
void ledit_buffer_delete_range_base( | |
- ledit_buffer *buffer, int line_based, | |
+ ledit_buffer *buffer, enum delete_mode delmode, | |
int line_index1, int byte_index1, | |
int line_index2, int byte_index2, | |
int *new_line_ret, int *new_byte_ret, | |
t@@ -135,7 +141,7 @@ void ledit_buffer_delete_line_entries(ledit_buffer *buffer… | |
void ledit_buffer_delete_line_entry(ledit_buffer *buffer, int index); | |
int ledit_buffer_delete_unicode_char(ledit_buffer *buffer, int line_index, int… | |
void ledit_buffer_delete_range( | |
- ledit_buffer *buffer, int line_based, | |
+ ledit_buffer *buffer, enum delete_mode delmode, | |
int line_index1, int byte_index1, | |
int line_index2, int byte_index2, | |
int *new_line_ret, int *new_byte_ret, | |
diff --git a/keys_basic.c b/keys_basic.c | |
t@@ -78,6 +78,7 @@ static struct { | |
} key_stack = {0, 0, NULL}; | |
static struct action (*grab_char_cb)(ledit_buffer *buffer, char *text, int len… | |
+static int hard_line_based = 1; | |
void | |
basic_key_cleanup(void) { | |
t@@ -322,62 +323,72 @@ finalize_repetition_stack(void) { | |
repetition_stack.tmp_stack = tmpstack; | |
} | |
-/* get the new line and softline when moving 'movement' softlines up or | |
+/* get the new line and softline when moving 'movement' softlines | |
+ (or hardlines if hard_line_based is set) up or | |
down (negative means up, positive means down) */ | |
static void | |
get_new_line_softline( | |
ledit_buffer *buffer, int cur_line, int cur_index, int movement, | |
int *new_line_ret, int *new_softline_ret) { | |
- ledit_line *line = ledit_buffer_get_line(buffer, cur_line); | |
- int x, softline; | |
- pango_layout_index_to_line_x(line->layout, cur_index, 0, &softline, &x… | |
- if (movement > 0) { | |
- int softlines = pango_layout_get_line_count(line->layout); | |
- if (softlines - softline > movement) { | |
- *new_line_ret = cur_line; | |
- *new_softline_ret = softline + movement; | |
- } else { | |
- movement -= (softlines - softline - 1); | |
- int endline = cur_line + 1; | |
- while (movement > 0 && endline < buffer->lines_num) { | |
- line = ledit_buffer_get_line(buffer, endline); | |
- softlines = pango_layout_get_line_count(line->… | |
- movement -= softlines; | |
- endline++; | |
- } | |
- endline--; | |
- if (movement <= 0) { | |
- *new_softline_ret = movement + softlines - 1; | |
+ if (hard_line_based) { | |
+ *new_line_ret = cur_line + movement; | |
+ if (*new_line_ret < 0) | |
+ *new_line_ret = 0; | |
+ else if (*new_line_ret >= buffer->lines_num) | |
+ *new_line_ret = buffer->lines_num - 1; | |
+ *new_softline_ret = 0; | |
+ } else { | |
+ ledit_line *line = ledit_buffer_get_line(buffer, cur_line); | |
+ int x, softline; | |
+ pango_layout_index_to_line_x(line->layout, cur_index, 0, &soft… | |
+ if (movement > 0) { | |
+ int softlines = pango_layout_get_line_count(line->layo… | |
+ if (softlines - softline > movement) { | |
+ *new_line_ret = cur_line; | |
+ *new_softline_ret = softline + movement; | |
} else { | |
- *new_softline_ret = softlines - 1; | |
- } | |
- *new_line_ret = endline; | |
- } | |
- } else if (movement < 0) { | |
- int softlines = 0; | |
- if (softline + movement >= 0) { | |
- *new_line_ret = cur_line; | |
- *new_softline_ret = softline + movement; | |
- } else { | |
- movement += softline; | |
- int endline = cur_line - 1; | |
- while (movement < 0 && endline >= 0) { | |
- line = ledit_buffer_get_line(buffer, endline); | |
- softlines = pango_layout_get_line_count(line->… | |
- movement += softlines; | |
+ movement -= (softlines - softline - 1); | |
+ int endline = cur_line + 1; | |
+ while (movement > 0 && endline < buffer->lines… | |
+ line = ledit_buffer_get_line(buffer, e… | |
+ softlines = pango_layout_get_line_coun… | |
+ movement -= softlines; | |
+ endline++; | |
+ } | |
endline--; | |
+ if (movement <= 0) { | |
+ *new_softline_ret = movement + softlin… | |
+ } else { | |
+ *new_softline_ret = softlines - 1; | |
+ } | |
+ *new_line_ret = endline; | |
} | |
- endline++; | |
- if (movement >= 0) { | |
- *new_softline_ret = movement; | |
+ } else if (movement < 0) { | |
+ int softlines = 0; | |
+ if (softline + movement >= 0) { | |
+ *new_line_ret = cur_line; | |
+ *new_softline_ret = softline + movement; | |
} else { | |
- *new_softline_ret = 0; | |
+ movement += softline; | |
+ int endline = cur_line - 1; | |
+ while (movement < 0 && endline >= 0) { | |
+ line = ledit_buffer_get_line(buffer, e… | |
+ softlines = pango_layout_get_line_coun… | |
+ movement += softlines; | |
+ endline--; | |
+ } | |
+ endline++; | |
+ if (movement >= 0) { | |
+ *new_softline_ret = movement; | |
+ } else { | |
+ *new_softline_ret = 0; | |
+ } | |
+ *new_line_ret = endline; | |
} | |
- *new_line_ret = endline; | |
+ } else { | |
+ *new_line_ret = cur_line; | |
+ *new_softline_ret = softline; | |
} | |
- } else { | |
- *new_line_ret = cur_line; | |
- *new_softline_ret = softline; | |
} | |
} | |
t@@ -396,8 +407,15 @@ delete_range( | |
ledit_range cur_range, del_range; | |
cur_range.line1 = buffer->cur_line; | |
cur_range.byte1 = buffer->cur_index; | |
+ enum delete_mode delmode = DELETE_CHAR; | |
+ if (line_based) { | |
+ if (hard_line_based) | |
+ delmode = DELETE_HARDLINE; | |
+ else | |
+ delmode = DELETE_SOFTLINE; | |
+ } | |
ledit_buffer_delete_range( | |
- buffer, line_based, | |
+ buffer, delmode, | |
line_index1, byte_index1, | |
line_index2, byte_index2, | |
&buffer->cur_line, &buffer->cur_index, | |
t@@ -544,8 +562,10 @@ append_line_above(ledit_buffer *buffer, char *text, int l… | |
/* do this here already so the mode group is the same for the newline … | |
enter_insert(buffer, text, len); | |
ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line); | |
+ /* FIXME: this is more "elegant", but inefficient because this doesn't | |
+ actually need to be called when hard_line_based == 1 */ | |
pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &… | |
- if (sli == 0) { | |
+ if (hard_line_based || sli == 0) { | |
insert_text(buffer, buffer->cur_line, 0, "\n", -1, -1, -1, buf… | |
} else { | |
PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layou… | |
t@@ -561,7 +581,7 @@ append_line_below(ledit_buffer *buffer, char *text, int le… | |
ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line); | |
pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &… | |
PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, sli); | |
- if (sl->start_index + sl->length == ll->len) { | |
+ if (hard_line_based || sl->start_index + sl->length == ll->len) { | |
insert_text(buffer, buffer->cur_line, ll->len, "\n", -1, -1, -… | |
} else { | |
insert_text(buffer, buffer->cur_line, sl->start_index + sl->le… | |
t@@ -587,9 +607,13 @@ append_after_eol(ledit_buffer *buffer, char *text, int le… | |
/* make cursor jump back to original position on undo */ | |
push_undo_empty_insert(buffer, buffer->cur_line, buffer->cur_index, 1); | |
ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line); | |
- pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &… | |
- PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, sli); | |
- buffer->cur_index = sl->start_index + sl->length; | |
+ if (hard_line_based) { | |
+ buffer->cur_index = ll->len; | |
+ } else { | |
+ pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0,… | |
+ PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layou… | |
+ buffer->cur_index = sl->start_index + sl->length; | |
+ } | |
return (struct action){ACTION_NONE, NULL}; | |
} | |
t@@ -629,6 +653,7 @@ move_to_line(ledit_buffer *buffer, char *text, int len) { | |
return (struct action){ACTION_NONE, NULL}; | |
} | |
+/* FIXME: should these scrolling functions change behavior when hard_line_base… | |
static void | |
scroll_lines(ledit_buffer *buffer, int lines, int dir) { | |
int final_lines; | |
t@@ -802,20 +827,21 @@ static struct action | |
delete_to_eol(ledit_buffer *buffer, char *text, int len) { | |
(void)text; | |
(void)len; | |
- /* FIXME: move to separate function */ | |
- if (!key_stack_empty()) { | |
- clear_key_stack(); | |
- ledit_window_show_message(buffer->window, "Invalid key", -1); | |
- return (struct action){ACTION_NONE, NULL}; | |
- } | |
- int x, sli; | |
+ if (!key_stack_empty()) | |
+ return err_invalid_key(buffer); | |
+ int end, x, sli; | |
ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line); | |
- pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &… | |
- PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, sli); | |
+ if (hard_line_based) { | |
+ end = ll->len; | |
+ } else { | |
+ pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0,… | |
+ PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layou… | |
+ end = sl->start_index + sl->length; | |
+ } | |
delete_range( | |
buffer, 0, 0, | |
buffer->cur_line, buffer->cur_index, | |
- buffer->cur_line, sl->start_index + sl->length, 1 | |
+ buffer->cur_line, end, 1 | |
); | |
paste_buffer_line_based = 0; | |
buffer->cur_index = ledit_buffer_get_legal_normal_pos( | |
t@@ -829,20 +855,22 @@ static struct action | |
change_to_eol(ledit_buffer *buffer, char *text, int len) { | |
(void)text; | |
(void)len; | |
- if (!key_stack_empty()) { | |
- clear_key_stack(); | |
- ledit_window_show_message(buffer->window, "Invalid key", -1); | |
- return (struct action){ACTION_NONE, NULL}; | |
- } | |
+ if (!key_stack_empty()) | |
+ return err_invalid_key(buffer); | |
ledit_buffer_set_mode(buffer, INSERT); | |
- int x, sli; | |
+ int end, x, sli; | |
ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line); | |
- pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &… | |
- PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, sli); | |
+ if (hard_line_based) { | |
+ end = ll->len; | |
+ } else { | |
+ pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0,… | |
+ PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layou… | |
+ end = sl->start_index + sl->length; | |
+ } | |
delete_range( | |
buffer, 0, 0, | |
buffer->cur_line, buffer->cur_index, | |
- buffer->cur_line, sl->start_index + sl->length, 1 | |
+ buffer->cur_line, end, 1 | |
); | |
paste_buffer_line_based = 0; | |
ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); | |
t@@ -896,7 +924,7 @@ change_cb(ledit_buffer *buffer, int line, int char_pos, en… | |
/* this hackery is needed to avoid deleting the entire last line and | |
instead leave an empty line - this should be made nicer (FIXME) */ | |
int pos1 = buffer->cur_index, pos2 = char_pos, x, sli; | |
- if (line_based) { | |
+ if (line_based && !hard_line_based) { | |
ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_lin… | |
pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0,… | |
PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layou… | |
t@@ -905,6 +933,10 @@ change_cb(ledit_buffer *buffer, int line, int char_pos, e… | |
pango_layout_index_to_line_x(ll->layout, char_pos, 0, &sli, &x… | |
sl = pango_layout_get_line_readonly(ll->layout, sli); | |
pos2 = sl->start_index + sl->length; | |
+ } else if (line_based && hard_line_based) { | |
+ pos1 = 0; | |
+ ledit_line *ll = ledit_buffer_get_line(buffer, line); | |
+ pos2 = ll->len; | |
} | |
/* force line_based to 0 (see comment about hackery above) */ | |
delete_range( | |
t@@ -989,6 +1021,9 @@ yank_lines(ledit_buffer *buffer, char *text, int len) { | |
return (struct action){ACTION_NONE, NULL}; | |
} | |
+/* FIXME: delete_range and yank put different things in past_buffer - yank doe… | |
+ extra newlines at the beginning and end (this doesn't really matter because… | |
+ ignores them anyways, but it is a bit weird) */ | |
static void | |
yank_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type) { | |
int line_based = type == KEY_MOTION_LINE ? 1 : 0; | |
t@@ -999,7 +1034,7 @@ yank_cb(ledit_buffer *buffer, int line, int char_pos, enu… | |
swap(&l1, &l2); | |
swap(&b1, &b2); | |
} | |
- if (line_based) { | |
+ if (line_based && !hard_line_based) { | |
int x, sl1, sl2; | |
ledit_line *ll1 = ledit_buffer_get_line(buffer, l1); | |
pango_layout_index_to_line_x(ll1->layout, b1, 0, &sl1, &x); | |
t@@ -1011,6 +1046,11 @@ yank_cb(ledit_buffer *buffer, int line, int char_pos, e… | |
ledit_buffer_copy_text_to_txtbuf( | |
buffer, paste_buffer, l1, pl1->start_index, l2, pl2->start… | |
); | |
+ } else if (line_based && hard_line_based) { | |
+ ledit_line *ll = ledit_buffer_get_line(buffer, l2); | |
+ ledit_buffer_copy_text_to_txtbuf( | |
+ buffer, paste_buffer, l1, 0, l2, ll->len | |
+ ); | |
} else { | |
ledit_buffer_copy_text_to_txtbuf( | |
buffer, paste_buffer, l1, b1, l2, b2 | |
t@@ -1091,10 +1131,16 @@ paste_normal(ledit_buffer *buffer, char *text, int len… | |
int x, softline; | |
ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); | |
ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_lin… | |
- pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0,… | |
- PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layou… | |
+ int brk = 0; | |
+ if (hard_line_based) { | |
+ brk = ll->len; | |
+ } else { | |
+ pango_layout_index_to_line_x(ll->layout, buffer->cur_i… | |
+ PangoLayoutLine *sl = pango_layout_get_line_readonly(l… | |
+ brk = sl->start_index + sl->length; | |
+ } | |
insert_text( | |
- buffer, buffer->cur_line, sl->start_index + sl->length, | |
+ buffer, buffer->cur_line, brk, | |
"\n", -1, -1, -1, buffer->cur_line, buffer->cur_index, 1 | |
); | |
int text_len = paste_buffer->len; | |
t@@ -1143,10 +1189,14 @@ paste_normal_backwards(ledit_buffer *buffer, char *tex… | |
int x, softline; | |
ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); | |
ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_lin… | |
- pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0,… | |
- PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layou… | |
+ int brk = 0; | |
+ if (!hard_line_based) { | |
+ pango_layout_index_to_line_x(ll->layout, buffer->cur_i… | |
+ PangoLayoutLine *sl = pango_layout_get_line_readonly(l… | |
+ brk = sl->start_index; | |
+ } | |
insert_text( | |
- buffer, buffer->cur_line, sl->start_index, | |
+ buffer, buffer->cur_line, brk, | |
"\n", -1, -1, -1, buffer->cur_line, buffer->cur_index, 1 | |
); | |
int text_len = paste_buffer->len; | |
t@@ -1341,8 +1391,11 @@ move_to_eol(ledit_buffer *buffer, char *text, int len) { | |
&new_line, &new_softline | |
); | |
ledit_line *ll = ledit_buffer_get_line(buffer, new_line); | |
- PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, new_s… | |
- int end_index = sl->start_index + sl->length; | |
+ int end_index = ll->len; | |
+ if (!hard_line_based) { | |
+ PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layou… | |
+ end_index = sl->start_index + sl->length; | |
+ } | |
if (cb != NULL) { | |
cb(buffer, new_line, end_index, KEY_MOTION_CHAR); | |
} else { | |
t@@ -1671,7 +1724,7 @@ join_lines(ledit_buffer *buffer, char *text, int len) { | |
oldlen = ll1->len; | |
/* FIXME: truncate whitespace to one space */ | |
ledit_buffer_delete_range( | |
- buffer, 0, | |
+ buffer, DELETE_CHAR, | |
cur_line, ll1->len, cur_line + 1, 0, | |
NULL, NULL, &del_range, buf | |
); | |
t@@ -1697,12 +1750,16 @@ insert_at_beginning(ledit_buffer *buffer, char *text, … | |
if (!key_stack_empty()) | |
return err_invalid_key(buffer); | |
enter_insert(buffer, text, len); | |
- int x, sli; | |
- ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line); | |
- pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &… | |
- PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layout, sli); | |
+ int new_index = 0; | |
+ if (!hard_line_based) { | |
+ int x, sli; | |
+ ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_lin… | |
+ pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0,… | |
+ PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layou… | |
+ new_index = pl->start_index; | |
+ } | |
push_undo_empty_insert(buffer, buffer->cur_line, buffer->cur_index, 1); | |
- buffer->cur_index = pl->start_index; | |
+ buffer->cur_index = new_index; | |
ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line); | |
return (struct action){ACTION_NONE, NULL}; | |
} | |
t@@ -1711,20 +1768,25 @@ static struct action | |
cursor_to_first_non_ws(ledit_buffer *buffer, char *text, int len) { | |
(void)text; | |
(void)len; | |
- int x, sli; | |
motion_callback cb; | |
int num = get_key_repeat_and_motion_cb(&cb); | |
if (num != 0) | |
return err_invalid_key(buffer); | |
+ int new_index = 0; | |
ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line); | |
- pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &… | |
- PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layout, sli); | |
- int new_index = ledit_line_next_non_whitespace(ll, pl->start_index); | |
- /* next non-whitespace might be on next softline */ | |
- if (new_index >= pl->start_index + pl->length) { | |
- new_index = ledit_buffer_prev_cursor_pos( | |
- buffer, buffer->cur_line, pl->start_index + pl->length, 1 | |
- ); | |
+ if (hard_line_based) { | |
+ new_index = ledit_line_next_non_whitespace(ll, 0); | |
+ } else { | |
+ int x, sli; | |
+ pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0,… | |
+ PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layou… | |
+ new_index = ledit_line_next_non_whitespace(ll, pl->start_index… | |
+ /* next non-whitespace might be on next softline */ | |
+ if (new_index >= pl->start_index + pl->length) { | |
+ new_index = ledit_buffer_prev_cursor_pos( | |
+ buffer, buffer->cur_line, pl->start_index + pl->le… | |
+ ); | |
+ } | |
} | |
if (cb != NULL) { | |
cb(buffer, buffer->cur_line, new_index, KEY_MOTION_CHAR); | |
t@@ -1748,13 +1810,17 @@ cursor_to_beginning(ledit_buffer *buffer, char *text, … | |
if (num != 0) | |
return err_invalid_key(buffer); | |
/* FIXME: should anything be done with num? */ | |
- ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line); | |
- pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &… | |
- PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layout, sli); | |
+ int start_index = 0; | |
+ if (!hard_line_based) { | |
+ ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_lin… | |
+ pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0,… | |
+ PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layou… | |
+ start_index = pl->start_index; | |
+ } | |
if (cb != NULL) { | |
- cb(buffer, buffer->cur_line, pl->start_index, KEY_MOTION_CHAR); | |
+ cb(buffer, buffer->cur_line, start_index, KEY_MOTION_CHAR); | |
} else { | |
- buffer->cur_index = pl->start_index; | |
+ buffer->cur_index = start_index; | |
if (buffer->common->mode == VISUAL) { | |
ledit_buffer_set_selection( | |
buffer, | |
t@@ -2166,6 +2232,31 @@ replace(ledit_buffer *buffer, char *text, int len) { | |
return (struct action){ACTION_NONE, NULL}; | |
} | |
+static void | |
+set_hard_line_based(ledit_buffer *buffer, int hl) { | |
+ hard_line_based = hl; | |
+ char *text = hl ? "|HL" : "|SL"; | |
+ ledit_window_set_mode_extra_text(buffer->window, text); | |
+} | |
+ | |
+static struct action | |
+toggle_hard_line_based(ledit_buffer *buffer, char *text, int len) { | |
+ (void)buffer; | |
+ (void)text; | |
+ (void)len; | |
+ int num = get_key_repeat(); | |
+ if (num != 0) | |
+ return err_invalid_key(buffer); | |
+ set_hard_line_based(buffer, !hard_line_based); | |
+ return (struct action){ACTION_NONE, NULL}; | |
+} | |
+ | |
+/* FIXME: this is sort of all over the place and ugly */ | |
+void | |
+keys_basic_init(ledit_buffer *buffer) { | |
+ set_hard_line_based(buffer, 1); | |
+} | |
+ | |
static struct action | |
handle_key(ledit_buffer *buffer, char *key_text, int len, KeySym sym, unsigned… | |
struct key *cur_keys = keys[lang_index].keys; | |
diff --git a/keys_basic.h b/keys_basic.h | |
t@@ -1,2 +1,3 @@ | |
+void keys_basic_init(ledit_buffer *buffer); | |
void basic_key_cleanup(void); | |
struct action basic_key_handler(ledit_buffer *buffer, XEvent *event, int lang_… | |
diff --git a/keys_basic_config.h b/keys_basic_config.h | |
t@@ -1,3 +1,4 @@ | |
+/* FIXME: these aren't really used properly */ | |
enum key_type { | |
KEY_NONE = 0, | |
KEY_MISC = 1, | |
t@@ -93,6 +94,7 @@ static struct action replace(ledit_buffer *buffer, char *tex… | |
static struct action cursor_to_first_non_ws(ledit_buffer *buffer, char *text, … | |
static struct action join_lines(ledit_buffer *buffer, char *text, int len); | |
static struct action insert_at_beginning(ledit_buffer *buffer, char *text, int… | |
+static struct action toggle_hard_line_based(ledit_buffer *buffer, char *text, … | |
/* FIXME: maybe sort these and use binary search | |
-> but that would mess with the catch-all keys */ | |
t@@ -111,6 +113,7 @@ static struct key keys_en[] = { | |
{"j", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &… | |
{"k", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &… | |
{"h", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBER… | |
+ {"t", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &toggle_hard_l… | |
{NULL, 0, XK_space, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERAL… | |
{"j", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBER… | |
{"n", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBER… | |
diff --git a/ledit.c b/ledit.c | |
t@@ -292,6 +292,7 @@ setup(int argc, char *argv[]) { | |
} | |
ledit_buffer_set_mode(buffer, NORMAL); | |
ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->c… | |
+ keys_basic_init(buffer); | |
redraw(); | |
} | |
diff --git a/memory.c b/memory.c | |
t@@ -47,3 +47,20 @@ ledit_realloc(void *ptr, size_t size) { | |
fatal_err("Out of memory.\n"); | |
return new_ptr; | |
} | |
+ | |
+/* Concatenate the two given strings and return the result. | |
+ This allocates new memory for the result string, unlike | |
+ the actual strcat. Aborts program on error */ | |
+char * | |
+ledit_strcat(const char *str1, const char *str2) { | |
+ int len1, len2; | |
+ char *ret; | |
+ | |
+ len1 = strlen(str1); | |
+ len2 = strlen(str2); | |
+ ret = ledit_malloc(len1 + len2 + 1); | |
+ strcpy(ret, str1); | |
+ strcpy(ret + len1, str2); | |
+ | |
+ return ret; | |
+} | |
diff --git a/memory.h b/memory.h | |
t@@ -3,3 +3,4 @@ char *ledit_strndup(const char *s, size_t n); | |
void *ledit_malloc(size_t size); | |
void *ledit_calloc(size_t nmemb, size_t size); | |
void *ledit_realloc(void *ptr, size_t size); | |
+char *ledit_strcat(const char *str1, const char *str2); | |
diff --git a/window.c b/window.c | |
t@@ -240,20 +240,24 @@ ledit_window_hide_message(ledit_window *window) { | |
void | |
ledit_window_set_mode(ledit_window *window, enum ledit_mode mode) { | |
+ char *text; | |
switch (mode) { | |
case NORMAL: | |
- pango_layout_set_text(window->bb->mode, "Normal", -1); | |
+ text = "Normal"; | |
break; | |
case VISUAL: | |
- pango_layout_set_text(window->bb->mode, "Visual", -1); | |
+ text = "Visual"; | |
break; | |
case INSERT: | |
- pango_layout_set_text(window->bb->mode, "Insert", -1); | |
+ text = "Insert"; | |
break; | |
default: | |
- pango_layout_set_text(window->bb->mode, "ledit is bugg… | |
+ text = "ledit is buggy"; | |
break; | |
} | |
+ char *final_text = ledit_strcat(text, window->mode_extra_text ? window… | |
+ pango_layout_set_text(window->bb->mode, final_text, -1); | |
+ free(final_text); | |
pango_layout_get_pixel_size(window->bb->mode, &window->bb->mode_w, &wi… | |
ledit_draw_grow(window, window->bb->mode_draw, window->bb->mode_w, win… | |
XftDrawRect(window->bb->mode_draw->xftdraw, &window->theme->text_bg, 0… | |
t@@ -261,6 +265,12 @@ ledit_window_set_mode(ledit_window *window, enum ledit_mo… | |
recalc_text_size(window); | |
} | |
+void | |
+ledit_window_set_mode_extra_text(ledit_window *window, char *text) { | |
+ window->mode_extra_text = ledit_strdup(text); | |
+ ledit_window_set_mode(window, window->common->mode); | |
+} | |
+ | |
/* FIXME: give these functions more sensible names */ | |
static void | |
get_scroll_pos_height(ledit_window *window, double *pos, double *height) { | |
t@@ -411,6 +421,7 @@ ledit_window_create(ledit_common *common, ledit_theme *the… | |
window->scroll_grab_handle = 0; | |
window->w = 500; | |
window->h = 500; | |
+ window->mode_extra_text = NULL; | |
memset(&window->wattrs, 0, sizeof(attrs)); | |
window->wattrs.background_pixel = BlackPixel(common->dpy, common->scre… | |
t@@ -516,6 +527,8 @@ ledit_window_destroy(ledit_window *window) { | |
g_object_unref(window->bb->line); | |
ledit_draw_destroy(window, window->bb->mode_draw); | |
ledit_draw_destroy(window, window->bb->line_draw); | |
+ if (window->mode_extra_text) | |
+ free(window->mode_extra_text); | |
free(window->bb->line_text); | |
free(window->bb); | |
free(window); | |
diff --git a/window.h b/window.h | |
t@@ -38,6 +38,7 @@ typedef struct { | |
void *paste_cb_data; | |
void *scroll_cb_data; | |
void *button_cb_data; | |
+ char *mode_extra_text; | |
} ledit_window; | |
ledit_window *ledit_window_create(ledit_common *common, ledit_theme *theme); | |
t@@ -62,6 +63,7 @@ void ledit_window_show_message(ledit_window *window, char *t… | |
void ledit_window_hide_message(ledit_window *window); | |
int ledit_window_message_shown(ledit_window *window); | |
void ledit_window_set_mode(ledit_window *window, enum ledit_mode mode); | |
+void ledit_window_set_mode_extra_text(ledit_window *window, char *text); | |
void ledit_window_set_scroll_max(ledit_window *window, long max); | |
void ledit_window_set_scroll_pos(ledit_window *window, long pos); |