Introduction
Introduction Statistics Contact Development Disclaimer Help
tSupport highlighting entire words when searching and replacing - ledit - Text …
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 b7f7a516c405f90fb1294a6b7cf4463373294cb0
parent 4e39cee7c2670c566dd05abc926f01aa8444e018
Author: lumidify <[email protected]>
Date: Sat, 22 Oct 2022 11:47:14 +0200
Support highlighting entire words when searching and replacing
Diffstat:
M buffer.c | 1 +
M configparser.c | 29 +++++++++++++++++++++++++++++
M configparser.h | 1 +
M keys_basic.c | 14 ++++++++------
M keys_command.c | 65 ++++++++++++++++++++++++-----…
M ledit.1 | 2 --
M leditrc.5 | 16 +++++++++++-----
M leditrc.example | 5 +++--
M search.c | 21 +++++++++++++--------
M search.h | 4 ++--
M theme_config.h | 3 +++
M util.c | 2 +-
M util.h | 2 +-
M view.c | 14 +++++++++++---
14 files changed, 134 insertions(+), 45 deletions(-)
---
diff --git a/buffer.c b/buffer.c
t@@ -274,6 +274,7 @@ buffer_set_hard_line_based(ledit_buffer *buffer, int hl) {
buffer->hard_line_based = hl;
}
+/* FIXME: lock view if others are locked! */
void
buffer_add_view(ledit_buffer *buffer, ledit_mode mode, size_t line, size_t pos…
size_t new_num = add_sz(buffer->views_num, 1);
diff --git a/configparser.c b/configparser.c
t@@ -522,6 +522,34 @@ destroy_theme_string(ledit_common *common, void *obj) {
free(*obj_str);
}
+static int
+parse_theme_bool(
+ ledit_common *common,
+ void *obj, const char *val, size_t val_len, char *key,
+ char *filename, size_t line, size_t line_offset, char **errstr) {
+ (void)common;
+ int *num = (int *)obj;
+ if (str_array_equal("true", val, val_len)) {
+ *num = 1;
+ return 0;
+ } else if (str_array_equal("false", val, val_len)) {
+ *num = 0;
+ return 0;
+ }
+ *errstr = print_fmt(
+ "%s: Invalid boolean '%.*s' "
+ "for '%s' at line %zu, position %zu",
+ filename, val_len, val, key, line, line_offset
+ );
+ return 1;
+}
+
+static void
+destroy_theme_bool(ledit_common *common, void *obj) {
+ (void)common;
+ (void)obj;
+}
+
/* FIXME: This interface is absolutely horrible - it's mainly this way to reus…
theme array for the destroy function */
/* If theme is NULL, a new theme is loaded, else it is destroyed */
t@@ -560,6 +588,7 @@ load_destroy_theme(ledit_common *common, ast_list *theme_l…
{"bar-fmt", &theme->bar_fmt, &parse_theme_string, &destroy_the…
{"scrollbar-fg", &theme->scrollbar_fg, &parse_theme_color, &de…
{"scrollbar-bg", &theme->scrollbar_bg, &parse_theme_color, &de…
+ {"highlight-search", &theme->highlight_search, &parse_theme_bo…
};
if (default_init)
diff --git a/configparser.h b/configparser.h
t@@ -10,6 +10,7 @@ typedef struct {
int scrollbar_width;
int scrollbar_step;
int text_size;
+ int highlight_search;
XftColor text_fg;
XftColor text_bg;
XftColor cursor_fg;
diff --git a/keys_basic.c b/keys_basic.c
t@@ -1,3 +1,4 @@
+/* FIXME: all movement commands that modify the selection should first check i…
/* FIXME: should motion callbacks be ignored in visual mode as they currently …
/* FIXME: check allowed modes at beginning of functions */
/* FIXME: the stacks here are shared for all views which can cause weird
t@@ -180,8 +181,8 @@ static struct basic_key_cb basic_key_cb_map[] = {
{"delete-to-eol", &delete_to_eol, KEY_FLAG_JUMP_TO_CURSOR, NORMAL|INSE…
{"enter-commandedit", &enter_commandedit, KEY_FLAG_NONE|KEY_FLAG_LOCK_…
{"enter-insert", &enter_insert, KEY_FLAG_JUMP_TO_CURSOR, NORMAL|VISUAL…
- {"enter-searchedit-backwards", &enter_searchedit_backward, KEY_FLAG_NO…
- {"enter-searchedit-forwards", &enter_searchedit_forward, KEY_FLAG_NONE…
+ {"enter-searchedit-backwards", &enter_searchedit_backward, KEY_FLAG_NO…
+ {"enter-searchedit-forwards", &enter_searchedit_forward, KEY_FLAG_NONE…
{"enter-visual", &enter_visual, KEY_FLAG_JUMP_TO_CURSOR, NORMAL|INSERT…
{"return-to-normal", &return_to_normal, KEY_FLAG_JUMP_TO_CURSOR|KEY_FL…
{"find-char-backwards", &find_char_backwards, KEY_FLAG_JUMP_TO_CURSOR|…
t@@ -224,8 +225,8 @@ static struct basic_key_cb basic_key_cb_map[] = {
{"scroll-lines-up", &scroll_lines_up, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG…
{"scroll-with-cursor-down", &scroll_with_cursor_down, KEY_FLAG_JUMP_TO…
{"scroll-with-cursor-up", &scroll_with_cursor_up, KEY_FLAG_JUMP_TO_CUR…
- {"search-next", &key_search_next, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOC…
- {"search-previous", &key_search_prev, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG…
+ {"search-next", &key_search_next, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG_LOC…
+ {"search-previous", &key_search_prev, KEY_FLAG_JUMP_TO_CURSOR|KEY_FLAG…
{"show-line", &show_line, KEY_FLAG_LOCK_ALLOWED, NORMAL|VISUAL|INSERT},
{"switch-selection-end", &switch_selection_end, KEY_FLAG_JUMP_TO_CURSO…
{"toggle-hard-line-based", &toggle_hard_line_based, KEY_FLAG_NONE|KEY_…
t@@ -695,8 +696,8 @@ delete_selection(ledit_view *view) {
);
paste_buffer_line_based = 0;
view->sel_valid = 0;
- view->sel.line1 = view->sel.line2 = 0;
- view->sel.byte1 = view->sel.byte2 = 0;
+ view->sel.line1 = view->sel.line2 = view->cur_line;
+ view->sel.byte1 = view->sel.byte2 = view->cur_index;
view_wipe_line_cursor_attrs(view, view->cur_line);
return 1;
}
t@@ -1797,6 +1798,7 @@ move_cursor_left_right(ledit_view *view, int dir, int al…
} else {
view->cur_index = new_index;
if (view->mode == VISUAL) {
+ /* FIXME: check if view->sel_valid and only use it the…
view_set_selection(view, view->sel.line1, view->sel.by…
} else if (view->mode == INSERT && view->sel_valid) {
/* FIXME: I guess this is unnecessary now that no
diff --git a/keys_command.c b/keys_command.c
t@@ -355,20 +355,36 @@ next_replace_pos(
/* 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);
+ ledit_theme *theme = config_get_theme();
+ if (view->mode == NORMAL)
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ else if (view->mode == VISUAL)
+ view_wipe_selection(view);
if (!next_replace_pos(view, sub_state.line, sub_state.byte, sub_state.…
+ /* FIXME: why are these set here? */
view->cur_line = sub_state.line;
view->cur_index = sub_state.byte;
- if (view->mode == NORMAL)
+ if (view->mode == NORMAL) {
+ view->cur_index = view_get_legal_normal_pos(view, view…
view_set_line_cursor_attrs(view, view->cur_line, view-…
+ } else if (view->mode == VISUAL) {
+ view_set_selection(view, view->cur_line, view->cur_ind…
+ }
window_show_message(view->window, "No more matches", -1);
buffer_unlock_all_views(view->buffer);
return 0;
}
+ if (theme->highlight_search && view->mode != VISUAL) {
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ view_set_mode(view, VISUAL);
+ }
view->cur_line = sub_state.line;
view->cur_index = sub_state.byte;
- if (view->mode == NORMAL)
+ if (view->mode == NORMAL) {
view_set_line_cursor_attrs(view, view->cur_line, view->cur_ind…
+ } else if (view->mode == VISUAL && theme->highlight_search) {
+ view_set_selection(view, view->cur_line, view->cur_index, view…
+ }
window_show_message(view->window, "Replace? (y/Y/n/N)", -1);
view_ensure_cursor_shown(view);
return 1;
t@@ -402,7 +418,10 @@ substitute_single(ledit_view *view) {
static void
substitute_all_remaining(ledit_view *view) {
- view_wipe_line_cursor_attrs(view, view->cur_line);
+ if (view->mode == NORMAL)
+ view_wipe_line_cursor_attrs(view, view->cur_line);
+ else if (view->mode == VISUAL)
+ view_wipe_selection(view);
size_t min_line = SIZE_MAX;
while (next_replace_pos(view, sub_state.line, sub_state.byte, sub_stat…
if (sub_state.line < min_line)
t@@ -424,6 +443,8 @@ substitute_all_remaining(ledit_view *view) {
/* this doesn't need to be added to the undo stack since it's …
view->cur_index = view_get_legal_normal_pos(view, view->cur_li…
view_set_line_cursor_attrs(view, view->cur_line, view->cur_ind…
+ } else if (view->mode == VISUAL) {
+ view_set_selection(view, view->cur_line, view->cur_index, view…
}
view_ensure_cursor_shown(view);
buffer_unlock_all_views(view->buffer);
t@@ -462,6 +483,8 @@ handle_substitute(ledit_view *view, char *cmd, size_t l1, …
}
c++;
}
+ free(sep);
+ sep = NULL;
free(sub_state.search);
free(sub_state.replace);
sub_state.search = ledit_strdup(cmd);
t@@ -477,12 +500,6 @@ handle_substitute(ledit_view *view, char *cmd, size_t l1,…
sub_state.num = 0;
sub_state.start_group = 1;
- /* trying to perform substitution in visual mode would make
- it unnecessarily complicated */
- if (view->mode == VISUAL) {
- view_wipe_selection(view);
- view_set_mode(view, NORMAL);
- }
if (confirm) {
buffer_lock_all_views_except(view->buffer, view, "Ongoing subs…
view->cur_command_type = CMD_SUBSTITUTE;
t@@ -490,7 +507,6 @@ handle_substitute(ledit_view *view, char *cmd, size_t l1, …
} else {
substitute_all_remaining(view);
}
- free(sep);
return 0;
error:
window_show_message(view->window, "Invalid command", -1);
t@@ -871,13 +887,24 @@ edit_nextsearch(ledit_view *view, char *key_text, size_t…
return 1;
}
+/* FIXME: the current "highlight_search" support is a bit weird and will proba…
+ in some way if other support for visual mode (e.g. only search in selection…
/* FIXME: support visual mode, i.e. change selection to new place? */
void
search_next(ledit_view *view) {
view_wipe_line_cursor_attrs(view, view->cur_line);
- search_state ret = ledit_search_next(view, &view->cur_line, &view->cur…
- if (view->mode == NORMAL)
+ size_t len = 0;
+ search_state ret = ledit_search_next(view, &view->cur_line, &view->cur…
+ ledit_theme *theme = config_get_theme();
+ /* FIXME: figure out key stack handling when modes are also changed he…
+ if (theme->highlight_search && len > 0 && (ret == SEARCH_NORMAL || ret…
+ view_set_mode(view, VISUAL);
+ view_set_selection(view, view->cur_line, view->cur_index, view…
+ } else if (view->mode == VISUAL) {
+ view_set_selection(view, view->cur_line, view->cur_index, view…
+ } else if (view->mode == NORMAL) {
view_set_line_cursor_attrs(view, view->cur_line, view->cur_ind…
+ }
view_ensure_cursor_shown(view);
if (ret != SEARCH_NORMAL)
window_show_message(view->window, search_state_to_str(ret), -1…
t@@ -886,9 +913,17 @@ search_next(ledit_view *view) {
void
search_prev(ledit_view *view) {
view_wipe_line_cursor_attrs(view, view->cur_line);
- search_state ret = ledit_search_prev(view, &view->cur_line, &view->cur…
- if (view->mode == NORMAL)
+ size_t len = 0;
+ search_state ret = ledit_search_prev(view, &view->cur_line, &view->cur…
+ ledit_theme *theme = config_get_theme();
+ if (theme->highlight_search && len > 0 && (ret == SEARCH_NORMAL || ret…
+ view_set_mode(view, VISUAL);
+ view_set_selection(view, view->cur_line, view->cur_index, view…
+ } else if (view->mode == VISUAL) {
+ view_set_selection(view, view->cur_line, view->cur_index, view…
+ } if (view->mode == NORMAL) {
view_set_line_cursor_attrs(view, view->cur_line, view->cur_ind…
+ }
view_ensure_cursor_shown(view);
if (ret != SEARCH_NORMAL)
window_show_message(view->window, search_state_to_str(ret), -1…
diff --git a/ledit.1 b/ledit.1
t@@ -1,5 +1,3 @@
-.\" WARNING: Some parts of this are stolen shamelessly from OpenBSD's
-.\" vi(1) manpage!
.Dd May 27, 2022
.Dt LEDIT 1
.Os
diff --git a/leditrc.5 b/leditrc.5
t@@ -1,4 +1,4 @@
-.Dd September 2, 2022
+.Dd October 22, 2022
.Dt LEDITRC 5
.Os
.Sh NAME
t@@ -169,6 +169,12 @@ Default: #CCCCCC
.It Ar scrollbar-fg
Color of scrollbar handle.
Default: #000000
+.It Ar highlight-search
+Whether entire words should be highlighted when searching or replacing with co…
+Note that the mode is automatically switched to visual when this is set and a …
+This is a bit weird, but in order to keep everything a bit more consistent, se…
+only allowed in visual mode.
+Default: true
.El
.Sh BINDINGS
The key bindings may be configured by assigning
t@@ -423,10 +429,10 @@ In visual mode, the selection range is automatically pas…
so commands can be performed on it.
.It Ar enter-insert Op normal, visual
Enter insert mode.
-.It Ar enter-searchedit-backwards Op normal, insert
+.It Ar enter-searchedit-backwards Op normal, insert, visual
Open the line editor for searching backwards.
Note that no regex is currently supported.
-.It Ar enter-searchedit-forwards Op normal, insert
+.It Ar enter-searchedit-forwards Op normal, insert, visual
Open the line editor for searching forwards.
Note that no regex is currently supported.
.It Ar enter-visual Op normal, insert
t@@ -652,9 +658,9 @@ Move
.Ar num
lines up, attempting to leave the cursor in its current line and character pos…
Note that this command works with soft lines, regardless of the current mode.
-.It Ar search-next Op normal, insert
+.It Ar search-next Op normal, insert, visual
Move to the next search result.
-.It Ar search-previous Op normal, insert
+.It Ar search-previous Op normal, insert, visual
Move to the previous search result.
.It Ar show-line Op normal, visual, insert
Show the current file name, whether the buffer has been modified since the last
diff --git a/leditrc.example b/leditrc.example
t@@ -18,6 +18,7 @@ theme = {
scrollbar-step = 20
scrollbar-bg = CCCCCC
scrollbar-fg = 000000
+ highlight-search = true
}
bindings = {
t@@ -66,8 +67,8 @@ bindings = {
bind enter-commandedit text ":" modes normal|visual
bind enter-searchedit-backwards text "?" modes normal
bind enter-searchedit-forwards text "/" modes normal
- bind search-next text "n" modes normal
- bind search-previous text "N" modes normal
+ bind search-next text "n" modes normal|visual
+ bind search-previous text "N" modes normal|visual
bind undo text "u" modes normal
bind redo text "U" modes normal
bind repeat-command text "." modes normal
diff --git a/search.c b/search.c
t@@ -7,6 +7,7 @@
/* FIXME: make sure only whole utf8 chars are matched */
static char *last_search = NULL;
+static size_t last_search_len = 0;
enum {
FORWARD,
BACKWARD
t@@ -22,6 +23,7 @@ set_search_forward(char *pattern) {
last_dir = FORWARD;
free(last_search);
last_search = ledit_strdup(pattern);
+ last_search_len = strlen(last_search);
}
void
t@@ -29,12 +31,14 @@ set_search_backward(char *pattern) {
last_dir = BACKWARD;
free(last_search);
last_search = ledit_strdup(pattern);
+ last_search_len = strlen(last_search);
}
static search_state
-search_forward(ledit_view *view, size_t *line_ret, size_t *byte_ret) {
+search_forward(ledit_view *view, size_t *line_ret, size_t *byte_ret, size_t *l…
*line_ret = view->cur_line;
*byte_ret = view->cur_index;
+ *len_ret = last_search_len;
/* if last_search is empty, strstr will find the ending '\0' */
if (last_search == NULL || last_search[0] == '\0')
return SEARCH_NO_PATTERN;
t@@ -81,9 +85,10 @@ search_forward(ledit_view *view, size_t *line_ret, size_t *…
/* FIXME: this is insanely inefficient */
/* FIXME: just go backwards char-by-char and compare */
static search_state
-search_backward(ledit_view *view, size_t *line_ret, size_t *byte_ret) {
+search_backward(ledit_view *view, size_t *line_ret, size_t *byte_ret, size_t *…
*line_ret = view->cur_line;
*byte_ret = view->cur_index;
+ *len_ret = last_search_len;
if (last_search == NULL || last_search[0] == '\0')
return SEARCH_NO_PATTERN;
size_t line = view->cur_line;
t@@ -145,19 +150,19 @@ search_backward(ledit_view *view, size_t *line_ret, size…
}
search_state
-ledit_search_next(ledit_view *view, size_t *line_ret, size_t *byte_ret) {
+ledit_search_next(ledit_view *view, size_t *line_ret, size_t *byte_ret, size_t…
if (last_dir == FORWARD)
- return search_forward(view, line_ret, byte_ret);
+ return search_forward(view, line_ret, byte_ret, len_ret);
else
- return search_backward(view, line_ret, byte_ret);
+ return search_backward(view, line_ret, byte_ret, len_ret);
}
search_state
-ledit_search_prev(ledit_view *view, size_t *line_ret, size_t *byte_ret) {
+ledit_search_prev(ledit_view *view, size_t *line_ret, size_t *byte_ret, size_t…
if (last_dir == FORWARD)
- return search_backward(view, line_ret, byte_ret);
+ return search_backward(view, line_ret, byte_ret, len_ret);
else
- return search_forward(view, line_ret, byte_ret);
+ return search_forward(view, line_ret, byte_ret, len_ret);
}
char *
diff --git a/search.h b/search.h
t@@ -13,8 +13,8 @@ typedef enum {
void search_cleanup(void);
void set_search_forward(char *pattern);
void set_search_backward(char *pattern);
-search_state ledit_search_next(ledit_view *view, size_t *line_ret, size_t *byt…
-search_state ledit_search_prev(ledit_view *view, size_t *line_ret, size_t *byt…
+search_state ledit_search_next(ledit_view *view, size_t *line_ret, size_t *byt…
+search_state ledit_search_prev(ledit_view *view, size_t *line_ret, size_t *byt…
/*
* Get a string corresponding to a search_state.
diff --git a/theme_config.h b/theme_config.h
t@@ -45,5 +45,8 @@ static const char *SCROLLBAR_STEP = "20";
static const char *SCROLLBAR_BG = "#CCCCCC";
/* color of scrollbar handle */
static const char *SCROLLBAR_FG = "#000000";
+/* whether to highlight entire words when searching/replacing */
+/* FIXME: this should maybe be in a separate "general config" section */
+static const char *HIGHLIGHT_SEARCH = "true";
#endif /* _THEME_CONFIG_H_ */
diff --git a/util.c b/util.c
t@@ -50,7 +50,7 @@ sort_range(size_t *l1, size_t *b1, size_t *l2, size_t *b2) {
}
int
-str_array_equal(char *terminated, char *array, size_t len) {
+str_array_equal(const char *terminated, const char *array, size_t len) {
if (!strncmp(terminated, array, len)) {
/* this is kind of inefficient, but there's no way to know
otherwise if strncmp just stopped comparing after a '\0' */
diff --git a/util.h b/util.h
t@@ -32,7 +32,7 @@ void sort_range(size_t *l1, size_t *b1, size_t *l2, size_t *…
* Returns non-zero if they are equal, 0 otherwise.
*/
/* Note: this doesn't work if array contains '\0'. */
-int str_array_equal(char *terminated, char *array, size_t len);
+int str_array_equal(const char *terminated, const char *array, size_t len);
#define LEDIT_MIN(x, y) ((x) < (y) ? (x) : (y))
#define LEDIT_MAX(x, y) ((x) > (y) ? (x) : (y))
diff --git a/view.c b/view.c
t@@ -24,6 +24,9 @@
#include "assert.h"
#include "configparser.h"
+/* FIXME: handle selections better - it can happen that the cursor is moved in…
+ the selection, leading to weird "jumping selection" - this should be made i…
+
/* Basic attributes set for all text. */
static PangoAttrList *basic_attrs = NULL;
t@@ -1746,9 +1749,14 @@ view_wipe_selection(ledit_view *view) {
}
}
view->sel_valid = 0;
- view->sel.line1 = view->sel.line2 = 0;
- view->sel.byte1 = view->sel.byte2 = 0;
- view_set_line_cursor_attrs(view, view->cur_line, view->cur_index);
+ /* FIXME: check what makes most sense here - this used to be set to 0,…
+ caused "jumping effects" because some functions (cursor movement) u…
+ values without checking view->sel_valid before (which should actual…
+ changed because it is an error) */
+ view->sel.line1 = view->sel.line2 = view->cur_line;
+ view->sel.byte1 = view->sel.byte2 = view->cur_index;
+ if (view->mode == NORMAL)
+ view_set_line_cursor_attrs(view, view->cur_line, view->cur_ind…
}
void
You are viewing proxied material from lumidify.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.