~martanne/devel

add vis-selection-new-match-all v3 PROPOSED

Changes in v3:
- remove useless variable leftover from refactor
- change unecessary goto to break

Changes in v2:
- literal next/prev funcs in text-objects.c and separate commit
- don't change view/primary selection when matching all

Evan Gates (3):
  vis: add text_object_literal_find_next/prev
  vis: refactor selections_match_next
  vis: add vis-selection-new-match-all

 config.def.h   |  1 +
 main.c         | 77 ++++++++++++++++++++++----------------------------
 man/vis.1      |  3 ++
 text-objects.c | 20 +++++++++++++
 text-objects.h |  3 ++
 5 files changed, 61 insertions(+), 43 deletions(-)

-- 
2.28.0
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~martanne/devel/patches/14085/mbox | git am -3
Learn more about email & git
View this thread in the archives

[PATCH v3 1/3] vis: add text_object_literal_find_next/prev Export this patch

Add two new text-object functions to search forwards/backwards
for a string literal (not a regex) with the same signature as
text_object_word_find_next/prev.  This allows them to be used
interchangeably with the word based variant through function pointers.
---
 text-objects.c | 20 ++++++++++++++++++++
 text-objects.h |  3 +++
 2 files changed, 23 insertions(+)

diff --git a/text-objects.c b/text-objects.c
index fb5adc2..240304b 100644
--- a/text-objects.c
+++ b/text-objects.c
@@ -137,6 +137,26 @@ Filerange text_object_word_find_prev(Text *txt, size_t pos, const char *word) {
	}
}

static Filerange text_object_literal_find(
	Text *txt, size_t pos, const char *search,
	size_t (*text_find)(Text *, size_t, const char *)
) {
	size_t start = text_find(txt, pos, search);
	if (start == pos)
		return text_range_empty();

	size_t len = strlen(search);
	return text_range_new(start, start+len);
}

Filerange text_object_literal_find_next(Text *txt, size_t pos, const char *search) {
	return text_object_literal_find(txt, pos, search, text_find_next);
}

Filerange text_object_literal_find_prev(Text *txt, size_t pos, const char *search) {
	return text_object_literal_find(txt, pos, search, text_find_prev);
}

Filerange text_object_line(Text *txt, size_t pos) {
	Filerange r;
	r.start = text_line_begin(txt, pos);
diff --git a/text-objects.h b/text-objects.h
index abab46e..734bf8c 100644
--- a/text-objects.h
+++ b/text-objects.h
@@ -19,6 +19,9 @@ Filerange text_object_word_outer(Text*, size_t pos);
/* find next occurance of `word' (as word not substring) in forward/backward direction */
Filerange text_object_word_find_next(Text*, size_t pos, const char *word);
Filerange text_object_word_find_prev(Text*, size_t pos, const char *word);
/* find next occurance of a literal string (not regex) in forward/backward direction */
Filerange text_object_literal_find_next(Text *txt, size_t pos, const char *search);
Filerange text_object_literal_find_prev(Text *txt, size_t pos, const char *search);
/* same semantics as above but for a longword (i.e. delimited by white spaces) */
Filerange text_object_longword(Text*, size_t pos);
Filerange text_object_longword_outer(Text*, size_t pos);
-- 
2.28.0

[PATCH v3 2/3] vis: refactor selections_match_next Export this patch

A lot of code from selections_match_next was
duplicated in selections_match_next_literal.  Use the new
text_object_literal_find_next/prev functions to combine the two match_next
functions into one.
---
 main.c | 43 ++++++++-----------------------------------
 1 file changed, 8 insertions(+), 35 deletions(-)

diff --git a/main.c b/main.c
index eb855ae..13ce71f 100644
--- a/main.c
+++ b/main.c
@@ -1337,37 +1337,6 @@ static const Selection *selection_new_primary(View *view, Filerange *r) {
	return s;
}

static const char *selections_match_next_literal(Vis *vis, const char *keys, const Arg *arg) {
	Text *txt = vis_text(vis);
	View *view = vis_view(vis);
	Selection *s = view_selections_primary_get(view);
	Filerange sel = view_selections_get(s);
	size_t len = text_range_size(&sel);
	if (!len)
		return keys;

	char *buf = text_bytes_alloc0(txt, sel.start, len);
	if (!buf)
		return keys;

	size_t start = text_find_next(txt, sel.end, buf);
	Filerange match = text_range_new(start, start+len);
	if (start != sel.end && selection_new_primary(view, &match))
		goto out;

	sel = view_selections_get(view_selections(view));
	start = text_find_prev(txt, sel.start, buf);
	if (start == sel.start)
		goto out;

	match = text_range_new(start, start+len);
	selection_new_primary(view, &match);

out:
	free(buf);
	return keys;
}

static const char *selections_match_next(Vis *vis, const char *keys, const Arg *arg) {
	Text *txt = vis_text(vis);
	View *view = vis_view(vis);
@@ -1383,19 +1352,23 @@ static const char *selections_match_next(Vis *vis, const char *keys, const Arg *
		match_word = text_range_equal(&sel, &word);
	}

	if (!match_word)
		return selections_match_next_literal(vis, keys, arg);
	Filerange (*find_next)(Text *, size_t, const char *) = text_object_word_find_next;
	Filerange (*find_prev)(Text *, size_t, const char *) = text_object_word_find_prev;
	if (!match_word) {
		find_next = text_object_literal_find_next;
		find_prev = text_object_literal_find_prev;
	}

	char *buf = text_bytes_alloc0(txt, sel.start, text_range_size(&sel));
	if (!buf)
		return keys;

	Filerange word = text_object_word_find_next(txt, sel.end, buf);
	Filerange word = find_next(txt, sel.end, buf);
	if (text_range_valid(&word) && selection_new_primary(view, &word))
		goto out;

	sel = view_selections_get(view_selections(view));
	word = text_object_word_find_prev(txt, sel.start, buf);
	word = find_prev(txt, sel.start, buf);
	if (!text_range_valid(&word))
		goto out;
	selection_new_primary(view, &word);
-- 
2.28.0

[PATCH v3 3/3] vis: add vis-selection-new-match-all Export this patch

Add new vis-selection-new-match-all command, default keybinding <C-a>
in visual mode.  Refactor selections_next_match to find all matches if
arg.b is true.  This does not affect existing configs as arg.b defaults
to false.
---
 config.def.h |  1 +
 main.c       | 38 ++++++++++++++++++++++++++++----------
 man/vis.1    |  3 +++
 3 files changed, 32 insertions(+), 10 deletions(-)

diff --git a/config.def.h b/config.def.h
index 6a4555e..61b97b3 100644
--- a/config.def.h
+++ b/config.def.h
@@ -243,6 +243,7 @@ static const KeyBinding bindings_visual[] = {
	{ "+",                  ACTION(SELECTIONS_ROTATE_RIGHT)             },
	{ "<",                  ALIAS("<vis-operator-shift-left>gv")        },
	{ ">",                  ALIAS("<vis-operator-shift-right>gv")       },
	{ "<C-a>",              ACTION(SELECTIONS_NEW_MATCH_ALL)            },
	{ "<C-b>",              ALIAS("<PageUp>")                           },
	{ "<C-c>",              ACTION(SELECTIONS_REMOVE_COLUMN)            },
	{ "<C-d>",              ACTION(SELECTIONS_NEXT)                     },
diff --git a/main.c b/main.c
index 13ce71f..5a0339e 100644
--- a/main.c
+++ b/main.c
@@ -260,6 +260,7 @@ enum {
	VIS_ACTION_SELECTIONS_NEW_LINE_BELOW_LAST,
	VIS_ACTION_SELECTIONS_NEW_LINES_BEGIN,
	VIS_ACTION_SELECTIONS_NEW_LINES_END,
	VIS_ACTION_SELECTIONS_NEW_MATCH_ALL,
	VIS_ACTION_SELECTIONS_NEW_MATCH_NEXT,
	VIS_ACTION_SELECTIONS_NEW_MATCH_SKIP,
	VIS_ACTION_SELECTIONS_ALIGN,
@@ -917,6 +918,11 @@ static const KeyAction vis_action[] = {
		VIS_HELP("Create a new selection at the end of every line covered by selection")
		operator, { .i = VIS_OP_CURSOR_EOL }
	},
	[VIS_ACTION_SELECTIONS_NEW_MATCH_ALL] = {
		"vis-selection-new-match-all",
		VIS_HELP("Select all regions matching the current selection")
		selections_match_next, { .b = true }
	},
	[VIS_ACTION_SELECTIONS_NEW_MATCH_NEXT] = {
		"vis-selection-new-match-next",
		VIS_HELP("Select the next region matching the current selection")
@@ -1325,7 +1331,7 @@ static const char *selections_clear(Vis *vis, const char *keys, const Arg *arg)
	return keys;
}

static const Selection *selection_new_primary(View *view, Filerange *r) {
static Selection *selection_new(View *view, Filerange *r, bool isprimary) {
	Text *txt = view_text(view);
	size_t pos = text_char_prev(txt, r->end);
	Selection *s = view_selections_new(view, pos);
@@ -1333,7 +1339,8 @@ static const Selection *selection_new_primary(View *view, Filerange *r) {
		return NULL;
	view_selections_set(s, r);
	view_selections_anchor(s, true);
	view_selections_primary_set(s);
	if (isprimary)
		view_selections_primary_set(s);
	return s;
}

@@ -1363,15 +1370,26 @@ static const char *selections_match_next(Vis *vis, const char *keys, const Arg *
	if (!buf)
		return keys;

	Filerange word = find_next(txt, sel.end, buf);
	if (text_range_valid(&word) && selection_new_primary(view, &word))
		goto out;
	bool match_all = arg->b;

	for (;;) {
		sel = view_selections_get(s);
		Filerange word = find_next(txt, sel.end, buf);
		if (!text_range_valid(&word) || !(s = selection_new(view, &word, !match_all)))
			break;
		if (!match_all)
			goto out;
	}

	sel = view_selections_get(view_selections(view));
	word = find_prev(txt, sel.start, buf);
	if (!text_range_valid(&word))
		goto out;
	selection_new_primary(view, &word);
	for (;;) {
		sel = view_selections_get(view_selections(view));
		Filerange word = find_prev(txt, sel.start, buf);
		if (!text_range_valid(&word))
			break;
		selection_new(view, &word, !match_all);
		if (!match_all)
			break;
	}

out:
	free(buf);
diff --git a/man/vis.1 b/man/vis.1
index 10ad5bb..4082997 100644
--- a/man/vis.1
+++ b/man/vis.1
@@ -1097,6 +1097,9 @@ left align selections by inserting spaces
.It Aq Ic S-Tab
right align selections by inserting spaces
.
.It Aq Ic C-a
create new selections everywhere matching current word or selection
.
.It Aq Ic C-n
create new selection and select next word matching current selection
.
-- 
2.28.0