From f15ecc3a1dd257cf6526d0a8b4b597c14b77f866 Mon Sep 17 00:00:00 2001 From: Sumedh Pendurkar Date: Wed, 19 Oct 2016 15:37:15 +0200 Subject: [PATCH] new feature: complete a preceding fragment to a longer word in the file This function is by default bound to the ^] keystroke. --- src/global.c | 8 +++++ src/nano.c | 7 +++- src/proto.h | 3 ++ src/text.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) diff --git a/src/global.c b/src/global.c index 402575f..d5cf115 100644 --- a/src/global.c +++ b/src/global.c @@ -48,6 +48,9 @@ bool focusing = TRUE; message_type lastmessage = HUSH; /* Messages of type HUSH should not overwrite type MILD nor ALERT. */ +filestruct *pletion_line = NULL; + /* The line where the last completion was found, if any. */ + int controlleft, controlright, controlup, controldown; #ifndef NANO_TINY int shiftcontrolleft, shiftcontrolright, shiftcontrolup, shiftcontroldown; @@ -525,6 +528,7 @@ void shortcut_init(void) #endif const char *nano_undo_msg = N_("Undo the last operation"); const char *nano_redo_msg = N_("Redo the last undone operation"); + const char *nano_completion_msg = N_("Try and complete the current word"); #endif const char *nano_back_msg = N_("Go back one character"); const char *nano_forward_msg = N_("Go forward one character"); @@ -802,6 +806,9 @@ void shortcut_init(void) N_("Undo"), IFSCHELP(nano_undo_msg), TOGETHER, NOVIEW); add_to_funcs(do_redo, MMAIN, N_("Redo"), IFSCHELP(nano_redo_msg), BLANKAFTER, NOVIEW); + + add_to_funcs(complete_a_word, MMAIN, + N_("Complete"), IFSCHELP(nano_completion_msg), BLANKAFTER, NOVIEW); #endif /* !NANO_TINY */ add_to_funcs(do_left, MMAIN, @@ -1084,6 +1091,7 @@ void shortcut_init(void) add_to_sclist(MMAIN, "M-{", 0, do_unindent, 0); add_to_sclist(MMAIN, "M-U", 0, do_undo, 0); add_to_sclist(MMAIN, "M-E", 0, do_redo, 0); + add_to_sclist(MMAIN, "^]", 0, complete_a_word, 0); #endif #ifdef ENABLE_COMMENT add_to_sclist(MMAIN, "M-3", 0, do_comment, 0); diff --git a/src/nano.c b/src/nano.c index 6cd68da..fa57459 100644 --- a/src/nano.c +++ b/src/nano.c @@ -1671,7 +1671,9 @@ int do_input(bool allow_funcs) } } - if (have_shortcut) { + if (!have_shortcut) + pletion_line = NULL; + else { const subnfunc *f = sctofunc(s); if (ISSET(VIEW_MODE) && f && !f->viewok) { @@ -1689,6 +1691,9 @@ int do_input(bool allow_funcs) preserve = TRUE; #ifndef NANO_TINY + if (s->scfunc != complete_a_word) + pletion_line = NULL; + if (s->scfunc == do_toggle_void) { do_toggle(s->toggle); if (s->toggle != CUT_TO_END) diff --git a/src/proto.h b/src/proto.h index b4087e9..3ac12c9 100644 --- a/src/proto.h +++ b/src/proto.h @@ -40,6 +40,8 @@ extern bool focusing; extern message_type lastmessage; +extern filestruct *pletion_line; + extern int controlleft; extern int controlright; extern int controlup; @@ -672,6 +674,7 @@ void do_formatter(void); void do_wordlinechar_count(void); #endif void do_verbatim_input(void); +void complete_a_word(void); /* All functions in utils.c. */ void get_homedir(void); diff --git a/src/text.c b/src/text.c index bdc4517..e95558a 100644 --- a/src/text.c +++ b/src/text.c @@ -48,6 +48,11 @@ static filestruct *jusbottom = NULL; /* A pointer to the end of the buffer with unjustified text. */ #endif +static int pletion_x = 0; + /* The x position in pletion_line of the last found completion. */ +static int pleted_length = 0; + /* The number of bytes added in the last completion. */ + #ifndef NANO_TINY /* Toggle the mark. */ void do_mark(void) @@ -3684,3 +3689,113 @@ void do_verbatim_input(void) free(output); } + +/* Copy the found possible completion word. */ +char *copy_completion(char *check_line, int start) +{ + char *word; + int i = start, j = 0; + int len_of_word = 0; + + while (is_word_mbchar(&check_line[i++], FALSE)) + len_of_word++; + + word = (char *)malloc((len_of_word + 1) * sizeof(char)); + if (word == NULL) + return NULL; + + i = start; + + while (is_word_mbchar(&check_line[i], FALSE)) + word[j++] = check_line[i++]; + + word[j] = '\0'; + return word; +} + +/* 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 fill in the next + * possible completion. */ +void complete_a_word(void) +{ + char *shard, *completion = NULL; + int to_find_start_pos, len_to_find = 0; + int i = 0, j = 0; + + /* If this is a fresh completion attempt, initialize the starting point + * for searching; otherwise, remove the earlier completion suggestion. */ + if (pletion_line == NULL) { + pletion_line = openfile->fileage; + pletion_x = 0; + } else { + for (i = 0; i < pleted_length; i++) + do_backspace(); + } + + to_find_start_pos = openfile->current_x; + + /* Find the start of the fragment that the user typed. */ + while (--to_find_start_pos >= 0) + if (!is_word_mbchar(&openfile->current->data[to_find_start_pos], FALSE)) + break; + to_find_start_pos++; + + if (to_find_start_pos == openfile->current_x) { + pletion_line = NULL; + return; + } + + shard = (char *)malloc((openfile->current_x - to_find_start_pos + 1) * sizeof(char)); + if (shard == NULL) { + statusline(HUSH, "Insufficient Memory"); + return; + } + + /* Copy the fragment that has to be searched for. */ + while (to_find_start_pos < openfile->current_x) + shard[len_to_find++] = openfile->current->data[to_find_start_pos++]; + shard[len_to_find] = '\0'; + + /* Search the fragment in the file. */ + while (pletion_line != NULL) { + int line_length = strlen(pletion_line->data); + + for (i = pletion_x; i + len_to_find < line_length; i++) { + /* Ignore the fragment itself. */ + if (pletion_line == openfile->current && i == openfile->current_x - len_to_find) + continue; + + for (j = 0; (i == 0 || !is_word_mbchar(&pletion_line->data[i - 1], FALSE)) && + j < len_to_find; j++) + if (shard[j] != pletion_line->data[i + j]) + break; + if (j == len_to_find && (i + j < line_length && + is_word_mbchar(&pletion_line->data[i + j], FALSE))) { + completion = copy_completion(pletion_line->data, i); + + if (!completion) { + statusline(HUSH, "Insufficient Memory"); + return; + } + + /* Inject the completion and store this state*/ + pleted_length = strlen(completion) - len_to_find; + do_output(&completion[len_to_find], pleted_length, FALSE); + pletion_x = ++i; + return; + } + } + + pletion_line = pletion_line->next; + pletion_x = 0; + } + + if (pletion_line == NULL) { + edit_refresh(); + statusline(HUSH, "No further matches"); + } + + free(shard); + free(completion); +} \ No newline at end of file -- 2.9.3