commit f9064673e6ced9b9d8a2c1461c108170c15a96bc
parent f46f28e4d372daa0353489d65a29078e69fe0376
Author: lumidify <nobody@lumidify.org>
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:
10 files changed, 322 insertions(+), 110 deletions(-)
diff --git a/buffer.c b/buffer.c
@@ -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 much use? */
+/* FIXME: handle all undo within buffer to keep it consistent */
#include <stdio.h>
#include <errno.h>
@@ -1404,13 +1405,13 @@ ledit_buffer_get_legal_normal_pos(ledit_buffer *buffer, int line, int pos) {
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,
@@ -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,
@@ -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 then using
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 to be cleared */
+ 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, dell2);
+ }
+ } 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
@@ -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, ledit_window *window);
int ledit_buffer_load_file(ledit_buffer *buffer, char *filename, int line, char **errstr);
int ledit_buffer_write_to_file(ledit_buffer *buffer, char *filename, char **errstr);
@@ -110,7 +116,7 @@ void ledit_buffer_delete_line_entries_base(ledit_buffer *buffer, int index1, int
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, int byte_index, int dir);
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,
@@ -135,7 +141,7 @@ void ledit_buffer_delete_line_entries(ledit_buffer *buffer, int index1, int inde
void ledit_buffer_delete_line_entry(ledit_buffer *buffer, int index);
int ledit_buffer_delete_unicode_char(ledit_buffer *buffer, int line_index, int byte_index, int dir);
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
@@ -78,6 +78,7 @@ static struct {
} key_stack = {0, 0, NULL};
static struct action (*grab_char_cb)(ledit_buffer *buffer, char *text, int len) = NULL;
+static int hard_line_based = 1;
void
basic_key_cleanup(void) {
@@ -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->layout);
- 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, &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 {
- *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->layout);
- movement += softlines;
+ 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->layout);
+ movement -= softlines;
+ endline++;
+ }
endline--;
+ if (movement <= 0) {
+ *new_softline_ret = movement + softlines - 1;
+ } 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, endline);
+ softlines = pango_layout_get_line_count(line->layout);
+ 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;
}
}
@@ -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,
@@ -544,8 +562,10 @@ append_line_above(ledit_buffer *buffer, char *text, int len) {
/* do this here already so the mode group is the same for the newline insertion */
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, &x);
- if (sli == 0) {
+ if (hard_line_based || sli == 0) {
insert_text(buffer, buffer->cur_line, 0, "\n", -1, -1, -1, buffer->cur_line, 0, 1);
} else {
PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, sli);
@@ -561,7 +581,7 @@ append_line_below(ledit_buffer *buffer, char *text, int len) {
ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line);
pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &x);
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, -1, buffer->cur_line + 1, 0, 1);
} else {
insert_text(buffer, buffer->cur_line, sl->start_index + sl->length, "\n\n", -1, -1, -1, buffer->cur_line + 1, 0, 1);
@@ -587,9 +607,13 @@ append_after_eol(ledit_buffer *buffer, char *text, int len) {
/* 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, &x);
- 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, &sli, &x);
+ PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, sli);
+ buffer->cur_index = sl->start_index + sl->length;
+ }
return (struct action){ACTION_NONE, NULL};
}
@@ -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_based == 1? */
static void
scroll_lines(ledit_buffer *buffer, int lines, int dir) {
int final_lines;
@@ -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, &x);
- 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, &sli, &x);
+ PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, sli);
+ 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(
@@ -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, &x);
- 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, &sli, &x);
+ PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, sli);
+ 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);
@@ -896,7 +924,7 @@ change_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type) {
/* 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_line);
pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &x);
PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, sli);
@@ -905,6 +933,10 @@ change_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type) {
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(
@@ -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 doesn't include
+ extra newlines at the beginning and end (this doesn't really matter because paste
+ 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;
@@ -999,7 +1034,7 @@ yank_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type) {
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);
@@ -1011,6 +1046,11 @@ yank_cb(ledit_buffer *buffer, int line, int char_pos, enum key_type type) {
ledit_buffer_copy_text_to_txtbuf(
buffer, paste_buffer, l1, pl1->start_index, l2, pl2->start_index + pl2->length
);
+ } 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
@@ -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_line);
- pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &softline, &x);
- PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, softline);
+ int brk = 0;
+ if (hard_line_based) {
+ brk = ll->len;
+ } else {
+ pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &softline, &x);
+ PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, softline);
+ 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;
@@ -1143,10 +1189,14 @@ paste_normal_backwards(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_line);
- pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &softline, &x);
- PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, softline);
+ int brk = 0;
+ if (!hard_line_based) {
+ pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &softline, &x);
+ PangoLayoutLine *sl = pango_layout_get_line_readonly(ll->layout, softline);
+ 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;
@@ -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_softline);
- 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->layout, new_softline);
+ end_index = sl->start_index + sl->length;
+ }
if (cb != NULL) {
cb(buffer, new_line, end_index, KEY_MOTION_CHAR);
} else {
@@ -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
);
@@ -1697,12 +1750,16 @@ insert_at_beginning(ledit_buffer *buffer, char *text, int len) {
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, &x);
- 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_line);
+ pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &x);
+ PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layout, sli);
+ 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};
}
@@ -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, &x);
- 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, &sli, &x);
+ PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layout, sli);
+ 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 (cb != NULL) {
cb(buffer, buffer->cur_line, new_index, KEY_MOTION_CHAR);
@@ -1748,13 +1810,17 @@ cursor_to_beginning(ledit_buffer *buffer, char *text, int len) {
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, &x);
- 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_line);
+ pango_layout_index_to_line_x(ll->layout, buffer->cur_index, 0, &sli, &x);
+ PangoLayoutLine *pl = pango_layout_get_line_readonly(ll->layout, sli);
+ 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,
@@ -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 int key_state, int lang_index, int *found) {
struct key *cur_keys = keys[lang_index].keys;
diff --git a/keys_basic.h b/keys_basic.h
@@ -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_index);
diff --git a/keys_basic_config.h b/keys_basic_config.h
@@ -1,3 +1,4 @@
+/* FIXME: these aren't really used properly */
enum key_type {
KEY_NONE = 0,
KEY_MISC = 1,
@@ -93,6 +94,7 @@ static struct action replace(ledit_buffer *buffer, char *text, int len);
static struct action cursor_to_first_non_ws(ledit_buffer *buffer, char *text, int len);
static struct action join_lines(ledit_buffer *buffer, char *text, int len);
static struct action insert_at_beginning(ledit_buffer *buffer, char *text, int len);
+static struct action toggle_hard_line_based(ledit_buffer *buffer, char *text, int len);
/* FIXME: maybe sort these and use binary search
-> but that would mess with the catch-all keys */
@@ -111,6 +113,7 @@ static struct key keys_en[] = {
{"j", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down},
{"k", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_up},
{"h", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_left},
+ {"t", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &toggle_hard_line_based},
{NULL, 0, XK_space, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_right},
{"j", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down},
{"n", ControlMask, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down},
diff --git a/ledit.c b/ledit.c
@@ -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->cur_index);
+ keys_basic_init(buffer);
redraw();
}
diff --git a/memory.c b/memory.c
@@ -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
@@ -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
@@ -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 buggy", -1);
+ text = "ledit is buggy";
break;
}
+ char *final_text = ledit_strcat(text, window->mode_extra_text ? window->mode_extra_text : "");
+ 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, &window->bb->mode_h);
ledit_draw_grow(window, window->bb->mode_draw, window->bb->mode_w, window->bb->mode_h);
XftDrawRect(window->bb->mode_draw->xftdraw, &window->theme->text_bg, 0, 0, window->bb->mode_w, window->bb->mode_h);
@@ -261,6 +265,12 @@ ledit_window_set_mode(ledit_window *window, enum ledit_mode mode) {
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) {
@@ -411,6 +421,7 @@ ledit_window_create(ledit_common *common, ledit_theme *theme) {
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->screen);
@@ -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
@@ -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);
@@ -62,6 +63,7 @@ void ledit_window_show_message(ledit_window *window, char *text, int len);
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);