blob: 65fdeb73b04c5cc66aa8d1682399cf5904921e92 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * winio.c *
4 * *
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +00005 * Copyright (C) 1999-2004 Chris Allegretta *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00006 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
Chris Allegretta3a24f3f2001-10-24 11:33:54 +00008 * the Free Software Foundation; either version 2, or (at your option) *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00009 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +000022#include "config.h"
23
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000024#include <stdarg.h>
25#include <string.h>
Chris Allegrettadba37ae2000-07-07 05:13:09 +000026#include <stdlib.h>
Chris Allegretta8a0de3b2000-11-24 20:45:14 +000027#include <unistd.h>
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +000028#include <ctype.h>
Chris Allegretta6232d662002-05-12 19:52:15 +000029#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000030#include "proto.h"
31#include "nano.h"
32
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000033static int statblank = 0; /* Number of keystrokes left after
Chris Allegretta88520c92001-05-05 17:45:54 +000034 we call statusbar(), before we
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000035 actually blank the statusbar */
Robert Siemborskid8510b22000-06-06 23:04:06 +000036
David Lawrence Ramsey0381c212004-05-01 01:21:38 +000037/* Control character compatibility:
38 *
39 * - NANO_BACKSPACE_KEY is Ctrl-H, which is Backspace under ASCII, ANSI,
40 * VT100, and VT220.
41 * - NANO_TAB_KEY is Ctrl-I, which is Tab under ASCII, ANSI, VT100,
42 * VT220, and VT320.
43 * - NANO_ENTER_KEY is Ctrl-M, which is Enter under ASCII, ANSI, VT100,
44 * VT220, and VT320.
45 * - NANO_XON_KEY is Ctrl-Q, which is XON under ASCII, ANSI, VT100,
46 * VT220, and VT320.
47 * - NANO_XOFF_KEY is Ctrl-S, which is XOFF under ASCII, ANSI, VT100,
48 * VT220, and VT320.
David Lawrence Ramseya849ab12004-05-01 04:13:06 +000049 * - NANO_CONTROL_8 is Ctrl-8 (Ctrl-?), which is Delete under ASCII,
David Lawrence Ramsey0381c212004-05-01 01:21:38 +000050 * ANSI, VT100, and VT220, and which is Backspace under VT320.
51 *
52 * Note: VT220s and VT320s also generate Esc [ 3 ~ for Delete. By
David Lawrence Ramseya849ab12004-05-01 04:13:06 +000053 * default, xterm assumes it's running on a VT320 and generates Ctrl-8
54 * (Ctrl-?) for Backspace and Esc [ 3 ~ for Delete. This causes
David Lawrence Ramsey0381c212004-05-01 01:21:38 +000055 * problems for VT100-derived terminals such as the FreeBSD console,
David Lawrence Ramseya849ab12004-05-01 04:13:06 +000056 * which expect Ctrl-H for Backspace and Ctrl-8 (Ctrl-?) for Delete, and
David Lawrence Ramsey0381c212004-05-01 01:21:38 +000057 * on which the VT320 sequences are translated by the keypad to KEY_DC
58 * and [nothing]. We work around this conflict via the REBIND_DELETE
59 * flag: if it's not set, we assume VT320 compatibility, and if it is,
60 * we assume VT100 compatibility. Thanks to Lee Nelson and Wouter van
61 * Hemel for helping work this conflict out.
62 *
63 * Escape sequence compatibility:
64 *
65 * We support escape sequences for ANSI, VT100, VT220, VT320, the Linux
66 * console, the FreeBSD console, the Hurd console (a.k.a. the Mach
67 * console), xterm, rxvt, and Eterm. Among these, there are several
68 * conflicts and omissions, outlined as follows:
69 *
70 * - Tab on ANSI == PageUp on FreeBSD console; the former is omitted.
71 * (Ctrl-I is also Tab on ANSI, which we already support.)
72 * - PageDown on FreeBSD console == Center (5) on numeric keypad with
73 * NumLock off on Linux console; the latter is omitted. (The editing
74 * keypad key is more important to have working than the numeric
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +000075 * keypad key, because the latter has no value when NumLock is off.)
David Lawrence Ramsey0381c212004-05-01 01:21:38 +000076 * - F1 on FreeBSD console == the mouse key on xterm/rxvt/Eterm; the
77 * latter is omitted. (Mouse input will only work properly if the
78 * extended keypad value KEY_MOUSE is generated on mouse events
79 * instead of the escape sequence.)
80 * - F9 on FreeBSD console == PageDown on Hurd console; the former is
81 * omitted. (The editing keypad is more important to have working
82 * than the function keys, because the functions of the former are not
83 * arbitrary and the functions of the latter are.)
84 * - F10 on FreeBSD console == PageUp on Hurd console; the former is
85 * omitted. (Same as above.)
86 * - F13 on FreeBSD console == End on Hurd console; the former is
87 * omitted. (Same as above.)
88 * - The Hurd console has no escape sequences for F11, F12, F13, F14, or
89 * Center (5) on the numeric keypad with NumLock off.
90 *
91 * Note that Center (5) on the numeric keypad with NumLock off can also
92 * be the Begin key. */
David Lawrence Ramsey0a258082004-04-23 18:02:37 +000093
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +000094#ifndef NANO_SMALL
95/* Reset all the input routines that rely on character sequences. */
96void reset_kbinput(void)
97{
98 get_translated_kbinput(0, NULL, TRUE);
99 get_ascii_kbinput(0, 0, TRUE);
100 get_untranslated_kbinput(0, 0, FALSE, TRUE);
101}
102#endif
103
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000104/* Read in a single input character. If it's ignored, swallow it and go
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000105 * on. Otherwise, try to translate it from ASCII, extended keypad
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000106 * values, and/or escape sequences. Set meta_key to TRUE when we get a
107 * meta sequence. Supported extended keypad values consist of [arrow
108 * key], Ctrl-[arrow key], Shift-[arrow key], Enter, Backspace, the
109 * editing keypad (Insert, Delete, Home, End, PageUp, and PageDown), the
110 * function keypad (F1-F14), and the numeric keypad with NumLock off.
111 * Assume nodelay(win) is FALSE. */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000112int get_kbinput(WINDOW *win, int *meta_key)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000113{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000114 int kbinput, es, retval = ERR;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000115
David Lawrence Ramsey369732f2004-02-16 20:32:40 +0000116#ifndef NANO_SMALL
117 allow_pending_sigwinch(TRUE);
118#endif
119
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000120 *meta_key = FALSE;
121
122 while (retval == ERR) {
123 /* Read a character using blocking input, since using
124 * non-blocking input will eat up all unused CPU. Then pass it
125 * to get_translated_kbinput(). Continue until we get a
126 * complete sequence. */
127 kbinput = wgetch(win);
128 retval = get_translated_kbinput(kbinput, &es
129#ifndef NANO_SMALL
130 , FALSE
131#endif
132 );
133
134 /* If we got an escape sequence, read it in, including the
135 * initial non-escape, as verbatim input. */
136 if (es) {
137 int *escape_seq = NULL;
138 size_t es_len;
139
140 /* First, assume that we got a meta sequence. Set meta_key
141 * to TRUE and save the character we got as the result. We
142 * do this so that if there's a delay greater than nodelay()
143 * between Escape and the character we got (after we
144 * ungetch() it below), it'll still be properly interpreted
145 * as a meta sequence. */
146 *meta_key = TRUE;
147 retval = tolower(kbinput);
148
149 /* Next, send back the character we got and read in the
150 * complete escape sequence. */
151 ungetch(kbinput);
152 escape_seq = get_verbatim_kbinput(win, escape_seq, &es_len,
153 FALSE);
154
David Lawrence Ramseye65e6392004-06-04 18:18:17 +0000155 /* If the escape sequence is more than one character
156 * long, set meta_key to FALSE, translate the escape
157 * sequence into the corresponding key value, and save
158 * that as the result. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000159 if (es_len > 1) {
David Lawrence Ramseye65e6392004-06-04 18:18:17 +0000160 int ignore_seq;
161
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000162 *meta_key = FALSE;
David Lawrence Ramseye65e6392004-06-04 18:18:17 +0000163 retval = get_escape_seq_kbinput(escape_seq, es_len,
164 &ignore_seq);
165
166 if (retval == ERR && !ignore_seq) {
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000167 /* This escape sequence is unrecognized. Send it
168 * back. */
169 for (; es_len > 1; es_len--)
170 ungetch(escape_seq[es_len - 1]);
171 retval = escape_seq[0];
172 }
173 }
174 free(escape_seq);
175 }
176 }
177
178#ifdef DEBUG
179 fprintf(stderr, "get_kbinput(): kbinput = %d, meta_key = %d\n", kbinput, *meta_key);
180#endif
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000181
David Lawrence Ramsey369732f2004-02-16 20:32:40 +0000182#ifndef NANO_SMALL
183 allow_pending_sigwinch(FALSE);
184#endif
185
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000186 return retval;
187}
188
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000189/* Translate acceptable ASCII, extended keypad values, and escape
190 * sequences into their corresponding key values. Set es to TRUE when
191 * we get an escape sequence. Assume nodelay(win) is FALSE. */
192int get_translated_kbinput(int kbinput, int *es
193#ifndef NANO_SMALL
194 , int reset
195#endif
196 )
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000197{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000198 static size_t escapes = 0, ascii_digits = 0;
199 int retval = ERR;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000200
David Lawrence Ramsey369732f2004-02-16 20:32:40 +0000201#ifndef NANO_SMALL
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000202 if (reset) {
203 escapes = 0;
204 ascii_digits = 0;
205 return ERR;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000206 }
David Lawrence Ramsey369732f2004-02-16 20:32:40 +0000207#endif
208
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000209 *es = FALSE;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000210
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000211 switch (kbinput) {
212 case ERR:
213 break;
214 case NANO_CONTROL_3:
215 /* Increment the escape counter. */
216 escapes++;
217 switch (escapes) {
218 case 1:
219 /* One escape: wait for more input. */
220 case 2:
221 /* Two escapes: wait for more input. */
222 break;
223 default:
224 /* More than two escapes: reset the escape counter
225 * and wait for more input. */
226 escapes = 0;
227 }
228 break;
229#if !defined(NANO_SMALL) && defined(KEY_RESIZE)
230 /* Since we don't change the default SIGWINCH handler when
231 * NANO_SMALL is defined, KEY_RESIZE is never generated. Also,
232 * Slang and SunOS 5.7-5.9 don't support KEY_RESIZE. */
233 case KEY_RESIZE:
David Lawrence Ramseyd8974452004-06-04 22:28:55 +0000234 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000235#endif
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000236#ifdef PDCURSES
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000237 case KEY_SHIFT_L:
238 case KEY_SHIFT_R:
239 case KEY_CONTROL_L:
240 case KEY_CONTROL_R:
241 case KEY_ALT_L:
242 case KEY_ALT_R:
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000243 break;
David Lawrence Ramseyd8974452004-06-04 22:28:55 +0000244#endif
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000245 default:
246 switch (escapes) {
247 case 0:
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000248 switch (kbinput) {
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000249 case NANO_CONTROL_8:
250 retval = ISSET(REBIND_DELETE) ?
251 NANO_DELETE_KEY : NANO_BACKSPACE_KEY;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000252 break;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000253 case KEY_DOWN:
254 retval = NANO_NEXTLINE_KEY;
255 break;
256 case KEY_UP:
257 retval = NANO_PREVLINE_KEY;
258 break;
259 case KEY_LEFT:
260 retval = NANO_BACK_KEY;
261 break;
262 case KEY_RIGHT:
263 retval = NANO_FORWARD_KEY;
264 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000265#ifdef KEY_HOME
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000266 /* HP-UX 10 and 11 don't support KEY_HOME. */
267 case KEY_HOME:
268 retval = NANO_HOME_KEY;
269 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000270#endif
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000271 case KEY_BACKSPACE:
272 retval = NANO_BACKSPACE_KEY;
273 break;
274 case KEY_DC:
275 retval = ISSET(REBIND_DELETE) ?
276 NANO_BACKSPACE_KEY : NANO_DELETE_KEY;
277 break;
278 case KEY_IC:
279 retval = NANO_INSERTFILE_KEY;
280 break;
281 case KEY_NPAGE:
282 retval = NANO_NEXTPAGE_KEY;
283 break;
284 case KEY_PPAGE:
285 retval = NANO_PREVPAGE_KEY;
286 break;
287 case KEY_ENTER:
288 retval = NANO_ENTER_KEY;
289 break;
David Lawrence Ramsey16eb5182004-06-03 20:26:12 +0000290 case KEY_A1: /* Home (7) on numeric keypad
291 * with NumLock off. */
292 retval = NANO_HOME_KEY;
293 break;
294 case KEY_A3: /* PageUp (9) on numeric keypad
295 * with NumLock off. */
296 retval = NANO_PREVPAGE_KEY;
297 break;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000298 case KEY_B2: /* Center (5) on numeric keypad
David Lawrence Ramsey16eb5182004-06-03 20:26:12 +0000299 * with NumLock off. */
David Lawrence Ramsey16eb5182004-06-03 20:26:12 +0000300 break;
301 case KEY_C1: /* End (1) on numeric keypad
302 * with NumLock off. */
303 retval = NANO_END_KEY;
304 break;
305 case KEY_C3: /* PageDown (4) on numeric
306 * keypad with NumLock off. */
307 retval = NANO_NEXTPAGE_KEY;
308 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000309#ifdef KEY_BEG
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000310 /* Slang doesn't support KEY_BEG. */
311 case KEY_BEG: /* Center (5) on numeric keypad
David Lawrence Ramsey16eb5182004-06-03 20:26:12 +0000312 * with NumLock off. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000313 break;
David Lawrence Ramsey16eb5182004-06-03 20:26:12 +0000314#endif
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000315#ifdef KEY_END
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000316 /* HP-UX 10 and 11 don't support KEY_END. */
317 case KEY_END:
318 retval = NANO_END_KEY;
319 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000320#endif
321#ifdef KEY_SUSPEND
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000322 /* Slang doesn't support KEY_SUSPEND. */
323 case KEY_SUSPEND:
324 retval = NANO_SUSPEND_KEY;
325 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000326#endif
327#ifdef KEY_SLEFT
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000328 /* Slang doesn't support KEY_SLEFT. */
329 case KEY_SLEFT:
330 retval = NANO_BACK_KEY;
331 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000332#endif
333#ifdef KEY_SRIGHT
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000334 /* Slang doesn't support KEY_SRIGHT. */
335 case KEY_SRIGHT:
336 retval = NANO_FORWARD_KEY;
337 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000338#endif
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000339 default:
340 retval = kbinput;
341 break;
342 }
343 break;
344 case 1:
345 /* One escape followed by a non-escape: escape
346 * sequence mode. Reset the escape counter and set
347 * es to TRUE. */
348 escapes = 0;
349 *es = TRUE;
350 break;
351 case 2:
352 switch (kbinput) {
353 case '0':
354 case '1':
355 case '2':
356 case '3':
357 case '4':
358 case '5':
359 case '6':
360 case '7':
361 case '8':
362 case '9':
363 /* Two escapes followed by one or more
364 * digits: ASCII character sequence mode.
365 * If the digit sequence's range is limited
366 * to 2XX (the first digit is in the '0' to
367 * '2' range and it's the first digit, or if
368 * it's in the full digit range and it's not
369 * the first digit), increment the ASCII
370 * digit counter and interpret the digit.
371 * If the digit sequence's range is not
372 * limited to 2XX, fall through. */
373 if (kbinput <= '2' || ascii_digits > 0) {
374 ascii_digits++;
375 kbinput = get_ascii_kbinput(kbinput,
376 ascii_digits
377#ifndef NANO_SMALL
378 , FALSE
379#endif
380 );
381
382 if (kbinput != ERR) {
383 /* If we've read in a complete ASCII
384 * digit sequence, reset the ASCII
385 * digit counter and the escape
386 * counter and save the corresponding
387 * ASCII character as the result. */
388 ascii_digits = 0;
389 escapes = 0;
390 retval = kbinput;
391 }
392 break;
393 }
394 default:
395 /* Reset the escape counter. */
396 escapes = 0;
397 if (ascii_digits == 0)
398 /* Two escapes followed by a non-digit
399 * or a digit that would create an ASCII
400 * digit sequence greater than 2XX, and
401 * we're not in the middle of an ASCII
402 * character sequence: control character
403 * sequence mode. Interpret the control
404 * sequence and save the corresponding
405 * control character as the result. */
406 retval = get_control_kbinput(kbinput);
407 else {
408 /* If we were in the middle of an ASCII
409 * character sequence, reset the ASCII
410 * digit counter and save the character
411 * we got as the result. */
412 ascii_digits = 0;
413 retval = kbinput;
414 }
415 }
416 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000417 }
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000418
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000419#ifdef DEBUG
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000420 fprintf(stderr, "get_translated_kbinput(): kbinput = %d, es = %d, escapes = %d, ascii_digits = %d, retval = %d\n", kbinput, *es, escapes, ascii_digits, retval);
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000421#endif
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000422
423 /* Return the result. */
424 return retval;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000425}
426
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000427/* Translate an ASCII character sequence: turn a three-digit decimal
428 * ASCII code from 000-255 into its corresponding ASCII character. */
429int get_ascii_kbinput(int kbinput, size_t ascii_digits
430#ifndef NANO_SMALL
431 , int reset
432#endif
433 )
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000434{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000435 static int ascii_kbinput = 0;
436 int retval = ERR;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000437
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000438#ifndef NANO_SMALL
439 if (reset) {
440 ascii_kbinput = 0;
441 return ERR;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000442 }
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000443#endif
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000444
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000445 switch (ascii_digits) {
446 case 1:
447 /* Read in the first of the three ASCII digits. */
448 switch (kbinput) {
449 /* Add the digit we got to the 100's position of the
450 * ASCII character sequence holder. */
451 case '0':
452 case '1':
453 case '2':
454 ascii_kbinput += (kbinput - '0') * 100;
455 break;
456 default:
457 retval = kbinput;
458 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000459 break;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000460 case 2:
461 /* Read in the second of the three ASCII digits. */
462 switch (kbinput) {
463 /* Add the digit we got to the 10's position of the
464 * ASCII character sequence holder. */
465 case '0':
466 case '1':
467 case '2':
468 case '3':
469 case '4':
470 case '5':
471 ascii_kbinput += (kbinput - '0') * 10;
472 break;
473 case '6':
474 case '7':
475 case '8':
476 case '9':
477 if (ascii_kbinput < 200) {
478 ascii_kbinput += (kbinput - '0') * 10;
479 break;
480 }
481 default:
482 retval = kbinput;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000483 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000484 break;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000485 case 3:
486 /* Read in the third of the three ASCII digits. */
487 switch (kbinput) {
488 /* Add the digit we got to the 1's position of the ASCII
489 * character sequence holder, and save the corresponding
490 * ASCII character as the result. */
491 case '0':
492 case '1':
493 case '2':
494 case '3':
495 case '4':
496 case '5':
497 ascii_kbinput += (kbinput - '0');
498 retval = ascii_kbinput;
499 break;
500 case '6':
501 case '7':
502 case '8':
503 case '9':
504 if (ascii_kbinput < 250) {
505 ascii_kbinput += (kbinput - '0');
506 retval = ascii_kbinput;
507 break;
508 }
509 default:
510 retval = kbinput;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000511 }
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000512 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000513 }
514
515#ifdef DEBUG
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000516 fprintf(stderr, "get_ascii_kbinput(): kbinput = %d, ascii_digits = %d, ascii_kbinput = %d, retval = %d\n", kbinput, ascii_digits, ascii_kbinput, retval);
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000517#endif
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000518
519 /* If the result is an ASCII character, reset the ASCII character
520 * sequence holder. */
521 if (retval != ERR)
522 ascii_kbinput = 0;
523
524 return retval;
525}
526
527/* Translate a control character sequence: turn an ASCII non-control
528 * character into its corresponding control character. */
529int get_control_kbinput(int kbinput)
530{
531 int retval = ERR;
532
533 /* We don't handle Ctrl-2 here, since Esc Esc 2 could be the first
534 * part of an ASCII character sequence. */
535
536 /* Ctrl-2 (Ctrl-Space) == Ctrl-@ == Ctrl-` */
537 if (kbinput == ' ' || kbinput == '@' || kbinput == '`')
538 retval = NANO_CONTROL_SPACE;
539 /* Ctrl-3 (Ctrl-[, Esc) to Ctrl-7 (Ctrl-_) */
540 else if (kbinput >= '3' && kbinput <= '7')
541 retval = kbinput - 24;
542 /* Ctrl-8 (Ctrl-?) */
543 else if (kbinput == '8' || kbinput == '?')
544 retval = NANO_CONTROL_8;
545 /* Ctrl-A to Ctrl-_ */
546 else if (kbinput >= 'A' && kbinput <= '_')
547 retval = kbinput - 64;
548 /* Ctrl-a to Ctrl-~ */
549 else if (kbinput >= 'a' && kbinput <= '~')
550 retval = kbinput - 96;
551 else
552 retval = kbinput;
553
554#ifdef DEBUG
555 fprintf(stderr, "get_control_kbinput(): kbinput = %d, retval = %d\n", kbinput, ascii_digits, *complete, retval);
556#endif
557
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000558 return retval;
559}
560
David Lawrence Ramsey58f6d832004-01-27 07:12:47 +0000561/* Translate escape sequences, most of which correspond to extended
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000562 * keypad values, nto their corresponding key values. These sequences
David Lawrence Ramseye65e6392004-06-04 18:18:17 +0000563 * are generated when the keypad doesn't support the needed keys. If
564 * the escape sequence is recognized but we want to ignore it, return
565 * ERR and set ignore_seq to TRUE; if it's unrecognized, return ERR and
566 * set ignore_seq to FALSE. Assume that Escape has already been read
567 * in. */
568int get_escape_seq_kbinput(int *escape_seq, size_t es_len, int
569 *ignore_seq)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000570{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000571 int retval = ERR;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000572
David Lawrence Ramseye65e6392004-06-04 18:18:17 +0000573 *ignore_seq = FALSE;
574
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000575 if (es_len > 1) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000576 switch (escape_seq[0]) {
577 case 'O':
578 switch (escape_seq[1]) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000579 case '2':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000580 if (es_len >= 3) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000581 switch (escape_seq[2]) {
582 case 'P': /* Esc O 2 P == F13 on
583 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000584 retval = KEY_F(13);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000585 break;
586 case 'Q': /* Esc O 2 Q == F14 on
587 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000588 retval = KEY_F(14);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000589 break;
590 }
591 }
592 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000593 case 'A': /* Esc O A == Up on VT100/VT320/xterm. */
594 case 'B': /* Esc O B == Down on
595 * VT100/VT320/xterm. */
596 case 'C': /* Esc O C == Right on
597 * VT100/VT320/xterm. */
598 case 'D': /* Esc O D == Left on
599 * VT100/VT320/xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000600 retval = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000601 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000602 case 'E': /* Esc O E == Center (5) on numeric keypad
603 * with NumLock off on xterm. */
David Lawrence Ramseye65e6392004-06-04 18:18:17 +0000604 *ignore_seq = TRUE;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000605 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000606 case 'F': /* Esc O F == End on xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000607 retval = NANO_END_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000608 break;
609 case 'H': /* Esc O H == Home on xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000610 retval = NANO_HOME_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000611 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000612 case 'M': /* Esc O M == Enter on numeric keypad with
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000613 * NumLock off on
614 * VT100/VT220/VT320/xterm/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000615 retval = NANO_ENTER_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000616 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000617 case 'P': /* Esc O P == F1 on VT100/VT220/VT320/Hurd
618 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000619 retval = KEY_F(1);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000620 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000621 case 'Q': /* Esc O Q == F2 on VT100/VT220/VT320/Hurd
622 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000623 retval = KEY_F(2);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000624 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000625 case 'R': /* Esc O R == F3 on VT100/VT220/VT320/Hurd
626 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000627 retval = KEY_F(3);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000628 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000629 case 'S': /* Esc O S == F4 on VT100/VT220/VT320/Hurd
630 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000631 retval = KEY_F(4);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000632 break;
633 case 'T': /* Esc O T == F5 on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000634 retval = KEY_F(5);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000635 break;
636 case 'U': /* Esc O U == F6 on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000637 retval = KEY_F(6);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000638 break;
639 case 'V': /* Esc O V == F7 on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000640 retval = KEY_F(7);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000641 break;
642 case 'W': /* Esc O W == F8 on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000643 retval = KEY_F(8);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000644 break;
645 case 'X': /* Esc O X == F9 on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000646 retval = KEY_F(9);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000647 break;
648 case 'Y': /* Esc O Y == F10 on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000649 retval = KEY_F(10);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000650 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000651 case 'a': /* Esc O a == Ctrl-Up on rxvt. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000652 case 'b': /* Esc O b == Ctrl-Down on rxvt. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000653 case 'c': /* Esc O c == Ctrl-Right on rxvt. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000654 case 'd': /* Esc O d == Ctrl-Left on rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000655 retval = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000656 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000657 case 'j': /* Esc O j == '*' on numeric keypad with
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000658 * NumLock off on
659 * VT100/VT220/VT320/xterm/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000660 retval = '*';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000661 break;
662 case 'k': /* Esc O k == '+' on numeric keypad with
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000663 * NumLock off on
664 * VT100/VT220/VT320/xterm/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000665 retval = '+';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000666 break;
667 case 'l': /* Esc O l == ',' on numeric keypad with
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000668 * NumLock off on
669 * VT100/VT220/VT320/xterm/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000670 retval = '+';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000671 break;
672 case 'm': /* Esc O m == '-' on numeric keypad with
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000673 * NumLock off on
674 * VT100/VT220/VT320/xterm/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000675 retval = '-';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000676 break;
677 case 'n': /* Esc O n == Delete (.) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000678 * with NumLock off on
679 * VT100/VT220/VT320/xterm/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000680 retval = NANO_DELETE_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000681 break;
682 case 'o': /* Esc O o == '/' on numeric keypad with
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000683 * NumLock off on
684 * VT100/VT220/VT320/xterm/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000685 retval = '/';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000686 break;
687 case 'p': /* Esc O p == Insert (0) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000688 * with NumLock off on
689 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000690 retval = NANO_INSERTFILE_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000691 break;
692 case 'q': /* Esc O q == End (1) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000693 * with NumLock off on
694 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000695 retval = NANO_END_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000696 break;
697 case 'r': /* Esc O r == Down (2) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000698 * with NumLock off on
699 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000700 retval = NANO_NEXTLINE_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000701 break;
702 case 's': /* Esc O s == PageDown (3) on numeric
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000703 * keypad with NumLock off on
704 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000705 retval = NANO_NEXTPAGE_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000706 break;
707 case 't': /* Esc O t == Left (4) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000708 * with NumLock off on
709 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000710 retval = NANO_BACK_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000711 break;
712 case 'u': /* Esc O u == Center (5) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000713 * with NumLock off on
714 * VT100/VT220/VT320/rxvt/Eterm. */
David Lawrence Ramseye65e6392004-06-04 18:18:17 +0000715 *ignore_seq = TRUE;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000716 break;
717 case 'v': /* Esc O v == Right (6) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000718 * with NumLock off on
719 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000720 retval = NANO_FORWARD_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000721 break;
722 case 'w': /* Esc O w == Home (7) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000723 * with NumLock off on
724 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000725 retval = NANO_HOME_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000726 break;
727 case 'x': /* Esc O x == Up (8) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000728 * with NumLock off on
729 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000730 retval = NANO_PREVLINE_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000731 break;
732 case 'y': /* Esc O y == PageUp (9) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000733 * with NumLock off on
734 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000735 retval = NANO_PREVPAGE_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000736 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000737 }
738 break;
739 case 'o':
740 switch (escape_seq[1]) {
741 case 'a': /* Esc o a == Ctrl-Up on Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000742 case 'b': /* Esc o b == Ctrl-Down on Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000743 case 'c': /* Esc o c == Ctrl-Right on Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000744 case 'd': /* Esc o d == Ctrl-Left on Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000745 retval = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000746 break;
747 }
748 break;
749 case '[':
750 switch (escape_seq[1]) {
751 case '1':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000752 if (es_len >= 3) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000753 switch (escape_seq[2]) {
754 case '1': /* Esc [ 1 1 ~ == F1 on
755 * rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000756 retval = KEY_F(1);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000757 break;
758 case '2': /* Esc [ 1 2 ~ == F2 on
759 * rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000760 retval = KEY_F(2);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000761 break;
762 case '3': /* Esc [ 1 3 ~ == F3 on
763 * rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000764 retval = KEY_F(3);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000765 break;
766 case '4': /* Esc [ 1 4 ~ == F4 on
767 * rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000768 retval = KEY_F(4);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000769 break;
770 case '5': /* Esc [ 1 5 ~ == F5 on
771 * xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000772 retval = KEY_F(5);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000773 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000774 case '7': /* Esc [ 1 7 ~ == F6 on
775 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000776 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000777 retval = KEY_F(6);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000778 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000779 case '8': /* Esc [ 1 8 ~ == F7 on
780 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000781 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000782 retval = KEY_F(7);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000783 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000784 case '9': /* Esc [ 1 9 ~ == F8 on
785 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000786 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000787 retval = KEY_F(8);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000788 break;
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000789 case ';':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000790 if (es_len >= 4) {
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000791 switch (escape_seq[3]) {
792 case '2':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000793 if (es_len >= 5) {
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000794 switch (escape_seq[4]) {
795 case 'A': /* Esc [ 1 ; 2 A == Shift-Up on
796 * xterm. */
797 case 'B': /* Esc [ 1 ; 2 B == Shift-Down on
798 * xterm. */
799 case 'C': /* Esc [ 1 ; 2 C == Shift-Right on
800 * xterm. */
801 case 'D': /* Esc [ 1 ; 2 D == Shift-Left on
802 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000803 retval = get_escape_seq_abcd(escape_seq[4]);
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000804 break;
805 }
806 }
807 break;
808 case '5':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000809 if (es_len >= 5) {
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000810 switch (escape_seq[4]) {
811 case 'A': /* Esc [ 1 ; 5 A == Ctrl-Up on
812 * xterm. */
813 case 'B': /* Esc [ 1 ; 5 B == Ctrl-Down on
814 * xterm. */
815 case 'C': /* Esc [ 1 ; 5 C == Ctrl-Right on
816 * xterm. */
817 case 'D': /* Esc [ 1 ; 5 D == Ctrl-Left on
818 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000819 retval = get_escape_seq_abcd(escape_seq[4]);
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000820 break;
821 }
822 }
823 break;
824 }
825 }
826 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000827 default: /* Esc [ 1 ~ == Home on
828 * VT320/Linux console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000829 retval = NANO_HOME_KEY;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000830 break;
831 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000832 }
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000833 break;
834 case '2':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000835 if (es_len >= 3) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000836 switch (escape_seq[2]) {
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000837 case '0': /* Esc [ 2 0 ~ == F9 on
838 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000839 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000840 retval = KEY_F(9);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000841 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000842 case '1': /* Esc [ 2 1 ~ == F10 on
843 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000844 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000845 retval = KEY_F(10);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000846 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000847 case '3': /* Esc [ 2 3 ~ == F11 on
848 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000849 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000850 retval = KEY_F(11);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000851 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000852 case '4': /* Esc [ 2 4 ~ == F12 on
853 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000854 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000855 retval = KEY_F(12);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000856 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000857 case '5': /* Esc [ 2 5 ~ == F13 on
858 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000859 * console/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000860 retval = KEY_F(13);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000861 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000862 case '6': /* Esc [ 2 6 ~ == F14 on
863 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000864 * console/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000865 retval = KEY_F(14);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000866 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000867 default: /* Esc [ 2 ~ == Insert on
868 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000869 * console/xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000870 retval = NANO_INSERTFILE_KEY;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000871 break;
872 }
873 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000874 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000875 case '3': /* Esc [ 3 ~ == Delete on
876 * VT220/VT320/Linux console/xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000877 retval = NANO_DELETE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000878 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000879 case '4': /* Esc [ 4 ~ == End on VT220/VT320/Linux
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000880 * console/xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000881 retval = NANO_END_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000882 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000883 case '5': /* Esc [ 5 ~ == PageUp on
884 * VT220/VT320/Linux console/xterm; Esc [
885 * 5 ^ == PageUp on Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000886 retval = NANO_PREVPAGE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000887 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000888 case '6': /* Esc [ 6 ~ == PageDown on
889 * VT220/VT320/Linux console/xterm; Esc [
890 * 6 ^ == PageDown on Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000891 retval = NANO_NEXTPAGE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000892 break;
893 case '7': /* Esc [ 7 ~ == Home on rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000894 retval = NANO_HOME_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000895 break;
896 case '8': /* Esc [ 8 ~ == End on rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000897 retval = NANO_END_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000898 break;
899 case '9': /* Esc [ 9 == Delete on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000900 retval = NANO_DELETE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000901 break;
902 case '@': /* Esc [ @ == Insert on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000903 retval = NANO_INSERTFILE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000904 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000905 case 'A': /* Esc [ A == Up on ANSI/VT220/Linux
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000906 * console/FreeBSD console/Hurd
907 * console/rxvt/Eterm. */
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000908 case 'B': /* Esc [ B == Down on ANSI/VT220/Linux
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000909 * console/FreeBSD console/Hurd
910 * console/rxvt/Eterm. */
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000911 case 'C': /* Esc [ C == Right on ANSI/VT220/Linux
912 * console/FreeBSD console/Hurd
913 * console/rxvt/Eterm. */
914 case 'D': /* Esc [ D == Left on ANSI/VT220/Linux
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000915 * console/FreeBSD console/Hurd
916 * console/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000917 retval = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000918 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000919 case 'E': /* Esc [ E == Center (5) on numeric keypad
920 * with NumLock off on FreeBSD console. */
David Lawrence Ramseye65e6392004-06-04 18:18:17 +0000921 *ignore_seq = TRUE;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000922 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000923 case 'F': /* Esc [ F == End on FreeBSD
924 * console/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000925 retval = NANO_END_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000926 break;
927 case 'G': /* Esc [ G == PageDown on FreeBSD
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000928 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000929 retval = NANO_NEXTPAGE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000930 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000931 case 'H': /* Esc [ H == Home on ANSI/VT220/FreeBSD
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000932 * console/Hurd console/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000933 retval = NANO_HOME_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000934 break;
935 case 'I': /* Esc [ I == PageUp on FreeBSD
936 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000937 retval = NANO_PREVPAGE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000938 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000939 case 'L': /* Esc [ L == Insert on ANSI/FreeBSD
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000940 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000941 retval = NANO_INSERTFILE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000942 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000943 case 'M': /* Esc [ M == F1 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000944 retval = KEY_F(1);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000945 break;
946 case 'N': /* Esc [ N == F2 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000947 retval = KEY_F(2);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000948 break;
949 case 'O':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000950 if (es_len >= 3) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000951 switch (escape_seq[2]) {
952 case 'P': /* Esc [ O P == F1 on
953 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000954 retval = KEY_F(1);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000955 break;
956 case 'Q': /* Esc [ O Q == F2 on
957 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000958 retval = KEY_F(2);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000959 break;
960 case 'R': /* Esc [ O R == F3 on
961 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000962 retval = KEY_F(3);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000963 break;
964 case 'S': /* Esc [ O S == F4 on
965 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000966 retval = KEY_F(4);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000967 break;
968 default: /* Esc [ O == F3 on
969 * FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000970 retval = KEY_F(3);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000971 break;
972 }
973 }
974 break;
975 case 'P': /* Esc [ P == F4 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000976 retval = KEY_F(4);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000977 break;
978 case 'Q': /* Esc [ Q == F5 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000979 retval = KEY_F(5);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000980 break;
981 case 'R': /* Esc [ R == F6 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000982 retval = KEY_F(6);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000983 break;
984 case 'S': /* Esc [ S == F7 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000985 retval = KEY_F(7);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000986 break;
987 case 'T': /* Esc [ T == F8 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000988 retval = KEY_F(8);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000989 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000990 case 'U': /* Esc [ U == PageDown on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000991 retval = NANO_NEXTPAGE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000992 break;
993 case 'V': /* Esc [ V == PageUp on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000994 retval = NANO_PREVPAGE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000995 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000996 case 'W': /* Esc [ W == F11 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000997 retval = KEY_F(11);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000998 break;
999 case 'X': /* Esc [ X == F12 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001000 retval = KEY_F(12);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001001 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001002 case 'Y': /* Esc [ Y == End on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001003 retval = NANO_END_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001004 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001005 case 'Z': /* Esc [ Z == F14 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001006 retval = KEY_F(14);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001007 break;
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +00001008 case 'a': /* Esc [ a == Shift-Up on rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +00001009 case 'b': /* Esc [ b == Shift-Down on rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +00001010 case 'c': /* Esc [ c == Shift-Right on
1011 * rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +00001012 case 'd': /* Esc [ d == Shift-Left on rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001013 retval = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001014 break;
1015 case '[':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001016 if (es_len >= 3) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001017 switch (escape_seq[2]) {
1018 case 'A': /* Esc [ [ A == F1 on Linux
1019 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001020 retval = KEY_F(1);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001021 break;
1022 case 'B': /* Esc [ [ B == F2 on Linux
1023 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001024 retval = KEY_F(2);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001025 break;
1026 case 'C': /* Esc [ [ C == F3 on Linux
1027 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001028 retval = KEY_F(3);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001029 break;
1030 case 'D': /* Esc [ [ D == F4 on Linux
1031 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001032 retval = KEY_F(4);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001033 break;
1034 case 'E': /* Esc [ [ E == F5 on Linux
1035 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001036 retval = KEY_F(5);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001037 break;
1038 }
1039 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001040 break;
1041 }
1042 break;
1043 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001044 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001045
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001046#ifdef DEBUG
David Lawrence Ramseye65e6392004-06-04 18:18:17 +00001047 fprintf(stderr, "get_escape_seq_kbinput(): retval = %d, ignore_seq = %d\n", retval, *ignore_seq);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001048#endif
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001049
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001050 return retval;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001051}
1052
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001053/* Return the equivalent arrow key value for the case-insensitive
David Lawrence Ramseyb7e5cf62004-02-07 03:39:48 +00001054 * letters A (up), B (down), C (right), and D (left). These are common
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001055 * to many escape sequences. */
1056int get_escape_seq_abcd(int kbinput)
1057{
1058 switch (tolower(kbinput)) {
1059 case 'a':
1060 return NANO_PREVLINE_KEY;
1061 case 'b':
1062 return NANO_NEXTLINE_KEY;
1063 case 'c':
1064 return NANO_FORWARD_KEY;
1065 case 'd':
1066 return NANO_BACK_KEY;
1067 default:
1068 return ERR;
1069 }
1070}
1071
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001072/* Read in a string of input characters (e.g. an escape sequence)
1073 * verbatim. Store the string in v_kbinput and return the length
1074 * of the string in v_len. Assume nodelay(win) is FALSE. */
1075int *get_verbatim_kbinput(WINDOW *win, int *v_kbinput, size_t
1076 *v_len, int allow_ascii)
1077{
1078 int kbinput;
1079 size_t i = 0, v_newlen = 0;
1080
1081#ifndef NANO_SMALL
1082 allow_pending_sigwinch(TRUE);
1083#endif
1084
1085 *v_len = 0;
1086 v_kbinput = (int *)nmalloc(sizeof(int));
1087
1088 /* Turn off flow control characters if necessary so that we can type
1089 * them in verbatim, and turn the keypad off so that we don't get
1090 * extended keypad values outside the ASCII range. */
1091 if (ISSET(PRESERVE))
1092 disable_flow_control();
1093 keypad(win, FALSE);
1094
1095 /* Read the first character using blocking input, since using
1096 * non-blocking input will eat up all unused CPU. Then increment
1097 * v_len and save the character in v_kbinput. */
1098 kbinput = wgetch(win);
1099 (*v_len)++;
1100 v_kbinput[0] = kbinput;
1101#ifdef DEBUG
1102 fprintf(stderr, "get_verbatim_kbinput(): kbinput = %d, v_len = %d\n", kbinput, *v_len);
1103#endif
1104
1105 /* Read any following characters using non-blocking input, until
1106 * there aren't any left to be read, and save the complete string of
1107 * characters in v_kbinput, incrementing v_len accordingly. We read
1108 * them all at once in order to minimize the chance that there might
1109 * be a delay greater than nodelay() provides for between them, in
1110 * which case we'll stop before all of them are read. */
1111 nodelay(win, TRUE);
1112 while ((kbinput = wgetch(win)) != ERR) {
1113 (*v_len)++;
1114 v_kbinput = (int *)nrealloc(v_kbinput, *v_len * sizeof(int));
1115 v_kbinput[*v_len - 1] = kbinput;
1116#ifdef DEBUG
1117 fprintf(stderr, "get_verbatim_kbinput(): kbinput = %d, v_len = %d\n", kbinput, *v_len);
1118#endif
1119 }
1120 nodelay(win, FALSE);
1121
1122 /* Pass the string of characters to get_untranslated_kbinput(), one
1123 * by one, so it can handle them as ASCII character sequences and/or
1124 * escape sequences. Filter out ERR's from v_kbinput in the
1125 * process; they shouldn't occur in the string of characters unless
1126 * we're reading an incomplete sequence, in which case we only want
1127 * to keep the complete sequence. */
1128 for (; i < *v_len; i++) {
1129 v_kbinput[v_newlen] = get_untranslated_kbinput(v_kbinput[i], i,
1130 allow_ascii
1131#ifndef NANO_SMALL
1132 , FALSE
1133#endif
1134 );
1135 if (v_kbinput[i] != ERR && v_kbinput[v_newlen] != ERR)
1136 v_newlen++;
1137 }
1138
1139 if (v_newlen == 0) {
1140 /* If there were no characters after the ERR's were filtered
1141 * out, set v_len and reallocate v_kbinput to account for
1142 * one character, and set that character to ERR. */
1143 *v_len = 1;
1144 v_kbinput = (int *)nrealloc(v_kbinput, sizeof(int));
1145 v_kbinput[0] = ERR;
1146 } else if (v_newlen != *v_len) {
1147 /* If there were fewer characters after the ERR's were filtered
1148 * out, set v_len and reallocate v_kbinput to account for
1149 * the new number of characters. */
1150 *v_len = v_newlen;
1151 v_kbinput = (int *)nrealloc(v_kbinput, *v_len * sizeof(int));
1152 }
1153
1154 /* If allow_ascii is TRUE and v_kbinput[0] is ERR, we need to
1155 * complete an ASCII character sequence. Keep reading in characters
1156 * using blocking input until we get a complete sequence. */
1157 if (allow_ascii && v_kbinput[0] == ERR) {
1158 while (v_kbinput[0] == ERR) {
1159 kbinput = wgetch(win);
1160 v_kbinput[0] = get_untranslated_kbinput(kbinput, i,
1161 allow_ascii
1162#ifndef NANO_SMALL
1163 , FALSE
1164#endif
1165 );
1166 i++;
1167 }
1168 }
1169
1170 /* Turn flow control characters back on if necessary and turn the
1171 * keypad back on now that we're done. */
1172 if (ISSET(PRESERVE))
1173 enable_flow_control();
1174 keypad(win, TRUE);
1175
1176#ifndef NANO_SMALL
1177 allow_pending_sigwinch(FALSE);
1178#endif
1179
1180 return v_kbinput;
1181}
1182
1183int get_untranslated_kbinput(int kbinput, size_t position, int
1184 allow_ascii
1185#ifndef NANO_SMALL
1186 , int reset
1187#endif
1188 )
1189{
1190 static size_t ascii_digits = 0;
1191 int retval;
1192
1193#ifndef NANO_SMALL
1194 if (reset) {
1195 ascii_digits = 0;
1196 return ERR;
1197 }
1198#endif
1199
1200 if (allow_ascii) {
1201 /* position is equal to the number of ASCII digits we've read so
1202 * far, and kbinput is a digit from '0' to '9': ASCII character
1203 * sequence mode. If the digit sequence's range is limited to
1204 * 2XX (the first digit is in the '0' to '2' range and it's the
1205 * first digit, or if it's in the full digit range and it's not
1206 * the first digit), increment the ASCII digit counter and
1207 * interpret the digit. If the digit sequence's range is not
1208 * limited to 2XX, fall through. */
1209 if (position == ascii_digits && kbinput >= '0' && kbinput <= '9') {
1210 if (kbinput <= '2' || ascii_digits > 0) {
1211 ascii_digits++;
1212 kbinput = get_ascii_kbinput(kbinput, ascii_digits
1213#ifndef NANO_SMALL
1214 , FALSE
1215#endif
1216 );
1217 if (kbinput != ERR)
1218 /* If we've read in a complete ASCII digit sequence,
1219 * reset the ASCII digit counter. */
1220 ascii_digits = 0;
1221 }
1222 } else if (ascii_digits > 0)
1223 /* position is not equal to the number of ASCII digits we've
1224 * read or kbinput is a non-digit, and we're in the middle
1225 * of an ASCII character sequence. Reset the ASCII digit
1226 * counter. */
1227 ascii_digits = 0;
1228 }
1229
1230 /* Save the corresponding ASCII character as the result if we've
1231 * read in a complete ASCII digit sequence, or the passed-in
1232 * character if we haven't. */
1233 retval = kbinput;
1234
1235#ifdef DEBUG
1236 fprintf(stderr, "get_untranslated_kbinput(): kbinput = %d, position = %d, ascii_digits = %d\n", kbinput, position, ascii_digits);
1237#endif
1238
1239 return retval;
1240}
1241
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001242#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001243/* Check for a mouse event, and if one's taken place, save the
1244 * coordinates where it took place in mouse_x and mouse_y. After that,
1245 * if allow_shortcuts is zero, return 0. Otherwise, if the mouse event
1246 * took place on the shortcut list on the bottom two lines of the screen
1247 * (assuming that the shortcut list is visible), figure out which
1248 * shortcut was clicked and ungetch() the equivalent keystroke(s).
1249 * Return 0 if no keystrokes were ungetch()ed, or 1 if at least one was.
1250 * Assume that KEY_MOUSE has already been read in. */
1251int get_mouseinput(int *mouse_x, int *mouse_y, int allow_shortcuts)
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001252{
1253 MEVENT mevent;
1254
1255 *mouse_x = -1;
1256 *mouse_y = -1;
1257
1258 /* First, get the actual mouse event. */
1259 if (getmouse(&mevent) == ERR)
1260 return 0;
1261
1262 /* Save the screen coordinates where the mouse event took place. */
1263 *mouse_x = mevent.x;
1264 *mouse_y = mevent.y;
1265
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001266 /* If we're not allowing shortcuts' we're done now. */
1267 if (!allow_shortcuts)
1268 return 0;
1269
1270 /* Otherwise, if the current shortcut list is being displayed on the
1271 * last two lines of the screen and the mouse event took place
1272 * inside it, we need to figure out which shortcut was clicked and
1273 * ungetch() the equivalent keystroke(s) for it. */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001274 if (!ISSET(NO_HELP) && wenclose(bottomwin, *mouse_y, *mouse_x)) {
1275 int i, j;
1276 int currslen;
1277 /* The number of shortcuts in the current shortcut list. */
1278 const shortcut *s = currshortcut;
1279 /* The actual shortcut we clicked on, starting at the first
1280 * one in the current shortcut list. */
1281
1282 /* Get the shortcut lists' length. */
1283 if (currshortcut == main_list)
1284 currslen = MAIN_VISIBLE;
1285 else
1286 currslen = length_of_list(currshortcut);
1287
1288 /* Calculate the width of each shortcut in the list (it's the
1289 * same for all of them). */
1290 if (currslen < 2)
1291 i = COLS / 6;
1292 else
1293 i = COLS / ((currslen / 2) + (currslen % 2));
1294
1295 /* Calculate the y-coordinates relative to the beginning of
1296 * bottomwin, i.e, the bottom three lines of the screen. */
1297 j = *mouse_y - (editwinrows + 3);
1298
1299 /* If we're on the statusbar, beyond the end of the shortcut
1300 * list, or beyond the end of a shortcut on the right side of
1301 * the screen, don't do anything. */
1302 if (j < 0 || (*mouse_x / i) >= currslen)
1303 return 0;
1304 j = (*mouse_x / i) * 2 + j;
1305 if (j >= currslen)
1306 return 0;
1307
1308 /* Go through the shortcut list to determine which shortcut was
1309 * clicked. */
1310 for (; j > 0; j--)
1311 s = s->next;
1312
David Lawrence Ramsey32613fa2004-05-24 18:40:41 +00001313 /* And ungetch() the equivalent control key. If it's a meta key
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001314 * sequence, we need to ungetch() Escape too. Assume that the
1315 * shortcut has an equivalent control key, meta key sequence, or
1316 * both. */
1317 if (s->ctrlval != NANO_NO_KEY)
1318 ungetch(s->ctrlval);
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001319 else if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001320 ungetch(s->metaval);
1321 ungetch(NANO_CONTROL_3);
1322 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001323
1324 return 1;
1325 }
1326 return 0;
1327}
1328#endif
1329
Chris Allegretta6df90f52002-07-19 01:08:59 +00001330/* Return the placewewant associated with current_x. That is, xplustabs
1331 * is the zero-based column position of the cursor. Value is no smaller
1332 * than current_x. */
1333size_t xplustabs(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001334{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001335 return strnlenpt(current->data, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001336}
1337
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001338/* actual_x() gives the index in str of the character displayed at
1339 * column xplus. That is, actual_x() is the largest value such that
1340 * strnlenpt(str, actual_x(str, xplus)) <= xplus. */
1341size_t actual_x(const char *str, size_t xplus)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001342{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001343 size_t i = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001344 /* the position in str, returned */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001345 size_t length = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001346 /* the screen display width to str[i] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001347
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001348 assert(str != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001349
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001350 for (; length < xplus && *str != '\0'; i++, str++) {
1351 if (*str == '\t')
David Lawrence Ramsey0362c582003-09-30 03:31:56 +00001352 length += tabsize - (length % tabsize);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001353 else if (is_cntrl_char((int)*str))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001354 length += 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001355 else
1356 length++;
1357 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001358 assert(length == strnlenpt(str - i, i));
1359 assert(i <= strlen(str - i));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001360
Chris Allegretta6df90f52002-07-19 01:08:59 +00001361 if (length > xplus)
1362 i--;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001363
Chris Allegretta6df90f52002-07-19 01:08:59 +00001364 return i;
Robert Siemborskid8510b22000-06-06 23:04:06 +00001365}
1366
David Lawrence Ramseya3370c42004-04-05 01:08:14 +00001367/* A strlen() with tabs factored in, similar to xplustabs(). How many
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +00001368 * columns wide are the first size characters of buf? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001369size_t strnlenpt(const char *buf, size_t size)
Robert Siemborskid8510b22000-06-06 23:04:06 +00001370{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001371 size_t length = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001372
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +00001373 assert(buf != NULL);
1374 for (; *buf != '\0' && size != 0; size--, buf++) {
1375 if (*buf == '\t')
1376 length += tabsize - (length % tabsize);
1377 else if (is_cntrl_char((int)*buf))
1378 length += 2;
1379 else
1380 length++;
1381 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001382 return length;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001383}
1384
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +00001385/* How many columns wide is buf? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001386size_t strlenpt(const char *buf)
Chris Allegrettad4fa0d32002-03-05 19:55:55 +00001387{
David Lawrence Ramsey0b047c52004-03-29 23:09:08 +00001388 return strnlenpt(buf, (size_t)-1);
Chris Allegrettad4fa0d32002-03-05 19:55:55 +00001389}
1390
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001391void blank_titlebar(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001392{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001393 mvwaddstr(topwin, 0, 0, hblank);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001394}
1395
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001396void blank_edit(void)
1397{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001398 size_t i;
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001399 for (i = 0; i < editwinrows; i++)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001400 mvwaddstr(edit, i, 0, hblank);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001401}
1402
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001403void blank_statusbar(void)
1404{
1405 mvwaddstr(bottomwin, 0, 0, hblank);
1406}
1407
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001408void check_statblank(void)
1409{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001410 if (statblank > 1)
1411 statblank--;
1412 else if (statblank == 1 && !ISSET(CONSTUPDATE)) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001413 statblank = 0;
1414 blank_statusbar();
1415 wnoutrefresh(bottomwin);
1416 reset_cursor();
1417 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001418 }
1419}
1420
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001421void blank_bottombars(void)
1422{
1423 if (!ISSET(NO_HELP)) {
1424 mvwaddstr(bottomwin, 1, 0, hblank);
1425 mvwaddstr(bottomwin, 2, 0, hblank);
1426 }
1427}
1428
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001429/* Convert buf into a string that can be displayed on screen. The
1430 * caller wants to display buf starting with column start_col, and
1431 * extending for at most len columns. start_col is zero-based. len is
1432 * one-based, so len == 0 means you get "" returned. The returned
1433 * string is dynamically allocated, and should be freed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001434char *display_string(const char *buf, size_t start_col, size_t len)
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001435{
1436 size_t start_index;
1437 /* Index in buf of first character shown in return value. */
1438 size_t column;
1439 /* Screen column start_index corresponds to. */
1440 size_t end_index;
1441 /* Index in buf of last character shown in return value. */
1442 size_t alloc_len;
1443 /* The length of memory allocated for converted. */
1444 char *converted;
1445 /* The string we return. */
1446 size_t index;
1447 /* Current position in converted. */
1448
1449 if (len == 0)
1450 return mallocstrcpy(NULL, "");
1451
1452 start_index = actual_x(buf, start_col);
1453 column = strnlenpt(buf, start_index);
1454 assert(column <= start_col);
1455 end_index = actual_x(buf, start_col + len - 1);
1456 alloc_len = strnlenpt(buf, end_index + 1) - column;
1457 if (len > alloc_len + column - start_col)
1458 len = alloc_len + column - start_col;
1459 converted = charalloc(alloc_len + 1);
1460 buf += start_index;
1461 index = 0;
1462
1463 for (; index < alloc_len; buf++) {
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00001464 if (*buf == '\t') {
1465 converted[index++] =
1466#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
1467 ISSET(WHITESPACE_DISPLAY) ? whitespace[0] :
1468#endif
1469 ' ';
1470 while ((column + index) % tabsize)
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001471 converted[index++] = ' ';
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00001472 } else if (is_cntrl_char(*buf)) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001473 converted[index++] = '^';
1474 if (*buf == '\n')
1475 /* Treat newlines embedded in a line as encoded nulls;
1476 * the line in question should be run through unsunder()
1477 * before reaching here. */
1478 converted[index++] = '@';
1479 else if (*buf == NANO_CONTROL_8)
1480 converted[index++] = '?';
1481 else
1482 converted[index++] = *buf + 64;
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00001483 } else if (*buf == ' ')
1484 converted[index++] =
1485#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
1486 ISSET(WHITESPACE_DISPLAY) ? whitespace[1] :
1487#endif
1488 ' ';
1489 else
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001490 converted[index++] = *buf;
1491 }
1492 assert(len <= alloc_len + column - start_col);
1493 charmove(converted, converted + start_col - column, len);
1494 null_at(&converted, len);
1495
1496 return charealloc(converted, len + 1);
1497}
1498
Chris Allegretta7662c862003-01-13 01:35:15 +00001499/* Repaint the statusbar when getting a character in nanogetstr(). buf
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001500 * should be no longer than max(0, COLS - 4).
Chris Allegretta6df90f52002-07-19 01:08:59 +00001501 *
Chris Allegretta7662c862003-01-13 01:35:15 +00001502 * Note that we must turn on A_REVERSE here, since do_help() turns it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001503 * off! */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001504void nanoget_repaint(const char *buf, const char *inputbuf, size_t x)
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001505{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001506 size_t x_real = strnlenpt(inputbuf, x);
1507 int wid = COLS - strlen(buf) - 2;
Chris Allegretta0d1e8d62000-11-02 15:30:24 +00001508
Chris Allegretta6df90f52002-07-19 01:08:59 +00001509 assert(0 <= x && x <= strlen(inputbuf));
1510
Chris Allegrettab3655b42001-10-22 03:15:31 +00001511 wattron(bottomwin, A_REVERSE);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001512 blank_statusbar();
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001513
Chris Allegretta6df90f52002-07-19 01:08:59 +00001514 mvwaddstr(bottomwin, 0, 0, buf);
1515 waddch(bottomwin, ':');
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001516
1517 if (COLS > 1)
1518 waddch(bottomwin, x_real < wid ? ' ' : '$');
1519 if (COLS > 2) {
1520 size_t page_start = x_real - x_real % wid;
1521 char *expanded = display_string(inputbuf, page_start, wid);
1522
1523 assert(wid > 0);
1524 assert(strlen(expanded) <= wid);
1525 waddstr(bottomwin, expanded);
1526 free(expanded);
1527 wmove(bottomwin, 0, COLS - wid + x_real - page_start);
1528 } else
1529 wmove(bottomwin, 0, COLS - 1);
Chris Allegrettab3655b42001-10-22 03:15:31 +00001530 wattroff(bottomwin, A_REVERSE);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001531}
1532
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001533/* Get the input from the keyboard; this should only be called from
Chris Allegretta6df90f52002-07-19 01:08:59 +00001534 * statusq(). */
Chris Allegrettaf717f982003-02-13 22:25:01 +00001535int nanogetstr(int allowtabs, const char *buf, const char *def,
Chris Allegretta5beed502003-01-05 20:41:21 +00001536#ifndef NANO_SMALL
1537 historyheadtype *history_list,
1538#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001539 const shortcut *s
Rocco Corsi06aca1c2001-01-11 05:30:31 +00001540#ifndef DISABLE_TABCOMP
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001541 , int *list
Chris Allegrettabe77c612000-11-24 14:00:16 +00001542#endif
Chris Allegretta65f075d2003-02-13 03:03:49 +00001543 )
Chris Allegretta6df90f52002-07-19 01:08:59 +00001544{
1545 int kbinput;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001546 int meta_key;
Chris Allegretta09fc4302003-01-16 22:16:38 +00001547 static int x = -1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001548 /* the cursor position in 'answer' */
1549 int xend;
1550 /* length of 'answer', the status bar text */
1551 int tabbed = 0;
1552 /* used by input_tab() */
1553 const shortcut *t;
Chris Allegretta598106e2002-01-19 01:59:37 +00001554
Chris Allegretta5beed502003-01-05 20:41:21 +00001555#ifndef NANO_SMALL
1556 /* for history */
1557 char *history = NULL;
Chris Allegretta8031f832003-01-09 05:29:58 +00001558 char *currentbuf = NULL;
Chris Allegretta5beed502003-01-05 20:41:21 +00001559 char *complete = NULL;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001560 int last_kbinput = 0;
1561
1562 /* This variable is used in the search history code. use_cb == 0
1563 means that we're using the existing history and ignoring
1564 currentbuf. use_cb == 1 means that the entry in answer should be
1565 moved to currentbuf or restored from currentbuf to answer.
1566 use_cb == 2 means that the entry in currentbuf should be moved to
1567 answer or restored from answer to currentbuf. */
1568 int use_cb = 0;
Chris Allegretta5beed502003-01-05 20:41:21 +00001569#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001570 xend = strlen(def);
Chris Allegretta09fc4302003-01-16 22:16:38 +00001571
1572 /* Only put x at the end of the string if it's uninitialized or if
1573 it would be past the end of the string as it is. Otherwise,
1574 leave it alone. This is so the cursor position stays at the same
1575 place if a prompt-changing toggle is pressed. */
Chris Allegretta65f075d2003-02-13 03:03:49 +00001576 if (x == -1 || x > xend || resetstatuspos)
Chris Allegretta09fc4302003-01-16 22:16:38 +00001577 x = xend;
1578
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00001579 answer = charealloc(answer, xend + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001580 if (xend > 0)
1581 strcpy(answer, def);
1582 else
1583 answer[0] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001584
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001585#if !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001586 currshortcut = s;
Chris Allegretta6fe61492001-05-21 12:56:25 +00001587#endif
1588
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001589 /* Get the input! */
Chris Allegretta31925e42000-11-02 04:40:39 +00001590
Chris Allegretta6df90f52002-07-19 01:08:59 +00001591 nanoget_repaint(buf, answer, x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001592
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001593 /* Make sure any editor screen updates are displayed before getting
1594 input */
Chris Allegretta022b96f2000-11-14 17:47:58 +00001595 wrefresh(edit);
1596
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00001597 /* If we're using restricted mode, we aren't allowed to change the
1598 * name of a file once it has one because that would allow writing
1599 * to files not specified on the command line. In this case,
1600 * disable all keys that would change the text if the filename isn't
1601 * blank and we're at the "Write File" prompt. */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001602 while ((kbinput = get_kbinput(bottomwin, &meta_key)) != NANO_ENTER_KEY) {
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001603 for (t = s; t != NULL; t = t->next) {
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001604#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001605 fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput, kbinput);
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001606#endif
1607
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001608 /* Temporary hack to interpret NANO_HELP_FKEY correctly. */
1609 if (kbinput == t->funcval)
1610 kbinput = t->ctrlval;
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00001611
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001612 if (kbinput == t->ctrlval && is_cntrl_char(kbinput)) {
Chris Allegretta5bf51d32000-11-16 06:01:10 +00001613
Chris Allegrettab3655b42001-10-22 03:15:31 +00001614#ifndef DISABLE_HELP
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001615 /* Have to do this here, it would be too late to do it
1616 in statusq() */
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00001617 if (kbinput == NANO_HELP_KEY) {
Chris Allegrettab3655b42001-10-22 03:15:31 +00001618 do_help();
1619 break;
1620 }
1621#endif
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001622#ifndef NANO_SMALL
1623 /* Have to handle these here too, for the time being */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001624 if (kbinput == NANO_PREVLINE_KEY || kbinput == NANO_NEXTLINE_KEY)
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001625 break;
1626#endif
Chris Allegretta5af58892003-01-17 21:07:38 +00001627
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001628 return t->ctrlval;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001629 }
1630 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001631 assert(0 <= x && x <= xend && xend == strlen(answer));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001632
Chris Allegretta04d848e2000-11-05 17:54:41 +00001633 if (kbinput != '\t')
1634 tabbed = 0;
1635
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001636 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001637#ifndef DISABLE_MOUSE
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001638 case KEY_MOUSE:
1639 do_mouse();
1640 break;
1641#endif
Chris Allegretta658399a2001-06-14 02:54:22 +00001642 case NANO_HOME_KEY:
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00001643#ifndef NANO_SMALL
1644 if (ISSET(SMART_HOME)) {
1645 int old_x = x;
1646
1647 for (x = 0; isblank(answer[x]) && x < xend; x++)
1648 ;
1649
1650 if (x == old_x || x == xend)
1651 x = 0;
1652 } else
1653#endif
1654 x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001655 break;
Chris Allegretta658399a2001-06-14 02:54:22 +00001656 case NANO_END_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001657 x = xend;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001658 break;
Chris Allegretta35dac582001-03-21 15:07:20 +00001659 case NANO_FORWARD_KEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001660 if (x < xend)
1661 x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001662 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001663 case NANO_DELETE_KEY:
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00001664 /* If we're using restricted mode, the filename isn't blank,
1665 * and we're at the "Write File" prompt, disable Delete. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001666 if (!ISSET(RESTRICTED) || filename[0] == '\0' || s != writefile_list) {
1667 if (x < xend) {
1668 charmove(answer + x, answer + x + 1, xend - x);
1669 xend--;
1670 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001671 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001672 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001673 case NANO_CUT_KEY:
1674 case NANO_UNCUT_KEY:
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00001675 /* If we're using restricted mode, the filename isn't blank,
1676 * and we're at the "Write File" prompt, disable Cut and
1677 * UnCut. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001678 if (!ISSET(RESTRICTED) || filename[0] == '\0' || s != writefile_list) {
1679 null_at(&answer, 0);
1680 xend = 0;
1681 x = 0;
1682 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001683 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001684 case NANO_BACKSPACE_KEY:
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00001685 /* If we're using restricted mode, the filename isn't blank,
1686 * and we're at the "Write File" prompt, disable
1687 * Backspace. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001688 if (!ISSET(RESTRICTED) || filename[0] == '\0' || s != writefile_list) {
1689 if (x > 0) {
1690 charmove(answer + x - 1, answer + x, xend - x + 1);
1691 x--;
1692 xend--;
1693 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001694 }
Chris Allegretta04d848e2000-11-05 17:54:41 +00001695 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001696 case NANO_TAB_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001697#ifndef NANO_SMALL
1698 /* tab history completion */
Chris Allegretta7662c862003-01-13 01:35:15 +00001699 if (history_list != NULL) {
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001700 if (!complete || last_kbinput != NANO_TAB_KEY) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001701 history_list->current = (historytype *)history_list;
1702 history_list->len = strlen(answer);
1703 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001704
Chris Allegretta7662c862003-01-13 01:35:15 +00001705 if (history_list->len > 0) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001706 complete = get_history_completion(history_list, answer);
1707 xend = strlen(complete);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001708 x = xend;
Chris Allegretta5beed502003-01-05 20:41:21 +00001709 answer = mallocstrcpy(answer, complete);
1710 }
Chris Allegretta7da4e9f2000-11-06 02:57:22 +00001711 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001712#ifndef DISABLE_TABCOMP
Chris Allegretta327abda2003-01-17 05:04:17 +00001713 else
1714#endif
Chris Allegrettabe77c612000-11-24 14:00:16 +00001715#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001716#ifndef DISABLE_TABCOMP
Chris Allegretta327abda2003-01-17 05:04:17 +00001717 if (allowtabs) {
1718 int shift = 0;
Chris Allegretta5beed502003-01-05 20:41:21 +00001719
Chris Allegretta327abda2003-01-17 05:04:17 +00001720 answer = input_tab(answer, x, &tabbed, &shift, list);
1721 xend = strlen(answer);
1722 x += shift;
1723 if (x > xend)
1724 x = xend;
Chris Allegretta5beed502003-01-05 20:41:21 +00001725 }
1726#endif
1727 break;
Chris Allegretta35dac582001-03-21 15:07:20 +00001728 case NANO_BACK_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001729 if (x > 0)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001730 x--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001731 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001732 case NANO_PREVLINE_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001733#ifndef NANO_SMALL
Chris Allegretta09fc4302003-01-16 22:16:38 +00001734 if (history_list != NULL) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001735
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001736 /* if currentbuf is NULL, or if use_cb is 1, currentbuf
1737 isn't NULL, and currentbuf is different from answer,
1738 it means that we're scrolling up at the top of the
1739 search history, and we need to save the current
1740 answer in currentbuf; do this and reset use_cb to
1741 0 */
1742 if (currentbuf == NULL || (use_cb == 1 && strcmp(currentbuf, answer))) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001743 currentbuf = mallocstrcpy(currentbuf, answer);
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001744 use_cb = 0;
Chris Allegretta8031f832003-01-09 05:29:58 +00001745 }
1746
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001747 /* if currentbuf isn't NULL, use_cb is 2, and currentbuf
1748 is different from answer, it means that we're
1749 scrolling up at the bottom of the search history, and
1750 we need to make the string in currentbuf the current
1751 answer; do this, blow away currentbuf since we don't
1752 need it anymore, and reset use_cb to 0 */
1753 if (currentbuf != NULL && use_cb == 2 && strcmp(currentbuf, answer)) {
1754 answer = mallocstrcpy(answer, currentbuf);
1755 free(currentbuf);
1756 currentbuf = NULL;
1757 xend = strlen(answer);
1758 use_cb = 0;
1759
1760 /* else get older search from the history list and save
1761 it in answer; if there is no older search, blank out
1762 answer */
1763 } else if ((history = get_history_older(history_list)) != NULL) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001764 answer = mallocstrcpy(answer, history);
1765 xend = strlen(history);
1766 } else {
1767 answer = mallocstrcpy(answer, "");
1768 xend = 0;
1769 }
1770 x = xend;
1771 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001772#endif
Chris Allegretta54abd942003-01-09 23:43:12 +00001773 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001774 case NANO_NEXTLINE_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001775#ifndef NANO_SMALL
Chris Allegretta09fc4302003-01-16 22:16:38 +00001776 if (history_list != NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001777
1778 /* get newer search from the history list and save it
1779 in answer */
Chris Allegretta7662c862003-01-13 01:35:15 +00001780 if ((history = get_history_newer(history_list)) != NULL) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001781 answer = mallocstrcpy(answer, history);
1782 xend = strlen(history);
Chris Allegretta8031f832003-01-09 05:29:58 +00001783
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001784 /* if there is no newer search, we're here */
1785
1786 /* if currentbuf isn't NULL and use_cb isn't 2, it means
1787 that we're scrolling down at the bottom of the search
1788 history and we need to make the string in currentbuf
1789 the current answer; do this, blow away currentbuf
1790 since we don't need it anymore, and set use_cb to
1791 1 */
1792 } else if (currentbuf != NULL && use_cb != 2) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001793 answer = mallocstrcpy(answer, currentbuf);
Chris Allegretta09fc4302003-01-16 22:16:38 +00001794 free(currentbuf);
1795 currentbuf = NULL;
1796 xend = strlen(answer);
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001797 use_cb = 1;
1798
1799 /* otherwise, if currentbuf is NULL and use_cb isn't 2,
1800 it means that we're scrolling down at the bottom of
Chris Allegrettac30fc242003-08-11 00:32:45 +00001801 the search history and the current answer (if it's
1802 not blank) needs to be saved in currentbuf; do this,
1803 blank out answer (if necessary), and set use_cb to
1804 2 */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001805 } else if (use_cb != 2) {
Chris Allegrettac30fc242003-08-11 00:32:45 +00001806 if (answer[0] != '\0') {
1807 currentbuf = mallocstrcpy(currentbuf, answer);
1808 answer = mallocstrcpy(answer, "");
1809 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001810 xend = 0;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001811 use_cb = 2;
Chris Allegretta5beed502003-01-05 20:41:21 +00001812 }
1813 x = xend;
1814 }
1815#endif
1816 break;
Chris Allegretta658399a2001-06-14 02:54:22 +00001817 default:
1818
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001819 for (t = s; t != NULL; t = t->next) {
Chris Allegretta658399a2001-06-14 02:54:22 +00001820#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001821 fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput,
Chris Allegretta598106e2002-01-19 01:59:37 +00001822 kbinput);
Chris Allegretta658399a2001-06-14 02:54:22 +00001823#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001824 if (meta_key == TRUE && (kbinput == t->metaval || kbinput == t->miscval))
David Lawrence Ramsey32613fa2004-05-24 18:40:41 +00001825 /* We hit a meta key. Do like above. We don't
David Lawrence Ramsey82138502003-12-24 08:03:54 +00001826 * just ungetch() the letter and let it get
1827 * caught above cause that screws the
1828 * keypad... */
1829 return kbinput;
Chris Allegretta658399a2001-06-14 02:54:22 +00001830 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001831
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00001832 /* If we're using restricted mode, the filename isn't blank,
1833 * and we're at the "Write File" prompt, act as though the
1834 * unhandled character we got is a control character and
1835 * throw it away. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001836 if (is_cntrl_char(kbinput) || (ISSET(RESTRICTED) && filename[0] != '\0' && s == writefile_list))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001837 break;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001838 answer = charealloc(answer, xend + 2);
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001839 charmove(answer + x + 1, answer + x, xend - x + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001840 xend++;
1841 answer[x] = kbinput;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001842 x++;
1843
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001844#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001845 fprintf(stderr, "input \'%c\' (%d)\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001846#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001847 } /* switch (kbinput) */
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001848#ifndef NANO_SMALL
Chris Allegretta5beed502003-01-05 20:41:21 +00001849 last_kbinput = kbinput;
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001850#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001851 nanoget_repaint(buf, answer, x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001852 wrefresh(bottomwin);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001853 } /* while (kbinput ...) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001854
Chris Allegretta5af58892003-01-17 21:07:38 +00001855 /* We finished putting in an answer; reset x */
1856 x = -1;
1857
Chris Allegretta7662c862003-01-13 01:35:15 +00001858 /* Just check for a blank answer here */
Chris Allegretta15c28f82003-01-05 21:47:06 +00001859 if (answer[0] == '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001860 return -2;
1861 else
1862 return 0;
1863}
1864
Chris Allegrettaf717f982003-02-13 22:25:01 +00001865void titlebar(const char *path)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001866{
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001867 size_t space;
1868 /* The space we have available for display. */
1869 size_t verlen = strlen(VERMSG) + 1;
1870 /* The length of the version message. */
1871 const char *prefix;
1872 /* "File:", "Dir:", or "New Buffer". Goes before filename. */
1873 size_t prefixlen;
1874 /* strlen(prefix) + 1. */
1875 const char *state;
1876 /* "Modified", "View", or spaces the length of "Modified".
1877 * Tells the state of this buffer. */
1878 size_t statelen = 0;
1879 /* strlen(state) + 1. */
1880 char *exppath = NULL;
1881 /* The file name, expanded for display. */
1882 size_t explen = 0;
1883 /* strlen(exppath) + 1. */
1884 int newbuffer = FALSE;
1885 /* Do we say "New Buffer"? */
1886 int dots = FALSE;
1887 /* Do we put an ellipsis before the path? */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001888
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001889 assert(path != NULL || filename != NULL);
1890 assert(COLS >= 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001891
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001892 wattron(topwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001893
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001894 blank_titlebar();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001895
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001896 if (COLS <= 5 || COLS - 5 < verlen)
1897 space = 0;
1898 else {
1899 space = COLS - 5 - verlen;
David Lawrence Ramsey8328fc22004-05-25 23:34:43 +00001900 /* Reserve 2/3 of the screen plus one column for after the
1901 * version message. */
1902 if (space < COLS - (COLS / 3) + 1)
1903 space = COLS - (COLS / 3) + 1;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001904 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001905
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001906 if (COLS > 4) {
David Lawrence Ramsey8328fc22004-05-25 23:34:43 +00001907 /* The version message should only take up 1/3 of the screen
1908 * minus one column. */
1909 mvwaddnstr(topwin, 0, 2, VERMSG, (COLS / 3) - 3);
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001910 waddstr(topwin, " ");
1911 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001912
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001913 if (ISSET(MODIFIED))
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001914 state = _("Modified");
1915 else if (path == NULL && ISSET(VIEW_MODE))
1916 state = _("View");
1917 else {
1918 if (space > 0)
1919 statelen = strnlen(_("Modified"), space - 1) + 1;
1920 state = &hblank[COLS - statelen];
1921 }
1922 statelen = strnlen(state, COLS);
1923 /* We need a space before state. */
1924 if ((ISSET(MODIFIED) || ISSET(VIEW_MODE)) && statelen < COLS)
1925 statelen++;
1926
1927 assert(space >= 0);
1928 if (space == 0 || statelen >= space)
1929 goto the_end;
1930
1931#ifndef DISABLE_BROWSER
1932 if (path != NULL)
1933 prefix = _("DIR:");
1934 else
1935#endif
1936 if (filename[0] == '\0') {
1937 prefix = _("New Buffer");
1938 newbuffer = TRUE;
1939 } else
1940 prefix = _("File:");
1941 assert(statelen < space);
1942 prefixlen = strnlen(prefix, space - statelen);
1943 /* If newbuffer is FALSE, we need a space after prefix. */
1944 if (!newbuffer && prefixlen + statelen < space)
1945 prefixlen++;
1946
1947 if (path == NULL)
1948 path = filename;
David Lawrence Ramsey1dcf36a2004-05-23 21:17:56 +00001949 space -= prefixlen + statelen;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001950 /* space is now the room we have for the file name. */
1951 if (!newbuffer) {
1952 size_t lenpt = strlenpt(path), start_col;
1953
1954 if (lenpt > space)
1955 start_col = actual_x(path, lenpt - space);
1956 else
1957 start_col = 0;
1958 exppath = display_string(path, start_col, space);
1959 dots = (lenpt > space);
1960 explen = strlen(exppath);
1961 }
1962
1963 if (!dots) {
1964 /* There is room for the whole filename, so we center it. */
1965 waddnstr(topwin, hblank, (space - explen) / 3);
1966 waddnstr(topwin, prefix, prefixlen);
1967 if (!newbuffer) {
1968 assert(strlen(prefix) + 1 == prefixlen);
1969 waddch(topwin, ' ');
1970 waddstr(topwin, exppath);
1971 }
1972 } else {
1973 /* We will say something like "File: ...ename". */
1974 waddnstr(topwin, prefix, prefixlen);
David Lawrence Ramsey1dcf36a2004-05-23 21:17:56 +00001975 if (space <= 0 || newbuffer)
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001976 goto the_end;
1977 waddch(topwin, ' ');
1978 waddnstr(topwin, "...", space);
1979 if (space <= 3)
1980 goto the_end;
1981 space -= 3;
1982 assert(explen = space + 3);
1983 waddnstr(topwin, exppath + 3, space);
1984 }
1985
1986 the_end:
1987
1988 free(exppath);
1989
1990 if (COLS <= 1 || statelen >= COLS - 1)
1991 mvwaddnstr(topwin, 0, 0, state, COLS);
1992 else {
1993 assert(COLS - statelen - 2 >= 0);
1994 mvwaddch(topwin, 0, COLS - statelen - 2, ' ');
1995 mvwaddnstr(topwin, 0, COLS - statelen - 1, state, statelen);
1996 }
Chris Allegretta8ce24132001-04-30 11:28:46 +00001997
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001998 wattroff(topwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001999
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002000 wnoutrefresh(topwin);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002001 reset_cursor();
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002002 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002003}
2004
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002005/* If modified is not already set, set it and update titlebar. */
2006void set_modified(void)
2007{
2008 if (!ISSET(MODIFIED)) {
2009 SET(MODIFIED);
2010 titlebar(NULL);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002011 }
2012}
2013
2014void statusbar(const char *msg, ...)
2015{
2016 va_list ap;
2017
2018 va_start(ap, msg);
2019
2020 /* Curses mode is turned off. If we use wmove() now, it will muck
2021 * up the terminal settings. So we just use vfprintf(). */
2022 if (curses_ended) {
2023 vfprintf(stderr, msg, ap);
2024 va_end(ap);
2025 return;
2026 }
2027
2028 /* Blank out the line. */
2029 blank_statusbar();
2030
2031 if (COLS >= 4) {
2032 char *bar;
2033 char *foo;
2034 size_t start_x = 0, foo_len;
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00002035#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
2036 int old_whitespace = ISSET(WHITESPACE_DISPLAY);
2037 UNSET(WHITESPACE_DISPLAY);
2038#endif
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002039 bar = charalloc(COLS - 3);
2040 vsnprintf(bar, COLS - 3, msg, ap);
2041 va_end(ap);
2042 foo = display_string(bar, 0, COLS - 4);
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00002043#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
2044 if (old_whitespace)
2045 SET(WHITESPACE_DISPLAY);
2046#endif
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002047 free(bar);
2048 foo_len = strlen(foo);
2049 start_x = (COLS - foo_len - 4) / 2;
2050
2051 wmove(bottomwin, 0, start_x);
2052 wattron(bottomwin, A_REVERSE);
2053
2054 waddstr(bottomwin, "[ ");
2055 waddstr(bottomwin, foo);
2056 free(foo);
2057 waddstr(bottomwin, " ]");
2058 wattroff(bottomwin, A_REVERSE);
2059 wnoutrefresh(bottomwin);
2060 reset_cursor();
2061 wrefresh(edit);
2062 /* Leave the cursor at its position in the edit window, not
2063 * in the statusbar. */
2064 }
2065
2066 SET(DISABLE_CURPOS);
2067 statblank = 26;
2068}
2069
Chris Allegretta6232d662002-05-12 19:52:15 +00002070void bottombars(const shortcut *s)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002071{
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002072 size_t i, colwidth, slen;
2073 char *keystr;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002074
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002075 if (ISSET(NO_HELP))
2076 return;
2077
Chris Allegretta6232d662002-05-12 19:52:15 +00002078 if (s == main_list) {
2079 slen = MAIN_VISIBLE;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002080 assert(slen <= length_of_list(s));
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002081 } else {
Chris Allegretta6232d662002-05-12 19:52:15 +00002082 slen = length_of_list(s);
2083
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002084 /* Don't show any more shortcuts than the main list does. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002085 if (slen > MAIN_VISIBLE)
2086 slen = MAIN_VISIBLE;
2087 }
2088
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002089 /* There will be this many characters per column. We need at least
2090 * 3 to display anything properly.*/
2091 colwidth = COLS / ((slen / 2) + (slen % 2));
2092 keystr = charalloc(colwidth);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002093
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002094 blank_bottombars();
Chris Allegretta658399a2001-06-14 02:54:22 +00002095
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002096 for (i = 0; i < slen; i++, s = s->next) {
2097 wmove(bottomwin, 1 + i % 2, (i / 2) * colwidth);
Chris Allegretta658399a2001-06-14 02:54:22 +00002098
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002099 /* Yucky sentinel values we can't handle a better way. */
Chris Allegrettaa65ba512003-01-05 20:57:07 +00002100#ifndef NANO_SMALL
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002101 if (s->ctrlval == NANO_HISTORY_KEY)
2102 strncpy(keystr, _("Up"), colwidth);
2103 else
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002104#endif
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002105 if (s->ctrlval == NANO_CONTROL_SPACE)
2106 strncpy(keystr, "^ ", colwidth);
2107 else if (s->ctrlval == NANO_CONTROL_8)
2108 strncpy(keystr, "^?", colwidth);
2109 /* Normal values. Assume that the shortcut has an equivalent
2110 * control key, meta key sequence, or both. */
2111 else if (s->ctrlval != NANO_NO_KEY)
2112 snprintf(keystr, colwidth, "^%c", s->ctrlval + 64);
2113 else if (s->metaval != NANO_NO_KEY)
2114 snprintf(keystr, colwidth, "M-%c", toupper(s->metaval));
Chris Allegretta658399a2001-06-14 02:54:22 +00002115
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002116 onekey(keystr, s->desc, colwidth);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002117 }
2118
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002119 free(keystr);
2120
2121 wnoutrefresh(bottomwin);
2122 reset_cursor();
2123 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002124}
2125
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002126/* Write a shortcut key to the help area at the bottom of the window.
2127 * keystroke is e.g. "^G" and desc is e.g. "Get Help". We are careful
2128 * to write at most len characters, even if len is very small and
2129 * keystroke and desc are long. Note that waddnstr(,,(size_t)-1) adds
2130 * the whole string! We do not bother padding the entry with blanks. */
2131void onekey(const char *keystroke, const char *desc, size_t len)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002132{
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002133 assert(keystroke != NULL && desc != NULL && len >= 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002134 wattron(bottomwin, A_REVERSE);
2135 waddnstr(bottomwin, keystroke, len);
2136 wattroff(bottomwin, A_REVERSE);
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002137 len -= strlen(keystroke) + 1;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002138 if (len > 0) {
2139 waddch(bottomwin, ' ');
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002140 waddnstr(bottomwin, desc, len);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002141 }
2142}
2143
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002144/* And so start the display update routines. */
2145
2146#ifndef NDEBUG
2147int check_linenumbers(const filestruct *fileptr)
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002148{
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002149 int check_line = 0;
2150 const filestruct *filetmp;
Robert Siemborskid8510b22000-06-06 23:04:06 +00002151
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002152 for (filetmp = edittop; filetmp != fileptr; filetmp = filetmp->next)
2153 check_line++;
2154 return check_line;
Robert Siemborskid8510b22000-06-06 23:04:06 +00002155}
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002156#endif
Robert Siemborskid8510b22000-06-06 23:04:06 +00002157
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00002158/* nano scrolls horizontally within a line in chunks. This function
2159 * returns the column number of the first character displayed in the
2160 * window when the cursor is at the given column. Note that
2161 * 0 <= column - get_page_start(column) < COLS. */
2162size_t get_page_start(size_t column)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002163{
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00002164 assert(COLS > 0);
2165 if (column == 0 || column < COLS - 1)
2166 return 0;
2167 else if (COLS > 9)
David Lawrence Ramsey66081d42004-01-22 07:25:31 +00002168 return column - 7 - (column - 7) % (COLS - 8);
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00002169 else if (COLS > 2)
2170 return column - (COLS - 2);
2171 else
2172 return column - (COLS - 1);
2173 /* The parentheses are necessary to avoid overflow. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002174}
2175
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002176/* Resets current_y, based on the position of current, and puts the
2177 * cursor at (current_y, current_x). */
2178void reset_cursor(void)
2179{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002180 /* Yuck. This condition can be true after open_file() when opening
2181 * the first file. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002182 if (edittop == NULL)
2183 return;
2184
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002185 current_y = current->lineno - edittop->lineno;
2186 if (current_y < editwinrows) {
2187 size_t x = xplustabs();
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002188
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002189 wmove(edit, current_y, x - get_page_start(x));
2190 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002191}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002192
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002193/* edit_add() takes care of the job of actually painting a line into the
2194 * edit window. fileptr is the line to be painted, at row yval of the
2195 * window. converted is the actual string to be written to the window,
2196 * with tabs and control characters replaced by strings of regular
David Lawrence Ramsey4178db02004-05-23 21:23:23 +00002197 * characters. start is the column number of the first character of
2198 * this page. That is, the first character of converted corresponds to
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002199 * character number actual_x(fileptr->data, start) of the line. */
David Lawrence Ramsey07d3feb2004-04-16 05:15:11 +00002200void edit_add(const filestruct *fileptr, const char *converted, int
2201 yval, size_t start)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002202{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002203#if defined(ENABLE_COLOR) || !defined(NANO_SMALL)
2204 size_t startpos = actual_x(fileptr->data, start);
2205 /* The position in fileptr->data of the leftmost character
2206 * that displays at least partially on the window. */
2207 size_t endpos = actual_x(fileptr->data, start + COLS - 1) + 1;
2208 /* The position in fileptr->data of the first character that is
2209 * completely off the window to the right.
2210 *
2211 * Note that endpos might be beyond the null terminator of the
2212 * string. */
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002213#endif
2214
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002215 assert(fileptr != NULL && converted != NULL);
2216 assert(strlen(converted) <= COLS);
2217
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002218 /* Just paint the string in any case (we'll add color or reverse on
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002219 * just the text that needs it). */
2220 mvwaddstr(edit, yval, 0, converted);
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002221
Chris Allegretta7dd77682001-12-08 19:52:28 +00002222#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002223 if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002224 const colortype *tmpcolor = colorstrings;
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002225
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002226 for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
2227 int x_start;
2228 /* Starting column for mvwaddnstr. Zero-based. */
2229 int paintlen;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002230 /* Number of chars to paint on this line. There are COLS
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002231 * characters on a whole line. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002232 regmatch_t startmatch; /* match position for start_regexp */
2233 regmatch_t endmatch; /* match position for end_regexp */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002234
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002235 if (tmpcolor->bright)
2236 wattron(edit, A_BOLD);
2237 wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002238 /* Two notes about regexec(). Return value 0 means there is
2239 * a match. Also, rm_eo is the first non-matching character
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002240 * after the match. */
2241
2242 /* First case, tmpcolor is a single-line expression. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002243 if (tmpcolor->end == NULL) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002244 size_t k = 0;
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002245
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002246 /* We increment k by rm_eo, to move past the end of the
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002247 * last match. Even though two matches may overlap, we
2248 * want to ignore them, so that we can highlight
2249 * C-strings correctly. */
2250 while (k < endpos) {
2251 /* Note the fifth parameter to regexec(). It says
2252 * not to match the beginning-of-line character
2253 * unless k is 0. If regexec() returns REG_NOMATCH,
2254 * there are no more matches in the line. */
Chris Allegrettace452fb2003-02-03 02:56:44 +00002255 if (regexec(&tmpcolor->start, &fileptr->data[k], 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002256 &startmatch, k == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002257 break;
2258 /* Translate the match to the beginning of the line. */
2259 startmatch.rm_so += k;
2260 startmatch.rm_eo += k;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002261 if (startmatch.rm_so == startmatch.rm_eo) {
2262 startmatch.rm_eo++;
Chris Allegretta7c27be42002-05-05 23:03:54 +00002263 statusbar(_("Refusing 0 length regex match"));
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002264 } else if (startmatch.rm_so < endpos &&
2265 startmatch.rm_eo > startpos) {
2266 if (startmatch.rm_so <= startpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002267 x_start = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002268 else
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002269 x_start = strnlenpt(fileptr->data,
2270 startmatch.rm_so) - start;
2271 paintlen = strnlenpt(fileptr->data,
2272 startmatch.rm_eo) - start - x_start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002273 if (paintlen > COLS - x_start)
2274 paintlen = COLS - x_start;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002275
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002276 assert(0 <= x_start && 0 < paintlen &&
2277 x_start + paintlen <= COLS);
2278 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002279 converted + x_start, paintlen);
2280 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002281 k = startmatch.rm_eo;
Chris Allegretta598106e2002-01-19 01:59:37 +00002282 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002283 } else {
2284 /* This is a multi-line regexp. There are two steps.
2285 * First, we have to see if the beginning of the line is
2286 * colored by a start on an earlier line, and an end on
2287 * this line or later.
2288 *
2289 * We find the first line before fileptr matching the
2290 * start. If every match on that line is followed by an
2291 * end, then go to step two. Otherwise, find the next line
2292 * after start_line matching the end. If that line is not
2293 * before fileptr, then paint the beginning of this line. */
Chris Allegretta3674c1d2002-05-12 20:43:49 +00002294
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002295 const filestruct *start_line = fileptr->prev;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002296 /* the first line before fileptr matching start */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002297 regoff_t start_col;
2298 /* where it starts in that line */
2299 const filestruct *end_line;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002300
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002301 while (start_line != NULL &&
Chris Allegrettace452fb2003-02-03 02:56:44 +00002302 regexec(&tmpcolor->start, start_line->data, 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002303 &startmatch, 0) == REG_NOMATCH) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002304 /* If there is an end on this line, there is no need
2305 * to look for starts on earlier lines. */
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002306 if (regexec(tmpcolor->end, start_line->data, 0,
2307 NULL, 0) == 0)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002308 goto step_two;
2309 start_line = start_line->prev;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002310 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002311 /* No start found, so skip to the next step. */
2312 if (start_line == NULL)
2313 goto step_two;
2314 /* Now start_line is the first line before fileptr
2315 * containing a start match. Is there a start on this
2316 * line not followed by an end on this line? */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002317
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002318 start_col = 0;
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002319 while (TRUE) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002320 start_col += startmatch.rm_so;
2321 startmatch.rm_eo -= startmatch.rm_so;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002322 if (regexec(tmpcolor->end,
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002323 start_line->data + start_col + startmatch.rm_eo,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002324 0, NULL, start_col + startmatch.rm_eo == 0 ? 0 :
2325 REG_NOTBOL) == REG_NOMATCH)
2326 /* No end found after this start. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002327 break;
2328 start_col++;
Chris Allegrettace452fb2003-02-03 02:56:44 +00002329 if (regexec(&tmpcolor->start,
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002330 start_line->data + start_col, 1,
2331 &startmatch, REG_NOTBOL) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002332 /* No later start on this line. */
2333 goto step_two;
2334 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002335 /* Indeed, there is a start not followed on this line by
2336 * an end. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002337
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002338 /* We have already checked that there is no end before
2339 * fileptr and after the start. Is there an end after
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002340 * the start at all? We don't paint unterminated
2341 * starts. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002342 end_line = fileptr;
Chris Allegrettace452fb2003-02-03 02:56:44 +00002343 while (end_line != NULL &&
2344 regexec(tmpcolor->end, end_line->data, 1, &endmatch, 0))
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002345 end_line = end_line->next;
2346
2347 /* No end found, or it is too early. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002348 if (end_line == NULL ||
2349 (end_line == fileptr && endmatch.rm_eo <= startpos))
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002350 goto step_two;
2351
2352 /* Now paint the start of fileptr. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002353 paintlen = end_line != fileptr ? COLS :
2354 strnlenpt(fileptr->data, endmatch.rm_eo) - start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002355 if (paintlen > COLS)
2356 paintlen = COLS;
2357
2358 assert(0 < paintlen && paintlen <= COLS);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002359 mvwaddnstr(edit, yval, 0, converted, paintlen);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002360
2361 /* We have already painted the whole line. */
2362 if (paintlen == COLS)
2363 goto skip_step_two;
2364
David Lawrence Ramsey94e70942004-05-13 18:04:31 +00002365 step_two:
2366 /* Second step, we look for starts on this line. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002367 start_col = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002368 while (start_col < endpos) {
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002369 if (regexec(&tmpcolor->start,
2370 fileptr->data + start_col, 1, &startmatch,
2371 start_col == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH ||
2372 start_col + startmatch.rm_so >= endpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002373 /* No more starts on this line. */
2374 break;
2375 /* Translate the match to be relative to the
2376 * beginning of the line. */
2377 startmatch.rm_so += start_col;
2378 startmatch.rm_eo += start_col;
2379
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002380 if (startmatch.rm_so <= startpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002381 x_start = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002382 else
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002383 x_start = strnlenpt(fileptr->data,
2384 startmatch.rm_so) - start;
2385 if (regexec(tmpcolor->end,
2386 fileptr->data + startmatch.rm_eo, 1, &endmatch,
2387 startmatch.rm_eo == 0 ? 0 : REG_NOTBOL) == 0) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002388 /* Translate the end match to be relative to the
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002389 * beginning of the line. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002390 endmatch.rm_so += startmatch.rm_eo;
2391 endmatch.rm_eo += startmatch.rm_eo;
2392 /* There is an end on this line. But does it
David Lawrence Ramsey94e70942004-05-13 18:04:31 +00002393 * appear on this page, and is the match more
2394 * than zero characters long? */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002395 if (endmatch.rm_eo > startpos &&
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002396 endmatch.rm_eo > startmatch.rm_so) {
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002397 paintlen = strnlenpt(fileptr->data,
2398 endmatch.rm_eo) - start - x_start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002399 if (x_start + paintlen > COLS)
2400 paintlen = COLS - x_start;
2401
2402 assert(0 <= x_start && 0 < paintlen &&
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002403 x_start + paintlen <= COLS);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002404 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002405 converted + x_start, paintlen);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002406 }
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002407 } else {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002408 /* There is no end on this line. But we haven't
2409 * yet looked for one on later lines. */
2410 end_line = fileptr->next;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002411 while (end_line != NULL &&
2412 regexec(tmpcolor->end, end_line->data, 0,
2413 NULL, 0) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002414 end_line = end_line->next;
2415 if (end_line != NULL) {
2416 assert(0 <= x_start && x_start < COLS);
2417 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002418 converted + x_start, COLS - x_start);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002419 /* We painted to the end of the line, so
2420 * don't bother checking any more starts. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002421 break;
Chris Allegretta3674c1d2002-05-12 20:43:49 +00002422 }
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002423 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002424 start_col = startmatch.rm_so + 1;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002425 } /* while start_col < endpos */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002426 } /* if (tmp_color->end != NULL) */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002427
Chris Allegrettace452fb2003-02-03 02:56:44 +00002428 skip_step_two:
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002429 wattroff(edit, A_BOLD);
2430 wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
2431 } /* for tmpcolor in colorstrings */
2432 }
Chris Allegretta598106e2002-01-19 01:59:37 +00002433#endif /* ENABLE_COLOR */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002434
Chris Allegretta7dd77682001-12-08 19:52:28 +00002435#ifndef NANO_SMALL
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002436 if (ISSET(MARK_ISSET)
2437 && (fileptr->lineno <= mark_beginbuf->lineno
2438 || fileptr->lineno <= current->lineno)
2439 && (fileptr->lineno >= mark_beginbuf->lineno
2440 || fileptr->lineno >= current->lineno)) {
2441 /* fileptr is at least partially selected. */
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002442
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002443 const filestruct *top;
2444 /* Either current or mark_beginbuf, whichever is first. */
2445 size_t top_x;
2446 /* current_x or mark_beginx, corresponding to top. */
2447 const filestruct *bot;
2448 size_t bot_x;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002449 int x_start;
2450 /* Starting column for mvwaddnstr. Zero-based. */
2451 int paintlen;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002452 /* Number of chars to paint on this line. There are COLS
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002453 * characters on a whole line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002454
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002455 mark_order(&top, &top_x, &bot, &bot_x);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002456
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002457 if (top->lineno < fileptr->lineno || top_x < startpos)
2458 top_x = startpos;
2459 if (bot->lineno > fileptr->lineno || bot_x > endpos)
2460 bot_x = endpos;
2461
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00002462 /* The selected bit of fileptr is on this page. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002463 if (top_x < endpos && bot_x > startpos) {
2464 assert(startpos <= top_x);
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00002465
2466 /* x_start is the expanded location of the beginning of the
2467 * mark minus the beginning of the page. */
2468 x_start = strnlenpt(fileptr->data, top_x) - start;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002469
2470 if (bot_x >= endpos)
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00002471 /* If the end of the mark is off the page, paintlen is
2472 * -1, meaning that everything on the line gets
2473 * painted. */
2474 paintlen = -1;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002475 else
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00002476 /* Otherwise, paintlen is the expanded location of the
2477 * end of the mark minus the expanded location of the
2478 * beginning of the mark. */
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002479 paintlen = strnlenpt(fileptr->data, bot_x)
2480 - (x_start + start);
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00002481
2482 /* If x_start is before the beginning of the page, shift
2483 * paintlen x_start characters to compensate, and put
2484 * x_start at the beginning of the page. */
2485 if (x_start < 0) {
2486 paintlen += x_start;
2487 x_start = 0;
2488 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002489
2490 assert(x_start >= 0 && x_start <= strlen(converted));
2491
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002492 wattron(edit, A_REVERSE);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002493 mvwaddnstr(edit, yval, x_start, converted + x_start, paintlen);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002494 wattroff(edit, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002495 }
Chris Allegretta08893e02001-11-29 02:42:27 +00002496 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002497#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002498}
2499
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002500/* Just update one line in the edit buffer. Basically a wrapper for
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002501 * edit_add().
2502 *
David Lawrence Ramsey07d3feb2004-04-16 05:15:11 +00002503 * If fileptr != current, then index is considered 0. The line will be
2504 * displayed starting with fileptr->data[index]. Likely args are
2505 * current_x or 0. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002506void update_line(const filestruct *fileptr, size_t index)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002507{
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002508 int line;
2509 /* line in the edit window for CURSES calls */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002510 char *converted;
2511 /* fileptr->data converted to have tabs and control characters
2512 * expanded. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002513 size_t page_start;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002514
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002515 assert(fileptr != NULL);
Robert Siemborski53154a72000-06-18 00:11:03 +00002516
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002517 line = fileptr->lineno - edittop->lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002518
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002519 /* We assume the line numbers are valid. Is that really true? */
2520 assert(line < 0 || line == check_linenumbers(fileptr));
2521
2522 if (line < 0 || line >= editwinrows)
2523 return;
2524
2525 /* First, blank out the line (at a minimum) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002526 mvwaddstr(edit, line, 0, hblank);
2527
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002528 /* Next, convert variables that index the line to their equivalent
2529 * positions in the expanded line. */
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00002530 index = (fileptr == current) ? strnlenpt(fileptr->data, index) : 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002531 page_start = get_page_start(index);
Chris Allegretta5beed502003-01-05 20:41:21 +00002532
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002533 /* Expand the line, replacing Tab by spaces, and control characters
2534 * by their display form. */
2535 converted = display_string(fileptr->data, page_start, COLS);
Robert Siemborski53875912000-06-16 04:25:30 +00002536
Chris Allegretta4dc03d52002-05-11 03:04:44 +00002537 /* Now, paint the line */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002538 edit_add(fileptr, converted, line, page_start);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002539 free(converted);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002540
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002541 if (page_start > 0)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002542 mvwaddch(edit, line, 0, '$');
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002543 if (strlenpt(fileptr->data) > page_start + COLS)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002544 mvwaddch(edit, line, COLS - 1, '$');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002545}
2546
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002547/* Return a nonzero value if we need an update after moving
2548 * horizontally. We need one if the mark is on or if old_pww and
David Lawrence Ramsey684b1932004-05-31 14:47:12 +00002549 * placewewant are on different pages. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002550int need_horizontal_update(int old_pww)
2551{
2552 return
2553#ifndef NANO_SMALL
2554 ISSET(MARK_ISSET) ||
2555#endif
2556 get_page_start(old_pww) != get_page_start(placewewant);
2557}
2558
2559/* Return a nonzero value if we need an update after moving vertically.
2560 * We need one if the mark is on or if old_pww and placewewant
David Lawrence Ramsey684b1932004-05-31 14:47:12 +00002561 * are on different pages. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002562int need_vertical_update(int old_pww)
2563{
2564 return
2565#ifndef NANO_SMALL
2566 ISSET(MARK_ISSET) ||
2567#endif
2568 get_page_start(old_pww) != get_page_start(placewewant);
2569}
2570
2571/* Scroll the edit window in the given direction and the given number
2572 * of lines, and draw new lines on the blank lines left after the
2573 * scrolling. direction is the direction to scroll, either UP or DOWN,
2574 * and nlines is the number of lines to scroll. Don't redraw the old
2575 * topmost or bottommost line (where we assume current is) before
2576 * scrolling or draw the new topmost or bottommost line after scrolling
2577 * (where we assume current will be), since we don't know where we are
David Lawrence Ramsey684b1932004-05-31 14:47:12 +00002578 * on the page or whether we'll stay there. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002579void edit_scroll(updown direction, int nlines)
2580{
2581 filestruct *foo;
2582 int i, scroll_rows = 0;
2583
2584 /* Scrolling less than one line or more than editwinrows lines is
2585 * redundant, so don't allow it. */
2586 if (nlines < 1 || nlines > editwinrows)
2587 return;
2588
2589 /* Move the top line of the edit window up or down (depending on the
2590 * value of direction) nlines lines. If there are fewer lines of
2591 * text than that left, move it to the top or bottom line of the
2592 * file (depending on the value of direction). Keep track of
2593 * how many lines we moved in scroll_rows. */
2594 for (i = nlines; i > 0; i--) {
2595 if (direction == UP) {
2596 if (edittop->prev == NULL)
2597 break;
2598 edittop = edittop->prev;
2599 scroll_rows--;
2600 } else {
2601 if (edittop->next == NULL)
2602 break;
2603 edittop = edittop->next;
2604 scroll_rows++;
2605 }
2606 }
2607
2608 /* Scroll the text on the screen up or down scroll_rows lines,
2609 * depending on the value of direction. */
2610 scrollok(edit, TRUE);
2611 wscrl(edit, scroll_rows);
2612 scrollok(edit, FALSE);
2613
2614 foo = edittop;
2615 if (direction != UP) {
2616 int slines = editwinrows - nlines;
2617 for (; slines > 0 && foo != NULL; slines--)
2618 foo = foo->next;
2619 }
2620
2621 /* And draw new lines on the blank top or bottom lines of the edit
2622 * window, depending on the value of direction. Don't draw the new
2623 * topmost or new bottommost line. */
2624 while (scroll_rows != 0 && foo != NULL) {
2625 if (foo->next != NULL)
2626 update_line(foo, 0);
2627 if (direction == UP)
2628 scroll_rows++;
2629 else
2630 scroll_rows--;
2631 foo = foo->next;
2632 }
2633}
2634
2635/* Update any lines between old_current and current that need to be
David Lawrence Ramsey684b1932004-05-31 14:47:12 +00002636 * updated. */
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00002637void edit_redraw(const filestruct *old_current, int old_pww)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002638{
David Lawrence Ramseyce1d7652004-06-01 18:32:36 +00002639 int do_refresh = need_vertical_update(0) ||
2640 need_vertical_update(old_pww);
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002641 const filestruct *foo;
2642
2643 /* If either old_current or current is offscreen, refresh the screen
2644 * and get out. */
2645 if (old_current->lineno < edittop->lineno || old_current->lineno >=
2646 edittop->lineno + editwinrows || current->lineno <
2647 edittop->lineno || current->lineno >= edittop->lineno +
2648 editwinrows) {
2649 edit_refresh();
2650 return;
2651 }
2652
David Lawrence Ramseyce1d7652004-06-01 18:32:36 +00002653 /* Update old_current and current if we're not on the first page
2654 * and/or we're not on the same page as before. If the mark is on,
2655 * update all the lines between old_current and current too. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002656 foo = old_current;
2657 while (foo != current) {
2658 if (do_refresh)
2659 update_line(foo, 0);
2660#ifndef NANO_SMALL
2661 if (!ISSET(MARK_ISSET))
2662#endif
2663 break;
2664 if (foo->lineno > current->lineno)
2665 foo = foo->prev;
2666 else
2667 foo = foo->next;
2668 }
2669 if (do_refresh)
2670 update_line(current, current_x);
2671}
2672
Chris Allegretta6df90f52002-07-19 01:08:59 +00002673/* Refresh the screen without changing the position of lines. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002674void edit_refresh(void)
2675{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002676 /* Neither of these conditions should occur, but they do. edittop
2677 * is NULL when you open an existing file on the command line, and
Chris Allegretta6df90f52002-07-19 01:08:59 +00002678 * ENABLE_COLOR is defined. Yuck. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002679 if (current == NULL)
2680 return;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002681 if (edittop == NULL)
2682 edittop = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002683
Chris Allegretta63d0b482003-01-26 19:47:10 +00002684 if (current->lineno < edittop->lineno ||
2685 current->lineno >= edittop->lineno + editwinrows)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002686 /* Note that edit_update() changes edittop so that
2687 * current->lineno = edittop->lineno + editwinrows / 2. Thus
2688 * when it then calls edit_refresh(), there is no danger of
2689 * getting an infinite loop. */
Chris Allegrettada721be2000-07-31 01:26:42 +00002690 edit_update(current, CENTER);
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002691 else {
2692 int nlines = 0;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002693 const filestruct *foo = edittop;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002694
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002695#ifdef DEBUG
2696 fprintf(stderr, "edit_refresh(): edittop->lineno = %ld\n", edittop->lineno);
2697#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002698
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002699 while (nlines < editwinrows) {
David Lawrence Ramsey9d325a02004-05-29 03:03:52 +00002700 update_line(foo, foo == current ? current_x : 0);
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002701 nlines++;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002702 if (foo->next == NULL)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002703 break;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002704 foo = foo->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002705 }
2706 while (nlines < editwinrows) {
2707 mvwaddstr(edit, nlines, 0, hblank);
2708 nlines++;
2709 }
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002710 reset_cursor();
David Lawrence Ramsey07d3feb2004-04-16 05:15:11 +00002711
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002712 /* What the hell are we expecting to update the screen if this
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002713 * isn't here? Luck? */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002714 wrefresh(edit);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002715 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002716}
2717
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002718/* Nice generic routine to update the edit buffer, given a pointer to the
2719 * file struct =) */
David Lawrence Ramsey1356a0a2003-09-10 20:31:02 +00002720void edit_update(filestruct *fileptr, topmidnone location)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002721{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002722 if (fileptr == NULL)
2723 return;
2724
Chris Allegretta6df90f52002-07-19 01:08:59 +00002725 if (location != TOP) {
David Lawrence Ramsey07d3feb2004-04-16 05:15:11 +00002726 int goal = (location == NONE) ? current_y : editwinrows / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002727
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00002728 for (; goal > 0 && fileptr->prev != NULL; goal--)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002729 fileptr = fileptr->prev;
2730 }
2731 edittop = fileptr;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002732 edit_refresh();
2733}
2734
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002735/* Ask a question on the statusbar. Answer will be stored in answer
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002736 * global. Returns -1 on aborted enter, -2 on a blank string, and 0
Chris Allegretta88520c92001-05-05 17:45:54 +00002737 * otherwise, the valid shortcut key caught. Def is any editable text we
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002738 * want to put up by default.
Chris Allegretta7da4e9f2000-11-06 02:57:22 +00002739 *
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002740 * New arg tabs tells whether or not to allow tab completion. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002741int statusq(int allowtabs, const shortcut *s, const char *def,
Chris Allegretta5beed502003-01-05 20:41:21 +00002742#ifndef NANO_SMALL
2743 historyheadtype *which_history,
2744#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002745 const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002746{
2747 va_list ap;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002748 char *foo = charalloc(COLS - 3);
Chris Allegretta9caa1932002-02-15 20:08:05 +00002749 int ret;
Chris Allegretta2084acc2001-11-29 03:43:08 +00002750#ifndef DISABLE_TABCOMP
Chris Allegrettaa16e4e92002-01-05 18:59:54 +00002751 int list = 0;
Chris Allegretta2084acc2001-11-29 03:43:08 +00002752#endif
2753
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002754 bottombars(s);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002755
2756 va_start(ap, msg);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002757 vsnprintf(foo, COLS - 4, msg, ap);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002758 va_end(ap);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002759 foo[COLS - 4] = '\0';
Chris Allegretta8ce24132001-04-30 11:28:46 +00002760
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002761 ret = nanogetstr(allowtabs, foo, def,
Chris Allegretta5beed502003-01-05 20:41:21 +00002762#ifndef NANO_SMALL
2763 which_history,
Chris Allegretta2084acc2001-11-29 03:43:08 +00002764#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00002765 s
2766#ifndef DISABLE_TABCOMP
2767 , &list
2768#endif
Chris Allegretta65f075d2003-02-13 03:03:49 +00002769 );
Chris Allegretta6df90f52002-07-19 01:08:59 +00002770 free(foo);
Chris Allegretta65f075d2003-02-13 03:03:49 +00002771 resetstatuspos = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002772
2773 switch (ret) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002774 case NANO_FIRSTLINE_KEY:
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00002775 case NANO_FIRSTLINE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002776 do_first_line();
Chris Allegretta65f075d2003-02-13 03:03:49 +00002777 resetstatuspos = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002778 break;
2779 case NANO_LASTLINE_KEY:
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00002780 case NANO_LASTLINE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002781 do_last_line();
Chris Allegretta65f075d2003-02-13 03:03:49 +00002782 resetstatuspos = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002783 break;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002784#ifndef DISABLE_JUSTIFY
2785 case NANO_PARABEGIN_KEY:
2786 do_para_begin();
2787 resetstatuspos = 1;
2788 break;
2789 case NANO_PARAEND_KEY:
2790 do_para_end();
2791 resetstatuspos = 1;
2792 break;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002793 case NANO_FULLJUSTIFY_KEY:
David Lawrence Ramseyd12fd4b2004-05-28 15:05:56 +00002794 if (!ISSET(VIEW_MODE))
2795 do_full_justify();
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002796 resetstatuspos = 1;
2797 break;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002798#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002799 case NANO_CANCEL_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002800 ret = -1;
Chris Allegretta65f075d2003-02-13 03:03:49 +00002801 resetstatuspos = 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002802 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002803 }
Chris Allegrettaa90d0cf2003-02-10 02:55:03 +00002804 blank_statusbar();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002805
2806#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00002807 fprintf(stderr, "I got \"%s\"\n", answer);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002808#endif
2809
Chris Allegretta6df90f52002-07-19 01:08:59 +00002810#ifndef DISABLE_TABCOMP
2811 /* if we've done tab completion, there might be a list of
2812 filename matches on the edit window at this point; make sure
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002813 they're cleared off. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002814 if (list)
2815 edit_refresh();
2816#endif
2817
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002818 return ret;
2819}
2820
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002821/* Ask a simple yes/no question on the statusbar. Returns 1 for Y, 0
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002822 * for N, 2 for All (if all is nonzero when passed in) and -1 for abort
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002823 * (^C). */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002824int do_yesno(int all, const char *msg)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002825{
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002826 int ok = -2, width = 16;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002827 const char *yesstr; /* String of yes characters accepted */
2828 const char *nostr; /* Same for no */
2829 const char *allstr; /* And all, surprise! */
Chris Allegretta235ab192001-04-12 13:24:40 +00002830
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002831 /* Yes, no and all are strings of any length. Each string consists
2832 * of all characters accepted as a valid character for that value.
2833 * The first value will be the one displayed in the shortcuts. */
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002834 yesstr = _("Yy");
2835 nostr = _("Nn");
2836 allstr = _("Aa");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002837
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002838 /* Remove gettext() call for keybindings until we clear the thing
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002839 * up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002840 if (!ISSET(NO_HELP)) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002841 char shortstr[3]; /* Temp string for Y, N, A. */
Chris Allegretta6232d662002-05-12 19:52:15 +00002842
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002843 if (COLS < 32)
2844 width = COLS / 2;
2845
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002846 /* Write the bottom of the screen. */
Chris Allegrettadb28e962003-01-28 01:23:40 +00002847 blank_bottombars();
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002848
Chris Allegretta6232d662002-05-12 19:52:15 +00002849 sprintf(shortstr, " %c", yesstr[0]);
Chris Allegrettadb28e962003-01-28 01:23:40 +00002850 wmove(bottomwin, 1, 0);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002851 onekey(shortstr, _("Yes"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002852
2853 if (all) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002854 wmove(bottomwin, 1, width);
Chris Allegretta6232d662002-05-12 19:52:15 +00002855 shortstr[1] = allstr[0];
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002856 onekey(shortstr, _("All"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002857 }
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002858
Chris Allegrettadb28e962003-01-28 01:23:40 +00002859 wmove(bottomwin, 2, 0);
Chris Allegretta6232d662002-05-12 19:52:15 +00002860 shortstr[1] = nostr[0];
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002861 onekey(shortstr, _("No"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002862
Chris Allegrettadb28e962003-01-28 01:23:40 +00002863 wmove(bottomwin, 2, 16);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002864 onekey("^C", _("Cancel"), width);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002865 }
Chris Allegrettadb28e962003-01-28 01:23:40 +00002866
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002867 wattron(bottomwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002868
2869 blank_statusbar();
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002870 mvwaddnstr(bottomwin, 0, 0, msg, COLS - 1);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002871
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002872 wattroff(bottomwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002873
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002874 wrefresh(bottomwin);
2875
Chris Allegrettadb28e962003-01-28 01:23:40 +00002876 do {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002877 int kbinput;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002878 int meta_key;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002879#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002880 int mouse_x, mouse_y;
Chris Allegretta235ab192001-04-12 13:24:40 +00002881#endif
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002882
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002883 kbinput = get_kbinput(edit, &meta_key);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002884
2885 if (kbinput == NANO_CANCEL_KEY)
Chris Allegrettadb28e962003-01-28 01:23:40 +00002886 ok = -1;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002887#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002888 /* Look ma! We get to duplicate lots of code from
2889 * do_mouse()!! */
2890 else if (kbinput == KEY_MOUSE) {
2891 kbinput = get_mouseinput(&mouse_x, &mouse_y, 0);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002892
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002893 if (mouse_x != -1 && mouse_y != -1 && !ISSET(NO_HELP) &&
2894 wenclose(bottomwin, mouse_y, mouse_x) && mouse_x <
2895 (width * 2) && mouse_y >= editwinrows + 3) {
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002896
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002897 int x = mouse_x / width;
2898 /* Did we click in the first column of shortcuts, or
2899 * the second? */
2900 int y = mouse_y - editwinrows - 3;
2901 /* Did we click in the first row of shortcuts? */
2902
2903 assert(0 <= x && x <= 1 && 0 <= y && y <= 1);
2904
2905 /* x = 0 means they clicked Yes or No.
2906 * y = 0 means Yes or All. */
2907 ok = -2 * x * y + x - y + 1;
2908
2909 if (ok == 2 && !all)
2910 ok = -2;
2911 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002912 }
Chris Allegrettadb28e962003-01-28 01:23:40 +00002913#endif
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002914 /* Look for the kbinput in the yes, no and (optionally) all
2915 * str. */
Chris Allegrettadb28e962003-01-28 01:23:40 +00002916 else if (strchr(yesstr, kbinput) != NULL)
2917 ok = 1;
2918 else if (strchr(nostr, kbinput) != NULL)
2919 ok = 0;
2920 else if (all && strchr(allstr, kbinput) != NULL)
2921 ok = 2;
2922 } while (ok == -2);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002923
Chris Allegrettadb28e962003-01-28 01:23:40 +00002924 return ok;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002925}
2926
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002927int total_refresh(void)
2928{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002929 clearok(topwin, TRUE);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002930 clearok(edit, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002931 clearok(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002932 wnoutrefresh(topwin);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002933 wnoutrefresh(edit);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002934 wnoutrefresh(bottomwin);
2935 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002936 clearok(topwin, FALSE);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002937 clearok(edit, FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002938 clearok(bottomwin, FALSE);
2939 edit_refresh();
2940 titlebar(NULL);
2941 return 1;
2942}
2943
2944void display_main_list(void)
2945{
2946 bottombars(main_list);
2947}
2948
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002949/* If constant is FALSE, the user typed ^C so we unconditionally display
Chris Allegrettad26ab912003-01-28 01:16:47 +00002950 * the cursor position. Otherwise, we display it only if the character
2951 * position changed, and DISABLE_CURPOS is not set.
2952 *
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002953 * If constant is TRUE and DISABLE_CURPOS is set, we unset it and update
2954 * old_i and old_totsize. That way, we leave the current statusbar
2955 * alone, but next time we will display. */
Chris Allegretta2084acc2001-11-29 03:43:08 +00002956int do_cursorpos(int constant)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002957{
Chris Allegrettad26ab912003-01-28 01:16:47 +00002958 const filestruct *fileptr;
2959 unsigned long i = 0;
2960 static unsigned long old_i = 0;
2961 static long old_totsize = -1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002962
Chris Allegrettad26ab912003-01-28 01:16:47 +00002963 assert(current != NULL && fileage != NULL && totlines != 0);
Chris Allegretta2084acc2001-11-29 03:43:08 +00002964
2965 if (old_totsize == -1)
2966 old_totsize = totsize;
2967
Chris Allegrettad26ab912003-01-28 01:16:47 +00002968 for (fileptr = fileage; fileptr != current; fileptr = fileptr->next) {
2969 assert(fileptr != NULL);
Chris Allegrettaf27c6972002-02-12 01:57:24 +00002970 i += strlen(fileptr->data) + 1;
Chris Allegrettad26ab912003-01-28 01:16:47 +00002971 }
Chris Allegrettaf27c6972002-02-12 01:57:24 +00002972 i += current_x;
Chris Allegretta14b3ca92002-01-25 21:59:02 +00002973
Chris Allegrettad26ab912003-01-28 01:16:47 +00002974 if (constant && ISSET(DISABLE_CURPOS)) {
2975 UNSET(DISABLE_CURPOS);
2976 old_i = i;
2977 old_totsize = totsize;
2978 return 0;
2979 }
Chris Allegretta14b3ca92002-01-25 21:59:02 +00002980
David Lawrence Ramsey4178db02004-05-23 21:23:23 +00002981 /* If constant is FALSE, display the position on the statusbar
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002982 * unconditionally; otherwise, only display the position when the
2983 * character values have changed. */
Chris Allegrettad26ab912003-01-28 01:16:47 +00002984 if (!constant || old_i != i || old_totsize != totsize) {
2985 unsigned long xpt = xplustabs() + 1;
2986 unsigned long cur_len = strlenpt(current->data) + 1;
2987 int linepct = 100 * current->lineno / totlines;
2988 int colpct = 100 * xpt / cur_len;
2989 int bytepct = totsize == 0 ? 0 : 100 * i / totsize;
2990
2991 statusbar(
2992 _("line %ld/%ld (%d%%), col %lu/%lu (%d%%), char %lu/%ld (%d%%)"),
2993 current->lineno, totlines, linepct,
2994 xpt, cur_len, colpct,
2995 i, totsize, bytepct);
2996 UNSET(DISABLE_CURPOS);
Chris Allegretta2084acc2001-11-29 03:43:08 +00002997 }
2998
2999 old_i = i;
3000 old_totsize = totsize;
3001
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003002 reset_cursor();
Chris Allegrettad26ab912003-01-28 01:16:47 +00003003 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003004}
3005
Chris Allegretta2084acc2001-11-29 03:43:08 +00003006int do_cursorpos_void(void)
3007{
3008 return do_cursorpos(0);
3009}
3010
Chris Allegretta4640fe32003-02-10 03:10:03 +00003011/* Calculate the next line of help_text, starting at ptr. */
3012int line_len(const char *ptr)
3013{
3014 int j = 0;
3015
3016 while (*ptr != '\n' && *ptr != '\0' && j < COLS - 5) {
3017 ptr++;
3018 j++;
3019 }
3020 if (j == COLS - 5) {
3021 /* Don't wrap at the first of two spaces following a period. */
3022 if (*ptr == ' ' && *(ptr + 1) == ' ')
3023 j++;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003024 /* Don't print half a word if we've run out of space. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00003025 while (*ptr != ' ' && j > 0) {
3026 ptr--;
3027 j--;
3028 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003029 /* Word longer than COLS - 5 chars just gets broken. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00003030 if (j == 0)
3031 j = COLS - 5;
3032 }
3033 assert(j >= 0 && j <= COLS - 4 && (j > 0 || *ptr == '\n'));
3034 return j;
3035}
3036
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003037#ifndef DISABLE_HELP
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003038/* Our shortcut-list-compliant help function, which is better than
3039 * nothing, and dynamic! */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003040int do_help(void)
3041{
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003042 int line = 0;
3043 /* The line number in help_text of the first displayed help line.
3044 * This variable is zero-based. */
3045 int no_more = 0;
3046 /* no_more means the end of the help text is shown, so don't go down
3047 * any more. */
3048 int kbinput = ERR, meta_key;
3049
David Lawrence Ramseye7638ea2004-06-01 19:49:38 +00003050 int old_no_help = ISSET(NO_HELP);
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003051#ifndef DISABLE_MOUSE
3052 const shortcut *oldshortcut = currshortcut;
3053 /* We will set currshortcut to allow clicking on the help
3054 screen shortcut list. */
3055#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003056
David Lawrence Ramseyae064bf2004-06-01 20:38:00 +00003057 curs_set(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003058 blank_edit();
Chris Allegrettab3655b42001-10-22 03:15:31 +00003059 wattroff(bottomwin, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003060 blank_statusbar();
3061
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003062 /* Set help_text as the string to display. */
Chris Allegrettab3655b42001-10-22 03:15:31 +00003063 help_init();
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003064 assert(help_text != NULL);
Chris Allegrettab3655b42001-10-22 03:15:31 +00003065
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003066#ifndef DISABLE_MOUSE
3067 /* Set currshortcut to allow clicking on the help screen shortcut
3068 * list, AFTER help_init(). */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003069 currshortcut = help_list;
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003070#endif
Chris Allegretta6fe61492001-05-21 12:56:25 +00003071
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003072 if (ISSET(NO_HELP)) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003073 /* Well, if we're going to do this, we should at least do it the
3074 * right way. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +00003075 UNSET(NO_HELP);
Chris Allegretta70444892001-01-07 23:02:02 +00003076 window_init();
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003077 }
3078 bottombars(help_list);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003079
3080 do {
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003081 int i;
3082 int old_line = line;
3083 /* We redisplay the help only if it moved. */
Chris Allegrettaf717f982003-02-13 22:25:01 +00003084 const char *ptr = help_text;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003085
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003086 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003087#ifndef DISABLE_MOUSE
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003088 case KEY_MOUSE:
3089 do_mouse();
3090 break;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003091#endif
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003092 case NANO_NEXTPAGE_KEY:
3093 case NANO_NEXTPAGE_FKEY:
3094 if (!no_more)
3095 line += editwinrows - 2;
3096 break;
3097 case NANO_PREVPAGE_KEY:
3098 case NANO_PREVPAGE_FKEY:
3099 if (line > 0) {
3100 line -= editwinrows - 2;
3101 if (line < 0)
3102 line = 0;
3103 }
3104 break;
3105 case NANO_PREVLINE_KEY:
3106 if (line > 0)
3107 line--;
3108 break;
3109 case NANO_NEXTLINE_KEY:
3110 if (!no_more)
3111 line++;
3112 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003113 }
3114
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003115 if (line == old_line && kbinput != ERR)
3116 goto skip_redisplay;
3117
3118 blank_edit();
3119
3120 assert(COLS > 5);
3121
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003122 /* Calculate where in the text we should be, based on the
3123 * page. */
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003124 for (i = 0; i < line; i++) {
Chris Allegretta4640fe32003-02-10 03:10:03 +00003125 ptr += line_len(ptr);
3126 if (*ptr == '\n')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003127 ptr++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003128 }
3129
Chris Allegretta4640fe32003-02-10 03:10:03 +00003130 for (i = 0; i < editwinrows && *ptr != '\0'; i++) {
3131 int j = line_len(ptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003132
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003133 mvwaddnstr(edit, i, 0, ptr, j);
Chris Allegretta4640fe32003-02-10 03:10:03 +00003134 ptr += j;
3135 if (*ptr == '\n')
3136 ptr++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003137 }
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003138 no_more = (*ptr == '\0');
Chris Allegretta4640fe32003-02-10 03:10:03 +00003139
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003140 skip_redisplay:
3141 kbinput = get_kbinput(edit, &meta_key);
3142 } while (kbinput != NANO_EXIT_KEY && kbinput != NANO_EXIT_FKEY);
Chris Allegrettad1627cf2000-12-18 05:03:16 +00003143
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003144#ifndef DISABLE_MOUSE
Chris Allegrettab3655b42001-10-22 03:15:31 +00003145 currshortcut = oldshortcut;
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003146#endif
Chris Allegrettab3655b42001-10-22 03:15:31 +00003147
David Lawrence Ramseye7638ea2004-06-01 19:49:38 +00003148 if (old_no_help) {
Chris Allegretta70444892001-01-07 23:02:02 +00003149 blank_bottombars();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00003150 wrefresh(bottomwin);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003151 SET(NO_HELP);
Chris Allegretta70444892001-01-07 23:02:02 +00003152 window_init();
Chris Allegretta598106e2002-01-19 01:59:37 +00003153 } else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003154 bottombars(currshortcut);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003155
David Lawrence Ramseyae064bf2004-06-01 20:38:00 +00003156 curs_set(1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003157 edit_refresh();
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003158
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003159 /* The help_init() at the beginning allocated help_text, which has
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003160 * now been written to the screen. */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003161 free(help_text);
3162 help_text = NULL;
3163
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003164 return 1;
3165}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003166#endif /* !DISABLE_HELP */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003167
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003168/* Highlight the current word being replaced or spell checked. We
3169 * expect word to have tabs and control characters expanded. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003170void do_replace_highlight(int highlight_flag, const char *word)
Chris Allegrettafb62f732000-12-05 11:36:41 +00003171{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003172 int y = xplustabs();
3173 size_t word_len = strlen(word);
Chris Allegrettafb62f732000-12-05 11:36:41 +00003174
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003175 y = get_page_start(y) + COLS - y;
3176 /* Now y is the number of characters we can display on this
3177 * line. */
Chris Allegrettafb62f732000-12-05 11:36:41 +00003178
3179 reset_cursor();
Chris Allegretta598106e2002-01-19 01:59:37 +00003180
Chris Allegrettafb62f732000-12-05 11:36:41 +00003181 if (highlight_flag)
3182 wattron(edit, A_REVERSE);
3183
David Lawrence Ramsey2a4ab6d2003-12-24 08:29:49 +00003184#ifdef HAVE_REGEX_H
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00003185 /* This is so we can show zero-length regexes. */
3186 if (word_len == 0)
3187 waddstr(edit, " ");
3188 else
David Lawrence Ramsey2a4ab6d2003-12-24 08:29:49 +00003189#endif
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00003190 waddnstr(edit, word, y - 1);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003191
3192 if (word_len > y)
3193 waddch(edit, '$');
3194 else if (word_len == y)
3195 waddch(edit, word[word_len - 1]);
Chris Allegrettafb62f732000-12-05 11:36:41 +00003196
3197 if (highlight_flag)
3198 wattroff(edit, A_REVERSE);
Chris Allegrettafb62f732000-12-05 11:36:41 +00003199}
3200
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003201#ifdef DEBUG
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003202/* Dump the passed-in file structure to stderr. */
3203void dump_buffer(const filestruct *inptr)
3204{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003205 if (inptr == fileage)
Jordi Mallachf9390af2003-08-05 19:31:12 +00003206 fprintf(stderr, "Dumping file buffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003207 else if (inptr == cutbuffer)
Jordi Mallachf9390af2003-08-05 19:31:12 +00003208 fprintf(stderr, "Dumping cutbuffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003209 else
Jordi Mallachf9390af2003-08-05 19:31:12 +00003210 fprintf(stderr, "Dumping a buffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003211
3212 while (inptr != NULL) {
3213 fprintf(stderr, "(%d) %s\n", inptr->lineno, inptr->data);
3214 inptr = inptr->next;
3215 }
3216}
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003217
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003218/* Dump the file structure to stderr in reverse. */
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00003219void dump_buffer_reverse(void)
3220{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003221 const filestruct *fileptr = filebot;
3222
3223 while (fileptr != NULL) {
3224 fprintf(stderr, "(%d) %s\n", fileptr->lineno, fileptr->data);
3225 fileptr = fileptr->prev;
3226 }
3227}
3228#endif /* DEBUG */
3229
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003230#ifdef NANO_EXTRA
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00003231#define CREDIT_LEN 53
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00003232#define XLCREDIT_LEN 8
3233
David Lawrence Ramseyfdece462004-01-19 18:15:03 +00003234/* Easter egg: Display credits. Assume nodelay(edit) is FALSE. */
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003235void do_credits(void)
3236{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003237 int crpos = 0, xlpos = 0;
3238 const char *credits[CREDIT_LEN] = {
3239 NULL, /* "The nano text editor" */
3240 NULL, /* "version" */
Chris Allegretta598106e2002-01-19 01:59:37 +00003241 VERSION,
3242 "",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003243 NULL, /* "Brought to you by:" */
Chris Allegretta598106e2002-01-19 01:59:37 +00003244 "Chris Allegretta",
3245 "Jordi Mallach",
3246 "Adam Rogoyski",
3247 "Rob Siemborski",
3248 "Rocco Corsi",
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003249 "David Lawrence Ramsey",
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00003250 "David Benbennick",
Chris Allegretta598106e2002-01-19 01:59:37 +00003251 "Ken Tyler",
3252 "Sven Guckes",
3253 "Florian König",
3254 "Pauli Virtanen",
3255 "Daniele Medri",
3256 "Clement Laforet",
3257 "Tedi Heriyanto",
3258 "Bill Soudan",
3259 "Christian Weisgerber",
3260 "Erik Andersen",
3261 "Big Gaute",
3262 "Joshua Jensen",
3263 "Ryan Krebs",
3264 "Albert Chin",
Chris Allegretta598106e2002-01-19 01:59:37 +00003265 "",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003266 NULL, /* "Special thanks to:" */
Chris Allegretta598106e2002-01-19 01:59:37 +00003267 "Plattsburgh State University",
3268 "Benet Laboratories",
3269 "Amy Allegretta",
3270 "Linda Young",
3271 "Jeremy Robichaud",
3272 "Richard Kolb II",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003273 NULL, /* "The Free Software Foundation" */
Chris Allegretta598106e2002-01-19 01:59:37 +00003274 "Linus Torvalds",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003275 NULL, /* "For ncurses:" */
Chris Allegrettadce44ab2002-03-16 01:03:41 +00003276 "Thomas Dickey",
3277 "Pavel Curtis",
3278 "Zeyd Ben-Halim",
3279 "Eric S. Raymond",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003280 NULL, /* "and anyone else we forgot..." */
3281 NULL, /* "Thank you for using nano!" */
3282 "",
3283 "",
3284 "",
3285 "",
David Lawrence Ramsey6481c3f2004-01-09 23:06:54 +00003286 "(c) 1999-2004 Chris Allegretta",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003287 "",
3288 "",
3289 "",
3290 "",
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00003291 "http://www.nano-editor.org/"
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003292 };
3293
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003294 const char *xlcredits[XLCREDIT_LEN] = {
David Lawrence Ramsey837a02b2004-05-18 15:23:31 +00003295 "The nano text editor",
3296 "version",
3297 "Brought to you by:",
3298 "Special thanks to:",
3299 "The Free Software Foundation",
3300 "For ncurses:",
3301 "and anyone else we forgot...",
3302 "Thank you for using nano!"
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003303 };
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00003304
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003305 curs_set(0);
3306 nodelay(edit, TRUE);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003307 scrollok(edit, TRUE);
3308 blank_titlebar();
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00003309 blank_edit();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003310 blank_statusbar();
3311 blank_bottombars();
3312 wrefresh(topwin);
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00003313 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003314 wrefresh(bottomwin);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003315
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003316 for (crpos = 0; crpos < CREDIT_LEN + editwinrows / 2; crpos++) {
3317 if (wgetch(edit) != ERR)
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003318 break;
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003319 if (crpos < CREDIT_LEN) {
3320 const char *what = credits[crpos];
3321 size_t start_x;
3322
3323 if (what == NULL) {
3324 assert(0 <= xlpos && xlpos < XLCREDIT_LEN);
David Lawrence Ramsey837a02b2004-05-18 15:23:31 +00003325 what = _(xlcredits[xlpos]);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003326 xlpos++;
3327 }
3328 start_x = COLS / 2 - strlen(what) / 2 - 1;
3329 mvwaddstr(edit, editwinrows - 1 - editwinrows % 2, start_x, what);
3330 }
3331 napms(700);
3332 scroll(edit);
3333 wrefresh(edit);
3334 if (wgetch(edit) != ERR)
3335 break;
3336 napms(700);
3337 scroll(edit);
3338 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003339 }
3340
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003341 scrollok(edit, FALSE);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003342 nodelay(edit, FALSE);
3343 curs_set(1);
3344 display_main_list();
3345 total_refresh();
Chris Allegretta598106e2002-01-19 01:59:37 +00003346}
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003347#endif