diff --git a/src/nano.h b/src/nano.h index e05ae523..9b2ae9f1 100644 --- a/src/nano.h +++ b/src/nano.h @@ -229,6 +229,8 @@ typedef struct syntaxtype { /* The list of libmagic results that this syntax applies to. */ char *linter; /* The command with which to lint this type of file. */ + char *completer; + /* The completer command to this type of file. */ char *formatter; /* The formatting command (for programming languages mainly). */ #ifdef ENABLE_COMMENT diff --git a/src/rcfile.c b/src/rcfile.c index 2e6675ea..7748cc7c 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -301,6 +301,7 @@ void parse_syntax(char *ptr) live_syntax->headers = NULL; live_syntax->magics = NULL; live_syntax->linter = NULL; + live_syntax->completer = NULL; live_syntax->formatter = NULL; #ifdef ENABLE_COMMENT live_syntax->comment = mallocstrcpy(NULL, GENERAL_COMMENT_CHARACTER); @@ -998,6 +999,8 @@ void parse_rcfile(FILE *rcstream, bool syntax_only) parse_colors(ptr, NANO_REG_EXTENDED | REG_ICASE); else if (strcasecmp(keyword, "linter") == 0) pick_up_name("linter", ptr, &live_syntax->linter); + else if (strcasecmp(keyword, "completer") == 0) + pick_up_name("completer", ptr, &live_syntax->completer); else if (strcasecmp(keyword, "formatter") == 0) #ifdef ENABLE_SPELLER pick_up_name("formatter", ptr, &live_syntax->formatter); diff --git a/src/text.c b/src/text.c index 936e8c2f..97415900 100644 --- a/src/text.c +++ b/src/text.c @@ -3549,6 +3549,262 @@ char *copy_completion(char *check_line, int start) return word; } +filestruct *get_dict(char *shard) +{ + fprintf (stderr, "Called get_dict\n"); + statusbar(_("Invoking dictionary, please wait")); + char *file = openfile->syntax->completer; + FILE *rcstream; + filestruct *lines = NULL, *tmpline = NULL, *curline = NULL; + + /* If no file is specified, return no dictionaray. */ + if (!file) + return NULL; + + /* Don't open directories, character files, or block files. */ + if (!is_good_file(file)) + return NULL; + + /* Open the included syntax file. */ + rcstream = fopen(file, "rb"); + + if (rcstream == NULL) { + rcfile_error(_("Error reading %s: %s"), file, strerror(errno)); + return NULL; + } + + fprintf(stderr, "Will begin parsing dictionary...\n"); + + char *buf = NULL; + ssize_t len; + size_t n = 0; + size_t lineno = 0; + + while ((len = getline(&buf, &n, rcstream)) > 0) { + char *ptr, *keyword, *option; + int set = 0; + size_t i; + fprintf (stderr, "Read line: %s\n", buf); + tmpline = curline; + curline = nmalloc(sizeof(filestruct)); + curline->next = NULL; + curline->prev = tmpline; + if (curline->prev != NULL) + curline->prev->next = curline; + curline->data = mallocstrcpy(NULL, buf); + curline->lineno = ++lineno; + curline->multidata = NULL; + + if (lines == NULL) + lines = curline; + } + return lines; +} + +/* Gets a competion dictionary for shard from external command */ +filestruct *get_dict2(char *shard) +{ + //fprintf(stderr, "Will generate dicionary for %s\n", shard); + /*static filestruct dict1, dict2; + dict1.data = "Brasilia"; + dict1.lineno = 1; + dict1.multidata = NULL; + dict1.prev = NULL; + dict1.next = &dict2; + dict2.data = "Brasil"; + dict2.lineno = 2; + dict2.multidata = NULL; + dict2.prev = &dict1; + dict2.next = NULL; + return &dict1;*/ + + char *read_buff, *read_buff_ptr, *read_buff_word; + size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread; + size_t parsesuccess = 0; + int lint_status, lint_fd[2]; + pid_t pid_lint; + static char **lintargs = NULL; + //char *lintargs[3]; + //lintstruct *lints = NULL, *tmplint = NULL, *curlint = NULL; + filestruct *lints = NULL, *tmplint = NULL, *curlint = NULL; + + /* Create a pipe up front. */ + if (pipe(lint_fd) == -1) { + statusbar(_("Could not create pipe")); + return NULL; + } + + statusbar(_("Invoking dictionary, please wait")); + + //construct_argument_list(&lintargs, openfile->syntax->linter, openfile->filename); + construct_argument_list(&lintargs, openfile->syntax->completer, NULL); + //fprintf(stderr, "current completer is: %s\n", openfile->syntax->completer); + char *current_arg; + int i = 0; + for(current_arg = lintargs[i]; current_arg != NULL; i++) { + //fprintf(stderr, "Arg %d: %s\n", i, lintargs[i]); + current_arg = lintargs[i]; + if(current_arg == NULL) + break; + if(strcmp(current_arg, "$shard") == 0) { + lintargs[i] = strdup(shard); + } + } + /*lintargs[0] = "grep"; + lintargs[1] = shard; + //lintargs[2] = "/usr/share/dict/words"; + lintargs[2] = "tags";*/ + + /* Start a new process to run the linter in. */ + if ((pid_lint = fork()) == 0) { + + /* Child continues here (i.e. the future linting process). */ + close(lint_fd[0]); + + /* Send the linter's standard output + err to the pipe. */ + if (dup2(lint_fd[1], STDOUT_FILENO) != STDOUT_FILENO) + exit(9); + if (dup2(lint_fd[1], STDERR_FILENO) != STDERR_FILENO) + exit(9); + + close(lint_fd[1]); + + /* Start the linter program; we are using $PATH. */ + execvp(lintargs[0], lintargs); + + /* This is only reached when the linter is not found. */ + exit(9); + } + + /* Parent continues here. */ + close(lint_fd[1]); + + /* If the child process was not forked successfully... */ + if (pid_lint < 0) { + close(lint_fd[0]); + statusbar(_("Could not fork")); + return NULL; + } + + /* Get the system pipe buffer size. */ + if ((pipe_buff_size = fpathconf(lint_fd[0], _PC_PIPE_BUF)) < 1) { + close(lint_fd[0]); + statusbar(_("Could not get size of pipe buffer")); + return NULL; + } + + /* Read in the returned syntax errors. */ + read_buff_read = 0; + read_buff_size = pipe_buff_size + 1; + read_buff = read_buff_ptr = charalloc(read_buff_size); + + while ((bytesread = read(lint_fd[0], read_buff_ptr, pipe_buff_size)) > 0) { + read_buff_read += bytesread; + read_buff_size += pipe_buff_size; + read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size); + read_buff_ptr += read_buff_read; + } + + *read_buff_ptr = '\0'; + close(lint_fd[0]); + + /* Process the linter output. */ + read_buff_word = read_buff_ptr = read_buff; + + while (*read_buff_ptr != '\0') { + if ((*read_buff_ptr == '\r') || (*read_buff_ptr == '\n')) { + *read_buff_ptr = '\0'; + if (read_buff_word != read_buff_ptr) { + char *filename = NULL, *linestr = NULL, *maybecol = NULL; + char *message = mallocstrcpy(NULL, read_buff_word); + //fprintf(stderr, "Got dict line: %s\n", message); + + parsesuccess++; + tmplint = curlint; + curlint = nmalloc(sizeof(filestruct)); + curlint->next = NULL; + curlint->prev = tmplint; + if (curlint->prev != NULL) + curlint->prev->next = curlint; + curlint->data = mallocstrcpy(NULL, message); + curlint->lineno = parsesuccess; + curlint->multidata = NULL; + + if (lints == NULL) + lints = curlint; + /* At the moment we handle the following formats: + * + * filenameorcategory:line:column:message (e.g. splint) + * filenameorcategory:line,column:message (e.g. pylint) + * filenameorcategory:line:message (e.g. pyflakes) */ + /*if (strstr(message, ": ") != NULL) { + filename = strtok(read_buff_word, ":"); + if ((linestr = strtok(NULL, ":")) != NULL) { + if ((maybecol = strtok(NULL, ":")) != NULL) { + ssize_t tmplineno = 0, tmpcolno = 0; + char *tmplinecol; + + tmplineno = strtol(linestr, NULL, 10); + if (tmplineno <= 0) { + read_buff_ptr++; + free(message); + continue; + } + + tmpcolno = strtol(maybecol, NULL, 10); + //* Check if the middle field is in comma format. * + if (tmpcolno <= 0) { + strtok(linestr, ","); + if ((tmplinecol = strtok(NULL, ",")) != NULL) + tmpcolno = strtol(tmplinecol, NULL, 10); + else + tmpcolno = 1; + } + + //* Nice. We have a lint message we can use. * + parsesuccess++; + tmplint = curlint; + curlint = nmalloc(sizeof(lintstruct)); + curlint->next = NULL; + curlint->prev = tmplint; + if (curlint->prev != NULL) + curlint->prev->next = curlint; + curlint->msg = mallocstrcpy(NULL, message); + curlint->lineno = tmplineno; + curlint->colno = tmpcolno; + curlint->filename = mallocstrcpy(NULL, filename); + + if (lints == NULL) + lints = curlint; + } + } + } else + free(message);*/ + } + read_buff_word = read_buff_ptr + 1; + } + read_buff_ptr++; + } + + /* Process the end of the linting process. */ + waitpid(pid_lint, &lint_status, 0); + + if (!WIFEXITED(lint_status) || WEXITSTATUS(lint_status) > 2) { + statusbar(invocation_error(openfile->syntax->linter)); + return NULL; + } + + free(read_buff); + + if (parsesuccess == 0) { + statusline(HUSH, _("Got 0 parsable lines from command: %s"), + openfile->syntax->linter); + return NULL; + } + + return lints; +} + /* Look at the fragment the user has typed, then search the current buffer for * the first word that starts with this fragment, and tentatively complete the * fragment. If the user types 'Complete' again, search and paste the next @@ -3562,6 +3818,7 @@ void complete_a_word(void) #ifdef ENABLE_WRAPPING bool was_set_wrapping = !ISSET(NO_WRAP); #endif + //openfilestruct *dict = openfile; /* If this is a fresh completion attempt... */ if (pletion_line == NULL) { @@ -3577,6 +3834,8 @@ void complete_a_word(void) openfile->last_action = OTHER; /* Initialize the starting point for searching. */ + //pletion_line = dict->fileage; + //pletion_line = get_dict(shard); pletion_line = openfile->fileage; pletion_x = 0; @@ -3610,13 +3869,21 @@ void complete_a_word(void) shard[shard_length++] = openfile->current->data[start_of_shard++]; shard[shard_length] = '\0'; + if (pletion_line == openfile->fileage) { + //fprintf(stderr, "This is a entire new completion...\n"); + pletion_line = get_dict(shard); + pletion_line = pletion_line == NULL ? openfile->fileage : pletion_line; + } + /* Run through all of the lines in the buffer, looking for shard. */ while (pletion_line != NULL) { int threshold = strlen(pletion_line->data) - shard_length - 1; /* The point where we can stop searching for shard. */ - + //fprintf(stderr, "pletion_x: %d, thresholhd: %d\n", pletion_x, threshold); + //fprintf(stderr, "Will compare %s with %s\n", pletion_line->data, shard); /* Traverse the whole line, looking for shard. */ for (i = pletion_x; (int)i < threshold; i++) { + //fprintf(stderr, "Entered for loop\n"); /* If the first byte doesn't match, run on. */ if (pletion_line->data[i] != shard[0]) continue; @@ -3684,6 +3951,7 @@ void complete_a_word(void) return; } + //fprintf(stderr, "Address of the next line in dictionary: %p\n", pletion_line->next); pletion_line = pletion_line->next; pletion_x = 0; }