Browse Source

Allow syntax definitions to add autocomplete options

K. Lange 9 months ago
parent
commit
e0d1e5d92b
4 changed files with 88 additions and 50 deletions
  1. 27 0
      bim-core.h
  2. 14 1
      bim-syntax.h
  3. 37 48
      bim.c
  4. 10 1
      syntax/bimcmd.c

+ 27 - 0
bim-core.h

@@ -302,11 +302,19 @@ struct syntax_state {
 	int i;
 };
 
+struct completion_match {
+	char * string;
+	char * file;
+	char * search;
+};
+
 struct syntax_definition {
 	char * name;
 	char ** ext;
 	int (*calculate)(struct syntax_state *);
 	int prefers_spaces;
+	int (*completion_qualifier)(int c);
+	int (*completion_matcher)(uint32_t * comp, struct completion_match ** matches, int * matches_count, int complete_match, int * matches_len);
 };
 
 extern struct syntax_definition * syntaxes;
@@ -460,4 +468,23 @@ extern void find_matching_paren(int * out_line, int * out_col, int in_col);
 extern void render_error(char * message, ...);
 extern void pause_for_key(void);
 
+#define add_match(match_string, match_file, match_search) do { \
+	if (*matches_count == *matches_len) { \
+		(*matches_len) *= 2; \
+		*matches = realloc(*matches, sizeof(struct completion_match) * (*matches_len)); \
+	} \
+	(*matches)[*matches_count].string = strdup(match_string); \
+	(*matches)[*matches_count].file = strdup(match_file); \
+	(*matches)[*matches_count].search = strdup(match_search); \
+	(*matches_count)++; \
+} while (0)
+
+#define add_if_match(name,desc) do { \
+	int i = 0; \
+	while (comp[i] && comp[i] == (unsigned char)name[i]) i++; \
+	if (comp[i] == '\0') { \
+		add_match(name,desc,""); \
+	} \
+} while (0)
+
 #endif /* _BIM_CORE_H */

+ 14 - 1
bim-syntax.h

@@ -3,9 +3,22 @@
 
 #define BIM_SYNTAX(name, spaces) \
 	__attribute__((constructor)) static void _load_ ## name (void) { \
-		add_syntax((struct syntax_definition){#name, syn_ ## name ## _ext, syn_ ## name ## _calculate, spaces}); \
+		add_syntax((struct syntax_definition){#name, syn_ ## name ## _ext, syn_ ## name ## _calculate, spaces, NULL, NULL}); \
 	} \
 
+#define BIM_SYNTAX_EXT(name, spaces, matcher) \
+	__attribute__((constructor)) static void _load_ ## name (void) { \
+		add_syntax((struct syntax_definition){#name, syn_ ## name ## _ext, syn_ ## name ## _calculate, spaces, matcher, _match_completions_ ## name}); \
+	} \
+
+#define BIM_SYNTAX_COMPLETER(name) \
+	static int _match_completions_ ## name ( \
+		uint32_t * comp __attribute__((unused)), \
+		struct completion_match **matches __attribute__((unused)), \
+		int * matches_count __attribute__((unused)), \
+		int complete_match __attribute__((unused)), \
+		int *matches_len __attribute__((unused)))
+
 #define paint(length, flag) do { for (int i = 0; i < (length) && state->i < state->line->actual; i++, state->i++) { state->line->text[state->i].flags = (flag); } } while (0)
 #define charat() (state->i < state->line->actual ? state->line->text[(state->i)].codepoint : -1)
 #define nextchar() (state->i + 1 < state->line->actual ? state->line->text[(state->i+1)].codepoint : -1)

+ 37 - 48
bim.c

@@ -7573,12 +7573,6 @@ BIM_ACTION(insert_at_end_of_selection, ACTION_IS_RW,
 	env->mode = MODE_INSERT;
 }
 
-struct completion_match {
-	char * string;
-	char * file;
-	char * search;
-};
-
 void free_completion_match(struct completion_match * match) {
 	if (match->string) free(match->string);
 	if (match->file) free(match->file);
@@ -7589,54 +7583,43 @@ void free_completion_match(struct completion_match * match) {
  * Read ctags file to find matches for a symbol
  */
 int read_tags(uint32_t * comp, struct completion_match **matches, int * matches_count, int complete_match) {
-	int matches_len = 4;
+	int _matches_len = 4;
+	int *matches_len = &_matches_len;
 	*matches_count = 0;
-	*matches = malloc(sizeof(struct completion_match) * (matches_len));
+	*matches = malloc(sizeof(struct completion_match) * (*matches_len));
 
 	FILE * tags = fopen("tags","r");
-	if (!tags) return 1;
-	char tmp[4096]; /* max line */
-	while (!feof(tags) && fgets(tmp, 4096, tags)) {
-		if (tmp[0] == '!') continue;
-		int i = 0;
-		while (comp[i] && comp[i] == (unsigned int)tmp[i]) i++;
-		if (comp[i] == '\0') {
-			if (complete_match && tmp[i] != '\t') continue;
-			int j = i;
-			while (tmp[j] != '\t' && tmp[j] != '\n' && tmp[j] != '\0') j++;
-			tmp[j] = '\0'; j++;
-			char * file = &tmp[j];
-			while (tmp[j] != '\t' && tmp[j] != '\n' && tmp[j] != '\0') j++;
-			tmp[j] = '\0'; j++;
-			char * search = &tmp[j];
-			while (!(tmp[j] == '/' && tmp[j+1] == ';' && tmp[j+2] == '"' && tmp[j+3] == '\t') /* /normal searches/ */
-			       && !(tmp[j] == ';' && tmp[j+1] == '"' && tmp[j+2] == '\t') /* Old ctags line number searches */
-			       && (tmp[j] != '\n' && tmp[j] != '\0')) j++;
-			tmp[j] = '\0'; j++;
-
-			/* Dedup */
-			#if 0
-			int match_found = 0;
-			for (int i = 0; i < *matches_count; ++i) {
-				if (!strcmp((*matches)[i].string, tmp)) {
-					match_found = 1;
-					break;
-				}
-			}
-			if (match_found) continue;
-			#endif
+	if (tags) {
+		char tmp[4096]; /* max line */
+		while (!feof(tags) && fgets(tmp, 4096, tags)) {
+			if (tmp[0] == '!') continue;
+			int i = 0;
+			while (comp[i] && comp[i] == (unsigned int)tmp[i]) i++;
+			if (comp[i] == '\0') {
+				if (complete_match && tmp[i] != '\t') continue;
+				int j = i;
+				while (tmp[j] != '\t' && tmp[j] != '\n' && tmp[j] != '\0') j++;
+				tmp[j] = '\0'; j++;
+				char * file = &tmp[j];
+				while (tmp[j] != '\t' && tmp[j] != '\n' && tmp[j] != '\0') j++;
+				tmp[j] = '\0'; j++;
+				char * search = &tmp[j];
+				while (!(tmp[j] == '/' && tmp[j+1] == ';' && tmp[j+2] == '"' && tmp[j+3] == '\t') /* /normal searches/ */
+				       && !(tmp[j] == ';' && tmp[j+1] == '"' && tmp[j+2] == '\t') /* Old ctags line number searches */
+				       && (tmp[j] != '\n' && tmp[j] != '\0')) j++;
+				tmp[j] = '\0'; j++;
 
-			if (*matches_count == matches_len) {
-				matches_len *= 2;
-				*matches = realloc(*matches, sizeof(struct completion_match) * (matches_len));
+				add_match(tmp,file,search);
 			}
-			(*matches)[*matches_count].string = strdup(tmp);
-			(*matches)[*matches_count].file = strdup(file);
-			(*matches)[*matches_count].search = strdup(search);
-			(*matches_count)++;
 		}
+		fclose(tags);
 	}
-	fclose(tags);
+
+	/* TODO: Get these from syntax files with a dynamic callback */
+	if (env->syntax && env->syntax->completion_matcher) {
+		env->syntax->completion_matcher(comp,matches,matches_count,complete_match,matches_len);
+	}
+
 	return 0;
 }
 
@@ -7714,11 +7697,17 @@ void draw_completion_matches(uint32_t * tmp, struct completion_match *matches, i
 int omni_complete(int quit_quietly_on_none) {
 	int c;
 
+	int (*qualifier)(int c) = simple_keyword_qualifier;
+	if (env->syntax && env->syntax->completion_qualifier) {
+		qualifier = env->syntax->completion_qualifier;
+	}
+
 	/* Pull the word from before the cursor */
 	int c_before = 0;
 	int i = env->col_no-1;
 	while (i > 0) {
-		if (!simple_keyword_qualifier(env->lines[env->line_no-1]->text[i-1].codepoint)) break;
+		int c = env->lines[env->line_no-1]->text[i-1].codepoint;
+		if (!qualifier(c)) break;
 		c_before++;
 		i--;
 	}

+ 10 - 1
syntax/bimcmd.c

@@ -127,4 +127,13 @@ int syn_bimcmd_calculate(struct syntax_state * state) {
 
 char * syn_bimcmd_ext[] = {".bimscript",".bimrc",NULL}; /* no files */
 
-BIM_SYNTAX(bimcmd, 1)
+BIM_SYNTAX_COMPLETER(bimcmd) {
+	for (struct command_def * c = regular_commands; regular_commands && c->name; ++c) {
+		add_if_match(c->name,c->description);
+	}
+	add_if_match("function","Define a function");
+	add_if_match("end","End a function definition");
+	return 0;
+}
+
+BIM_SYNTAX_EXT(bimcmd, 1, cmd_qualifier)