commit 0498ed82f507017d8a5c6d83da08c66b2520bf95
parent 3572b3d7dd300642a94067f72f30fc83c8651e39
Author: lumidify <nobody@lumidify.org>
Date: Thu, 9 Dec 2021 17:34:35 +0100
Somewhat properly implement substitution
Diffstat:
M | buffer.c | | | 29 | +++++++++++++++++++++++++++++ |
M | buffer.h | | | 11 | ++++++++++- |
M | keys_basic.c | | | 61 | ++++++++++++++++++++++++++++++++++++------------------------- |
M | keys_command.c | | | 242 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
M | view.c | | | 8 | ++++++-- |
5 files changed, 251 insertions(+), 100 deletions(-)
diff --git a/buffer.c b/buffer.c
@@ -202,6 +202,35 @@ buffer_insert_mark(ledit_buffer *buffer, char *mark, size_t len, size_t line, si
marklist->len++;
}
+/* FIXME: check that byte is actually at grapheme boundary
+ (difficult because that can't currently be done by the buffer) */
+int
+buffer_get_mark(ledit_buffer *buffer, char *mark, size_t len, size_t *line_ret, size_t *byte_ret) {
+ ledit_buffer_marklist *marklist = buffer->marklist;
+ int ret = 1;
+ for (size_t i = 0; i < marklist->len; i++) {
+ if (!strncmp(mark, marklist->marks[i].text, len)) {
+ ledit_line *ll;
+ ledit_buffer_mark *m = &marklist->marks[i];
+ if (m->line >= buffer->lines_num) {
+ *line_ret = buffer->lines_num - 1;
+ ll = buffer_get_line(buffer, *line_ret);
+ *byte_ret = ll->len;
+ } else {
+ *line_ret = m->line;
+ ll = buffer_get_line(buffer, m->line);
+ if (m->byte >= ll->len)
+ *byte_ret = ll->len;
+ else
+ *byte_ret = m->byte;
+ }
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
static ledit_buffer_marklist *
marklist_create(void) {
ledit_buffer_marklist *marklist = ledit_malloc(sizeof(ledit_buffer_marklist));
diff --git a/buffer.h b/buffer.h
@@ -184,11 +184,20 @@ size_t line_prev_utf8(ledit_line *line, size_t index);
size_t line_byte_to_char(ledit_line *line, size_t byte);
/*
- * Insert a mark with key 'mark' at line 'line' and byte 'byte'.
+ * Insert a mark with key 'mark' (which has byte length 'len') at line 'line' and byte 'byte'.
*/
void buffer_insert_mark(ledit_buffer *buffer, char *mark, size_t len, size_t line, size_t byte);
/*
+ * Retrieve mark 'mark' (with byte length 'len').
+ * The line and byte of the mark are written to 'line_ret' and 'byte_ret'.
+ * These returned positions are always valid positions in the buffer, even
+ * if the buffer has been modified and the mark points to an invalid location.
+ * Returns 0 if the mark was found, 1 otherwise.
+ */
+int buffer_get_mark(ledit_buffer *buffer, char *mark, size_t len, size_t *line_ret, size_t *byte_ret);
+
+/*
* Perform one undo step.
* 'mode' should be the current mode of the calling view.
* 'cur_line' and 'cur_byte' are filled with the new line and cursor
diff --git a/keys_basic.c b/keys_basic.c
@@ -121,6 +121,15 @@ static void change_cb(ledit_view *view, size_t line, size_t char_pos, enum key_t
static void push_undo_empty_insert(ledit_view *view, size_t line, size_t index, int start_group);
static void move_half_screen(ledit_view *view, int movement);
+static struct action
+view_locked_error(ledit_view *view) {
+ window_show_message(view->window, view->lock_text, -1);
+ return (struct action){ACTION_NONE, NULL};
+}
+
+#define CHECK_VIEW_LOCKED(view) if (view->lock_text) return view_locked_error(view)
+#define CHECK_VIEW_LOCKED_NORETURN(view) if (view->lock_text) (void)view_locked_error(view)
+
/* FIXME: move to common */
static void
swap_sz(size_t *a, size_t *b) {
@@ -478,6 +487,7 @@ static struct action
delete_chars_forwards(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
int num = get_key_repeat();
if (num == -1) {
window_show_message(view->window, "Invalid key", -1);
@@ -505,6 +515,7 @@ static struct action
delete_chars_backwards(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
int num = get_key_repeat();
if (num == -1) {
window_show_message(view->window, "Invalid key", -1);
@@ -543,6 +554,7 @@ push_undo_empty_insert(ledit_view *view, size_t line, size_t index, int start_gr
static struct action
append_line_above(ledit_view *view, char *text, size_t len) {
+ CHECK_VIEW_LOCKED(view);
size_t start, end;
/* do this here already so the mode group is the same for the newline insertion */
enter_insert(view, text, len);
@@ -558,6 +570,7 @@ append_line_above(ledit_view *view, char *text, size_t len) {
static struct action
append_line_below(ledit_view *view, char *text, size_t len) {
+ CHECK_VIEW_LOCKED(view);
size_t start, end;
enter_insert(view, text, len);
view_get_pos_softline_bounds(view, view->cur_line, view->cur_index, &start, &end);
@@ -572,6 +585,7 @@ append_line_below(ledit_view *view, char *text, size_t len) {
static struct action
append_after_cursor(ledit_view *view, char *text, size_t len) {
+ CHECK_VIEW_LOCKED(view);
enter_insert(view, text, len);
/* make cursor jump back to original position on undo */
push_undo_empty_insert(view, view->cur_line, view->cur_index, 1);
@@ -583,6 +597,7 @@ append_after_cursor(ledit_view *view, char *text, size_t len) {
static struct action
append_after_eol(ledit_view *view, char *text, size_t len) {
+ CHECK_VIEW_LOCKED(view);
size_t start, end;
enter_insert(view, text, len);
view_get_pos_softline_bounds(view, view->cur_line, view->cur_index, &start, &end);
@@ -833,6 +848,7 @@ static struct action
delete_to_eol(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
if (!key_stack_empty())
return err_invalid_key(view);
size_t start, end;
@@ -859,6 +875,7 @@ static struct action
change_to_eol(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
if (!key_stack_empty())
return err_invalid_key(view);
view_set_mode(view, INSERT);
@@ -885,6 +902,7 @@ static struct action
change(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
motion_callback cb = NULL;
int num = get_key_repeat_and_motion_cb(&cb);
if (num == -1)
@@ -921,6 +939,7 @@ change(ledit_view *view, char *text, size_t len) {
static void
change_cb(ledit_view *view, size_t line, size_t char_pos, enum key_type type) {
+ CHECK_VIEW_LOCKED_NORETURN(view);
/* set mode first so the deletion is included in the undo group */
view_set_mode(view, INSERT);
int line_based = type == KEY_MOTION_LINE ? 1 : 0;
@@ -1066,6 +1085,7 @@ static struct action
delete(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
motion_callback cb = NULL;
int num = get_key_repeat_and_motion_cb(&cb);
if (num == -1)
@@ -1104,6 +1124,7 @@ delete(ledit_view *view, char *text, size_t len) {
/* FIXME: should this get number of lines to remove or actual end line? */
static void
delete_cb(ledit_view *view, size_t line, size_t char_pos, enum key_type type) {
+ CHECK_VIEW_LOCKED_NORETURN(view);
view_wipe_line_cursor_attrs(view, view->cur_line);
int line_based = type == KEY_MOTION_LINE ? 1 : 0;
delete_range(
@@ -1124,6 +1145,7 @@ static struct action
paste_normal(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
if (!paste_buffer) {
window_show_message(view->window, "Nothing to paste", -1);
discard_repetition_stack();
@@ -1182,6 +1204,7 @@ static struct action
paste_normal_backwards(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
if (!paste_buffer) {
window_show_message(view->window, "Nothing to paste", -1);
discard_repetition_stack();
@@ -1347,6 +1370,7 @@ static struct action
backspace(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
/* FIXME: don't copy to paste buffer on del_sel here; delete entire grapheme */
if (delete_selection(view)) {
/* NOP */
@@ -1367,6 +1391,7 @@ static struct action
delete_key(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
ledit_line *cur_line = buffer_get_line(view->buffer, view->cur_line);
if (delete_selection(view)) {
/* NOP */
@@ -1387,6 +1412,7 @@ static struct action
move_to_eol(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
motion_callback cb;
int num = get_key_repeat_and_motion_cb(&cb);
if (num == -1)
@@ -1544,6 +1570,7 @@ static struct action
return_key(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
int start_group = 1;
if (delete_selection(view))
start_group = 0;
@@ -1591,6 +1618,7 @@ static struct action
enter_insert(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
if (view->mode == NORMAL)
view_wipe_line_cursor_attrs(view, view->cur_line);
view_set_mode(view, INSERT);
@@ -1663,6 +1691,7 @@ static struct action
join_lines(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
int num = get_key_repeat();
if (num == -1)
return err_invalid_key(view);
@@ -1696,6 +1725,7 @@ join_lines(ledit_view *view, char *text, size_t len) {
static struct action
insert_at_beginning(ledit_view *view, char *text, size_t len) {
+ CHECK_VIEW_LOCKED(view);
if (!key_stack_empty())
return err_invalid_key(view);
enter_insert(view, text, len);
@@ -1854,39 +1884,15 @@ mark_line_cb(ledit_view *view, char *text, size_t len) {
return (struct action){ACTION_NONE, NULL};
}
-/* FIXME: move part of this to buffer.c */
-/* FIXME: check that byte is actually at grapheme boundary */
static struct action
jump_to_mark_cb(ledit_view *view, char *text, size_t len) {
grab_char_cb = NULL;
- ledit_buffer_marklist *marklist = view->buffer->marklist;
motion_callback cb;
int num = get_key_repeat_and_motion_cb(&cb);
if (num > 0)
return err_invalid_key(view);
size_t line = 0, index = 0;
- int mark_found = 0;
- for (size_t i = 0; i < marklist->len; i++) {
- if (!strncmp(text, marklist->marks[i].text, len)) {
- ledit_line *ll;
- ledit_buffer_mark *m = &marklist->marks[i];
- if (m->line >= view->lines_num) {
- line = view->lines_num - 1;
- ll = buffer_get_line(view->buffer, line);
- index = ll->len;
- } else {
- line = m->line;
- ll = buffer_get_line(view->buffer, m->line);
- if (m->byte >= ll->len)
- index = ll->len;
- else
- index = m->byte;
- }
- mark_found = 1;
- break;
- }
- }
- if (!mark_found)
+ if (buffer_get_mark(view->buffer, text, len, &line, &index))
return err_invalid_key(view);
if (view->mode == VISUAL) {
view_set_selection(
@@ -1969,6 +1975,7 @@ static struct action
undo(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
view_wipe_selection(view);
view_wipe_line_cursor_attrs(view, view->cur_line);
view_undo(view);
@@ -1981,6 +1988,7 @@ static struct action
redo(ledit_view *view, char *text, size_t len) {
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
view_wipe_selection(view);
view_wipe_line_cursor_attrs(view, view->cur_line);
view_redo(view);
@@ -1991,6 +1999,7 @@ redo(ledit_view *view, char *text, size_t len) {
static struct action
insert_mode_insert_text(ledit_view *view, char *text, size_t len) {
+ CHECK_VIEW_LOCKED(view);
/* FIXME: set cur_index when deleting selection */
delete_selection(view);
insert_text(view, view->cur_line, view->cur_index, text, len, 0, 0, 0, 0, 0, 0, 1);
@@ -2149,6 +2158,7 @@ GEN_MOVE_TO_CHAR(
static struct action
replace_cb(ledit_view *view, char *text, size_t len) {
+ CHECK_VIEW_LOCKED(view);
size_t start_index = view->cur_index;
/* FIXME: replace with (key repeat) * text instead of just text */
size_t end_index = view_next_cursor_pos(
@@ -2176,6 +2186,7 @@ replace(ledit_view *view, char *text, size_t len) {
(void)view;
(void)text;
(void)len;
+ CHECK_VIEW_LOCKED(view);
int num = get_key_repeat();
if (num != 0)
return err_invalid_key(view);
diff --git a/keys_command.c b/keys_command.c
@@ -27,9 +27,20 @@
#include "keys_command.h"
#include "keys_command_config.h"
-static char *last_search = NULL;
-static char *last_replacement = NULL;
-static int last_replacement_global = 0;
+static struct {
+ char *search;
+ char *replace;
+ size_t slen;
+ size_t rlen;
+ size_t line;
+ size_t byte;
+ size_t old_line;
+ size_t old_byte;
+ size_t max_line;
+ int global;
+ int num;
+ int start_group; /* only set for the first replacement */
+} sub_state = {NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
static int
view_locked_error(ledit_view *view) {
@@ -37,7 +48,7 @@ view_locked_error(ledit_view *view) {
return 0;
}
-#define CHECK_VIEW_LOCKED if (view->lock_text) return view_locked_error(view)
+#define CHECK_VIEW_LOCKED(view) if (view->lock_text) return view_locked_error(view)
/* FIXME: history for search and commands */
@@ -110,13 +121,114 @@ handle_write_quit(ledit_view *view, char *cmd, size_t l1, size_t l2) {
return 0;
}
+static void
+show_num_substituted(ledit_view *view) {
+ char buf[30];
+ if (snprintf(buf, sizeof(buf), "%d substitution(s)", sub_state.num) < 0) {
+ window_show_message(view->window, "This message is a bug, tell lumidify about it", -1);
+ } else {
+ window_show_message(view->window, buf, -1);
+ }
+}
+
+/* returns 1 when match was found, 0 otherwise */
+static int
+next_replace_pos(
+ ledit_view *view,
+ size_t line, size_t byte, size_t max_line,
+ size_t *line_ret, size_t *byte_ret) {
+ size_t start_index = byte;
+ for (size_t i = line; i <= max_line; i++) {
+ ledit_line *ll = buffer_get_line(view->buffer, i);
+ buffer_normalize_line(ll);
+ char *pos = strstr(ll->text + start_index, sub_state.search);
+ if (pos != NULL) {
+ *line_ret = i;
+ *byte_ret = (size_t)(pos - ll->text);
+ return 1;
+ }
+ start_index = 0;
+ }
+ return 0;
+}
+
+/* returns whether keys should continue being captured */
+static int
+move_to_next_substitution(ledit_view *view) {
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ if (!next_replace_pos(view, sub_state.line, sub_state.byte, sub_state.max_line, &sub_state.line, &sub_state.byte)) {
+ view->cur_line = sub_state.line;
+ view->cur_index = sub_state.byte;
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
+ window_show_message(view->window, "No more matches", -1);
+ buffer_unlock_all_views(view->buffer);
+ return 0;
+ }
+ view->cur_line = sub_state.line;
+ view->cur_index = sub_state.byte;
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
+ window_show_message(view->window, "Replace? (y/Y/n/N)", -1);
+ view_ensure_cursor_shown(view);
+ return 1;
+}
+
+/* WARNING: sub_state must be set properly! */
+static void
+substitute_single(ledit_view *view) {
+ ledit_range cur_range;
+ cur_range.line1 = sub_state.old_line;
+ cur_range.byte1 = sub_state.old_byte;
+ cur_range.line2 = sub_state.line;
+ cur_range.byte2 = sub_state.byte;
+ buffer_delete_with_undo_base(
+ view->buffer, cur_range,
+ sub_state.start_group, view->mode,
+ sub_state.line, sub_state.byte,
+ sub_state.line, sub_state.byte + sub_state.slen, NULL
+ );
+ sub_state.start_group = 0;
+ cur_range.line1 = sub_state.line;
+ cur_range.byte1 = sub_state.byte;
+ buffer_insert_with_undo_base(
+ view->buffer, cur_range, 0, 0, view->mode,
+ sub_state.line, sub_state.byte,
+ sub_state.replace, sub_state.rlen,
+ NULL, NULL
+ );
+ sub_state.num++;
+}
+
+static void
+substitute_all_remaining(ledit_view *view) {
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ size_t min_line = SIZE_MAX;
+ while (next_replace_pos(view, sub_state.line, sub_state.byte, sub_state.max_line, &sub_state.line, &sub_state.byte)) {
+ if (sub_state.line < min_line)
+ min_line = sub_state.line;
+ substitute_single(view);
+ view->cur_line = sub_state.old_line = sub_state.line;
+ view->cur_index = sub_state.old_byte = sub_state.byte;
+ if (!sub_state.global) {
+ sub_state.line++;
+ sub_state.byte = 0;
+ } else {
+ sub_state.byte += sub_state.rlen;
+ }
+ }
+ if (min_line < view->lines_num)
+ buffer_recalc_all_views_from_line(view->buffer, min_line);
+ /* FIXME: show number replaced */
+ /* this doesn't need to be added to the undo stack since it's called on undo/redo anyways */
+ view->cur_index = view_get_legal_normal_pos(view, view->cur_line, view->cur_index);
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
+ view_ensure_cursor_shown(view);
+ show_num_substituted(view);
+ buffer_unlock_all_views(view->buffer);
+}
+
static int
handle_substitute(ledit_view *view, char *cmd, size_t l1, size_t l2) {
- (void)view;
- (void)cmd;
- (void)l1;
- (void)l2;
- CHECK_VIEW_LOCKED;
+ CHECK_VIEW_LOCKED(view);
cmd++; /* remove 's' at beginning */
size_t len = strlen(cmd);
if (len == 0) goto error;
@@ -146,64 +258,27 @@ handle_substitute(ledit_view *view, char *cmd, size_t l1, size_t l2) {
}
c++;
}
- free(last_search);
- free(last_replacement);
- last_search = ledit_strdup(cmd);
- last_replacement = ledit_strdup(next);
- last_replacement_global = global;
+ free(sub_state.search);
+ free(sub_state.replace);
+ sub_state.search = ledit_strdup(cmd);
+ sub_state.replace = ledit_strdup(next);
+ sub_state.slen = strlen(sub_state.search);
+ sub_state.rlen = strlen(sub_state.replace);
+ sub_state.global = global;
+ sub_state.line = l1;
+ sub_state.byte = 0;
+ sub_state.old_line = view->cur_line;
+ sub_state.old_byte = view->cur_index;
+ sub_state.max_line = l2;
+ sub_state.num = 0;
+ sub_state.start_group = 1;
if (confirm) {
buffer_lock_all_views_except(view->buffer, view, "Ongoing substitution in other view.");
- buffer_unlock_all_views(view->buffer);
+ view->cur_command_type = CMD_SUBSTITUTE;
+ return move_to_next_substitution(view);
} else {
- int num = 0;
- int start_undo_group = 1;
- size_t slen = strlen(last_search);
- size_t rlen = strlen(last_replacement);
- txtbuf *buf = txtbuf_new(); /* FIXME: don't allocate new every time */
- view_wipe_line_cursor_attrs(view, view->cur_line);
- size_t min_line = SIZE_MAX;
- for (size_t i = l1 - 1; i < l2; i++) {
- ledit_line *ll = buffer_get_line(view->buffer, i);
- buffer_normalize_line(ll);
- char *pos = strstr(ll->text, last_search);
- if (pos != NULL && i < min_line)
- min_line = i;
- while (pos != NULL) {
- size_t index = (size_t)(pos - ll->text);
- ledit_range cur_range;
- cur_range.line1 = view->cur_line;
- cur_range.byte1 = view->cur_line;
- cur_range.line2 = i;
- cur_range.byte2 = index;
- buffer_delete_with_undo_base(
- view->buffer, cur_range,
- start_undo_group, view->mode,
- i, index, i, index + slen, NULL
- );
- view->cur_line = i;
- view->cur_index = index;
- start_undo_group = 0;
- cur_range.line1 = i;
- cur_range.byte1 = index;
- buffer_insert_with_undo_base(
- view->buffer, cur_range, 0, 0, view->mode,
- i, index, last_replacement, rlen,
- NULL, NULL
- );
- num++;
- if (!global) break;
- buffer_normalize_line(ll); /* just in case */
- pos = strstr(ll->text + index + rlen, last_search);
- }
- }
- buffer_recalc_all_views_from_line(view->buffer, min_line);
- /* FIXME: show number replaced */
- /* this doesn't need to be added to the undo stack since it's called on undo/redo anyways */
- view->cur_index = view_get_legal_normal_pos(view, view->cur_line, view->cur_index);
- view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
- view_ensure_cursor_shown(view);
- txtbuf_destroy(buf);
+ substitute_all_remaining(view);
}
return 0;
error:
@@ -312,8 +387,9 @@ parse_range(ledit_view *view, char *cmd, size_t len, char **cmd_ret, size_t *lin
if ((*l1_valid || *l2_valid) && (l1 == 0 || l2 == 0 || l1 > view->lines_num || l2 > view->lines_num))
return 1; /* FIXME: better error messages */
*cmd_ret = c;
- *line1_ret = l1;
- *line2_ret = l2;
+ /* ranges are given 1-indexed by user */
+ *line1_ret = l1 - 1;
+ *line2_ret = l2 - 1;
return 0;
}
@@ -328,7 +404,9 @@ handle_cmd(ledit_view *view, char *cmd, size_t len) {
if (parse_range(view, cmd, len, &c, &l1, &l2, &l1_valid, &l2_valid))
return 0;
int range_given = l1_valid && l2_valid;
- /* FIXME: mandatory range */
+ if (!range_given) {
+ l1 = l2 = view->cur_line;
+ }
for (size_t i = 0; i < LENGTH(cmds); i++) {
if (!strncmp(cmds[i].cmd, c, strlen(cmds[i].cmd)) &&
(!range_given || cmds[i].type == CMD_OPTIONAL_RANGE)) {
@@ -340,33 +418,53 @@ handle_cmd(ledit_view *view, char *cmd, size_t len) {
static int
substitute_yes(ledit_view *view, char *key_text, size_t len) {
- (void)view;
(void)key_text;
(void)len;
- return 1;
+ substitute_single(view);
+ buffer_recalc_line(view->buffer, sub_state.line);
+ if (!sub_state.global) {
+ sub_state.line++;
+ sub_state.byte = 0;
+ } else {
+ sub_state.byte += sub_state.rlen;
+ }
+ int ret = move_to_next_substitution(view);
+ if (ret)
+ show_num_substituted(view);
+ return ret;
}
static int
substitute_yes_all(ledit_view *view, char *key_text, size_t len) {
- (void)view;
(void)key_text;
(void)len;
+ substitute_all_remaining(view);
+ show_num_substituted(view);
return 0;
}
static int
substitute_no(ledit_view *view, char *key_text, size_t len) {
- (void)view;
(void)key_text;
(void)len;
- return 1;
+ if (!sub_state.global) {
+ sub_state.line++;
+ sub_state.byte = 0;
+ } else {
+ sub_state.byte += sub_state.slen;
+ }
+ int ret = move_to_next_substitution(view);
+ if (ret)
+ show_num_substituted(view);
+ return ret;
}
static int
substitute_no_all(ledit_view *view, char *key_text, size_t len) {
- (void)view;
(void)key_text;
(void)len;
+ buffer_unlock_all_views(view->buffer);
+ show_num_substituted(view);
return 0;
}
diff --git a/view.c b/view.c
@@ -627,8 +627,8 @@ line_prev_word(
PangoLayout *layout = get_pango_layout(view, line);
const PangoLogAttr *attrs =
pango_layout_get_log_attrs_readonly(layout, &nattrs);
- if (char_index > (size_t)nattrs)
- return -1;
+ if (char_index > (size_t)nattrs - 1)
+ char_index = (size_t)nattrs - 1;
/* this is a bit weird because size_t can't be negative */
for (size_t i = char_index; i > 0; i--) {
if (attrs[i-1].is_word_start) {
@@ -655,6 +655,8 @@ line_prev_bigword(
size_t next_cursorb = byte;
size_t next_cursorc = char_index;
int found_word = 0;
+ if (char_index > (size_t)nattrs - 1)
+ char_index = (size_t)nattrs - 1;
/* this is a bit weird because size_t can't be negative */
for (size_t i = char_index; i > 0; i--) {
if (!found_word && !attrs[i-1].is_white) {
@@ -820,6 +822,7 @@ view_next_##name(
cur_line < view->lines_num - 1) { \
cur_line++; \
cur_byte = 0; \
+ cur_char = 0; \
wrapped_line = 1; \
} \
if (last_ret == -1 && cur_line == view->lines_num - 1) \
@@ -854,6 +857,7 @@ view_prev_##name(
cur_line--; \
ll = buffer_get_line(view->buffer, cur_line); \
cur_byte = ll->len; \
+ cur_char = ll->len; \
} \
if (last_ret == -1 && cur_line == 0) \
break; \