shithub: plumb-complete

Download patch

ref: 1b13f47873c44d49bbf4d72bca49fe0f82a197b9
parent: c00282de3cdec23843a7398ebefc0f9593ebf3be
author: glenda <glenda@cirno>
date: Fri Apr 4 12:35:05 EDT 2025

added general prefix finding for data, has duplicate results though

--- a/complete.c
+++ b/complete.c
@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <ctype.h>
 #include <plumb.h>
 #include <complete.h>
 
@@ -12,6 +13,11 @@
 	EQueue	*next;
 };
 
+typedef enum CompletionType {
+	DIRECTORY,
+	FILE_CONTENT
+} CompletionType;
+
 static int
 longestprefixlength(char *a, char *b, int n)
 {
@@ -146,6 +152,118 @@
 	}
 }
 
+Completion*
+completefile(char *content, char *s)
+{
+	char *p, *token, *next, **tokens;
+	int ntokens, maxtokens, i, j, len, minlen, nmatches;
+	Completion *c;
+	
+	if(s == nil || content == nil)
+		return nil;
+		
+	maxtokens = 1024;
+	tokens = malloc(maxtokens * sizeof(char*));
+	if(tokens == nil)
+		return nil;
+		
+	ntokens = 0;
+	len = strlen(s);
+	
+	p = content;
+	while(*p != '\0' && ntokens < maxtokens) {
+		while(*p != '\0' && !isalnum(*p) && *p != '_')
+			p++;
+			
+		if(*p == '\0')
+			break;
+			
+		token = p;
+		while(isalnum(*p) || *p == '_')
+			p++;
+			
+		next = p;
+		
+		if(next > token) {
+			int tokenlen = next - token;
+			char *newtok;
+			
+			if(tokenlen < len)
+				continue;
+				
+			if(strncmp(token, s, len) != 0)
+				continue;
+				
+			newtok = malloc(tokenlen + 1);
+			if(newtok == nil)
+				continue;
+				
+			strncpy(newtok, token, tokenlen);
+			newtok[tokenlen] = '\0';
+			
+			for(i = 0; i < ntokens; i++)
+				if(strcmp(tokens[i], newtok) == 0) {
+					free(newtok);
+					break;
+				}
+				
+			if(i == ntokens)
+				tokens[ntokens++] = newtok;
+			else
+				free(newtok);
+		}
+	}
+	
+	if(ntokens == 0) {
+		free(tokens);
+		return nil;
+	}
+	
+	c = malloc(sizeof(Completion) + 256);
+	if(c == nil) {
+		for(i = 0; i < ntokens; i++)
+			free(tokens[i]);
+		free(tokens);
+		return nil;
+	}
+	
+	memset(c, 0, sizeof(Completion));
+	
+	minlen = 10000;
+	for(i = 0; i < ntokens; i++)
+		if(minlen > strlen(tokens[i]))
+			minlen = strlen(tokens[i]);
+			
+	for(i = 1; i < ntokens; i++)
+		minlen = longestprefixlength(tokens[0], tokens[i], minlen);
+		
+	c->complete = (ntokens == 1);
+	c->advance = c->complete || (minlen > len);
+	c->string = (char*)(c+1);
+	memmove(c->string, tokens[0]+len, minlen-len);
+	if(c->complete)
+		c->string[minlen++ - len] = ' ';
+	c->string[minlen - len] = '\0';
+	c->nmatch = ntokens;
+	
+	c->filename = malloc(ntokens * sizeof(char*));
+	if(c->filename == nil) {
+		for(i = 0; i < ntokens; i++)
+			free(tokens[i]);
+		free(tokens);
+		free(c);
+		return nil;
+	}
+	
+	for(i = 0; i < ntokens; i++)
+		c->filename[i] = tokens[i];
+		
+	c->nfile = ntokens;
+	
+	free(tokens);
+	return c;
+}
+
 char*
 packcompletion(Completion *c, int *outlen)
 {
@@ -199,6 +317,17 @@
 	return prefix;
 }
 
+static CompletionType
+getcompletiontype(Plumbmsg *msg)
+{
+	char *type;
+	
+	type = plumblookup(msg->attr, "type");
+	if(type != nil && strcmp(type, "file") == 0)
+		return FILE_CONTENT;
+	return DIRECTORY;
+}
+
 static void
 sendcompletionresponse(Plumbmsg *msg, Completion *c)
 {
@@ -237,6 +366,7 @@
 	Plumbmsg *msg;
 	Completion *c;
 	char *prefix;
+	CompletionType ctype;
 	
 	ARGBEGIN{
 	default:
@@ -259,7 +389,19 @@
 			continue;
 		}
 		
-		c = complete(msg->wdir, prefix);
+		ctype = getcompletiontype(msg);
+		
+		if(ctype == FILE_CONTENT) {
+			if(msg->ndata <= 0) {
+				plumbfree(msg);
+				continue;
+			}
+			
+			c = completefile(msg->data, prefix);
+		} else {
+			c = complete(msg->wdir, prefix);
+		}
+		
 		if(c == nil){
 			plumbfree(msg);
 			continue;
--