blob: 8dceece0bbfb76d19210597409f4f2b2970758d5 [file] [log] [blame]
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +00001/**************************************************************************
Benno Schulenberg514cd9a2016-08-29 17:10:49 +02002 * prompt.c -- This file is part of GNU nano. *
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +00003 * *
Chris Allegretta8a07a962009-12-02 03:36:22 +00004 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
Benno Schulenberg7a9f4a42014-04-30 20:18:26 +00005 * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. *
Benno Schulenberg406e5242016-08-29 15:14:18 +02006 * Copyright (C) 2016 Benno Schulenberg *
7 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +02008 * GNU nano is free software: you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published *
10 * by the Free Software Foundation, either version 3 of the License, *
11 * or (at your option) any later version. *
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000012 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020013 * GNU nano is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty *
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
16 * See the GNU General Public License for more details. *
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000017 * *
18 * You should have received a copy of the GNU General Public License *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020019 * along with this program. If not, see http://www.gnu.org/licenses/. *
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000020 * *
21 **************************************************************************/
22
David Lawrence Ramsey034b9942005-12-08 02:47:10 +000023#include "proto.h"
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000024
David Lawrence Ramsey143b8c72005-11-01 18:35:47 +000025#include <stdio.h>
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000026#include <stdarg.h>
27#include <string.h>
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000028
29static char *prompt = NULL;
David Lawrence Ramsey6335fb52007-01-01 05:15:32 +000030 /* The prompt string used for statusbar questions. */
Benno Schulenberg0d5fbfb2016-08-22 13:54:55 +020031static size_t statusbar_x = HIGHEST_POSITIVE;
David Lawrence Ramseyc1c818e2006-05-14 18:22:01 +000032 /* The cursor position in answer. */
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000033
Benno Schulenberg2f9232a2016-08-22 14:05:25 +020034/* Read in a keystroke, interpret it if it is a shortcut or toggle, and
35 * return it. Set ran_func to TRUE if we ran a function associated with
36 * a shortcut key, and set finished to TRUE if we're done after running
Benno Schulenberg379b1552016-12-03 20:37:30 +010037 * or trying to run a function associated with a shortcut key. */
38int do_statusbar_input(bool *ran_func, bool *finished)
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000039{
40 int input;
41 /* The character we read in. */
42 static int *kbinput = NULL;
43 /* The input buffer. */
44 static size_t kbinput_len = 0;
45 /* The length of the input buffer. */
Chris Allegretta79a33bb2008-03-05 07:34:01 +000046 const sc *s;
Benno Schulenbergb5895f02014-06-28 08:29:18 +000047 bool have_shortcut = FALSE;
Chris Allegretta79a33bb2008-03-05 07:34:01 +000048 const subnfunc *f;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000049
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000050 *ran_func = FALSE;
51 *finished = FALSE;
52
53 /* Read in a character. */
Benno Schulenberg7e5324d2014-06-30 18:04:33 +000054 input = get_kbinput(bottomwin);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000055
Benno Schulenberg75d64e62015-05-28 13:02:29 +000056#ifndef NANO_TINY
57 if (input == KEY_WINCH)
58 return KEY_WINCH;
59#endif
60
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000061#ifndef DISABLE_MOUSE
Benno Schulenbergb5895f02014-06-28 08:29:18 +000062 /* If we got a mouse click and it was on a shortcut, read in the
63 * shortcut character. */
Benno Schulenbergcb10b2b2016-07-13 16:22:56 +020064 if (input == KEY_MOUSE) {
Benno Schulenbergb5895f02014-06-28 08:29:18 +000065 if (do_statusbar_mouse() == 1)
Benno Schulenberg7e5324d2014-06-30 18:04:33 +000066 input = get_kbinput(bottomwin);
Benno Schulenberg9cd30d42016-07-15 21:59:38 +020067 else
Benno Schulenberg6ad37002016-08-27 11:11:00 +020068 return ERR;
David Lawrence Ramsey8992d0a2006-05-10 12:48:47 +000069 }
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000070#endif
71
72 /* Check for a shortcut in the current list. */
Benno Schulenberg49816fe2014-07-01 10:41:10 +000073 s = get_shortcut(&input);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000074
75 /* If we got a shortcut from the current list, or a "universal"
76 * statusbar prompt shortcut, set have_shortcut to TRUE. */
Benno Schulenbergb5895f02014-06-28 08:29:18 +000077 have_shortcut = (s != NULL);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +000078
David Lawrence Ramseyd6eb1752006-05-25 21:39:25 +000079 /* If we got a non-high-bit control key, a meta key sequence, or a
80 * function key, and it's not a shortcut or toggle, throw it out. */
Benno Schulenbergb5895f02014-06-28 08:29:18 +000081 if (!have_shortcut) {
Benno Schulenbergcb10b2b2016-07-13 16:22:56 +020082 if (is_ascii_cntrl_char(input) || meta_key || !is_byte(input)) {
David Lawrence Ramsey106c1bf2006-06-03 19:36:02 +000083 beep();
David Lawrence Ramsey305d8892006-05-24 19:48:03 +000084 input = ERR;
David Lawrence Ramsey8e341e12006-05-24 17:36:00 +000085 }
86 }
87
Benno Schulenbergbd1fcc52016-08-06 12:15:03 +020088 /* If the keystroke isn't a shortcut nor a toggle, it's a normal text
89 * character: add the it to the input buffer, when allowed. */
Benno Schulenbergb5895f02014-06-28 08:29:18 +000090 if (input != ERR && !have_shortcut) {
Benno Schulenbergbd1fcc52016-08-06 12:15:03 +020091 /* Only accept input when not in restricted mode, or when not at
92 * the "Write File" prompt, or when there is no filename yet. */
93 if (!ISSET(RESTRICTED) || currmenu != MWRITEFILE ||
94 openfile->filename[0] == '\0') {
Benno Schulenbergb5895f02014-06-28 08:29:18 +000095 kbinput_len++;
96 kbinput = (int *)nrealloc(kbinput, kbinput_len * sizeof(int));
97 kbinput[kbinput_len - 1] = input;
98 }
99 }
100
Benno Schulenberg2f9232a2016-08-22 14:05:25 +0200101 /* If we got a shortcut, or if there aren't any other keystrokes waiting
102 * after the one we read in, we need to insert all the characters in the
103 * input buffer (if not empty) into the answer. */
Benno Schulenberg0d5fbfb2016-08-22 13:54:55 +0200104 if ((have_shortcut || get_key_buffer_len() == 0) && kbinput != NULL) {
Benno Schulenberg2f9232a2016-08-22 14:05:25 +0200105 /* Inject all characters in the input buffer at once, filtering out
106 * control characters. */
Benno Schulenberg908663e2016-12-27 12:20:20 +0100107 do_statusbar_output(kbinput, kbinput_len, TRUE);
Benno Schulenbergb5895f02014-06-28 08:29:18 +0000108
Benno Schulenberg2f9232a2016-08-22 14:05:25 +0200109 /* Empty the input buffer. */
110 kbinput_len = 0;
111 free(kbinput);
112 kbinput = NULL;
Benno Schulenberg0d5fbfb2016-08-22 13:54:55 +0200113 }
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000114
Benno Schulenberg0d5fbfb2016-08-22 13:54:55 +0200115 if (have_shortcut) {
Benno Schulenberg2f9232a2016-08-22 14:05:25 +0200116 if (s->scfunc == do_tab || s->scfunc == do_enter)
117 ;
Benno Schulenberg379b1552016-12-03 20:37:30 +0100118 else if (s->scfunc == do_left)
Benno Schulenberg2f9232a2016-08-22 14:05:25 +0200119 do_statusbar_left();
120 else if (s->scfunc == do_right)
121 do_statusbar_right();
Chris Allegrettaeb643142008-03-12 04:44:14 +0000122#ifndef NANO_TINY
Benno Schulenberg2f9232a2016-08-22 14:05:25 +0200123 else if (s->scfunc == do_prev_word_void)
124 do_statusbar_prev_word();
125 else if (s->scfunc == do_next_word_void)
126 do_statusbar_next_word();
Chris Allegrettaeb643142008-03-12 04:44:14 +0000127#endif
Benno Schulenberg2f9232a2016-08-22 14:05:25 +0200128 else if (s->scfunc == do_home)
129 do_statusbar_home();
130 else if (s->scfunc == do_end)
131 do_statusbar_end();
132 /* When in restricted mode at the "Write File" prompt and the
133 * filename isn't blank, disallow any input and deletion. */
134 else if (ISSET(RESTRICTED) && currmenu == MWRITEFILE &&
Benno Schulenbergaefe26d2016-07-25 12:31:40 +0200135 openfile->filename[0] != '\0' &&
136 (s->scfunc == do_verbatim_input ||
137 s->scfunc == do_cut_text_void ||
138 s->scfunc == do_delete ||
139 s->scfunc == do_backspace))
Benno Schulenberg2f9232a2016-08-22 14:05:25 +0200140 ;
141 else if (s->scfunc == do_verbatim_input) {
Benno Schulenberg908663e2016-12-27 12:20:20 +0100142 do_statusbar_verbatim_input();
Benno Schulenberg2f9232a2016-08-22 14:05:25 +0200143 } else if (s->scfunc == do_cut_text_void)
144 do_statusbar_cut_text();
145 else if (s->scfunc == do_delete)
146 do_statusbar_delete();
147 else if (s->scfunc == do_backspace)
148 do_statusbar_backspace();
149 else {
150 /* Handle any other shortcut in the current menu, setting
151 * ran_func to TRUE if we try to run their associated functions,
152 * and setting finished to TRUE to indicatethat we're done after
153 * running or trying to run their associated functions. */
154 f = sctofunc(s);
155 if (s->scfunc != NULL) {
156 *ran_func = TRUE;
157 if (f && (!ISSET(VIEW_MODE) || f->viewok) &&
158 f->scfunc != do_gotolinecolumn_void)
159 f->scfunc();
160 }
161 *finished = TRUE;
162 }
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000163 }
164
165 return input;
166}
167
168#ifndef DISABLE_MOUSE
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000169/* Handle a mouse click on the statusbar prompt or the shortcut list. */
David Lawrence Ramsey3a5eaeb2007-05-20 23:41:56 +0000170int do_statusbar_mouse(void)
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000171{
172 int mouse_x, mouse_y;
David Lawrence Ramsey3a5eaeb2007-05-20 23:41:56 +0000173 int retval = get_mouseinput(&mouse_x, &mouse_y, TRUE);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000174
David Lawrence Ramseyebc38fd2007-06-28 16:00:50 +0000175 /* We can click on the statusbar window text to move the cursor. */
Benno Schulenberg22a01ca2016-02-06 12:12:08 +0000176 if (retval == 0 && wmouse_trafo(bottomwin, &mouse_y, &mouse_x, FALSE)) {
David Lawrence Ramseyebc38fd2007-06-28 16:00:50 +0000177 size_t start_col;
David Lawrence Ramsey143b8c72005-11-01 18:35:47 +0000178
David Lawrence Ramsey281a4692007-12-08 07:00:27 +0000179 start_col = strlenpt(prompt) + 2;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000180
David Lawrence Ramseyebc38fd2007-06-28 16:00:50 +0000181 /* Move to where the click occurred. */
David Lawrence Ramsey281a4692007-12-08 07:00:27 +0000182 if (mouse_x >= start_col && mouse_y == 0) {
David Lawrence Ramseyebc38fd2007-06-28 16:00:50 +0000183 statusbar_x = actual_x(answer,
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000184 get_statusbar_page_start(start_col, start_col +
David Lawrence Ramsey281a4692007-12-08 07:00:27 +0000185 statusbar_xplustabs()) + mouse_x - start_col);
Benno Schulenberg4d2ada62016-08-28 17:37:25 +0200186 update_the_statusbar();
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000187 }
188 }
189
190 return retval;
191}
192#endif
193
Benno Schulenberg908663e2016-12-27 12:20:20 +0100194/* The user typed input_len multibyte characters. Add them to the answer,
195 * filtering out ASCII control characters if filtering is TRUE. */
Benno Schulenberge5400532016-02-14 12:03:47 +0000196void do_statusbar_output(int *the_input, size_t input_len,
Benno Schulenberg908663e2016-12-27 12:20:20 +0100197 bool filtering)
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000198{
Benno Schulenberge5400532016-02-14 12:03:47 +0000199 char *output = charalloc(input_len + 1);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000200 char *char_buf = charalloc(mb_cur_max());
Benno Schulenberg8a2dd972016-02-23 08:31:57 +0000201 int i, char_len;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000202
Benno Schulenbergef16a2a2016-02-14 11:16:54 +0000203 /* Copy the typed stuff so it can be treated. */
Benno Schulenberge5400532016-02-14 12:03:47 +0000204 for (i = 0; i < input_len; i++)
Benno Schulenbergef16a2a2016-02-14 11:16:54 +0000205 output[i] = (char)the_input[i];
206 output[i] = '\0';
207
Benno Schulenbergef16a2a2016-02-14 11:16:54 +0000208 i = 0;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000209
Benno Schulenberge5400532016-02-14 12:03:47 +0000210 while (i < input_len) {
Benno Schulenberg908663e2016-12-27 12:20:20 +0100211 /* Encode any NUL byte as 0x0A. */
212 if (output[i] == '\0')
213 output[i] = '\n';
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000214
215 /* Interpret the next multibyte character. */
Benno Schulenberg8a2dd972016-02-23 08:31:57 +0000216 char_len = parse_mbchar(output + i, char_buf, NULL);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000217
Benno Schulenberg8a2dd972016-02-23 08:31:57 +0000218 i += char_len;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000219
Benno Schulenberge5400532016-02-14 12:03:47 +0000220 /* When filtering, skip any ASCII control character. */
Benno Schulenberg8a2dd972016-02-23 08:31:57 +0000221 if (filtering && is_ascii_cntrl_char(*(output + i - char_len)))
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000222 continue;
223
Benno Schulenberg3ed08c52016-02-22 14:26:05 +0000224 /* Insert the typed character into the existing answer string. */
Benno Schulenberg8a2dd972016-02-23 08:31:57 +0000225 answer = charealloc(answer, strlen(answer) + char_len + 1);
226 charmove(answer + statusbar_x + char_len, answer + statusbar_x,
Benno Schulenberg3ed08c52016-02-22 14:26:05 +0000227 strlen(answer) - statusbar_x + 1);
Benno Schulenberg8a2dd972016-02-23 08:31:57 +0000228 strncpy(answer + statusbar_x, char_buf, char_len);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000229
Benno Schulenberg8a2dd972016-02-23 08:31:57 +0000230 statusbar_x += char_len;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000231 }
232
233 free(char_buf);
Benno Schulenbergef16a2a2016-02-14 11:16:54 +0000234 free(output);
David Lawrence Ramseyaf3314c2005-11-07 06:32:07 +0000235
Benno Schulenbergd844f052016-02-06 11:40:15 +0000236 update_the_statusbar();
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000237}
238
Benno Schulenberg7275e112016-08-28 18:15:20 +0200239/* Move to the beginning of the answer. */
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000240void do_statusbar_home(void)
241{
Benno Schulenberg7ade5de2016-01-31 13:26:15 +0000242 statusbar_x = 0;
Benno Schulenberg4d2ada62016-08-28 17:37:25 +0200243 update_the_statusbar();
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000244}
245
Benno Schulenberg7275e112016-08-28 18:15:20 +0200246/* Move to the end of the answer. */
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000247void do_statusbar_end(void)
248{
249 statusbar_x = strlen(answer);
Benno Schulenberg4d2ada62016-08-28 17:37:25 +0200250 update_the_statusbar();
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000251}
252
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000253/* Move left one character. */
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000254void do_statusbar_left(void)
255{
David Lawrence Ramseyaf3314c2005-11-07 06:32:07 +0000256 if (statusbar_x > 0) {
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000257 statusbar_x = move_mbleft(answer, statusbar_x);
Benno Schulenberg4d2ada62016-08-28 17:37:25 +0200258 update_the_statusbar();
David Lawrence Ramseyaf3314c2005-11-07 06:32:07 +0000259 }
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000260}
261
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000262/* Move right one character. */
263void do_statusbar_right(void)
264{
Benno Schulenberg7275e112016-08-28 18:15:20 +0200265 if (answer[statusbar_x] != '\0') {
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000266 statusbar_x = move_mbright(answer, statusbar_x);
Benno Schulenberg4d2ada62016-08-28 17:37:25 +0200267 update_the_statusbar();
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000268 }
269}
270
271/* Backspace over one character. */
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000272void do_statusbar_backspace(void)
273{
274 if (statusbar_x > 0) {
Benno Schulenberg8585bf22016-02-06 11:50:57 +0000275 statusbar_x = move_mbleft(answer, statusbar_x);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000276 do_statusbar_delete();
277 }
278}
279
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000280/* Delete one character. */
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000281void do_statusbar_delete(void)
282{
283 if (answer[statusbar_x] != '\0') {
Benno Schulenberg8a2dd972016-02-23 08:31:57 +0000284 int char_len = parse_mbchar(answer + statusbar_x, NULL, NULL);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000285
Benno Schulenberg8a2dd972016-02-23 08:31:57 +0000286 charmove(answer + statusbar_x, answer + statusbar_x + char_len,
287 strlen(answer) - statusbar_x - char_len + 1);
David Lawrence Ramseye19449e2005-11-07 21:45:44 +0000288
Benno Schulenbergd844f052016-02-06 11:40:15 +0000289 update_the_statusbar();
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000290 }
291}
292
Benno Schulenberg7275e112016-08-28 18:15:20 +0200293/* Zap some or all text from the answer. */
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000294void do_statusbar_cut_text(void)
295{
Benno Schulenberg7275e112016-08-28 18:15:20 +0200296 if (!ISSET(CUT_TO_END))
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000297 statusbar_x = 0;
Benno Schulenberg7275e112016-08-28 18:15:20 +0200298
299 null_at(&answer, statusbar_x);
David Lawrence Ramseyaf3314c2005-11-07 06:32:07 +0000300
Benno Schulenbergd844f052016-02-06 11:40:15 +0000301 update_the_statusbar();
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000302}
303
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000304#ifndef NANO_TINY
Benno Schulenberg7275e112016-08-28 18:15:20 +0200305/* Move to the next word in the answer. */
Benno Schulenbergeed1aab2016-01-24 15:42:45 +0000306void do_statusbar_next_word(void)
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000307{
Benno Schulenberga93a11e2016-01-26 10:31:16 +0000308 bool seen_space = !is_word_mbchar(answer + statusbar_x, FALSE);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000309
Benno Schulenberga93a11e2016-01-26 10:31:16 +0000310 /* Move forward until we reach the start of a word. */
311 while (answer[statusbar_x] != '\0') {
312 statusbar_x = move_mbright(answer, statusbar_x);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000313
Benno Schulenberga93a11e2016-01-26 10:31:16 +0000314 /* If this is not a word character, then it's a separator; else
315 * if we've already seen a separator, then it's a word start. */
316 if (!is_word_mbchar(answer + statusbar_x, FALSE))
317 seen_space = TRUE;
318 else if (seen_space)
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000319 break;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000320 }
321
Benno Schulenberg4d2ada62016-08-28 17:37:25 +0200322 update_the_statusbar();
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000323}
324
Benno Schulenberg7275e112016-08-28 18:15:20 +0200325/* Move to the previous word in the answer. */
Benno Schulenbergeed1aab2016-01-24 15:42:45 +0000326void do_statusbar_prev_word(void)
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000327{
Benno Schulenberg5688c162016-01-26 10:10:20 +0000328 bool seen_a_word = FALSE, step_forward = FALSE;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000329
Benno Schulenberg5688c162016-01-26 10:10:20 +0000330 /* Move backward until we pass over the start of a word. */
331 while (statusbar_x != 0) {
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000332 statusbar_x = move_mbleft(answer, statusbar_x);
333
Benno Schulenberg5688c162016-01-26 10:10:20 +0000334 if (is_word_mbchar(answer + statusbar_x, FALSE))
335 seen_a_word = TRUE;
336 else if (seen_a_word) {
337 /* This is space now: we've overshot the start of the word. */
338 step_forward = TRUE;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000339 break;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000340 }
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000341 }
342
Benno Schulenberg5688c162016-01-26 10:10:20 +0000343 if (step_forward)
344 /* Move one character forward again to sit on the start of the word. */
345 statusbar_x = move_mbright(answer, statusbar_x);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000346
Benno Schulenberg4d2ada62016-08-28 17:37:25 +0200347 update_the_statusbar();
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000348}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000349#endif /* !NANO_TINY */
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000350
Benno Schulenberg908663e2016-12-27 12:20:20 +0100351/* Get verbatim input and inject it into the answer, without filtering. */
352void do_statusbar_verbatim_input(void)
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000353{
354 int *kbinput;
Benno Schulenbergef16a2a2016-02-14 11:16:54 +0000355 size_t kbinput_len;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000356
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000357 kbinput = get_verbatim_kbinput(bottomwin, &kbinput_len);
358
Benno Schulenberg908663e2016-12-27 12:20:20 +0100359 do_statusbar_output(kbinput, kbinput_len, FALSE);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000360}
361
Benno Schulenberg4d2ada62016-08-28 17:37:25 +0200362/* Return the zero-based column position of the cursor in the answer. */
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000363size_t statusbar_xplustabs(void)
364{
365 return strnlenpt(answer, statusbar_x);
366}
367
Benno Schulenbergda2fce92016-08-26 22:46:01 +0200368/* Return the column number of the first character of the answer that is
369 * displayed in the statusbar when the cursor is at the given column,
370 * with the available room for the answer starting at base. Note that
371 * (0 <= column - get_statusbar_page_start(column) < COLS). */
372size_t get_statusbar_page_start(size_t base, size_t column)
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000373{
Benno Schulenbergda2fce92016-08-26 22:46:01 +0200374 if (column == base || column < COLS - 1)
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000375 return 0;
Benno Schulenbergda2fce92016-08-26 22:46:01 +0200376 else if (COLS > base + 2)
377 return column - base - 1 - (column - base - 1) % (COLS - base - 2);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000378 else
Benno Schulenberg92c97c72016-08-26 21:29:53 +0200379 return column - 2;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000380}
381
Benno Schulenberg7275e112016-08-28 18:15:20 +0200382/* Reinitialize the cursor position in the answer. */
Benno Schulenberg34a20f82016-04-17 15:24:05 +0200383void reinit_statusbar_x(void)
384{
Benno Schulenberg0d5fbfb2016-08-22 13:54:55 +0200385 statusbar_x = HIGHEST_POSITIVE;
Benno Schulenberg34a20f82016-04-17 15:24:05 +0200386}
387
Benno Schulenberg7275e112016-08-28 18:15:20 +0200388/* Put the cursor in the answer at statusbar_x. */
David Lawrence Ramsey60edb0a2006-05-15 15:17:50 +0000389void reset_statusbar_cursor(void)
390{
David Lawrence Ramsey281a4692007-12-08 07:00:27 +0000391 size_t start_col = strlenpt(prompt) + 2;
David Lawrence Ramsey60edb0a2006-05-15 15:17:50 +0000392 size_t xpt = statusbar_xplustabs();
393
Benno Schulenbergc22cd032016-08-25 10:42:46 +0200394 /* Work around a cursor-misplacement bug in VTEs. */
395 wmove(bottomwin, 0, 0);
396 wnoutrefresh(bottomwin);
397 doupdate();
398
David Lawrence Ramsey281a4692007-12-08 07:00:27 +0000399 wmove(bottomwin, 0, start_col + xpt -
Benno Schulenbergda2fce92016-08-26 22:46:01 +0200400 get_statusbar_page_start(start_col, start_col + xpt));
Benno Schulenbergc22cd032016-08-25 10:42:46 +0200401
402 wnoutrefresh(bottomwin);
David Lawrence Ramsey60edb0a2006-05-15 15:17:50 +0000403}
404
Benno Schulenbergd844f052016-02-06 11:40:15 +0000405/* Repaint the statusbar. */
406void update_the_statusbar(void)
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000407{
Benno Schulenbergda2fce92016-08-26 22:46:01 +0200408 size_t base, the_page, end_page;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000409 char *expanded;
410
Benno Schulenbergda2fce92016-08-26 22:46:01 +0200411 base = strlenpt(prompt) + 2;
412 the_page = get_statusbar_page_start(base, base + strnlenpt(answer, statusbar_x));
413 end_page = get_statusbar_page_start(base, base + strlenpt(answer) - 1);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000414
Benno Schulenberg960e8482016-07-12 09:35:48 +0200415 wattron(bottomwin, interface_color_pair[TITLE_BAR]);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000416
417 blank_statusbar();
418
Benno Schulenberg77d14072016-08-28 17:53:44 +0200419 mvwaddstr(bottomwin, 0, 0, prompt);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000420 waddch(bottomwin, ':');
Benno Schulenberg6142ef82016-08-27 09:29:09 +0200421 waddch(bottomwin, (the_page == 0) ? ' ' : '<');
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000422
Benno Schulenbergda2fce92016-08-26 22:46:01 +0200423 expanded = display_string(answer, the_page, COLS - base - 1, FALSE);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000424 waddstr(bottomwin, expanded);
425 free(expanded);
426
Benno Schulenberg6142ef82016-08-27 09:29:09 +0200427 waddch(bottomwin, (the_page >= end_page) ? ' ' : '>');
Benno Schulenberg1e3cffb2016-08-26 21:42:23 +0200428
Benno Schulenberg960e8482016-07-12 09:35:48 +0200429 wattroff(bottomwin, interface_color_pair[TITLE_BAR]);
Benno Schulenberg22a01ca2016-02-06 12:12:08 +0000430
David Lawrence Ramseya9c00002007-12-03 20:14:18 +0000431 reset_statusbar_cursor();
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000432}
433
Benno Schulenberg65c7c812016-01-26 09:16:09 +0000434/* Get a string of input at the statusbar prompt. */
Benno Schulenberg7e0c4e52016-08-25 20:20:50 +0200435functionptrtype acquire_an_answer(int *actual, bool allow_tabs,
Benno Schulenberg30f3c532016-04-26 17:50:25 +0200436 bool allow_files, bool *listed,
Benno Schulenbergb341f292014-06-19 20:05:24 +0000437#ifndef DISABLE_HISTORIES
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000438 filestruct **history_list,
439#endif
Benno Schulenbergebcc68f2014-07-01 11:50:35 +0000440 void (*refresh_func)(void))
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000441{
David Lawrence Ramsey591c4092006-02-08 20:14:49 +0000442 int kbinput = ERR;
Benno Schulenbergb5895f02014-06-28 08:29:18 +0000443 bool ran_func, finished;
Benno Schulenberg3933a302014-07-02 08:47:09 +0000444 functionptrtype func;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000445#ifndef DISABLE_TABCOMP
446 bool tabbed = FALSE;
447 /* Whether we've pressed Tab. */
448#endif
Benno Schulenbergb341f292014-06-19 20:05:24 +0000449#ifndef DISABLE_HISTORIES
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000450 char *history = NULL;
451 /* The current history string. */
452 char *magichistory = NULL;
453 /* The temporary string typed at the bottom of the history, if
454 * any. */
455#ifndef DISABLE_TABCOMP
456 int last_kbinput = ERR;
457 /* The key we pressed before the current key. */
458 size_t complete_len = 0;
459 /* The length of the original string that we're trying to
460 * tab complete, if any. */
461#endif
Benno Schulenbergb341f292014-06-19 20:05:24 +0000462#endif /* !DISABLE_HISTORIES */
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000463
Benno Schulenberg4d2ada62016-08-28 17:37:25 +0200464 if (statusbar_x > strlen(answer))
Benno Schulenberga4437602016-01-21 18:29:39 +0000465 statusbar_x = strlen(answer);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000466
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000467#ifdef DEBUG
Benno Schulenbergb77b1392016-08-26 12:18:04 +0200468 fprintf(stderr, "acquiring: answer = \"%s\", statusbar_x = %lu\n", answer, (unsigned long) statusbar_x);
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000469#endif
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000470
Benno Schulenbergd844f052016-02-06 11:40:15 +0000471 update_the_statusbar();
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000472
Benno Schulenberg22a01ca2016-02-06 12:12:08 +0000473 /* Refresh edit window and statusbar before getting input. */
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000474 wnoutrefresh(edit);
475 wnoutrefresh(bottomwin);
476
Benno Schulenbergb5895f02014-06-28 08:29:18 +0000477 while (TRUE) {
Benno Schulenberg0d5fbfb2016-08-22 13:54:55 +0200478 /* Ensure the cursor is shown when waiting for input. */
Benno Schulenberg568d2a32016-02-13 19:41:12 +0000479 curs_set(1);
480
Benno Schulenberg379b1552016-12-03 20:37:30 +0100481 kbinput = do_statusbar_input(&ran_func, &finished);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000482
Benno Schulenberg75d64e62015-05-28 13:02:29 +0000483#ifndef NANO_TINY
Benno Schulenberg50616142016-08-25 20:02:35 +0200484 /* If the window size changed, go reformat the prompt string. */
Benno Schulenberg65c7c812016-01-26 09:16:09 +0000485 if (kbinput == KEY_WINCH) {
486 refresh_func();
Benno Schulenberg50616142016-08-25 20:02:35 +0200487 *actual = KEY_WINCH;
Benno Schulenberg2dffcf12016-08-30 11:14:19 +0200488#ifndef DISABLE_HISTORIES
Benno Schulenberg50616142016-08-25 20:02:35 +0200489 free(magichistory);
Benno Schulenberg2dffcf12016-08-30 11:14:19 +0200490#endif
Benno Schulenberg50616142016-08-25 20:02:35 +0200491 return NULL;
Benno Schulenberg65c7c812016-01-26 09:16:09 +0000492 }
Benno Schulenberg2dffcf12016-08-30 11:14:19 +0200493#endif /* !NANO_TINY */
494
Benno Schulenberg3933a302014-07-02 08:47:09 +0000495 func = func_from_key(&kbinput);
Chris Allegrettaeb643142008-03-12 04:44:14 +0000496
Benno Schulenbergbde996d2015-11-11 19:56:35 +0000497 if (func == do_cancel || func == do_enter)
Benno Schulenberg3933a302014-07-02 08:47:09 +0000498 break;
Chris Allegrettaeb643142008-03-12 04:44:14 +0000499
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000500#ifndef DISABLE_TABCOMP
Benno Schulenberg3933a302014-07-02 08:47:09 +0000501 if (func != do_tab)
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000502 tabbed = FALSE;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000503
Benno Schulenberg3933a302014-07-02 08:47:09 +0000504 if (func == do_tab) {
Benno Schulenbergb341f292014-06-19 20:05:24 +0000505#ifndef DISABLE_HISTORIES
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000506 if (history_list != NULL) {
Benno Schulenberga9b5a0e2016-12-22 12:02:11 +0100507 if (last_kbinput != the_code_for(do_tab, TAB_CODE))
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000508 complete_len = strlen(answer);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000509
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000510 if (complete_len > 0) {
Benno Schulenberge86dc032016-02-20 12:16:43 +0000511 answer = get_history_completion(history_list,
512 answer, complete_len);
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000513 statusbar_x = strlen(answer);
514 }
515 } else
Benno Schulenbergb341f292014-06-19 20:05:24 +0000516#endif
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000517 if (allow_tabs)
518 answer = input_tab(answer, allow_files, &statusbar_x,
Benno Schulenberg17cf8332016-05-30 09:09:36 +0200519 &tabbed, refresh_func, listed);
Chris Allegretta637daa82011-02-07 14:45:56 +0000520 } else
David Lawrence Ramseyad074012005-11-16 21:34:46 +0000521#endif /* !DISABLE_TABCOMP */
Benno Schulenbergb341f292014-06-19 20:05:24 +0000522#ifndef DISABLE_HISTORIES
Benno Schulenberg3933a302014-07-02 08:47:09 +0000523 if (func == get_history_older_void) {
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000524 if (history_list != NULL) {
525 /* If we're scrolling up at the bottom of the history list
526 * and answer isn't blank, save answer in magichistory. */
Benno Schulenberg1d3d3072016-05-27 21:31:55 +0200527 if ((*history_list)->next == NULL && *answer != '\0')
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000528 magichistory = mallocstrcpy(magichistory, answer);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000529
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000530 /* Get the older search from the history list and save it in
531 * answer. If there is no older search, don't do anything. */
532 if ((history = get_history_older(history_list)) != NULL) {
533 answer = mallocstrcpy(answer, history);
534 statusbar_x = strlen(answer);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000535 }
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000536
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000537 /* This key has a shortcut-list entry when it's used to
538 * move to an older search, which means that finished has
539 * been set to TRUE. Set it back to FALSE here, so that
540 * we aren't kicked out of the statusbar prompt. */
Benno Schulenberga8a23ab2014-06-10 19:12:14 +0000541 finished = FALSE;
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000542 }
Benno Schulenberg3933a302014-07-02 08:47:09 +0000543 } else if (func == get_history_newer_void) {
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000544 if (history_list != NULL) {
545 /* Get the newer search from the history list and save it in
546 * answer. If there is no newer search, don't do anything. */
547 if ((history = get_history_newer(history_list)) != NULL) {
548 answer = mallocstrcpy(answer, history);
549 statusbar_x = strlen(answer);
550 }
551
552 /* If, after scrolling down, we're at the bottom of the
553 * history list, answer is blank, and magichistory is set,
554 * save magichistory in answer. */
555 if ((*history_list)->next == NULL &&
Benno Schulenberg65c7c812016-01-26 09:16:09 +0000556 *answer == '\0' && magichistory != NULL) {
557 answer = mallocstrcpy(answer, magichistory);
558 statusbar_x = strlen(answer);
559 }
David Lawrence Ramseyea9d03f2005-11-08 01:49:14 +0000560
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000561 /* This key has a shortcut-list entry when it's used to
562 * move to a newer search, which means that finished has
563 * been set to TRUE. Set it back to FALSE here, so that
564 * we aren't kicked out of the statusbar prompt. */
565 finished = FALSE;
566 }
Chris Allegrettaeb643142008-03-12 04:44:14 +0000567 } else
Benno Schulenbergb341f292014-06-19 20:05:24 +0000568#endif /* !DISABLE_HISTORIES */
Benno Schulenberg3933a302014-07-02 08:47:09 +0000569 if (func == do_help_void) {
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000570 /* This key has a shortcut-list entry when it's used to go to
571 * the help browser or display a message indicating that help
572 * is disabled, which means that finished has been set to TRUE.
573 * Set it back to FALSE here, so that we aren't kicked out of
574 * the statusbar prompt. */
575 finished = FALSE;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000576 }
577
Benno Schulenberg96c95cd2014-04-04 19:26:08 +0000578 /* If we have a shortcut with an associated function, break out if
579 * we're finished after running or trying to run the function. */
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000580 if (finished)
581 break;
582
Benno Schulenberg0242d842016-08-28 18:32:56 +0200583 update_the_statusbar();
584
Benno Schulenbergb341f292014-06-19 20:05:24 +0000585#if !defined(DISABLE_HISTORIES) && !defined(DISABLE_TABCOMP)
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000586 last_kbinput = kbinput;
587#endif
David Lawrence Ramsey83262542006-02-09 22:42:14 +0000588 }
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000589
Benno Schulenbergb341f292014-06-19 20:05:24 +0000590#ifndef DISABLE_HISTORIES
Benno Schulenberg22a01ca2016-02-06 12:12:08 +0000591 /* Set the current position in the history list to the bottom. */
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000592 if (history_list != NULL) {
593 history_reset(*history_list);
Benno Schulenbergc32a58a2015-06-14 19:14:41 +0000594 free(magichistory);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000595 }
596#endif
597
Chris Allegrettaeb643142008-03-12 04:44:14 +0000598 *actual = kbinput;
Benno Schulenberg3933a302014-07-02 08:47:09 +0000599
600 return func;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000601}
602
David Lawrence Ramseye19449e2005-11-07 21:45:44 +0000603/* Ask a question on the statusbar. The prompt will be stored in the
604 * static prompt, which should be NULL initially, and the answer will be
605 * stored in the answer global. Returns -1 on aborted enter, -2 on a
606 * blank string, and 0 otherwise, the valid shortcut key caught.
David Lawrence Ramsey68160072006-02-18 21:32:29 +0000607 * curranswer is any editable text that we want to put up by default,
608 * and refresh_func is the function we want to call to refresh the edit
609 * window.
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000610 *
611 * The allow_tabs parameter indicates whether we should allow tabs to be
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +0000612 * interpreted. The allow_files parameter indicates whether we should
Benno Schulenberg34fbb1f2016-01-13 20:32:40 +0000613 * allow all files (as opposed to just directories) to be tab completed. */
Benno Schulenbergfd0589d2017-01-02 21:12:44 +0100614int do_prompt(bool allow_tabs, bool allow_files,
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000615 int menu, const char *curranswer,
Benno Schulenbergb341f292014-06-19 20:05:24 +0000616#ifndef DISABLE_HISTORIES
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000617 filestruct **history_list,
618#endif
David Lawrence Ramsey68160072006-02-18 21:32:29 +0000619 void (*refresh_func)(void), const char *msg, ...)
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000620{
621 va_list ap;
Benno Schulenbergc11c6882016-08-30 09:11:33 +0200622 int retval;
Benno Schulenbergb77b1392016-08-26 12:18:04 +0200623 functionptrtype func = NULL;
Benno Schulenberg30f3c532016-04-26 17:50:25 +0200624 bool listed = FALSE;
Benno Schulenberg34a20f82016-04-17 15:24:05 +0200625 /* Save a possible current statusbar x position. */
626 size_t was_statusbar_x = statusbar_x;
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000627
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000628 bottombars(menu);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000629
Benno Schulenberg4f156aa2016-08-27 10:48:20 +0200630 answer = mallocstrcpy(answer, curranswer);
631
Benno Schulenbergc11c6882016-08-30 09:11:33 +0200632#ifndef NANO_TINY
633 redo_theprompt:
634#endif
635 prompt = charalloc((COLS * mb_cur_max()) + 1);
636 va_start(ap, msg);
637 vsnprintf(prompt, COLS * mb_cur_max(), msg, ap);
638 va_end(ap);
639 /* Reserve five columns for colon plus angles plus answer, ":<aa>". */
640 null_at(&prompt, actual_x(prompt, (COLS < 5) ? 0 : COLS - 5));
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000641
Benno Schulenbergfd0589d2017-01-02 21:12:44 +0100642 func = acquire_an_answer(&retval, allow_tabs, allow_files, &listed,
Benno Schulenbergb341f292014-06-19 20:05:24 +0000643#ifndef DISABLE_HISTORIES
Benno Schulenberg0d5fbfb2016-08-22 13:54:55 +0200644 history_list,
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +0000645#endif
Benno Schulenberg0d5fbfb2016-08-22 13:54:55 +0200646 refresh_func);
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000647
Benno Schulenbergc11c6882016-08-30 09:11:33 +0200648 free(prompt);
649 prompt = NULL;
650
651#ifndef NANO_TINY
652 if (retval == KEY_WINCH)
653 goto redo_theprompt;
654#endif
David Lawrence Ramsey143b8c72005-11-01 18:35:47 +0000655
Benno Schulenberg34a20f82016-04-17 15:24:05 +0200656 /* If we're done with this prompt, restore the x position to what
657 * it was at a possible previous prompt. */
Benno Schulenberg4d2ada62016-08-28 17:37:25 +0200658 if (func == do_cancel || func == do_enter)
Benno Schulenberg34a20f82016-04-17 15:24:05 +0200659 statusbar_x = was_statusbar_x;
David Lawrence Ramsey98332d42006-08-26 15:14:55 +0000660
David Lawrence Ramseye1e2cb72006-08-26 16:42:12 +0000661 /* If we left the prompt via Cancel or Enter, set the return value
662 * properly. */
Benno Schulenberg3933a302014-07-02 08:47:09 +0000663 if (func == do_cancel)
Chris Allegrettaeb643142008-03-12 04:44:14 +0000664 retval = -1;
Benno Schulenbergbde996d2015-11-11 19:56:35 +0000665 else if (func == do_enter)
Chris Allegrettaeb643142008-03-12 04:44:14 +0000666 retval = (*answer == '\0') ? -2 : 0;
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000667
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000668 blank_statusbar();
669 wnoutrefresh(bottomwin);
670
671#ifdef DEBUG
672 fprintf(stderr, "answer = \"%s\"\n", answer);
673#endif
674
Benno Schulenberg30f3c532016-04-26 17:50:25 +0200675#ifndef DISABLE_TABCOMP
676 /* If we've done tab completion, there might still be a list of
677 * filename matches on the edit window. Clear them off. */
678 if (listed)
679 refresh_func();
680#endif
681
David Lawrence Ramseyd24d0a42005-11-01 17:37:44 +0000682 return retval;
683}
684
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000685/* Ask a simple Yes/No (and optionally All) question, specified in msg,
686 * on the statusbar. Return 1 for Yes, 0 for No, 2 for All (if all is
687 * TRUE when passed in), and -1 for Cancel. */
David Lawrence Ramseye19449e2005-11-07 21:45:44 +0000688int do_yesno_prompt(bool all, const char *msg)
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000689{
Benno Schulenberge853c1e2016-02-07 13:41:46 +0000690 int response = -2, width = 16;
Benno Schulenberg99733662016-12-26 17:31:27 +0100691 char *message = display_string(msg, 0, COLS, FALSE);
692
David Lawrence Ramseycde90392006-04-09 18:27:42 +0000693 /* TRANSLATORS: For the next three strings, if possible, specify
David Lawrence Ramseybe7fd8a2006-04-09 18:24:54 +0000694 * the single-byte shortcuts for both your language and English.
Benno Schulenberg8f95f9b2016-12-01 15:25:35 +0100695 * For example, in French: "OoYy", for both "Oui" and "Yes". */
696 const char *yesstr = _("Yy");
697 const char *nostr = _("Nn");
698 const char *allstr = _("Aa");
699
700 /* The above three variables consist of all the single-byte characters
701 * that are accepted for the corresponding answer. Of each variable,
702 * the first character is displayed in the help lines. */
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000703
Benno Schulenberg1fb82032016-12-26 20:20:03 +0100704 while (response == -2) {
Benno Schulenberg75d64e62015-05-28 13:02:29 +0000705 int kbinput;
706 functionptrtype func;
Benno Schulenberg75d64e62015-05-28 13:02:29 +0000707
Benno Schulenberg59187b82015-05-28 13:28:37 +0000708 if (!ISSET(NO_HELP)) {
709 char shortstr[3];
Benno Schulenberg2661d6d2015-05-28 13:51:03 +0000710 /* Temporary string for (translated) " Y", " N" and " A". */
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000711
Benno Schulenberg59187b82015-05-28 13:28:37 +0000712 if (COLS < 32)
713 width = COLS / 2;
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000714
Benno Schulenberg59187b82015-05-28 13:28:37 +0000715 /* Clear the shortcut list from the bottom of the screen. */
716 blank_bottombars();
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000717
Benno Schulenberg59187b82015-05-28 13:28:37 +0000718 /* Now show the ones for "Yes", "No", "Cancel" and maybe "All". */
719 sprintf(shortstr, " %c", yesstr[0]);
720 wmove(bottomwin, 1, 0);
721 onekey(shortstr, _("Yes"), width);
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000722
Benno Schulenberg59187b82015-05-28 13:28:37 +0000723 if (all) {
Benno Schulenberg59187b82015-05-28 13:28:37 +0000724 shortstr[1] = allstr[0];
Benno Schulenberg2661d6d2015-05-28 13:51:03 +0000725 wmove(bottomwin, 1, width);
Benno Schulenberg59187b82015-05-28 13:28:37 +0000726 onekey(shortstr, _("All"), width);
727 }
728
Benno Schulenberg59187b82015-05-28 13:28:37 +0000729 shortstr[1] = nostr[0];
Benno Schulenberg2661d6d2015-05-28 13:51:03 +0000730 wmove(bottomwin, 2, 0);
Benno Schulenberg59187b82015-05-28 13:28:37 +0000731 onekey(shortstr, _("No"), width);
732
Benno Schulenberg2661d6d2015-05-28 13:51:03 +0000733 wmove(bottomwin, 2, width);
Benno Schulenberg59187b82015-05-28 13:28:37 +0000734 onekey("^C", _("Cancel"), width);
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000735 }
736
Benno Schulenbergc6512a92016-12-01 15:14:41 +0100737 /* Color the statusbar over its full width and display the question. */
Benno Schulenberg960e8482016-07-12 09:35:48 +0200738 wattron(bottomwin, interface_color_pair[TITLE_BAR]);
Benno Schulenberg59187b82015-05-28 13:28:37 +0000739 blank_statusbar();
Benno Schulenberg99733662016-12-26 17:31:27 +0100740 mvwaddnstr(bottomwin, 0, 0, message, actual_x(message, COLS - 1));
Benno Schulenberg960e8482016-07-12 09:35:48 +0200741 wattroff(bottomwin, interface_color_pair[TITLE_BAR]);
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000742
Benno Schulenberg59187b82015-05-28 13:28:37 +0000743 wnoutrefresh(bottomwin);
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000744
Benno Schulenberg86121cf2016-12-05 15:43:58 +0100745 /* When not replacing, show the cursor. */
746 if (!all)
747 curs_set(1);
748
Chris Allegrettacc593832008-03-19 02:32:48 +0000749 currmenu = MYESNO;
Benno Schulenberg7e5324d2014-06-30 18:04:33 +0000750 kbinput = get_kbinput(bottomwin);
Benno Schulenberg75d64e62015-05-28 13:02:29 +0000751
Benno Schulenberg266e0492014-07-27 19:32:03 +0000752 func = func_from_key(&kbinput);
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000753
Benno Schulenberg266e0492014-07-27 19:32:03 +0000754 if (func == do_cancel)
Benno Schulenberge853c1e2016-02-07 13:41:46 +0000755 response = -1;
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000756#ifndef DISABLE_MOUSE
Chris Allegrettaeb643142008-03-12 04:44:14 +0000757 else if (kbinput == KEY_MOUSE) {
Benno Schulenberg1fb82032016-12-26 20:20:03 +0100758 int mouse_x, mouse_y;
Benno Schulenberge5fee7e2016-02-07 13:37:16 +0000759 /* We can click on the Yes/No/All shortcuts to select an answer. */
760 if (get_mouseinput(&mouse_x, &mouse_y, FALSE) == 0 &&
761 wmouse_trafo(bottomwin, &mouse_y, &mouse_x, FALSE) &&
762 mouse_x < (width * 2) && mouse_y > 0) {
763 int x = mouse_x / width;
764 /* The x-coordinate among the Yes/No/All shortcuts. */
765 int y = mouse_y - 1;
766 /* The y-coordinate among the Yes/No/All shortcuts. */
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000767
Benno Schulenberge5fee7e2016-02-07 13:37:16 +0000768 assert(0 <= x && x <= 1 && 0 <= y && y <= 1);
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000769
Benno Schulenberge5fee7e2016-02-07 13:37:16 +0000770 /* x == 0 means they clicked Yes or No.
771 * y == 0 means Yes or All. */
Benno Schulenberge853c1e2016-02-07 13:41:46 +0000772 response = -2 * x * y + x - y + 1;
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000773
Benno Schulenberge853c1e2016-02-07 13:41:46 +0000774 if (response == 2 && !all)
775 response = -2;
Benno Schulenberge5fee7e2016-02-07 13:37:16 +0000776 }
Chris Allegretta0018d8e2008-03-13 08:23:52 +0000777 }
David Lawrence Ramseybc80cb12006-04-24 23:03:21 +0000778#endif /* !DISABLE_MOUSE */
Benno Schulenberg379b1552016-12-03 20:37:30 +0100779 else {
Benno Schulenberge5fee7e2016-02-07 13:37:16 +0000780 /* Look for the kbinput in the Yes, No (and All) strings. */
781 if (strchr(yesstr, kbinput) != NULL)
Benno Schulenberge853c1e2016-02-07 13:41:46 +0000782 response = 1;
Benno Schulenberge5fee7e2016-02-07 13:37:16 +0000783 else if (strchr(nostr, kbinput) != NULL)
Benno Schulenberge853c1e2016-02-07 13:41:46 +0000784 response = 0;
Benno Schulenberge5fee7e2016-02-07 13:37:16 +0000785 else if (all && strchr(allstr, kbinput) != NULL)
Benno Schulenberge853c1e2016-02-07 13:41:46 +0000786 response = 2;
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000787 }
Benno Schulenberg1fb82032016-12-26 20:20:03 +0100788 }
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000789
Benno Schulenberg99733662016-12-26 17:31:27 +0100790 free(message);
791
Benno Schulenberge853c1e2016-02-07 13:41:46 +0000792 return response;
David Lawrence Ramsey38ebba12005-11-03 21:07:24 +0000793}