>From dd516fad44871a08043af5791d8086ab1e8b2527 Mon Sep 17 00:00:00 2001 From: "sumedh.pendurkar" Date: Wed, 26 Oct 2016 23:34:41 +0530 Subject: [PATCH] Complete: made the code shorter and faster --- src/global.c | 8 +++ src/nano.c | 7 ++- src/proto.h | 4 ++ src/text.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 182 insertions(+), 1 deletion(-) diff --git a/src/global.c b/src/global.c index 029b68b..8ee715c 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) const char *nano_browser_refresh_msg = N_("Refresh the file list"); const char *nano_browser_lefthand_msg = N_("Go to lefthand column"); const char *nano_browser_righthand_msg = N_("Go to righthand column"); + const char *nano_completion_msg = N_("Try and complete the current word"); #endif const char *nano_prevpage_msg = N_("Go one screenful up"); const char *nano_nextpage_msg = N_("Go one screenful down"); @@ -827,6 +831,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, @@ -1109,6 +1116,7 @@ void shortcut_init(void) add_to_sclist(MMAIN, "M-{", do_unindent, 0); add_to_sclist(MMAIN, "M-U", do_undo, 0); add_to_sclist(MMAIN, "M-E", do_redo, 0); + add_to_sclist(MMAIN, "^]", complete_a_word, 0); #endif #ifdef ENABLE_COMMENT add_to_sclist(MMAIN, "M-3", do_comment, 0); diff --git a/src/nano.c b/src/nano.c index a542073..6d7969e 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 553418b..f8bed6f 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; @@ -674,6 +676,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); @@ -716,6 +719,7 @@ void remove_magicline(void); void mark_order(const filestruct **top, size_t *top_x, const filestruct **bot, size_t *bot_x, bool *right_side_up); void discard_until(const undo *thisitem, openfilestruct *thefile); +void pop_undo(void); void add_undo(undo_type action); void update_undo(undo_type action); #ifndef DISABLE_COMMENT diff --git a/src/text.c b/src/text.c index d0d1955..e18ecf3 100644 --- a/src/text.c +++ b/src/text.c @@ -46,6 +46,17 @@ static filestruct *jusbottom = NULL; /* Pointer to the end of the justify buffer. */ #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. */ +typedef struct pletion_word { + char *word; + struct pletion_word *next; +}pletion_word; +static pletion_word *pletion_word_list; + /* This is the list of the words that are the possible completions */ + #ifndef NANO_TINY /* Toggle the mark. */ void do_mark(void) @@ -1298,6 +1309,16 @@ void update_comment_undo(ssize_t lineno) } #endif /* ENABLE_COMMENT */ +/* Pop the top of the undo stack and set current_undo of the openfile to the top + * It also sets the last_action of the openfile to OTHER */ +void pop_undo(void) +{ + if (openfile->current_undo != NULL) { + discard_until(openfile->current_undo->next, openfile); + openfile->current_undo = openfile->undotop; + } +} + /* Update an undo item, or determine whether a new one is really needed * and bounce the data to add_undo instead. The latter functionality * just feels gimmicky and may just be more hassle than it's worth, @@ -3688,3 +3709,146 @@ 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; + pletion_word *word_current; + if (pletion_line == NULL) { + /* If this a fresh completion attempt, delete old words from previous + * attempt so that we can start afresh */ + while (pletion_word_list) { + pletion_word *n; + n = pletion_word_list; + free(pletion_word_list); + pletion_word_list = n->next; + } + + /* Setting last action to Other as we need to create a new struct when + * user uses Complete */ + openfile->last_action = OTHER; + + /* If this is a fresh completion attempt, initialize the starting point + * for searching; otherwise, remove the earlier completion suggestion. */ + pletion_word_list = NULL; + pletion_line = openfile->fileage; + pletion_x = 0; + blank_statusbar(); + wnoutrefresh(bottomwin); + } + else { + pop_undo(); + for (i = 0; i < pleted_length; i++) + do_backspace(); + pop_undo(); + } + to_find_start_pos = openfile->current_x; + word_current = pletion_word_list; + /* 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; + } + + /*check for duplicates*/ + while (word_current) { + if (strcmp(completion, word_current->word) == 0) + break; + word_current = word_current->next; + } + if (word_current) { + i++; + continue; + } + + /* Inject the completion*/ + word_current = (pletion_word *)malloc(sizeof(pletion_word)); + word_current->word = completion; + word_current->next = pletion_word_list; + pletion_word_list = word_current; + + /* Do the completion and store the state */ + pleted_length = strlen(completion) - len_to_find; + do_output(&word_current->word[len_to_find], pleted_length, FALSE); + pletion_x = ++i; + free(shard); + return; + } + } + + pletion_line = pletion_line->next; + pletion_x = 0; + } + + if (pletion_line == NULL) { + edit_refresh(); + statusline(HUSH, "No further matches"); + } + free(completion); + free(shard); +} -- 2.7.4