From: David Lawrence Ramsey Date: Tue, 1 Nov 2005 17:37:44 +0000 (+0000) Subject: move functions specific to the statusbar prompt to their own source X-Git-Tag: v1.3.10~181 X-Git-Url: https://git.wh0rd.org/?a=commitdiff_plain;h=d24d0a43e86d5a04b0b0b799a0ebd2ec7610ab05;p=nano.git move functions specific to the statusbar prompt to their own source file, prompt.c, and adjust related variables accordingly git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@3065 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- diff --git a/ChangeLog b/ChangeLog index 6f889dcb..afb744a1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,17 @@ CVS code - get_page_start(). (DLR) - Move xplustabs(), actual_x(), strnlenpt(), and strlenpt() from winio.c to utils.c, as they're really utility functions. (DLR) + - Move functions specific to the statusbar prompt to their own + source file, and adjust related variables accordingly. New + file prompt.c; changes to do_statusbar_input(), + do_statusbar_mouse(), do_statusbar_output(), + do_statusbar_home(), do_statusbar_end(), do_statusbar_right(), + do_statusbar_left(), do_statusbar_backspace(), + do_statusbar_delete(), do_statusbar_cut_text(), + do_statusbar_next_word(), do_statusbar_prev_word(), + do_statusbar_verbatim_input(), statusbar_xplustabs(), + get_statusbar_page_start(), nanoget_repaint(), nanogetstr(), + statusq(), and statusq_abort() (all moved to prompt.c). (DLR) - nano.h: - Readd MIN_EDITOR_COLS #define. (DLR) - winio.c: @@ -28,6 +39,8 @@ CVS code - - doc/nanorc.sample: - Tweak the "c-file" regex for characters to properly accept '\"' and reject '"' and '''. (DLR) +- src/Makefile.am: + - Add prompt.c to nano_SOURCES. (DLR) GNU nano 1.3.9 - 2005.10.23 - General: diff --git a/src/Makefile.am b/src/Makefile.am index f9621c26..635771aa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,6 +12,7 @@ nano_SOURCES = chars.c \ move.c \ nano.c \ nano.h \ + prompt.c \ proto.h \ rcfile.c \ search.c \ diff --git a/src/prompt.c b/src/prompt.c new file mode 100644 index 00000000..2c212b50 --- /dev/null +++ b/src/prompt.c @@ -0,0 +1,877 @@ +/* $Id$ */ +/************************************************************************** + * prompt.c * + * * + * Copyright (C) 2005 Chris Allegretta * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2, or (at your option) * + * any later version. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * + * 02110-1301, USA. * + * * + **************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include "proto.h" + +static char *prompt = NULL; + /* The prompt string for statusbar + * questions. */ +static size_t statusbar_x = (size_t)-1; + /* The cursor position in answer. */ +static bool resetstatuspos = FALSE; + /* Should we reset the cursor position + * at the statusbar prompt? */ + +int do_statusbar_input(bool *meta_key, bool *func_key, bool *s_or_t, + bool *ran_func, bool *finished, bool allow_funcs) +{ + int input; + /* The character we read in. */ + static int *kbinput = NULL; + /* The input buffer. */ + static size_t kbinput_len = 0; + /* The length of the input buffer. */ + const shortcut *s; + bool have_shortcut; + + *s_or_t = FALSE; + *ran_func = FALSE; + *finished = FALSE; + + /* Read in a character. */ + input = get_kbinput(bottomwin, meta_key, func_key); + +#ifndef DISABLE_MOUSE + /* If we got a mouse click and it was on a shortcut, read in the + * shortcut character. */ + if (allow_funcs && *func_key == TRUE && input == KEY_MOUSE) { + if (do_statusbar_mouse()) + input = get_kbinput(bottomwin, meta_key, func_key); + else + input = ERR; + } +#endif + + /* Check for a shortcut in the current list. */ + s = get_shortcut(currshortcut, &input, meta_key, func_key); + + /* If we got a shortcut from the current list, or a "universal" + * statusbar prompt shortcut, set have_shortcut to TRUE. */ + have_shortcut = (s != NULL || input == NANO_REFRESH_KEY || + input == NANO_HOME_KEY || input == NANO_END_KEY || + input == NANO_FORWARD_KEY || input == NANO_BACK_KEY || + input == NANO_BACKSPACE_KEY || input == NANO_DELETE_KEY || + input == NANO_CUT_KEY || +#ifndef NANO_SMALL + input == NANO_NEXTWORD_KEY || +#endif + (*meta_key == TRUE && ( +#ifndef NANO_SMALL + input == NANO_PREVWORD_KEY || +#endif + input == NANO_VERBATIM_KEY))); + + /* Set s_or_t to TRUE if we got a shortcut. */ + *s_or_t = have_shortcut; + + if (allow_funcs) { + /* If we got a character, and it isn't a shortcut or toggle, + * it's a normal text character. Display the warning if we're + * in view mode, or add the character to the input buffer if + * we're not. */ + if (input != ERR && *s_or_t == FALSE) { + /* If we're using restricted mode, the filename isn't blank, + * and we're at the "Write File" prompt, disable text + * input. */ + if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || + currshortcut != writefile_list) { + kbinput_len++; + kbinput = (int *)nrealloc(kbinput, kbinput_len * + sizeof(int)); + kbinput[kbinput_len - 1] = input; + } + } + + /* If we got a shortcut, or if there aren't any other characters + * waiting after the one we read in, we need to display all the + * characters in the input buffer if it isn't empty. */ + if (*s_or_t == TRUE || get_key_buffer_len() == 0) { + if (kbinput != NULL) { + + /* Display all the characters in the input buffer at + * once, filtering out control characters. */ + char *output = charalloc(kbinput_len + 1); + size_t i; + bool got_enter; + /* Whether we got the Enter key. */ + + for (i = 0; i < kbinput_len; i++) + output[i] = (char)kbinput[i]; + output[i] = '\0'; + + do_statusbar_output(output, kbinput_len, &got_enter, + FALSE); + + free(output); + + /* Empty the input buffer. */ + kbinput_len = 0; + free(kbinput); + kbinput = NULL; + } + } + + if (have_shortcut) { + switch (input) { + /* Handle the "universal" statusbar prompt shortcuts. */ + case NANO_REFRESH_KEY: + total_refresh(); + break; + case NANO_HOME_KEY: + do_statusbar_home(); + break; + case NANO_END_KEY: + do_statusbar_end(); + break; + case NANO_FORWARD_KEY: + do_statusbar_right(); + break; + case NANO_BACK_KEY: + do_statusbar_left(); + break; + case NANO_BACKSPACE_KEY: + /* If we're using restricted mode, the filename + * isn't blank, and we're at the "Write File" + * prompt, disable Backspace. */ + if (!ISSET(RESTRICTED) || openfile->filename[0] == + '\0' || currshortcut != writefile_list) + do_statusbar_backspace(); + break; + case NANO_DELETE_KEY: + /* If we're using restricted mode, the filename + * isn't blank, and we're at the "Write File" + * prompt, disable Delete. */ + if (!ISSET(RESTRICTED) || openfile->filename[0] == + '\0' || currshortcut != writefile_list) + do_statusbar_delete(); + break; + case NANO_CUT_KEY: + /* If we're using restricted mode, the filename + * isn't blank, and we're at the "Write File" + * prompt, disable Cut. */ + if (!ISSET(RESTRICTED) || openfile->filename[0] == + '\0' || currshortcut != writefile_list) + do_statusbar_cut_text(); + break; +#ifndef NANO_SMALL + case NANO_NEXTWORD_KEY: + do_statusbar_next_word(FALSE); + break; + case NANO_PREVWORD_KEY: + if (*meta_key == TRUE) + do_statusbar_prev_word(FALSE); + break; +#endif + case NANO_VERBATIM_KEY: + if (*meta_key == TRUE) { + /* If we're using restricted mode, the filename + * isn't blank, and we're at the "Write File" + * prompt, disable verbatim input. */ + if (!ISSET(RESTRICTED) || + openfile->filename[0] == '\0' || + currshortcut != writefile_list) { + bool got_enter; + /* Whether we got the Enter key. */ + + do_statusbar_verbatim_input(&got_enter); + + /* If we got the Enter key, set input to the + * key value for Enter, and set finished to + * TRUE to indicate that we're done. */ + if (got_enter) { + input = NANO_ENTER_KEY; + *finished = TRUE; + } + } + break; + } + /* Handle the normal statusbar prompt shortcuts, setting + * ran_func to TRUE if we try to run their associated + * functions and setting finished to TRUE to indicate + * that we're done after trying to run their associated + * functions. */ + default: + if (s->func != NULL) { + *ran_func = TRUE; + if (!ISSET(VIEW_MODE) || s->viewok) + s->func(); + } + *finished = TRUE; + } + } + } + + return input; +} + +#ifndef DISABLE_MOUSE +bool do_statusbar_mouse(void) +{ + int mouse_x, mouse_y; + bool retval = get_mouseinput(&mouse_x, &mouse_y, TRUE); + + if (!retval) { + /* We can click in the statusbar window text to move the + * cursor. */ + if (wenclose(bottomwin, mouse_y, mouse_x)) { + size_t start_col = strlenpt(prompt) + 1; + + /* Subtract out the sizes of topwin and edit. */ + mouse_y -= (2 - no_more_space()) + editwinrows; + + /* Move to where the click occurred. */ + if (mouse_x > start_col && mouse_y == 0) { + statusbar_x = actual_x(answer, + get_statusbar_page_start(start_col, start_col + + statusbar_xplustabs()) + mouse_x - start_col - + 1); + nanoget_repaint(answer, statusbar_x); + } + } + } + + return retval; +} +#endif + +/* The user typed output_len multibyte characters. Add them to the + * statusbar prompt, setting got_enter to TRUE if we get a newline, and + * filtering out all control characters if allow_cntrls is TRUE. */ +void do_statusbar_output(char *output, size_t output_len, bool + *got_enter, bool allow_cntrls) +{ + size_t answer_len, i = 0; + char *char_buf = charalloc(mb_cur_max()); + int char_buf_len; + + assert(answer != NULL); + + answer_len = strlen(answer); + *got_enter = FALSE; + + while (i < output_len) { + /* If allow_cntrls is FALSE, filter out nulls and newlines, + * since they're control characters. */ + if (allow_cntrls) { + /* Null to newline, if needed. */ + if (output[i] == '\0') + output[i] = '\n'; + /* Newline to Enter, if needed. */ + else if (output[i] == '\n') { + /* Set got_enter to TRUE to indicate that we got the + * Enter key, put back the rest of the characters in + * output so that they can be parsed and output again, + * and get out. */ + *got_enter = TRUE; + unparse_kbinput(output + i, output_len - i); + return; + } + } + + /* Interpret the next multibyte character. */ + char_buf_len = parse_mbchar(output + i, char_buf, NULL); + + i += char_buf_len; + + /* If allow_cntrls is FALSE, filter out a control character. */ + if (!allow_cntrls && is_cntrl_mbchar(output + i - char_buf_len)) + continue; + + /* More dangerousness fun =) */ + answer = charealloc(answer, answer_len + (char_buf_len * 2)); + + assert(statusbar_x <= answer_len); + + charmove(&answer[statusbar_x + char_buf_len], + &answer[statusbar_x], answer_len - statusbar_x + + char_buf_len); + strncpy(&answer[statusbar_x], char_buf, char_buf_len); + answer_len += char_buf_len; + + statusbar_x += char_buf_len; + } + + free(char_buf); +} + +void do_statusbar_home(void) +{ +#ifndef NANO_SMALL + if (ISSET(SMART_HOME)) { + size_t statusbar_x_save = statusbar_x; + + statusbar_x = indent_length(answer); + + if (statusbar_x == statusbar_x_save || + statusbar_x == strlen(answer)) + statusbar_x = 0; + } else +#endif + statusbar_x = 0; +} + +void do_statusbar_end(void) +{ + statusbar_x = strlen(answer); +} + +void do_statusbar_right(void) +{ + if (statusbar_x < strlen(answer)) + statusbar_x = move_mbright(answer, statusbar_x); +} + +void do_statusbar_left(void) +{ + if (statusbar_x > 0) + statusbar_x = move_mbleft(answer, statusbar_x); +} + +void do_statusbar_backspace(void) +{ + if (statusbar_x > 0) { + do_statusbar_left(); + do_statusbar_delete(); + } +} + +void do_statusbar_delete(void) +{ + if (answer[statusbar_x] != '\0') { + int char_buf_len = parse_mbchar(answer + statusbar_x, NULL, + NULL); + size_t line_len = strlen(answer + statusbar_x); + + assert(statusbar_x < strlen(answer)); + + charmove(answer + statusbar_x, answer + statusbar_x + + char_buf_len, strlen(answer) - statusbar_x - + char_buf_len + 1); + + null_at(&answer, statusbar_x + line_len - char_buf_len); + } +} + +/* Move text from the statusbar prompt into oblivion. */ +void do_statusbar_cut_text(void) +{ + assert(answer != NULL); + +#ifndef NANO_SMALL + if (ISSET(CUT_TO_END)) + null_at(&answer, statusbar_x); + else { +#endif + null_at(&answer, 0); + statusbar_x = 0; +#ifndef NANO_SMALL + } +#endif +} + +#ifndef NANO_SMALL +/* Move to the next word at the statusbar prompt. If allow_punct is + * TRUE, treat punctuation as part of a word. Return TRUE if we started + * on a word, and FALSE otherwise. */ +bool do_statusbar_next_word(bool allow_punct) +{ + char *char_mb; + int char_mb_len; + bool end_line = FALSE, started_on_word = FALSE; + + assert(answer != NULL); + + char_mb = charalloc(mb_cur_max()); + + /* Move forward until we find the character after the last letter of + * the current word. */ + while (!end_line) { + char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); + + /* If we've found it, stop moving forward through the current + * line. */ + if (!is_word_mbchar(char_mb, allow_punct)) + break; + + /* If we haven't found it, then we've started on a word, so set + * started_on_word to TRUE. */ + started_on_word = TRUE; + + if (answer[statusbar_x] == '\0') + end_line = TRUE; + else + statusbar_x += char_mb_len; + } + + /* Move forward until we find the first letter of the next word. */ + if (answer[statusbar_x] == '\0') + end_line = TRUE; + else + statusbar_x += char_mb_len; + + while (!end_line) { + char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); + + /* If we've found it, stop moving forward through the current + * line. */ + if (is_word_mbchar(char_mb, allow_punct)) + break; + + if (answer[statusbar_x] == '\0') + end_line = TRUE; + else + statusbar_x += char_mb_len; + } + + free(char_mb); + + /* Return whether we started on a word. */ + return started_on_word; +} + +/* Move to the previous word at the statusbar prompt. If allow_punct is + * TRUE, treat punctuation as part of a word. Return TRUE if we started + * on a word, and FALSE otherwise. */ +bool do_statusbar_prev_word(bool allow_punct) +{ + char *char_mb; + int char_mb_len; + bool begin_line = FALSE, started_on_word = FALSE; + + assert(answer != NULL); + + char_mb = charalloc(mb_cur_max()); + + /* Move backward until we find the character before the first letter + * of the current word. */ + while (!begin_line) { + char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); + + /* If we've found it, stop moving backward through the current + * line. */ + if (!is_word_mbchar(char_mb, allow_punct)) + break; + + /* If we haven't found it, then we've started on a word, so set + * started_on_word to TRUE. */ + started_on_word = TRUE; + + if (statusbar_x == 0) + begin_line = TRUE; + else + statusbar_x = move_mbleft(answer, statusbar_x); + } + + /* Move backward until we find the last letter of the previous + * word. */ + if (statusbar_x == 0) + begin_line = TRUE; + else + statusbar_x = move_mbleft(answer, statusbar_x); + + while (!begin_line) { + char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); + + /* If we've found it, stop moving backward through the current + * line. */ + if (is_word_mbchar(char_mb, allow_punct)) + break; + + if (statusbar_x == 0) + begin_line = TRUE; + else + statusbar_x = move_mbleft(answer, statusbar_x); + } + + /* If we've found it, move backward until we find the character + * before the first letter of the previous word. */ + if (!begin_line) { + if (statusbar_x == 0) + begin_line = TRUE; + else + statusbar_x = move_mbleft(answer, statusbar_x); + + while (!begin_line) { + char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, + NULL); + + /* If we've found it, stop moving backward through the + * current line. */ + if (!is_word_mbchar(char_mb, allow_punct)) + break; + + if (statusbar_x == 0) + begin_line = TRUE; + else + statusbar_x = move_mbleft(answer, statusbar_x); + } + + /* If we've found it, move forward to the first letter of the + * previous word. */ + if (!begin_line) + statusbar_x += char_mb_len; + } + + free(char_mb); + + /* Return whether we started on a word. */ + return started_on_word; +} +#endif /* !NANO_SMALL */ + +void do_statusbar_verbatim_input(bool *got_enter) +{ + int *kbinput; + size_t kbinput_len, i; + char *output; + + *got_enter = FALSE; + + /* Read in all the verbatim characters. */ + kbinput = get_verbatim_kbinput(bottomwin, &kbinput_len); + + /* Display all the verbatim characters at once, not filtering out + * control characters. */ + output = charalloc(kbinput_len + 1); + + for (i = 0; i < kbinput_len; i++) + output[i] = (char)kbinput[i]; + output[i] = '\0'; + + do_statusbar_output(output, kbinput_len, got_enter, TRUE); + + free(output); +} + +/* Return the placewewant associated with statusbar_x, i.e, the + * zero-based column position of the cursor. The value will be no + * smaller than statusbar_x. */ +size_t statusbar_xplustabs(void) +{ + return strnlenpt(answer, statusbar_x); +} + +/* nano scrolls horizontally within a line in chunks. This function + * returns the column number of the first character displayed in the + * statusbar prompt when the cursor is at the given column with the + * prompt ending at start_col. Note that (0 <= column - + * get_statusbar_page_start(column) < COLS). */ +size_t get_statusbar_page_start(size_t start_col, size_t column) +{ + if (column == start_col || column < COLS - 1) + return 0; + else + return column - start_col - (column - start_col) % (COLS - + start_col - 1); +} + +/* Repaint the statusbar when getting a character in nanogetstr(). Note + * that we must turn on A_REVERSE here, since do_help() turns it off! */ +void nanoget_repaint(const char *buf, size_t x) +{ + size_t start_col, xpt, page_start; + char *expanded; + + assert(x <= strlen(buf)); + + start_col = strlenpt(prompt) + 1; + xpt = strnlenpt(buf, x); + page_start = get_statusbar_page_start(start_col, start_col + xpt); + + wattron(bottomwin, A_REVERSE); + + blank_statusbar(); + + mvwaddnstr(bottomwin, 0, 0, prompt, actual_x(prompt, COLS - 2)); + waddch(bottomwin, ':'); + waddch(bottomwin, (page_start == 0) ? ' ' : '$'); + + expanded = display_string(buf, page_start, COLS - start_col - 1, + FALSE); + waddstr(bottomwin, expanded); + free(expanded); + + wmove(bottomwin, 0, start_col + xpt + 1 - page_start); + + wattroff(bottomwin, A_REVERSE); +} + +/* Get the input from the keyboard; this should only be called from + * statusq(). */ +int nanogetstr(bool allow_tabs, const char *curranswer, +#ifndef NANO_SMALL + filestruct **history_list, +#endif + const shortcut *s +#ifndef DISABLE_TABCOMP + , bool *list +#endif + ) +{ + int kbinput; + bool meta_key, func_key, s_or_t, ran_func, finished; + size_t curranswer_len; +#ifndef DISABLE_TABCOMP + bool tabbed = FALSE; + /* Whether we've pressed Tab. */ +#endif +#ifndef NANO_SMALL + char *history = NULL; + /* The current history string. */ + char *magichistory = NULL; + /* The temporary string typed at the bottom of the history, if + * any. */ +#ifndef DISABLE_TABCOMP + int last_kbinput = ERR; + /* The key we pressed before the current key. */ + size_t complete_len = 0; + /* The length of the original string that we're trying to + * tab complete, if any. */ +#endif +#endif /* !NANO_SMALL */ + + answer = mallocstrcpy(answer, curranswer); + curranswer_len = strlen(answer); + + /* Only put statusbar_x at the end of the string if it's + * uninitialized, if it would be past the end of curranswer, or if + * resetstatuspos is TRUE. Otherwise, leave it alone. This is so + * the cursor position stays at the same place if a prompt-changing + * toggle is pressed. */ + if (statusbar_x == (size_t)-1 || statusbar_x > curranswer_len || + resetstatuspos) + statusbar_x = curranswer_len; + + currshortcut = s; + + nanoget_repaint(answer, statusbar_x); + + /* Refresh the edit window and the statusbar before getting + * input. */ + wnoutrefresh(edit); + wnoutrefresh(bottomwin); + + /* If we're using restricted mode, we aren't allowed to change the + * name of a file once it has one because that would allow writing + * to files not specified on the command line. In this case, + * disable all keys that would change the text if the filename isn't + * blank and we're at the "Write File" prompt. */ + while ((kbinput = do_statusbar_input(&meta_key, &func_key, + &s_or_t, &ran_func, &finished, TRUE)) != NANO_CANCEL_KEY && + kbinput != NANO_ENTER_KEY) { + + assert(statusbar_x <= strlen(answer)); + +#ifndef DISABLE_TABCOMP + if (kbinput != NANO_TAB_KEY) + tabbed = FALSE; +#endif + + switch (kbinput) { + case NANO_TAB_KEY: +#ifndef DISABLE_TABCOMP +#ifndef NANO_SMALL + if (history_list != NULL) { + if (last_kbinput != NANO_TAB_KEY) + complete_len = strlen(answer); + + if (complete_len > 0) { + answer = mallocstrcpy(answer, + get_history_completion(history_list, + answer, complete_len)); + statusbar_x = strlen(answer); + } + } else +#endif /* !NANO_SMALL */ + if (allow_tabs) + answer = input_tab(answer, &statusbar_x, &tabbed, + list); +#endif /* !DISABLE_TABCOMP */ + break; + case NANO_PREVLINE_KEY: +#ifndef NANO_SMALL + if (history_list != NULL) { + /* If we're scrolling up at the bottom of the + * history list and answer isn't blank, save answer + * in magichistory. */ + if ((*history_list)->next == NULL && + answer[0] != '\0') + magichistory = mallocstrcpy(magichistory, + answer); + + /* Get the older search from the history list and + * save it in answer. If there is no older search, + * don't do anything. */ + if ((history = + get_history_older(history_list)) != NULL) { + answer = mallocstrcpy(answer, history); + statusbar_x = strlen(answer); + } + + /* This key has a shortcut list entry when it's used + * to move to an older search, which means that + * finished has been set to TRUE. Set it back to + * FALSE here, so that we aren't kicked out of the + * statusbar prompt. */ + finished = FALSE; + } +#endif /* !NANO_SMALL */ + break; + case NANO_NEXTLINE_KEY: +#ifndef NANO_SMALL + if (history_list != NULL) { + /* Get the newer search from the history list and + * save it in answer. If there is no newer search, + * don't do anything. */ + if ((history = + get_history_newer(history_list)) != NULL) { + answer = mallocstrcpy(answer, history); + statusbar_x = strlen(answer); + } + + /* If, after scrolling down, we're at the bottom of + * the history list, answer is blank, and + * magichistory is set, save magichistory in + * answer. */ + if ((*history_list)->next == NULL && + answer[0] == '\0' && magichistory != NULL) { + answer = mallocstrcpy(answer, magichistory); + statusbar_x = strlen(answer); + } + } +#endif /* !NANO_SMALL */ + break; + } + + /* If we have a shortcut with an associated function, break out + * if we're finished after running or trying to run the + * function. */ + if (finished) + break; + +#if !defined(NANO_SMALL) && !defined(DISABLE_TABCOMP) + last_kbinput = kbinput; +#endif + + nanoget_repaint(answer, statusbar_x); + wnoutrefresh(bottomwin); + } + +#ifndef NANO_SMALL + /* Set the current position in the history list to the bottom and + * free magichistory, if we need to. */ + if (history_list != NULL) { + history_reset(*history_list); + + if (magichistory != NULL) + free(magichistory); + } +#endif + + /* We finished putting in an answer or ran a normal shortcut's + * associated function, so reset statusbar_x. */ + if (kbinput == NANO_CANCEL_KEY || kbinput == NANO_ENTER_KEY || + ran_func) + statusbar_x = (size_t)-1; + + return kbinput; +} + +/* Ask a question on the statusbar. Answer will be stored in answer + * global. Returns -1 on aborted enter, -2 on a blank string, and 0 + * otherwise, the valid shortcut key caught. curranswer is any editable + * text that we want to put up by default. + * + * The allow_tabs parameter indicates whether we should allow tabs to be + * interpreted. */ +int statusq(bool allow_tabs, const shortcut *s, const char *curranswer, +#ifndef NANO_SMALL + filestruct **history_list, +#endif + const char *msg, ...) +{ + va_list ap; + int retval; +#ifndef DISABLE_TABCOMP + bool list = FALSE; +#endif + + prompt = charealloc(prompt, ((COLS - 4) * mb_cur_max()) + 1); + + bottombars(s); + + va_start(ap, msg); + vsnprintf(prompt, (COLS - 4) * mb_cur_max(), msg, ap); + va_end(ap); + null_at(&prompt, actual_x(prompt, COLS - 4)); + + retval = nanogetstr(allow_tabs, curranswer, +#ifndef NANO_SMALL + history_list, +#endif + s +#ifndef DISABLE_TABCOMP + , &list +#endif + ); + + resetstatuspos = FALSE; + + switch (retval) { + case NANO_CANCEL_KEY: + retval = -1; + resetstatuspos = TRUE; + break; + case NANO_ENTER_KEY: + retval = (answer[0] == '\0') ? -2 : 0; + resetstatuspos = TRUE; + break; + } + + blank_statusbar(); + wnoutrefresh(bottomwin); + +#ifdef DEBUG + fprintf(stderr, "answer = \"%s\"\n", answer); +#endif + +#ifndef DISABLE_TABCOMP + /* If we've done tab completion, there might be a list of filename + * matches on the edit window at this point. Make sure that they're + * cleared off. */ + if (list) + edit_refresh(); +#endif + + return retval; +} + +void statusq_abort(void) +{ + resetstatuspos = TRUE; +} diff --git a/src/proto.h b/src/proto.h index 955f8f25..3ca6f77a 100644 --- a/src/proto.h +++ b/src/proto.h @@ -416,6 +416,45 @@ bool do_mouse(void); #endif void do_output(char *output, size_t output_len, bool allow_cntrls); +/* Public functions in prompt.c. */ +int do_statusbar_input(bool *meta_key, bool *func_key, bool *s_or_t, + bool *ran_func, bool *finished, bool allow_funcs); +#ifndef DISABLE_MOUSE +bool do_statusbar_mouse(void); +#endif +void do_statusbar_output(char *output, size_t output_len, bool + *got_enter, bool allow_cntrls); +void do_statusbar_home(void); +void do_statusbar_end(void); +void do_statusbar_right(void); +void do_statusbar_left(void); +void do_statusbar_backspace(void); +void do_statusbar_delete(void); +void do_statusbar_cut_text(void); +#ifndef NANO_SMALL +bool do_statusbar_next_word(bool allow_punct); +bool do_statusbar_prev_word(bool allow_punct); +#endif +void do_statusbar_verbatim_input(bool *got_enter); +size_t statusbar_xplustabs(void); +size_t get_statusbar_page_start(size_t start_col, size_t column); +void nanoget_repaint(const char *buf, size_t x); +int nanogetstr(bool allow_tabs, const char *curranswer, +#ifndef NANO_SMALL + filestruct **history_list, +#endif + const shortcut *s +#ifndef DISABLE_TABCOMP + , bool *list +#endif + ); +int statusq(bool allow_tabs, const shortcut *s, const char *curranswer, +#ifndef NANO_SMALL + filestruct **history_list, +#endif + const char *msg, ...); +void statusq_abort(void); + /* Public functions in rcfile.c. */ #ifdef ENABLE_NANORC void rcfile_error(const char *msg, ...); @@ -617,27 +656,6 @@ const shortcut *get_shortcut(const shortcut *s_list, int *kbinput, bool #ifndef NANO_SMALL const toggle *get_toggle(int kbinput, bool meta_key); #endif -int do_statusbar_input(bool *meta_key, bool *func_key, bool *s_or_t, - bool *ran_func, bool *finished, bool allow_funcs); -#ifndef DISABLE_MOUSE -bool do_statusbar_mouse(void); -#endif -void do_statusbar_output(char *output, size_t output_len, bool - *got_enter, bool allow_cntrls); -void do_statusbar_home(void); -void do_statusbar_end(void); -void do_statusbar_right(void); -void do_statusbar_left(void); -void do_statusbar_backspace(void); -void do_statusbar_delete(void); -void do_statusbar_cut_text(void); -#ifndef NANO_SMALL -bool do_statusbar_next_word(bool allow_punct); -bool do_statusbar_prev_word(bool allow_punct); -#endif -void do_statusbar_verbatim_input(bool *got_enter); -size_t statusbar_xplustabs(void); -size_t get_statusbar_page_start(size_t start_col, size_t column); void blank_line(WINDOW *win, int y, int x, int n); void blank_titlebar(void); void blank_topbar(void); @@ -647,22 +665,6 @@ void blank_bottombars(void); void check_statusblank(void); char *display_string(const char *buf, size_t start_col, size_t len, bool dollars); -void nanoget_repaint(const char *buf, size_t x); -int nanogetstr(bool allow_tabs, const char *curranswer, -#ifndef NANO_SMALL - filestruct **history_list, -#endif - const shortcut *s -#ifndef DISABLE_TABCOMP - , bool *list -#endif - ); -int statusq(bool allow_tabs, const shortcut *s, const char *curranswer, -#ifndef NANO_SMALL - filestruct **history_list, -#endif - const char *msg, ...); -void statusq_abort(void); void titlebar(const char *path); void set_modified(void); void statusbar(const char *msg, ...); diff --git a/src/winio.c b/src/winio.c index bef79c42..91abf7b6 100644 --- a/src/winio.c +++ b/src/winio.c @@ -38,11 +38,6 @@ static int *key_buffer = NULL; static size_t key_buffer_len = 0; /* The length of the default keystroke * buffer. */ -static char *prompt = NULL; - /* The prompt string for statusbar - * questions. */ -static size_t statusbar_x = (size_t)-1; - /* The cursor position in answer. */ static int statusblank = 0; /* The number of keystrokes left after * we call statusbar(), before we @@ -50,9 +45,6 @@ static int statusblank = 0; static bool disable_cursorpos = FALSE; /* Should we temporarily disable * constant cursor position display? */ -static bool resetstatuspos = FALSE; - /* Should we reset the cursor position - * at the statusbar prompt? */ /* Control character compatibility: * @@ -1667,559 +1659,6 @@ const toggle *get_toggle(int kbinput, bool meta_key) } #endif /* !NANO_SMALL */ -int do_statusbar_input(bool *meta_key, bool *func_key, bool *s_or_t, - bool *ran_func, bool *finished, bool allow_funcs) -{ - int input; - /* The character we read in. */ - static int *kbinput = NULL; - /* The input buffer. */ - static size_t kbinput_len = 0; - /* The length of the input buffer. */ - const shortcut *s; - bool have_shortcut; - - *s_or_t = FALSE; - *ran_func = FALSE; - *finished = FALSE; - - /* Read in a character. */ - input = get_kbinput(bottomwin, meta_key, func_key); - -#ifndef DISABLE_MOUSE - /* If we got a mouse click and it was on a shortcut, read in the - * shortcut character. */ - if (allow_funcs && *func_key == TRUE && input == KEY_MOUSE) { - if (do_statusbar_mouse()) - input = get_kbinput(bottomwin, meta_key, func_key); - else - input = ERR; - } -#endif - - /* Check for a shortcut in the current list. */ - s = get_shortcut(currshortcut, &input, meta_key, func_key); - - /* If we got a shortcut from the current list, or a "universal" - * statusbar prompt shortcut, set have_shortcut to TRUE. */ - have_shortcut = (s != NULL || input == NANO_REFRESH_KEY || - input == NANO_HOME_KEY || input == NANO_END_KEY || - input == NANO_FORWARD_KEY || input == NANO_BACK_KEY || - input == NANO_BACKSPACE_KEY || input == NANO_DELETE_KEY || - input == NANO_CUT_KEY || -#ifndef NANO_SMALL - input == NANO_NEXTWORD_KEY || -#endif - (*meta_key == TRUE && ( -#ifndef NANO_SMALL - input == NANO_PREVWORD_KEY || -#endif - input == NANO_VERBATIM_KEY))); - - /* Set s_or_t to TRUE if we got a shortcut. */ - *s_or_t = have_shortcut; - - if (allow_funcs) { - /* If we got a character, and it isn't a shortcut or toggle, - * it's a normal text character. Display the warning if we're - * in view mode, or add the character to the input buffer if - * we're not. */ - if (input != ERR && *s_or_t == FALSE) { - /* If we're using restricted mode, the filename isn't blank, - * and we're at the "Write File" prompt, disable text - * input. */ - if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || - currshortcut != writefile_list) { - kbinput_len++; - kbinput = (int *)nrealloc(kbinput, kbinput_len * - sizeof(int)); - kbinput[kbinput_len - 1] = input; - } - } - - /* If we got a shortcut, or if there aren't any other characters - * waiting after the one we read in, we need to display all the - * characters in the input buffer if it isn't empty. */ - if (*s_or_t == TRUE || get_key_buffer_len() == 0) { - if (kbinput != NULL) { - - /* Display all the characters in the input buffer at - * once, filtering out control characters. */ - char *output = charalloc(kbinput_len + 1); - size_t i; - bool got_enter; - /* Whether we got the Enter key. */ - - for (i = 0; i < kbinput_len; i++) - output[i] = (char)kbinput[i]; - output[i] = '\0'; - - do_statusbar_output(output, kbinput_len, &got_enter, - FALSE); - - free(output); - - /* Empty the input buffer. */ - kbinput_len = 0; - free(kbinput); - kbinput = NULL; - } - } - - if (have_shortcut) { - switch (input) { - /* Handle the "universal" statusbar prompt shortcuts. */ - case NANO_REFRESH_KEY: - total_refresh(); - break; - case NANO_HOME_KEY: - do_statusbar_home(); - break; - case NANO_END_KEY: - do_statusbar_end(); - break; - case NANO_FORWARD_KEY: - do_statusbar_right(); - break; - case NANO_BACK_KEY: - do_statusbar_left(); - break; - case NANO_BACKSPACE_KEY: - /* If we're using restricted mode, the filename - * isn't blank, and we're at the "Write File" - * prompt, disable Backspace. */ - if (!ISSET(RESTRICTED) || openfile->filename[0] == - '\0' || currshortcut != writefile_list) - do_statusbar_backspace(); - break; - case NANO_DELETE_KEY: - /* If we're using restricted mode, the filename - * isn't blank, and we're at the "Write File" - * prompt, disable Delete. */ - if (!ISSET(RESTRICTED) || openfile->filename[0] == - '\0' || currshortcut != writefile_list) - do_statusbar_delete(); - break; - case NANO_CUT_KEY: - /* If we're using restricted mode, the filename - * isn't blank, and we're at the "Write File" - * prompt, disable Cut. */ - if (!ISSET(RESTRICTED) || openfile->filename[0] == - '\0' || currshortcut != writefile_list) - do_statusbar_cut_text(); - break; -#ifndef NANO_SMALL - case NANO_NEXTWORD_KEY: - do_statusbar_next_word(FALSE); - break; - case NANO_PREVWORD_KEY: - if (*meta_key == TRUE) - do_statusbar_prev_word(FALSE); - break; -#endif - case NANO_VERBATIM_KEY: - if (*meta_key == TRUE) { - /* If we're using restricted mode, the filename - * isn't blank, and we're at the "Write File" - * prompt, disable verbatim input. */ - if (!ISSET(RESTRICTED) || - openfile->filename[0] == '\0' || - currshortcut != writefile_list) { - bool got_enter; - /* Whether we got the Enter key. */ - - do_statusbar_verbatim_input(&got_enter); - - /* If we got the Enter key, set input to the - * key value for Enter, and set finished to - * TRUE to indicate that we're done. */ - if (got_enter) { - input = NANO_ENTER_KEY; - *finished = TRUE; - } - } - break; - } - /* Handle the normal statusbar prompt shortcuts, setting - * ran_func to TRUE if we try to run their associated - * functions and setting finished to TRUE to indicate - * that we're done after trying to run their associated - * functions. */ - default: - if (s->func != NULL) { - *ran_func = TRUE; - if (!ISSET(VIEW_MODE) || s->viewok) - s->func(); - } - *finished = TRUE; - } - } - } - - return input; -} - -#ifndef DISABLE_MOUSE -bool do_statusbar_mouse(void) -{ - int mouse_x, mouse_y; - bool retval = get_mouseinput(&mouse_x, &mouse_y, TRUE); - - if (!retval) { - /* We can click in the statusbar window text to move the - * cursor. */ - if (wenclose(bottomwin, mouse_y, mouse_x)) { - size_t start_col = strlenpt(prompt) + 1; - - /* Subtract out the sizes of topwin and edit. */ - mouse_y -= (2 - no_more_space()) + editwinrows; - - /* Move to where the click occurred. */ - if (mouse_x > start_col && mouse_y == 0) { - statusbar_x = actual_x(answer, - get_statusbar_page_start(start_col, start_col + - statusbar_xplustabs()) + mouse_x - start_col - - 1); - nanoget_repaint(answer, statusbar_x); - } - } - } - - return retval; -} -#endif - -/* The user typed output_len multibyte characters. Add them to the - * statusbar prompt, setting got_enter to TRUE if we get a newline, and - * filtering out all control characters if allow_cntrls is TRUE. */ -void do_statusbar_output(char *output, size_t output_len, bool - *got_enter, bool allow_cntrls) -{ - size_t answer_len, i = 0; - char *char_buf = charalloc(mb_cur_max()); - int char_buf_len; - - assert(answer != NULL); - - answer_len = strlen(answer); - *got_enter = FALSE; - - while (i < output_len) { - /* If allow_cntrls is FALSE, filter out nulls and newlines, - * since they're control characters. */ - if (allow_cntrls) { - /* Null to newline, if needed. */ - if (output[i] == '\0') - output[i] = '\n'; - /* Newline to Enter, if needed. */ - else if (output[i] == '\n') { - /* Set got_enter to TRUE to indicate that we got the - * Enter key, put back the rest of the characters in - * output so that they can be parsed and output again, - * and get out. */ - *got_enter = TRUE; - unparse_kbinput(output + i, output_len - i); - return; - } - } - - /* Interpret the next multibyte character. */ - char_buf_len = parse_mbchar(output + i, char_buf, NULL); - - i += char_buf_len; - - /* If allow_cntrls is FALSE, filter out a control character. */ - if (!allow_cntrls && is_cntrl_mbchar(output + i - char_buf_len)) - continue; - - /* More dangerousness fun =) */ - answer = charealloc(answer, answer_len + (char_buf_len * 2)); - - assert(statusbar_x <= answer_len); - - charmove(&answer[statusbar_x + char_buf_len], - &answer[statusbar_x], answer_len - statusbar_x + - char_buf_len); - strncpy(&answer[statusbar_x], char_buf, char_buf_len); - answer_len += char_buf_len; - - statusbar_x += char_buf_len; - } - - free(char_buf); -} - -void do_statusbar_home(void) -{ -#ifndef NANO_SMALL - if (ISSET(SMART_HOME)) { - size_t statusbar_x_save = statusbar_x; - - statusbar_x = indent_length(answer); - - if (statusbar_x == statusbar_x_save || - statusbar_x == strlen(answer)) - statusbar_x = 0; - } else -#endif - statusbar_x = 0; -} - -void do_statusbar_end(void) -{ - statusbar_x = strlen(answer); -} - -void do_statusbar_right(void) -{ - if (statusbar_x < strlen(answer)) - statusbar_x = move_mbright(answer, statusbar_x); -} - -void do_statusbar_left(void) -{ - if (statusbar_x > 0) - statusbar_x = move_mbleft(answer, statusbar_x); -} - -void do_statusbar_backspace(void) -{ - if (statusbar_x > 0) { - do_statusbar_left(); - do_statusbar_delete(); - } -} - -void do_statusbar_delete(void) -{ - if (answer[statusbar_x] != '\0') { - int char_buf_len = parse_mbchar(answer + statusbar_x, NULL, - NULL); - size_t line_len = strlen(answer + statusbar_x); - - assert(statusbar_x < strlen(answer)); - - charmove(answer + statusbar_x, answer + statusbar_x + - char_buf_len, strlen(answer) - statusbar_x - - char_buf_len + 1); - - null_at(&answer, statusbar_x + line_len - char_buf_len); - } -} - -/* Move text from the statusbar prompt into oblivion. */ -void do_statusbar_cut_text(void) -{ - assert(answer != NULL); - -#ifndef NANO_SMALL - if (ISSET(CUT_TO_END)) - null_at(&answer, statusbar_x); - else { -#endif - null_at(&answer, 0); - statusbar_x = 0; -#ifndef NANO_SMALL - } -#endif -} - -#ifndef NANO_SMALL -/* Move to the next word at the statusbar prompt. If allow_punct is - * TRUE, treat punctuation as part of a word. Return TRUE if we started - * on a word, and FALSE otherwise. */ -bool do_statusbar_next_word(bool allow_punct) -{ - char *char_mb; - int char_mb_len; - bool end_line = FALSE, started_on_word = FALSE; - - assert(answer != NULL); - - char_mb = charalloc(mb_cur_max()); - - /* Move forward until we find the character after the last letter of - * the current word. */ - while (!end_line) { - char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); - - /* If we've found it, stop moving forward through the current - * line. */ - if (!is_word_mbchar(char_mb, allow_punct)) - break; - - /* If we haven't found it, then we've started on a word, so set - * started_on_word to TRUE. */ - started_on_word = TRUE; - - if (answer[statusbar_x] == '\0') - end_line = TRUE; - else - statusbar_x += char_mb_len; - } - - /* Move forward until we find the first letter of the next word. */ - if (answer[statusbar_x] == '\0') - end_line = TRUE; - else - statusbar_x += char_mb_len; - - while (!end_line) { - char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); - - /* If we've found it, stop moving forward through the current - * line. */ - if (is_word_mbchar(char_mb, allow_punct)) - break; - - if (answer[statusbar_x] == '\0') - end_line = TRUE; - else - statusbar_x += char_mb_len; - } - - free(char_mb); - - /* Return whether we started on a word. */ - return started_on_word; -} - -/* Move to the previous word at the statusbar prompt. If allow_punct is - * TRUE, treat punctuation as part of a word. Return TRUE if we started - * on a word, and FALSE otherwise. */ -bool do_statusbar_prev_word(bool allow_punct) -{ - char *char_mb; - int char_mb_len; - bool begin_line = FALSE, started_on_word = FALSE; - - assert(answer != NULL); - - char_mb = charalloc(mb_cur_max()); - - /* Move backward until we find the character before the first letter - * of the current word. */ - while (!begin_line) { - char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); - - /* If we've found it, stop moving backward through the current - * line. */ - if (!is_word_mbchar(char_mb, allow_punct)) - break; - - /* If we haven't found it, then we've started on a word, so set - * started_on_word to TRUE. */ - started_on_word = TRUE; - - if (statusbar_x == 0) - begin_line = TRUE; - else - statusbar_x = move_mbleft(answer, statusbar_x); - } - - /* Move backward until we find the last letter of the previous - * word. */ - if (statusbar_x == 0) - begin_line = TRUE; - else - statusbar_x = move_mbleft(answer, statusbar_x); - - while (!begin_line) { - char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); - - /* If we've found it, stop moving backward through the current - * line. */ - if (is_word_mbchar(char_mb, allow_punct)) - break; - - if (statusbar_x == 0) - begin_line = TRUE; - else - statusbar_x = move_mbleft(answer, statusbar_x); - } - - /* If we've found it, move backward until we find the character - * before the first letter of the previous word. */ - if (!begin_line) { - if (statusbar_x == 0) - begin_line = TRUE; - else - statusbar_x = move_mbleft(answer, statusbar_x); - - while (!begin_line) { - char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, - NULL); - - /* If we've found it, stop moving backward through the - * current line. */ - if (!is_word_mbchar(char_mb, allow_punct)) - break; - - if (statusbar_x == 0) - begin_line = TRUE; - else - statusbar_x = move_mbleft(answer, statusbar_x); - } - - /* If we've found it, move forward to the first letter of the - * previous word. */ - if (!begin_line) - statusbar_x += char_mb_len; - } - - free(char_mb); - - /* Return whether we started on a word. */ - return started_on_word; -} -#endif /* !NANO_SMALL */ - -void do_statusbar_verbatim_input(bool *got_enter) -{ - int *kbinput; - size_t kbinput_len, i; - char *output; - - *got_enter = FALSE; - - /* Read in all the verbatim characters. */ - kbinput = get_verbatim_kbinput(bottomwin, &kbinput_len); - - /* Display all the verbatim characters at once, not filtering out - * control characters. */ - output = charalloc(kbinput_len + 1); - - for (i = 0; i < kbinput_len; i++) - output[i] = (char)kbinput[i]; - output[i] = '\0'; - - do_statusbar_output(output, kbinput_len, got_enter, TRUE); - - free(output); -} - -/* Return the placewewant associated with statusbar_x, i.e, the - * zero-based column position of the cursor. The value will be no - * smaller than statusbar_x. */ -size_t statusbar_xplustabs(void) -{ - return strnlenpt(answer, statusbar_x); -} - -/* nano scrolls horizontally within a line in chunks. This function - * returns the column number of the first character displayed in the - * statusbar prompt when the cursor is at the given column with the - * prompt ending at start_col. Note that (0 <= column - - * get_statusbar_page_start(column) < COLS). */ -size_t get_statusbar_page_start(size_t start_col, size_t column) -{ - if (column == start_col || column < COLS - 1) - return 0; - else - return column - start_col - (column - start_col) % (COLS - - start_col - 1); -} - /* Move to (x, y) in win, and display a line of n spaces with the * current attributes. */ void blank_line(WINDOW *win, int y, int x, int n) @@ -2434,292 +1873,6 @@ char *display_string(const char *buf, size_t start_col, size_t len, bool return converted; } -/* Repaint the statusbar when getting a character in nanogetstr(). Note - * that we must turn on A_REVERSE here, since do_help() turns it off! */ -void nanoget_repaint(const char *buf, size_t x) -{ - size_t start_col, xpt, page_start; - char *expanded; - - assert(x <= strlen(buf)); - - start_col = strlenpt(prompt) + 1; - xpt = strnlenpt(buf, x); - page_start = get_statusbar_page_start(start_col, start_col + xpt); - - wattron(bottomwin, A_REVERSE); - - blank_statusbar(); - - mvwaddnstr(bottomwin, 0, 0, prompt, actual_x(prompt, COLS - 2)); - waddch(bottomwin, ':'); - waddch(bottomwin, (page_start == 0) ? ' ' : '$'); - - expanded = display_string(buf, page_start, COLS - start_col - 1, - FALSE); - waddstr(bottomwin, expanded); - free(expanded); - - wmove(bottomwin, 0, start_col + xpt + 1 - page_start); - - wattroff(bottomwin, A_REVERSE); -} - -/* Get the input from the keyboard; this should only be called from - * statusq(). */ -int nanogetstr(bool allow_tabs, const char *curranswer, -#ifndef NANO_SMALL - filestruct **history_list, -#endif - const shortcut *s -#ifndef DISABLE_TABCOMP - , bool *list -#endif - ) -{ - int kbinput; - bool meta_key, func_key, s_or_t, ran_func, finished; - size_t curranswer_len; -#ifndef DISABLE_TABCOMP - bool tabbed = FALSE; - /* Whether we've pressed Tab. */ -#endif -#ifndef NANO_SMALL - char *history = NULL; - /* The current history string. */ - char *magichistory = NULL; - /* The temporary string typed at the bottom of the history, if - * any. */ -#ifndef DISABLE_TABCOMP - int last_kbinput = ERR; - /* The key we pressed before the current key. */ - size_t complete_len = 0; - /* The length of the original string that we're trying to - * tab complete, if any. */ -#endif -#endif /* !NANO_SMALL */ - - answer = mallocstrcpy(answer, curranswer); - curranswer_len = strlen(answer); - - /* Only put statusbar_x at the end of the string if it's - * uninitialized, if it would be past the end of curranswer, or if - * resetstatuspos is TRUE. Otherwise, leave it alone. This is so - * the cursor position stays at the same place if a prompt-changing - * toggle is pressed. */ - if (statusbar_x == (size_t)-1 || statusbar_x > curranswer_len || - resetstatuspos) - statusbar_x = curranswer_len; - - currshortcut = s; - - nanoget_repaint(answer, statusbar_x); - - /* Refresh the edit window and the statusbar before getting - * input. */ - wnoutrefresh(edit); - wnoutrefresh(bottomwin); - - /* If we're using restricted mode, we aren't allowed to change the - * name of a file once it has one because that would allow writing - * to files not specified on the command line. In this case, - * disable all keys that would change the text if the filename isn't - * blank and we're at the "Write File" prompt. */ - while ((kbinput = do_statusbar_input(&meta_key, &func_key, - &s_or_t, &ran_func, &finished, TRUE)) != NANO_CANCEL_KEY && - kbinput != NANO_ENTER_KEY) { - - assert(statusbar_x <= strlen(answer)); - -#ifndef DISABLE_TABCOMP - if (kbinput != NANO_TAB_KEY) - tabbed = FALSE; -#endif - - switch (kbinput) { - case NANO_TAB_KEY: -#ifndef DISABLE_TABCOMP -#ifndef NANO_SMALL - if (history_list != NULL) { - if (last_kbinput != NANO_TAB_KEY) - complete_len = strlen(answer); - - if (complete_len > 0) { - answer = mallocstrcpy(answer, - get_history_completion(history_list, - answer, complete_len)); - statusbar_x = strlen(answer); - } - } else -#endif /* !NANO_SMALL */ - if (allow_tabs) - answer = input_tab(answer, &statusbar_x, &tabbed, - list); -#endif /* !DISABLE_TABCOMP */ - break; - case NANO_PREVLINE_KEY: -#ifndef NANO_SMALL - if (history_list != NULL) { - /* If we're scrolling up at the bottom of the - * history list and answer isn't blank, save answer - * in magichistory. */ - if ((*history_list)->next == NULL && - answer[0] != '\0') - magichistory = mallocstrcpy(magichistory, - answer); - - /* Get the older search from the history list and - * save it in answer. If there is no older search, - * don't do anything. */ - if ((history = - get_history_older(history_list)) != NULL) { - answer = mallocstrcpy(answer, history); - statusbar_x = strlen(answer); - } - - /* This key has a shortcut list entry when it's used - * to move to an older search, which means that - * finished has been set to TRUE. Set it back to - * FALSE here, so that we aren't kicked out of the - * statusbar prompt. */ - finished = FALSE; - } -#endif /* !NANO_SMALL */ - break; - case NANO_NEXTLINE_KEY: -#ifndef NANO_SMALL - if (history_list != NULL) { - /* Get the newer search from the history list and - * save it in answer. If there is no newer search, - * don't do anything. */ - if ((history = - get_history_newer(history_list)) != NULL) { - answer = mallocstrcpy(answer, history); - statusbar_x = strlen(answer); - } - - /* If, after scrolling down, we're at the bottom of - * the history list, answer is blank, and - * magichistory is set, save magichistory in - * answer. */ - if ((*history_list)->next == NULL && - answer[0] == '\0' && magichistory != NULL) { - answer = mallocstrcpy(answer, magichistory); - statusbar_x = strlen(answer); - } - } -#endif /* !NANO_SMALL */ - break; - } - - /* If we have a shortcut with an associated function, break out - * if we're finished after running or trying to run the - * function. */ - if (finished) - break; - -#if !defined(NANO_SMALL) && !defined(DISABLE_TABCOMP) - last_kbinput = kbinput; -#endif - - nanoget_repaint(answer, statusbar_x); - wnoutrefresh(bottomwin); - } - -#ifndef NANO_SMALL - /* Set the current position in the history list to the bottom and - * free magichistory, if we need to. */ - if (history_list != NULL) { - history_reset(*history_list); - - if (magichistory != NULL) - free(magichistory); - } -#endif - - /* We finished putting in an answer or ran a normal shortcut's - * associated function, so reset statusbar_x. */ - if (kbinput == NANO_CANCEL_KEY || kbinput == NANO_ENTER_KEY || - ran_func) - statusbar_x = (size_t)-1; - - return kbinput; -} - -/* Ask a question on the statusbar. Answer will be stored in answer - * global. Returns -1 on aborted enter, -2 on a blank string, and 0 - * otherwise, the valid shortcut key caught. curranswer is any editable - * text that we want to put up by default. - * - * The allow_tabs parameter indicates whether we should allow tabs to be - * interpreted. */ -int statusq(bool allow_tabs, const shortcut *s, const char *curranswer, -#ifndef NANO_SMALL - filestruct **history_list, -#endif - const char *msg, ...) -{ - va_list ap; - int retval; -#ifndef DISABLE_TABCOMP - bool list = FALSE; -#endif - - prompt = charealloc(prompt, ((COLS - 4) * mb_cur_max()) + 1); - - bottombars(s); - - va_start(ap, msg); - vsnprintf(prompt, (COLS - 4) * mb_cur_max(), msg, ap); - va_end(ap); - null_at(&prompt, actual_x(prompt, COLS - 4)); - - retval = nanogetstr(allow_tabs, curranswer, -#ifndef NANO_SMALL - history_list, -#endif - s -#ifndef DISABLE_TABCOMP - , &list -#endif - ); - - resetstatuspos = FALSE; - - switch (retval) { - case NANO_CANCEL_KEY: - retval = -1; - resetstatuspos = TRUE; - break; - case NANO_ENTER_KEY: - retval = (answer[0] == '\0') ? -2 : 0; - resetstatuspos = TRUE; - break; - } - - blank_statusbar(); - wnoutrefresh(bottomwin); - -#ifdef DEBUG - fprintf(stderr, "answer = \"%s\"\n", answer); -#endif - -#ifndef DISABLE_TABCOMP - /* If we've done tab completion, there might be a list of filename - * matches on the edit window at this point. Make sure that they're - * cleared off. */ - if (list) - edit_refresh(); -#endif - - return retval; -} - -void statusq_abort(void) -{ - resetstatuspos = TRUE; -} - void titlebar(const char *path) { int space = COLS;