Skip to content

Commit

Permalink
Implement full auto-completion for e.g. hi c.<Tab>
Browse files Browse the repository at this point in the history
  • Loading branch information
craigbarnes committed Dec 24, 2024
1 parent 81464a7 commit eaa9c6c
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 16 deletions.
3 changes: 0 additions & 3 deletions docs/TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ Features
* Allow [`dte -s`] option to take multiple file arguments (e.g.
`dte -s config/syntax/*`)

* Implement auto-completion for e.g. `hi c.<Tab>`, by collecting all
`Action::emit_name` strings from the appropriate `Syntax` (if loaded)

* Implement auto-completion for e.g. `set filetype j<Tab>`

* Suggest programs found in `$PATH` (or a cached list thereof) when
Expand Down
31 changes: 29 additions & 2 deletions src/completion.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,35 @@ void collect_bound_normal_keys(EditorState *e, PointerArray *a, const char *pref

void collect_hl_styles(EditorState *e, PointerArray *a, const char *prefix)
{
collect_builtin_styles(a, prefix);
collect_hashmap_keys(&e->styles.other, a, prefix);
char filetype[FILETYPE_NAME_MAX + 1];
char *end = memccpy(filetype, prefix, '.', sizeof(filetype));

if (!end || end <= filetype + 1) {
// No dot found in prefix, or found at offset 0, or buffer too small;
// just collect matching highlight names added by the `hi` command
collect_builtin_styles(a, prefix);
collect_hashmap_keys(&e->styles.other, a, prefix);
return;
}

// Null terminate filetype[] by overwriting the dot
end[-1] = '\0';

// Find or load the Syntax matching the string before the dot
const Syntax *syn = find_syntax(&e->syntaxes, filetype);
if (!syn) {
if (e->flags & EFLAG_HEADLESS) {
return;
}
syn = load_syntax_by_filetype(e, filetype);
if (!syn) {
return;
}
}

// Collect all emit names from `syn` that start with the string after
// the dot
collect_syntax_emit_names(syn, a, prefix + (end - filetype));
}

void collect_compilers(EditorState *e, PointerArray *a, const char *prefix)
Expand Down
5 changes: 2 additions & 3 deletions src/syntax/merge.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,10 @@ State *merge_syntax(Syntax *syn, SyntaxMerge *merge, const StyleMap *styles)
BUG_ON(s->conds.alloc != 0);
}

// Mark unvisited so that state that is used only as a return
// state gets visited
// Mark unvisited, so that return-only states get visited
s->visited = false;

// Don't complain about unvisited copied states
// Don't complain about unvisited, copied states
s->copied = true;
}

Expand Down
7 changes: 4 additions & 3 deletions src/syntax/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,10 @@ static bool cmd_eat(EditorState *e, const CommandArgs *a)
}

const char *emit = a->args[1];
lint_emit_name(e, emit, e->syn.current_state->default_action.destination);
e->syn.current_state->default_action.emit_name = emit ? xstrdup(emit) : NULL;
e->syn.current_state->type = STATE_EAT;
State *curstate = e->syn.current_state;
lint_emit_name(e, emit, curstate->default_action.destination);
curstate->default_action.emit_name = emit ? xstrdup(emit) : NULL;
curstate->type = STATE_EAT;
e->syn.current_state = NULL;
return true;
}
Expand Down
53 changes: 48 additions & 5 deletions src/syntax/syntax.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include <stdlib.h>
#include <string.h>
#include "syntax.h"
#include "error.h"
#include "util/str-util.h"
#include "util/xmalloc.h"
#include "util/xsnprintf.h"

StringList *find_string_list(const Syntax *syn, const char *name)
Expand Down Expand Up @@ -153,13 +156,14 @@ static const char *find_default_style(const Syntax *syn, const char *name)
return hashmap_get(&syn->default_styles, name);
}

static void update_action_style(const Syntax *syn, Action *a, const StyleMap *styles)
static const char *get_effective_emit_name(const Action *a)
{
const char *name = a->emit_name;
if (!name) {
name = a->destination->emit_name;
}
return a->emit_name ? a->emit_name : a->destination->emit_name;
}

static void update_action_style(const Syntax *syn, Action *a, const StyleMap *styles)
{
const char *name = get_effective_emit_name(a);
char full[256];
xsnprintf(full, sizeof full, "%s.%s", syn->name, name);
a->emit_style = find_style(styles, full);
Expand Down Expand Up @@ -214,3 +218,42 @@ void find_unused_subsyntaxes(const HashMap *syntaxes)
}
}
}

void collect_syntax_emit_names (
const Syntax *syntax,
PointerArray *a,
const char *prefix
) {
HashSet set;
hashset_init(&set, 16, false);

// Insert all `Action::emit_name` strings beginning with `prefix` into
// a HashSet (to avoid duplicates)
for (HashMapIter it = hashmap_iter(&syntax->states); hashmap_next(&it); ) {
const State *s = it.entry->value;
const char *emit = get_effective_emit_name(&s->default_action);
if (str_has_prefix(emit, prefix)) {
hashset_insert(&set, emit, strlen(emit));
}
for (size_t i = 0, n = s->conds.count; i < n; i++) {
const Condition *cond = s->conds.ptrs[i];
emit = get_effective_emit_name(&cond->a);
if (str_has_prefix(emit, prefix)) {
hashset_insert(&set, emit, strlen(emit));
}
}
}

const char *ft = syntax->name;
size_t ftlen = strlen(ft);

// Append the collected strings to the PointerArray
for (size_t i = 0, n = set.table_size; i < n; i++) {
for (HashSetEntry *h = set.table[i]; h; h = h->next) {
char *str = xmemjoin3(ft, ftlen, STRN("."), h->str, h->str_len + 1);
ptr_array_append(a, str);
}
}

hashset_free(&set);
}
2 changes: 2 additions & 0 deletions src/syntax/syntax.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "syntax/color.h"
#include "util/hashmap.h"
#include "util/hashset.h"
#include "util/macros.h"
#include "util/ptr-array.h"
#include "util/string-view.h"

Expand Down Expand Up @@ -126,5 +127,6 @@ void update_syntax_styles(Syntax *syn, const StyleMap *styles);
void update_all_syntax_styles(const HashMap *syntaxes, const StyleMap *styles);
void find_unused_subsyntaxes(const HashMap *syntaxes);
void free_syntaxes(HashMap *syntaxes);
void collect_syntax_emit_names(const Syntax *syntax, PointerArray *a, const char *prefix) NONNULL_ARGS;

#endif
18 changes: 18 additions & 0 deletions src/util/xmalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ static inline size_t xmul(size_t a, size_t b)
return xmul_(a, b);
}

static inline size_t xadd3(size_t a, size_t b, size_t c)
{
return xadd(a, xadd(b, c));
}

RETURNS_NONNULL WARN_UNUSED_RESULT ALLOC_SIZE(2, 3)
static inline void *xreallocarray(void *ptr, size_t nmemb, size_t size)
{
Expand Down Expand Up @@ -72,6 +77,19 @@ static inline void *xmemjoin(const void *p1, size_t n1, const void *p2, size_t n
return joined;
}

NONNULL_ARGS_AND_RETURN
static inline void *xmemjoin3 (
const void *p1, size_t n1,
const void *p2, size_t n2,
const void *p3, size_t n3
) {
char *joined = xmalloc(xadd3(n1, n2, n3));
memcpy(joined, p1, n1);
memcpy(joined + n1, p2, n2);
memcpy(joined + n1 + n2, p3, n3);
return joined;
}

XSTRDUP
static inline char *xstrjoin(const char *s1, const char *s2)
{
Expand Down

0 comments on commit eaa9c6c

Please sign in to comment.