Skip to content

Commit ecb2709

Browse files
committed
wipmatchers
1 parent da85a1b commit ecb2709

13 files changed

Lines changed: 266 additions & 133 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ SOURCES = src/dged/binding.c src/dged/buffer.c src/dged/command.c src/dged/displ
4545

4646
MAIN_SOURCES = src/main/main.c src/main/cmds.c src/main/bindings.c src/main/search-replace.c src/main/completion.c \
4747
src/main/frame-hooks.c src/main/completion/buffer.c src/main/completion/command.c \
48-
src/main/completion/path.c src/main/dired.c
48+
src/main/completion/path.c src/main/dired.c src/main/completion/matchers.c
4949

5050
# HACK: added to MAIN_SOURCES to not be picked up in tests
5151
# since they have their own implementation

src/dged/display.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,10 @@ bool display_initialize(struct display *display) {
209209

210210
display->term = term;
211211

212-
use_alternate_buffer(display);
213-
flush_outbuf(display);
212+
if (getenv("DGED_FORCE_NORMAL_BUFFER") == NULL) {
213+
use_alternate_buffer(display);
214+
flush_outbuf(display);
215+
}
214216

215217
return true;
216218
}

src/dged/s8.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,30 @@ char *s8tocstr(struct s8 s) {
167167

168168
const char *s8ascstr(struct s8 s) { return (const char *)s.s; }
169169

170+
ssize_t s8findstr(struct s8 s, struct s8 find) {
171+
if (s8empty(s) || s8empty(find)) {
172+
return -1;
173+
}
174+
175+
if (s.l < find.l) {
176+
return -1;
177+
}
178+
179+
if (s.l == find.l) {
180+
return s8eq(s, find) ? 0 : -1;
181+
}
182+
183+
/* at this point, s is longer than find */
184+
for (size_t i = 0; i < s.l; ++i) {
185+
uint8_t *start = &s.s[i];
186+
if (s8startswith((struct s8){.s = start, .l = s.l - i}, find)) {
187+
return i;
188+
}
189+
}
190+
191+
return -1;
192+
}
193+
170194
bool s8startswith(struct s8 s, struct s8 prefix) {
171195
if (prefix.l == 0 || prefix.l > s.l) {
172196
return false;

src/dged/s8.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const char *s8ascstr(struct s8 s);
2424

2525
uint8_t s8at(struct s8 s, size_t index);
2626
ssize_t s8find(struct s8 s, uint8_t c);
27+
ssize_t s8findstr(struct s8 s, struct s8 find);
2728
bool s8eq(struct s8 s1, struct s8 s2);
2829
int s8cmp(struct s8 s1, struct s8 s2);
2930
int s8icmp(struct s8 s1, struct s8 s2);

src/main/cmds.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ int32_t unimplemented_command(struct command_ctx ctx, int argc,
5656
const char *argv[]) {
5757
(void)argc;
5858
(void)argv;
59+
5960
minibuffer_echo("TODO: %s is not implemented", (const char *)ctx.userdata);
6061
return 0;
6162
}

src/main/completion.c

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#include "dged/s8.h"
2+
#include "dged/vec.h"
3+
#include <stdlib.h>
14
#define _DEFAULT_SOURCE
25
#include "completion.h"
36

@@ -32,6 +35,9 @@ struct buffer_completion {
3235
struct completion_item {
3336
struct region area;
3437
struct completion completion;
38+
uint32_t score;
39+
size_t match_begin;
40+
size_t match_end;
3541
};
3642

3743
static struct completion_state {
@@ -300,16 +306,55 @@ static void open_completion(struct completion_state *state) {
300306
run_next_frame(update_window_pos_frame_hook, state);
301307
}
302308

303-
static void add_completions_impl(struct completion *completions,
309+
static int compare_completions(const void *c1, const void *c2) {
310+
struct completion_item *comp1 = (struct completion_item *)c1;
311+
struct completion_item *comp2 = (struct completion_item *)c2;
312+
313+
return comp1->score > comp2->score ? -1
314+
: comp1->score < comp2->score
315+
? 1
316+
: s8cmp(comp1->completion.sort_text(comp1->completion.data),
317+
comp2->completion.sort_text(comp2->completion.data));
318+
}
319+
320+
static void sort_completions(struct completion_state *state) {
321+
322+
qsort(VEC_ENTRIES(&state->completions), VEC_SIZE(&state->completions),
323+
sizeof(struct completion_item), compare_completions);
324+
}
325+
326+
static void add_completions_impl(struct s8 needle, filter_fn filter,
327+
struct completion *completions,
304328
size_t ncompletions) {
329+
if (ncompletions == 0) {
330+
return;
331+
}
332+
305333
for (uint32_t i = 0; i < ncompletions; ++i) {
306334
struct completion *c = &completions[i];
307-
struct region area = c->render(c->data, g_state.completions_buffer);
308-
VEC_APPEND(&g_state.completions, struct completion_item * new);
309-
new->area = area;
310-
new->completion = *c;
335+
336+
size_t match_begin, match_end;
337+
uint32_t score;
338+
if (filter(needle, c->filter_text(c->data), &match_begin, &match_end,
339+
&score)) {
340+
VEC_APPEND(&g_state.completions, struct completion_item * new);
341+
new->completion = *c;
342+
new->score = score;
343+
new->match_begin = match_begin;
344+
new->match_end = match_end;
345+
} else {
346+
if (c->cleanup != NULL) {
347+
c->cleanup(c->data);
348+
}
349+
}
311350
}
312351

352+
sort_completions(&g_state);
353+
VEC_FOR_EACH(&g_state.completions, struct completion_item * item) {
354+
struct region area = item->completion.render(item->completion.data,
355+
g_state.completions_buffer);
356+
item->area = area;
357+
}
313358
open_completion(&g_state);
314359
}
315360

@@ -348,6 +393,7 @@ static void update_comp_buffer(struct buffer *buffer, void *userdata) {
348393

349394
if (buffer_is_empty(buffer)) {
350395
abort_completion();
396+
return;
351397
}
352398

353399
struct region reg = active_completion_region(state);

src/main/completion.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,35 @@ struct buffers;
1414
struct buffer_view;
1515
struct commands;
1616

17+
typedef struct s8 str8;
18+
1719
typedef struct region (*completion_render_fn)(void *, struct buffer *);
1820
typedef void (*completion_selected_fn)(void *, struct buffer_view *);
1921
typedef void (*completion_cleanup_fn)(void *);
22+
typedef str8 (*completion_filter_text_fn)(void *);
23+
typedef str8 (*completion_sort_text_fn)(void *);
2024

2125
struct completion {
2226
void *data;
2327
completion_render_fn render;
2428
completion_selected_fn selected;
2529
completion_cleanup_fn cleanup;
30+
completion_filter_text_fn filter_text;
31+
completion_sort_text_fn sort_text;
2632
};
2733

28-
typedef void (*add_completions)(struct completion *, size_t);
34+
typedef bool (*filter_fn)(struct s8 needle, struct s8 item, size_t *match_begin,
35+
size_t *match_end, uint32_t *score);
36+
37+
typedef void (*add_completions)(struct s8, filter_fn filter,
38+
struct completion *, size_t);
39+
40+
bool filter_startswith(struct s8 needle, struct s8 item, size_t *match_begin,
41+
size_t *match_end, uint32_t *score);
42+
bool filter_contains(struct s8 needle, struct s8 item, size_t *match_begin,
43+
size_t *match_end, uint32_t *score);
44+
bool filter_fuzzy(struct s8 needle, struct s8 item, size_t *match_begin,
45+
size_t *match_end, uint32_t *score);
2946

3047
/**
3148
* Context for calculating completions.

src/main/completion/buffer.c

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "dged/buffers.h"
88
#include "dged/minibuffer.h"
99

10+
#include "dged/vec.h"
1011
#include "main/completion.h"
1112

1213
static bool is_space(const struct codepoint *c) {
@@ -47,37 +48,39 @@ static struct region buffer_comp_render(void *data,
4748
return region_new(begin, end);
4849
}
4950

51+
static struct s8 buffer_comp_filter_text(void *data) {
52+
struct buffer_completion *bc = (struct buffer_completion *)data;
53+
return s8(bc->buffer->name);
54+
}
55+
5056
static void buffer_comp_cleanup(void *data) {
5157
struct buffer_completion *bc = (struct buffer_completion *)data;
5258
free(bc);
5359
}
5460

55-
struct needle_match_ctx {
56-
const char *needle;
57-
struct completion *completions;
58-
uint32_t max_ncompletions;
59-
uint32_t ncompletions;
61+
typedef VEC(struct completion) completion_vec;
62+
63+
struct buffer_completions {
64+
completion_vec *completions;
6065
on_buffer_selected_cb on_buffer_selected;
6166
};
6267

63-
static void buffer_matches(struct buffer *buffer, void *userdata) {
64-
struct needle_match_ctx *ctx = (struct needle_match_ctx *)userdata;
65-
66-
if (strncmp(ctx->needle, buffer->name, strlen(ctx->needle)) == 0 &&
67-
ctx->ncompletions < ctx->max_ncompletions) {
68-
69-
struct buffer_completion *comp_data =
70-
calloc(1, sizeof(struct buffer_completion));
71-
comp_data->buffer = buffer;
72-
comp_data->on_buffer_selected = ctx->on_buffer_selected;
73-
ctx->completions[ctx->ncompletions] = (struct completion){
74-
.render = buffer_comp_render,
75-
.selected = buffer_comp_selected,
76-
.cleanup = buffer_comp_cleanup,
77-
.data = comp_data,
78-
};
79-
++ctx->ncompletions;
80-
}
68+
static void fill_buffer_completions(struct buffer *buffer, void *userdata) {
69+
struct buffer_completions *ctx = (struct buffer_completions *)userdata;
70+
71+
struct buffer_completion *comp_data =
72+
calloc(1, sizeof(struct buffer_completion));
73+
comp_data->buffer = buffer;
74+
comp_data->on_buffer_selected = ctx->on_buffer_selected;
75+
76+
struct completion comp = (struct completion){
77+
.render = buffer_comp_render,
78+
.selected = buffer_comp_selected,
79+
.cleanup = buffer_comp_cleanup,
80+
.data = comp_data,
81+
.filter_text = buffer_comp_filter_text,
82+
};
83+
VEC_PUSH(ctx->completions, comp);
8184
}
8285

8386
static void buffer_complete(struct completion_context ctx, bool deletion,
@@ -110,19 +113,17 @@ static void buffer_complete(struct completion_context ctx, bool deletion,
110113
free(txt.text);
111114
}
112115

113-
struct completion *completions = calloc(50, sizeof(struct completion));
114-
115-
struct needle_match_ctx match_ctx = (struct needle_match_ctx){
116-
.needle = needle,
117-
.max_ncompletions = 50,
118-
.completions = completions,
119-
.ncompletions = 0,
116+
completion_vec completions;
117+
VEC_INIT(&completions, 32);
118+
struct buffer_completions match_ctx = (struct buffer_completions){
119+
.completions = &completions,
120120
.on_buffer_selected = pd->on_buffer_selected,
121121
};
122122

123-
buffers_for_each(buffers, buffer_matches, &match_ctx);
124-
ctx.add_completions(match_ctx.completions, match_ctx.ncompletions);
125-
free(completions);
123+
buffers_for_each(buffers, fill_buffer_completions, &match_ctx);
124+
ctx.add_completions(s8(needle), filter_contains, VEC_ENTRIES(&completions),
125+
VEC_SIZE(&completions));
126+
VEC_DESTROY(&completions);
126127
free(needle);
127128
}
128129

src/main/completion/command.c

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "dged/minibuffer.h"
1010
#include "dged/utf8.h"
1111

12+
#include "dged/vec.h"
1213
#include "main/completion.h"
1314

1415
static bool is_space(const struct codepoint *c) {
@@ -50,37 +51,38 @@ static struct region command_comp_render(void *data,
5051
return region_new(begin, end);
5152
}
5253

54+
static struct s8 command_comp_filter_text(struct command_completion *comp) {
55+
return s8(comp->command->name);
56+
}
57+
5358
static void command_comp_cleanup(void *data) {
5459
struct command_completion *cc = (struct command_completion *)data;
5560
free(cc);
5661
}
5762

58-
struct needle_match_ctx {
59-
const char *needle;
60-
struct completion *completions;
61-
uint32_t max_ncompletions;
62-
uint32_t ncompletions;
63+
typedef VEC(struct completion) completion_vec;
64+
65+
struct buffer_completions {
66+
completion_vec *completions;
6367
on_command_selected_cb on_command_selected;
6468
};
6569

66-
static void command_matches(struct command *command, void *userdata) {
67-
struct needle_match_ctx *ctx = (struct needle_match_ctx *)userdata;
68-
69-
if (strncmp(ctx->needle, command->name, strlen(ctx->needle)) == 0 &&
70-
ctx->ncompletions < ctx->max_ncompletions) {
71-
72-
struct command_completion *comp_data =
73-
calloc(1, sizeof(struct command_completion));
74-
comp_data->command = command;
75-
comp_data->on_command_selected = ctx->on_command_selected;
76-
ctx->completions[ctx->ncompletions] = (struct completion){
77-
.render = command_comp_render,
78-
.selected = command_comp_selected,
79-
.cleanup = command_comp_cleanup,
80-
.data = comp_data,
81-
};
82-
++ctx->ncompletions;
83-
}
70+
static void fill_commands(struct command *command, void *userdata) {
71+
struct buffer_completions *ctx = (struct buffer_completions *)userdata;
72+
73+
struct command_completion *comp_data =
74+
calloc(1, sizeof(struct command_completion));
75+
comp_data->command = command;
76+
comp_data->on_command_selected = ctx->on_command_selected;
77+
struct completion comp = (struct completion){
78+
.render = command_comp_render,
79+
.selected = command_comp_selected,
80+
.cleanup = command_comp_cleanup,
81+
.data = comp_data,
82+
.filter_text = (completion_filter_text_fn)command_comp_filter_text,
83+
.sort_text = (completion_sort_text_fn)command_comp_filter_text,
84+
};
85+
VEC_PUSH(ctx->completions, comp);
8486
}
8587

8688
static void command_complete(struct completion_context ctx, bool deletion,
@@ -113,19 +115,18 @@ static void command_complete(struct completion_context ctx, bool deletion,
113115
free(txt.text);
114116
}
115117

116-
struct completion *completions = calloc(50, sizeof(struct completion));
118+
completion_vec completions;
119+
VEC_INIT(&completions, 32);
117120

118-
struct needle_match_ctx match_ctx = (struct needle_match_ctx){
119-
.needle = needle,
120-
.max_ncompletions = 50,
121-
.completions = completions,
122-
.ncompletions = 0,
121+
struct buffer_completions match_ctx = (struct buffer_completions){
122+
.completions = &completions,
123123
.on_command_selected = pd->on_command_selected,
124124
};
125125

126-
commands_for_each(commands, command_matches, &match_ctx);
127-
ctx.add_completions(match_ctx.completions, match_ctx.ncompletions);
128-
free(completions);
126+
commands_for_each(commands, fill_commands, &match_ctx);
127+
ctx.add_completions(s8(needle), filter_contains, VEC_ENTRIES(&completions),
128+
VEC_SIZE(&completions));
129+
VEC_DESTROY(&completions);
129130
free(needle);
130131
}
131132

0 commit comments

Comments
 (0)