blob: 72cde515bdd34f2e856a470f1fb87e1dd081443a [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 Ramsey0a258082004-04-23 18:02:37 +0000234#endif
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000235#ifdef PDCURSES
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000236 case KEY_SHIFT_L:
237 case KEY_SHIFT_R:
238 case KEY_CONTROL_L:
239 case KEY_CONTROL_R:
240 case KEY_ALT_L:
241 case KEY_ALT_R:
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000242#endif
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000243 break;
244 default:
245 switch (escapes) {
246 case 0:
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000247 switch (kbinput) {
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000248 case NANO_CONTROL_8:
249 retval = ISSET(REBIND_DELETE) ?
250 NANO_DELETE_KEY : NANO_BACKSPACE_KEY;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000251 break;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000252 case KEY_DOWN:
253 retval = NANO_NEXTLINE_KEY;
254 break;
255 case KEY_UP:
256 retval = NANO_PREVLINE_KEY;
257 break;
258 case KEY_LEFT:
259 retval = NANO_BACK_KEY;
260 break;
261 case KEY_RIGHT:
262 retval = NANO_FORWARD_KEY;
263 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000264#ifdef KEY_HOME
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000265 /* HP-UX 10 and 11 don't support KEY_HOME. */
266 case KEY_HOME:
267 retval = NANO_HOME_KEY;
268 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000269#endif
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000270 case KEY_BACKSPACE:
271 retval = NANO_BACKSPACE_KEY;
272 break;
273 case KEY_DC:
274 retval = ISSET(REBIND_DELETE) ?
275 NANO_BACKSPACE_KEY : NANO_DELETE_KEY;
276 break;
277 case KEY_IC:
278 retval = NANO_INSERTFILE_KEY;
279 break;
280 case KEY_NPAGE:
281 retval = NANO_NEXTPAGE_KEY;
282 break;
283 case KEY_PPAGE:
284 retval = NANO_PREVPAGE_KEY;
285 break;
286 case KEY_ENTER:
287 retval = NANO_ENTER_KEY;
288 break;
David Lawrence Ramsey16eb5182004-06-03 20:26:12 +0000289 case KEY_A1: /* Home (7) on numeric keypad
290 * with NumLock off. */
291 retval = NANO_HOME_KEY;
292 break;
293 case KEY_A3: /* PageUp (9) on numeric keypad
294 * with NumLock off. */
295 retval = NANO_PREVPAGE_KEY;
296 break;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000297 case KEY_B2: /* Center (5) on numeric keypad
David Lawrence Ramsey16eb5182004-06-03 20:26:12 +0000298 * with NumLock off. */
David Lawrence Ramsey16eb5182004-06-03 20:26:12 +0000299 break;
300 case KEY_C1: /* End (1) on numeric keypad
301 * with NumLock off. */
302 retval = NANO_END_KEY;
303 break;
304 case KEY_C3: /* PageDown (4) on numeric
305 * keypad with NumLock off. */
306 retval = NANO_NEXTPAGE_KEY;
307 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000308#ifdef KEY_BEG
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000309 /* Slang doesn't support KEY_BEG. */
310 case KEY_BEG: /* Center (5) on numeric keypad
David Lawrence Ramsey16eb5182004-06-03 20:26:12 +0000311 * with NumLock off. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000312 break;
David Lawrence Ramsey16eb5182004-06-03 20:26:12 +0000313#endif
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000314#ifdef KEY_END
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000315 /* HP-UX 10 and 11 don't support KEY_END. */
316 case KEY_END:
317 retval = NANO_END_KEY;
318 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000319#endif
320#ifdef KEY_SUSPEND
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000321 /* Slang doesn't support KEY_SUSPEND. */
322 case KEY_SUSPEND:
323 retval = NANO_SUSPEND_KEY;
324 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000325#endif
326#ifdef KEY_SLEFT
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000327 /* Slang doesn't support KEY_SLEFT. */
328 case KEY_SLEFT:
329 retval = NANO_BACK_KEY;
330 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000331#endif
332#ifdef KEY_SRIGHT
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000333 /* Slang doesn't support KEY_SRIGHT. */
334 case KEY_SRIGHT:
335 retval = NANO_FORWARD_KEY;
336 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000337#endif
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000338 default:
339 retval = kbinput;
340 break;
341 }
342 break;
343 case 1:
344 /* One escape followed by a non-escape: escape
345 * sequence mode. Reset the escape counter and set
346 * es to TRUE. */
347 escapes = 0;
348 *es = TRUE;
349 break;
350 case 2:
351 switch (kbinput) {
352 case '0':
353 case '1':
354 case '2':
355 case '3':
356 case '4':
357 case '5':
358 case '6':
359 case '7':
360 case '8':
361 case '9':
362 /* Two escapes followed by one or more
363 * digits: ASCII character sequence mode.
364 * If the digit sequence's range is limited
365 * to 2XX (the first digit is in the '0' to
366 * '2' range and it's the first digit, or if
367 * it's in the full digit range and it's not
368 * the first digit), increment the ASCII
369 * digit counter and interpret the digit.
370 * If the digit sequence's range is not
371 * limited to 2XX, fall through. */
372 if (kbinput <= '2' || ascii_digits > 0) {
373 ascii_digits++;
374 kbinput = get_ascii_kbinput(kbinput,
375 ascii_digits
376#ifndef NANO_SMALL
377 , FALSE
378#endif
379 );
380
381 if (kbinput != ERR) {
382 /* If we've read in a complete ASCII
383 * digit sequence, reset the ASCII
384 * digit counter and the escape
385 * counter and save the corresponding
386 * ASCII character as the result. */
387 ascii_digits = 0;
388 escapes = 0;
389 retval = kbinput;
390 }
391 break;
392 }
393 default:
394 /* Reset the escape counter. */
395 escapes = 0;
396 if (ascii_digits == 0)
397 /* Two escapes followed by a non-digit
398 * or a digit that would create an ASCII
399 * digit sequence greater than 2XX, and
400 * we're not in the middle of an ASCII
401 * character sequence: control character
402 * sequence mode. Interpret the control
403 * sequence and save the corresponding
404 * control character as the result. */
405 retval = get_control_kbinput(kbinput);
406 else {
407 /* If we were in the middle of an ASCII
408 * character sequence, reset the ASCII
409 * digit counter and save the character
410 * we got as the result. */
411 ascii_digits = 0;
412 retval = kbinput;
413 }
414 }
415 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000416 }
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000417
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000418#ifdef DEBUG
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000419 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 +0000420#endif
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000421
422 /* Return the result. */
423 return retval;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000424}
425
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000426/* Translate an ASCII character sequence: turn a three-digit decimal
427 * ASCII code from 000-255 into its corresponding ASCII character. */
428int get_ascii_kbinput(int kbinput, size_t ascii_digits
429#ifndef NANO_SMALL
430 , int reset
431#endif
432 )
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000433{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000434 static int ascii_kbinput = 0;
435 int retval = ERR;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000436
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000437#ifndef NANO_SMALL
438 if (reset) {
439 ascii_kbinput = 0;
440 return ERR;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000441 }
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000442#endif
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000443
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000444 switch (ascii_digits) {
445 case 1:
446 /* Read in the first of the three ASCII digits. */
447 switch (kbinput) {
448 /* Add the digit we got to the 100's position of the
449 * ASCII character sequence holder. */
450 case '0':
451 case '1':
452 case '2':
453 ascii_kbinput += (kbinput - '0') * 100;
454 break;
455 default:
456 retval = kbinput;
457 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000458 break;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000459 case 2:
460 /* Read in the second of the three ASCII digits. */
461 switch (kbinput) {
462 /* Add the digit we got to the 10's position of the
463 * ASCII character sequence holder. */
464 case '0':
465 case '1':
466 case '2':
467 case '3':
468 case '4':
469 case '5':
470 ascii_kbinput += (kbinput - '0') * 10;
471 break;
472 case '6':
473 case '7':
474 case '8':
475 case '9':
476 if (ascii_kbinput < 200) {
477 ascii_kbinput += (kbinput - '0') * 10;
478 break;
479 }
480 default:
481 retval = kbinput;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000482 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000483 break;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000484 case 3:
485 /* Read in the third of the three ASCII digits. */
486 switch (kbinput) {
487 /* Add the digit we got to the 1's position of the ASCII
488 * character sequence holder, and save the corresponding
489 * ASCII character as the result. */
490 case '0':
491 case '1':
492 case '2':
493 case '3':
494 case '4':
495 case '5':
496 ascii_kbinput += (kbinput - '0');
497 retval = ascii_kbinput;
498 break;
499 case '6':
500 case '7':
501 case '8':
502 case '9':
503 if (ascii_kbinput < 250) {
504 ascii_kbinput += (kbinput - '0');
505 retval = ascii_kbinput;
506 break;
507 }
508 default:
509 retval = kbinput;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000510 }
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000511 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000512 }
513
514#ifdef DEBUG
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000515 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 +0000516#endif
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000517
518 /* If the result is an ASCII character, reset the ASCII character
519 * sequence holder. */
520 if (retval != ERR)
521 ascii_kbinput = 0;
522
523 return retval;
524}
525
526/* Translate a control character sequence: turn an ASCII non-control
527 * character into its corresponding control character. */
528int get_control_kbinput(int kbinput)
529{
530 int retval = ERR;
531
532 /* We don't handle Ctrl-2 here, since Esc Esc 2 could be the first
533 * part of an ASCII character sequence. */
534
535 /* Ctrl-2 (Ctrl-Space) == Ctrl-@ == Ctrl-` */
536 if (kbinput == ' ' || kbinput == '@' || kbinput == '`')
537 retval = NANO_CONTROL_SPACE;
538 /* Ctrl-3 (Ctrl-[, Esc) to Ctrl-7 (Ctrl-_) */
539 else if (kbinput >= '3' && kbinput <= '7')
540 retval = kbinput - 24;
541 /* Ctrl-8 (Ctrl-?) */
542 else if (kbinput == '8' || kbinput == '?')
543 retval = NANO_CONTROL_8;
544 /* Ctrl-A to Ctrl-_ */
545 else if (kbinput >= 'A' && kbinput <= '_')
546 retval = kbinput - 64;
547 /* Ctrl-a to Ctrl-~ */
548 else if (kbinput >= 'a' && kbinput <= '~')
549 retval = kbinput - 96;
550 else
551 retval = kbinput;
552
553#ifdef DEBUG
554 fprintf(stderr, "get_control_kbinput(): kbinput = %d, retval = %d\n", kbinput, ascii_digits, *complete, retval);
555#endif
556
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000557 return retval;
558}
559
David Lawrence Ramsey58f6d832004-01-27 07:12:47 +0000560/* Translate escape sequences, most of which correspond to extended
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000561 * keypad values, nto their corresponding key values. These sequences
David Lawrence Ramseye65e6392004-06-04 18:18:17 +0000562 * are generated when the keypad doesn't support the needed keys. If
563 * the escape sequence is recognized but we want to ignore it, return
564 * ERR and set ignore_seq to TRUE; if it's unrecognized, return ERR and
565 * set ignore_seq to FALSE. Assume that Escape has already been read
566 * in. */
567int get_escape_seq_kbinput(int *escape_seq, size_t es_len, int
568 *ignore_seq)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000569{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000570 int retval = ERR;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000571
David Lawrence Ramseye65e6392004-06-04 18:18:17 +0000572 *ignore_seq = FALSE;
573
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000574 if (es_len > 1) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000575 switch (escape_seq[0]) {
576 case 'O':
577 switch (escape_seq[1]) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000578 case '2':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000579 if (es_len >= 3) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000580 switch (escape_seq[2]) {
581 case 'P': /* Esc O 2 P == F13 on
582 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000583 retval = KEY_F(13);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000584 break;
585 case 'Q': /* Esc O 2 Q == F14 on
586 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000587 retval = KEY_F(14);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000588 break;
589 }
590 }
591 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000592 case 'A': /* Esc O A == Up on VT100/VT320/xterm. */
593 case 'B': /* Esc O B == Down on
594 * VT100/VT320/xterm. */
595 case 'C': /* Esc O C == Right on
596 * VT100/VT320/xterm. */
597 case 'D': /* Esc O D == Left on
598 * VT100/VT320/xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000599 retval = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000600 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000601 case 'E': /* Esc O E == Center (5) on numeric keypad
602 * with NumLock off on xterm. */
David Lawrence Ramseye65e6392004-06-04 18:18:17 +0000603 *ignore_seq = TRUE;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000604 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000605 case 'F': /* Esc O F == End on xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000606 retval = NANO_END_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000607 break;
608 case 'H': /* Esc O H == Home on xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000609 retval = NANO_HOME_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000610 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000611 case 'M': /* Esc O M == Enter on numeric keypad with
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000612 * NumLock off on
613 * VT100/VT220/VT320/xterm/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000614 retval = NANO_ENTER_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000615 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000616 case 'P': /* Esc O P == F1 on VT100/VT220/VT320/Hurd
617 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000618 retval = KEY_F(1);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000619 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000620 case 'Q': /* Esc O Q == F2 on VT100/VT220/VT320/Hurd
621 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000622 retval = KEY_F(2);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000623 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000624 case 'R': /* Esc O R == F3 on VT100/VT220/VT320/Hurd
625 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000626 retval = KEY_F(3);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000627 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000628 case 'S': /* Esc O S == F4 on VT100/VT220/VT320/Hurd
629 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000630 retval = KEY_F(4);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000631 break;
632 case 'T': /* Esc O T == F5 on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000633 retval = KEY_F(5);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000634 break;
635 case 'U': /* Esc O U == F6 on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000636 retval = KEY_F(6);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000637 break;
638 case 'V': /* Esc O V == F7 on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000639 retval = KEY_F(7);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000640 break;
641 case 'W': /* Esc O W == F8 on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000642 retval = KEY_F(8);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000643 break;
644 case 'X': /* Esc O X == F9 on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000645 retval = KEY_F(9);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000646 break;
647 case 'Y': /* Esc O Y == F10 on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000648 retval = KEY_F(10);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000649 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000650 case 'a': /* Esc O a == Ctrl-Up on rxvt. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000651 case 'b': /* Esc O b == Ctrl-Down on rxvt. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000652 case 'c': /* Esc O c == Ctrl-Right on rxvt. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000653 case 'd': /* Esc O d == Ctrl-Left on rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000654 retval = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000655 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000656 case 'j': /* Esc O j == '*' on numeric keypad with
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000657 * NumLock off on
658 * VT100/VT220/VT320/xterm/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000659 retval = '*';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000660 break;
661 case 'k': /* Esc O k == '+' on numeric keypad with
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000662 * NumLock off on
663 * VT100/VT220/VT320/xterm/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000664 retval = '+';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000665 break;
666 case 'l': /* Esc O l == ',' on numeric keypad with
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000667 * NumLock off on
668 * VT100/VT220/VT320/xterm/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000669 retval = '+';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000670 break;
671 case 'm': /* Esc O m == '-' on numeric keypad with
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000672 * NumLock off on
673 * VT100/VT220/VT320/xterm/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000674 retval = '-';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000675 break;
676 case 'n': /* Esc O n == Delete (.) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000677 * with NumLock off on
678 * VT100/VT220/VT320/xterm/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000679 retval = NANO_DELETE_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000680 break;
681 case 'o': /* Esc O o == '/' on numeric keypad with
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000682 * NumLock off on
683 * VT100/VT220/VT320/xterm/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000684 retval = '/';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000685 break;
686 case 'p': /* Esc O p == Insert (0) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000687 * with NumLock off on
688 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000689 retval = NANO_INSERTFILE_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000690 break;
691 case 'q': /* Esc O q == End (1) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000692 * with NumLock off on
693 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000694 retval = NANO_END_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000695 break;
696 case 'r': /* Esc O r == Down (2) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000697 * with NumLock off on
698 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000699 retval = NANO_NEXTLINE_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000700 break;
701 case 's': /* Esc O s == PageDown (3) on numeric
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000702 * keypad with NumLock off on
703 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000704 retval = NANO_NEXTPAGE_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000705 break;
706 case 't': /* Esc O t == Left (4) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000707 * with NumLock off on
708 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000709 retval = NANO_BACK_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000710 break;
711 case 'u': /* Esc O u == Center (5) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000712 * with NumLock off on
713 * VT100/VT220/VT320/rxvt/Eterm. */
David Lawrence Ramseye65e6392004-06-04 18:18:17 +0000714 *ignore_seq = TRUE;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000715 break;
716 case 'v': /* Esc O v == Right (6) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000717 * with NumLock off on
718 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000719 retval = NANO_FORWARD_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000720 break;
721 case 'w': /* Esc O w == Home (7) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000722 * with NumLock off on
723 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000724 retval = NANO_HOME_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000725 break;
726 case 'x': /* Esc O x == Up (8) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000727 * with NumLock off on
728 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000729 retval = NANO_PREVLINE_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000730 break;
731 case 'y': /* Esc O y == PageUp (9) on numeric keypad
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000732 * with NumLock off on
733 * VT100/VT220/VT320/rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000734 retval = NANO_PREVPAGE_KEY;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000735 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000736 }
737 break;
738 case 'o':
739 switch (escape_seq[1]) {
740 case 'a': /* Esc o a == Ctrl-Up on Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000741 case 'b': /* Esc o b == Ctrl-Down on Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000742 case 'c': /* Esc o c == Ctrl-Right on Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000743 case 'd': /* Esc o d == Ctrl-Left on Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000744 retval = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000745 break;
746 }
747 break;
748 case '[':
749 switch (escape_seq[1]) {
750 case '1':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000751 if (es_len >= 3) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000752 switch (escape_seq[2]) {
753 case '1': /* Esc [ 1 1 ~ == F1 on
754 * rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000755 retval = KEY_F(1);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000756 break;
757 case '2': /* Esc [ 1 2 ~ == F2 on
758 * rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000759 retval = KEY_F(2);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000760 break;
761 case '3': /* Esc [ 1 3 ~ == F3 on
762 * rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000763 retval = KEY_F(3);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000764 break;
765 case '4': /* Esc [ 1 4 ~ == F4 on
766 * rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000767 retval = KEY_F(4);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000768 break;
769 case '5': /* Esc [ 1 5 ~ == F5 on
770 * xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000771 retval = KEY_F(5);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000772 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000773 case '7': /* Esc [ 1 7 ~ == F6 on
774 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000775 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000776 retval = KEY_F(6);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000777 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000778 case '8': /* Esc [ 1 8 ~ == F7 on
779 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000780 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000781 retval = KEY_F(7);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000782 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000783 case '9': /* Esc [ 1 9 ~ == F8 on
784 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000785 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000786 retval = KEY_F(8);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000787 break;
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000788 case ';':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000789 if (es_len >= 4) {
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000790 switch (escape_seq[3]) {
791 case '2':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000792 if (es_len >= 5) {
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000793 switch (escape_seq[4]) {
794 case 'A': /* Esc [ 1 ; 2 A == Shift-Up on
795 * xterm. */
796 case 'B': /* Esc [ 1 ; 2 B == Shift-Down on
797 * xterm. */
798 case 'C': /* Esc [ 1 ; 2 C == Shift-Right on
799 * xterm. */
800 case 'D': /* Esc [ 1 ; 2 D == Shift-Left on
801 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000802 retval = get_escape_seq_abcd(escape_seq[4]);
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000803 break;
804 }
805 }
806 break;
807 case '5':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000808 if (es_len >= 5) {
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000809 switch (escape_seq[4]) {
810 case 'A': /* Esc [ 1 ; 5 A == Ctrl-Up on
811 * xterm. */
812 case 'B': /* Esc [ 1 ; 5 B == Ctrl-Down on
813 * xterm. */
814 case 'C': /* Esc [ 1 ; 5 C == Ctrl-Right on
815 * xterm. */
816 case 'D': /* Esc [ 1 ; 5 D == Ctrl-Left on
817 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000818 retval = get_escape_seq_abcd(escape_seq[4]);
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000819 break;
820 }
821 }
822 break;
823 }
824 }
825 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000826 default: /* Esc [ 1 ~ == Home on
827 * VT320/Linux console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000828 retval = NANO_HOME_KEY;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000829 break;
830 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000831 }
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000832 break;
833 case '2':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000834 if (es_len >= 3) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000835 switch (escape_seq[2]) {
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000836 case '0': /* Esc [ 2 0 ~ == F9 on
837 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000838 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000839 retval = KEY_F(9);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000840 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000841 case '1': /* Esc [ 2 1 ~ == F10 on
842 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000843 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000844 retval = KEY_F(10);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000845 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000846 case '3': /* Esc [ 2 3 ~ == F11 on
847 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000848 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000849 retval = KEY_F(11);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000850 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000851 case '4': /* Esc [ 2 4 ~ == F12 on
852 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000853 * console/xterm/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000854 retval = KEY_F(12);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000855 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000856 case '5': /* Esc [ 2 5 ~ == F13 on
857 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000858 * console/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000859 retval = KEY_F(13);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000860 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000861 case '6': /* Esc [ 2 6 ~ == F14 on
862 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000863 * console/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000864 retval = KEY_F(14);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000865 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000866 default: /* Esc [ 2 ~ == Insert on
867 * VT220/VT320/Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000868 * console/xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000869 retval = NANO_INSERTFILE_KEY;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000870 break;
871 }
872 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000873 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000874 case '3': /* Esc [ 3 ~ == Delete on
875 * VT220/VT320/Linux console/xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000876 retval = NANO_DELETE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000877 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000878 case '4': /* Esc [ 4 ~ == End on VT220/VT320/Linux
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000879 * console/xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000880 retval = NANO_END_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000881 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000882 case '5': /* Esc [ 5 ~ == PageUp on
883 * VT220/VT320/Linux console/xterm; Esc [
884 * 5 ^ == PageUp on Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000885 retval = NANO_PREVPAGE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000886 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000887 case '6': /* Esc [ 6 ~ == PageDown on
888 * VT220/VT320/Linux console/xterm; Esc [
889 * 6 ^ == PageDown on Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000890 retval = NANO_NEXTPAGE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000891 break;
892 case '7': /* Esc [ 7 ~ == Home on rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000893 retval = NANO_HOME_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000894 break;
895 case '8': /* Esc [ 8 ~ == End on rxvt. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000896 retval = NANO_END_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000897 break;
898 case '9': /* Esc [ 9 == Delete on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000899 retval = NANO_DELETE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000900 break;
901 case '@': /* Esc [ @ == Insert on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000902 retval = NANO_INSERTFILE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000903 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000904 case 'A': /* Esc [ A == Up on ANSI/VT220/Linux
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000905 * console/FreeBSD console/Hurd
906 * console/rxvt/Eterm. */
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000907 case 'B': /* Esc [ B == Down on ANSI/VT220/Linux
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000908 * console/FreeBSD console/Hurd
909 * console/rxvt/Eterm. */
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000910 case 'C': /* Esc [ C == Right on ANSI/VT220/Linux
911 * console/FreeBSD console/Hurd
912 * console/rxvt/Eterm. */
913 case 'D': /* Esc [ D == Left on ANSI/VT220/Linux
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000914 * console/FreeBSD console/Hurd
915 * console/rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000916 retval = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000917 break;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000918 case 'E': /* Esc [ E == Center (5) on numeric keypad
919 * with NumLock off on FreeBSD console. */
David Lawrence Ramseye65e6392004-06-04 18:18:17 +0000920 *ignore_seq = TRUE;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000921 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000922 case 'F': /* Esc [ F == End on FreeBSD
923 * console/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000924 retval = NANO_END_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000925 break;
926 case 'G': /* Esc [ G == PageDown on FreeBSD
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000927 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000928 retval = NANO_NEXTPAGE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000929 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000930 case 'H': /* Esc [ H == Home on ANSI/VT220/FreeBSD
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000931 * console/Hurd console/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000932 retval = NANO_HOME_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000933 break;
934 case 'I': /* Esc [ I == PageUp on FreeBSD
935 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000936 retval = NANO_PREVPAGE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000937 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000938 case 'L': /* Esc [ L == Insert on ANSI/FreeBSD
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000939 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000940 retval = NANO_INSERTFILE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000941 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000942 case 'M': /* Esc [ M == F1 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000943 retval = KEY_F(1);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000944 break;
945 case 'N': /* Esc [ N == F2 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000946 retval = KEY_F(2);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000947 break;
948 case 'O':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000949 if (es_len >= 3) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000950 switch (escape_seq[2]) {
951 case 'P': /* Esc [ O P == F1 on
952 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000953 retval = KEY_F(1);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000954 break;
955 case 'Q': /* Esc [ O Q == F2 on
956 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000957 retval = KEY_F(2);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000958 break;
959 case 'R': /* Esc [ O R == F3 on
960 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000961 retval = KEY_F(3);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000962 break;
963 case 'S': /* Esc [ O S == F4 on
964 * xterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000965 retval = KEY_F(4);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000966 break;
967 default: /* Esc [ O == F3 on
968 * FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000969 retval = KEY_F(3);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000970 break;
971 }
972 }
973 break;
974 case 'P': /* Esc [ P == F4 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000975 retval = KEY_F(4);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000976 break;
977 case 'Q': /* Esc [ Q == F5 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000978 retval = KEY_F(5);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000979 break;
980 case 'R': /* Esc [ R == F6 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000981 retval = KEY_F(6);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000982 break;
983 case 'S': /* Esc [ S == F7 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000984 retval = KEY_F(7);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000985 break;
986 case 'T': /* Esc [ T == F8 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000987 retval = KEY_F(8);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000988 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000989 case 'U': /* Esc [ U == PageDown on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000990 retval = NANO_NEXTPAGE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000991 break;
992 case 'V': /* Esc [ V == PageUp on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000993 retval = NANO_PREVPAGE_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000994 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000995 case 'W': /* Esc [ W == F11 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000996 retval = KEY_F(11);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000997 break;
998 case 'X': /* Esc [ X == F12 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000999 retval = KEY_F(12);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001000 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001001 case 'Y': /* Esc [ Y == End on Hurd console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001002 retval = NANO_END_KEY;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001003 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001004 case 'Z': /* Esc [ Z == F14 on FreeBSD console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001005 retval = KEY_F(14);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001006 break;
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +00001007 case 'a': /* Esc [ a == Shift-Up on rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +00001008 case 'b': /* Esc [ b == Shift-Down on rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +00001009 case 'c': /* Esc [ c == Shift-Right on
1010 * rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +00001011 case 'd': /* Esc [ d == Shift-Left on rxvt/Eterm. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001012 retval = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001013 break;
1014 case '[':
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001015 if (es_len >= 3) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001016 switch (escape_seq[2]) {
1017 case 'A': /* Esc [ [ A == F1 on Linux
1018 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001019 retval = KEY_F(1);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001020 break;
1021 case 'B': /* Esc [ [ B == F2 on Linux
1022 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001023 retval = KEY_F(2);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001024 break;
1025 case 'C': /* Esc [ [ C == F3 on Linux
1026 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001027 retval = KEY_F(3);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001028 break;
1029 case 'D': /* Esc [ [ D == F4 on Linux
1030 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001031 retval = KEY_F(4);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001032 break;
1033 case 'E': /* Esc [ [ E == F5 on Linux
1034 * console. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001035 retval = KEY_F(5);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001036 break;
1037 }
1038 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001039 break;
1040 }
1041 break;
1042 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001043 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001044
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001045#ifdef DEBUG
David Lawrence Ramseye65e6392004-06-04 18:18:17 +00001046 fprintf(stderr, "get_escape_seq_kbinput(): retval = %d, ignore_seq = %d\n", retval, *ignore_seq);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001047#endif
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001048
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001049 return retval;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001050}
1051
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001052/* Return the equivalent arrow key value for the case-insensitive
David Lawrence Ramseyb7e5cf62004-02-07 03:39:48 +00001053 * letters A (up), B (down), C (right), and D (left). These are common
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001054 * to many escape sequences. */
1055int get_escape_seq_abcd(int kbinput)
1056{
1057 switch (tolower(kbinput)) {
1058 case 'a':
1059 return NANO_PREVLINE_KEY;
1060 case 'b':
1061 return NANO_NEXTLINE_KEY;
1062 case 'c':
1063 return NANO_FORWARD_KEY;
1064 case 'd':
1065 return NANO_BACK_KEY;
1066 default:
1067 return ERR;
1068 }
1069}
1070
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001071/* Read in a string of input characters (e.g. an escape sequence)
1072 * verbatim. Store the string in v_kbinput and return the length
1073 * of the string in v_len. Assume nodelay(win) is FALSE. */
1074int *get_verbatim_kbinput(WINDOW *win, int *v_kbinput, size_t
1075 *v_len, int allow_ascii)
1076{
1077 int kbinput;
1078 size_t i = 0, v_newlen = 0;
1079
1080#ifndef NANO_SMALL
1081 allow_pending_sigwinch(TRUE);
1082#endif
1083
1084 *v_len = 0;
1085 v_kbinput = (int *)nmalloc(sizeof(int));
1086
1087 /* Turn off flow control characters if necessary so that we can type
1088 * them in verbatim, and turn the keypad off so that we don't get
1089 * extended keypad values outside the ASCII range. */
1090 if (ISSET(PRESERVE))
1091 disable_flow_control();
1092 keypad(win, FALSE);
1093
1094 /* Read the first character using blocking input, since using
1095 * non-blocking input will eat up all unused CPU. Then increment
1096 * v_len and save the character in v_kbinput. */
1097 kbinput = wgetch(win);
1098 (*v_len)++;
1099 v_kbinput[0] = kbinput;
1100#ifdef DEBUG
1101 fprintf(stderr, "get_verbatim_kbinput(): kbinput = %d, v_len = %d\n", kbinput, *v_len);
1102#endif
1103
1104 /* Read any following characters using non-blocking input, until
1105 * there aren't any left to be read, and save the complete string of
1106 * characters in v_kbinput, incrementing v_len accordingly. We read
1107 * them all at once in order to minimize the chance that there might
1108 * be a delay greater than nodelay() provides for between them, in
1109 * which case we'll stop before all of them are read. */
1110 nodelay(win, TRUE);
1111 while ((kbinput = wgetch(win)) != ERR) {
1112 (*v_len)++;
1113 v_kbinput = (int *)nrealloc(v_kbinput, *v_len * sizeof(int));
1114 v_kbinput[*v_len - 1] = kbinput;
1115#ifdef DEBUG
1116 fprintf(stderr, "get_verbatim_kbinput(): kbinput = %d, v_len = %d\n", kbinput, *v_len);
1117#endif
1118 }
1119 nodelay(win, FALSE);
1120
1121 /* Pass the string of characters to get_untranslated_kbinput(), one
1122 * by one, so it can handle them as ASCII character sequences and/or
1123 * escape sequences. Filter out ERR's from v_kbinput in the
1124 * process; they shouldn't occur in the string of characters unless
1125 * we're reading an incomplete sequence, in which case we only want
1126 * to keep the complete sequence. */
1127 for (; i < *v_len; i++) {
1128 v_kbinput[v_newlen] = get_untranslated_kbinput(v_kbinput[i], i,
1129 allow_ascii
1130#ifndef NANO_SMALL
1131 , FALSE
1132#endif
1133 );
1134 if (v_kbinput[i] != ERR && v_kbinput[v_newlen] != ERR)
1135 v_newlen++;
1136 }
1137
1138 if (v_newlen == 0) {
1139 /* If there were no characters after the ERR's were filtered
1140 * out, set v_len and reallocate v_kbinput to account for
1141 * one character, and set that character to ERR. */
1142 *v_len = 1;
1143 v_kbinput = (int *)nrealloc(v_kbinput, sizeof(int));
1144 v_kbinput[0] = ERR;
1145 } else if (v_newlen != *v_len) {
1146 /* If there were fewer characters after the ERR's were filtered
1147 * out, set v_len and reallocate v_kbinput to account for
1148 * the new number of characters. */
1149 *v_len = v_newlen;
1150 v_kbinput = (int *)nrealloc(v_kbinput, *v_len * sizeof(int));
1151 }
1152
1153 /* If allow_ascii is TRUE and v_kbinput[0] is ERR, we need to
1154 * complete an ASCII character sequence. Keep reading in characters
1155 * using blocking input until we get a complete sequence. */
1156 if (allow_ascii && v_kbinput[0] == ERR) {
1157 while (v_kbinput[0] == ERR) {
1158 kbinput = wgetch(win);
1159 v_kbinput[0] = get_untranslated_kbinput(kbinput, i,
1160 allow_ascii
1161#ifndef NANO_SMALL
1162 , FALSE
1163#endif
1164 );
1165 i++;
1166 }
1167 }
1168
1169 /* Turn flow control characters back on if necessary and turn the
1170 * keypad back on now that we're done. */
1171 if (ISSET(PRESERVE))
1172 enable_flow_control();
1173 keypad(win, TRUE);
1174
1175#ifndef NANO_SMALL
1176 allow_pending_sigwinch(FALSE);
1177#endif
1178
1179 return v_kbinput;
1180}
1181
1182int get_untranslated_kbinput(int kbinput, size_t position, int
1183 allow_ascii
1184#ifndef NANO_SMALL
1185 , int reset
1186#endif
1187 )
1188{
1189 static size_t ascii_digits = 0;
1190 int retval;
1191
1192#ifndef NANO_SMALL
1193 if (reset) {
1194 ascii_digits = 0;
1195 return ERR;
1196 }
1197#endif
1198
1199 if (allow_ascii) {
1200 /* position is equal to the number of ASCII digits we've read so
1201 * far, and kbinput is a digit from '0' to '9': ASCII character
1202 * sequence mode. If the digit sequence's range is limited to
1203 * 2XX (the first digit is in the '0' to '2' range and it's the
1204 * first digit, or if it's in the full digit range and it's not
1205 * the first digit), increment the ASCII digit counter and
1206 * interpret the digit. If the digit sequence's range is not
1207 * limited to 2XX, fall through. */
1208 if (position == ascii_digits && kbinput >= '0' && kbinput <= '9') {
1209 if (kbinput <= '2' || ascii_digits > 0) {
1210 ascii_digits++;
1211 kbinput = get_ascii_kbinput(kbinput, ascii_digits
1212#ifndef NANO_SMALL
1213 , FALSE
1214#endif
1215 );
1216 if (kbinput != ERR)
1217 /* If we've read in a complete ASCII digit sequence,
1218 * reset the ASCII digit counter. */
1219 ascii_digits = 0;
1220 }
1221 } else if (ascii_digits > 0)
1222 /* position is not equal to the number of ASCII digits we've
1223 * read or kbinput is a non-digit, and we're in the middle
1224 * of an ASCII character sequence. Reset the ASCII digit
1225 * counter. */
1226 ascii_digits = 0;
1227 }
1228
1229 /* Save the corresponding ASCII character as the result if we've
1230 * read in a complete ASCII digit sequence, or the passed-in
1231 * character if we haven't. */
1232 retval = kbinput;
1233
1234#ifdef DEBUG
1235 fprintf(stderr, "get_untranslated_kbinput(): kbinput = %d, position = %d, ascii_digits = %d\n", kbinput, position, ascii_digits);
1236#endif
1237
1238 return retval;
1239}
1240
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001241#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001242/* Check for a mouse event, and if one's taken place, save the
1243 * coordinates where it took place in mouse_x and mouse_y. After that,
1244 * if allow_shortcuts is zero, return 0. Otherwise, if the mouse event
1245 * took place on the shortcut list on the bottom two lines of the screen
1246 * (assuming that the shortcut list is visible), figure out which
1247 * shortcut was clicked and ungetch() the equivalent keystroke(s).
1248 * Return 0 if no keystrokes were ungetch()ed, or 1 if at least one was.
1249 * Assume that KEY_MOUSE has already been read in. */
1250int get_mouseinput(int *mouse_x, int *mouse_y, int allow_shortcuts)
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001251{
1252 MEVENT mevent;
1253
1254 *mouse_x = -1;
1255 *mouse_y = -1;
1256
1257 /* First, get the actual mouse event. */
1258 if (getmouse(&mevent) == ERR)
1259 return 0;
1260
1261 /* Save the screen coordinates where the mouse event took place. */
1262 *mouse_x = mevent.x;
1263 *mouse_y = mevent.y;
1264
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001265 /* If we're not allowing shortcuts' we're done now. */
1266 if (!allow_shortcuts)
1267 return 0;
1268
1269 /* Otherwise, if the current shortcut list is being displayed on the
1270 * last two lines of the screen and the mouse event took place
1271 * inside it, we need to figure out which shortcut was clicked and
1272 * ungetch() the equivalent keystroke(s) for it. */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001273 if (!ISSET(NO_HELP) && wenclose(bottomwin, *mouse_y, *mouse_x)) {
1274 int i, j;
1275 int currslen;
1276 /* The number of shortcuts in the current shortcut list. */
1277 const shortcut *s = currshortcut;
1278 /* The actual shortcut we clicked on, starting at the first
1279 * one in the current shortcut list. */
1280
1281 /* Get the shortcut lists' length. */
1282 if (currshortcut == main_list)
1283 currslen = MAIN_VISIBLE;
1284 else
1285 currslen = length_of_list(currshortcut);
1286
1287 /* Calculate the width of each shortcut in the list (it's the
1288 * same for all of them). */
1289 if (currslen < 2)
1290 i = COLS / 6;
1291 else
1292 i = COLS / ((currslen / 2) + (currslen % 2));
1293
1294 /* Calculate the y-coordinates relative to the beginning of
1295 * bottomwin, i.e, the bottom three lines of the screen. */
1296 j = *mouse_y - (editwinrows + 3);
1297
1298 /* If we're on the statusbar, beyond the end of the shortcut
1299 * list, or beyond the end of a shortcut on the right side of
1300 * the screen, don't do anything. */
1301 if (j < 0 || (*mouse_x / i) >= currslen)
1302 return 0;
1303 j = (*mouse_x / i) * 2 + j;
1304 if (j >= currslen)
1305 return 0;
1306
1307 /* Go through the shortcut list to determine which shortcut was
1308 * clicked. */
1309 for (; j > 0; j--)
1310 s = s->next;
1311
David Lawrence Ramsey32613fa2004-05-24 18:40:41 +00001312 /* And ungetch() the equivalent control key. If it's a meta key
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001313 * sequence, we need to ungetch() Escape too. Assume that the
1314 * shortcut has an equivalent control key, meta key sequence, or
1315 * both. */
1316 if (s->ctrlval != NANO_NO_KEY)
1317 ungetch(s->ctrlval);
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001318 else if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001319 ungetch(s->metaval);
1320 ungetch(NANO_CONTROL_3);
1321 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001322
1323 return 1;
1324 }
1325 return 0;
1326}
1327#endif
1328
Chris Allegretta6df90f52002-07-19 01:08:59 +00001329/* Return the placewewant associated with current_x. That is, xplustabs
1330 * is the zero-based column position of the cursor. Value is no smaller
1331 * than current_x. */
1332size_t xplustabs(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001333{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001334 return strnlenpt(current->data, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001335}
1336
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001337/* actual_x() gives the index in str of the character displayed at
1338 * column xplus. That is, actual_x() is the largest value such that
1339 * strnlenpt(str, actual_x(str, xplus)) <= xplus. */
1340size_t actual_x(const char *str, size_t xplus)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001341{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001342 size_t i = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001343 /* the position in str, returned */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001344 size_t length = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001345 /* the screen display width to str[i] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001346
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001347 assert(str != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001348
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001349 for (; length < xplus && *str != '\0'; i++, str++) {
1350 if (*str == '\t')
David Lawrence Ramsey0362c582003-09-30 03:31:56 +00001351 length += tabsize - (length % tabsize);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001352 else if (is_cntrl_char((int)*str))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001353 length += 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001354 else
1355 length++;
1356 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001357 assert(length == strnlenpt(str - i, i));
1358 assert(i <= strlen(str - i));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001359
Chris Allegretta6df90f52002-07-19 01:08:59 +00001360 if (length > xplus)
1361 i--;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001362
Chris Allegretta6df90f52002-07-19 01:08:59 +00001363 return i;
Robert Siemborskid8510b22000-06-06 23:04:06 +00001364}
1365
David Lawrence Ramseya3370c42004-04-05 01:08:14 +00001366/* A strlen() with tabs factored in, similar to xplustabs(). How many
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +00001367 * columns wide are the first size characters of buf? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001368size_t strnlenpt(const char *buf, size_t size)
Robert Siemborskid8510b22000-06-06 23:04:06 +00001369{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001370 size_t length = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001371
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +00001372 assert(buf != NULL);
1373 for (; *buf != '\0' && size != 0; size--, buf++) {
1374 if (*buf == '\t')
1375 length += tabsize - (length % tabsize);
1376 else if (is_cntrl_char((int)*buf))
1377 length += 2;
1378 else
1379 length++;
1380 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001381 return length;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001382}
1383
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +00001384/* How many columns wide is buf? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001385size_t strlenpt(const char *buf)
Chris Allegrettad4fa0d32002-03-05 19:55:55 +00001386{
David Lawrence Ramsey0b047c52004-03-29 23:09:08 +00001387 return strnlenpt(buf, (size_t)-1);
Chris Allegrettad4fa0d32002-03-05 19:55:55 +00001388}
1389
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001390void blank_titlebar(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001391{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001392 mvwaddstr(topwin, 0, 0, hblank);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001393}
1394
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001395void blank_edit(void)
1396{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001397 size_t i;
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001398 for (i = 0; i < editwinrows; i++)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001399 mvwaddstr(edit, i, 0, hblank);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001400}
1401
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001402void blank_statusbar(void)
1403{
1404 mvwaddstr(bottomwin, 0, 0, hblank);
1405}
1406
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001407void check_statblank(void)
1408{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001409 if (statblank > 1)
1410 statblank--;
1411 else if (statblank == 1 && !ISSET(CONSTUPDATE)) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001412 statblank = 0;
1413 blank_statusbar();
1414 wnoutrefresh(bottomwin);
1415 reset_cursor();
1416 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001417 }
1418}
1419
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001420void blank_bottombars(void)
1421{
1422 if (!ISSET(NO_HELP)) {
1423 mvwaddstr(bottomwin, 1, 0, hblank);
1424 mvwaddstr(bottomwin, 2, 0, hblank);
1425 }
1426}
1427
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001428/* Convert buf into a string that can be displayed on screen. The
1429 * caller wants to display buf starting with column start_col, and
1430 * extending for at most len columns. start_col is zero-based. len is
1431 * one-based, so len == 0 means you get "" returned. The returned
1432 * string is dynamically allocated, and should be freed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001433char *display_string(const char *buf, size_t start_col, size_t len)
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001434{
1435 size_t start_index;
1436 /* Index in buf of first character shown in return value. */
1437 size_t column;
1438 /* Screen column start_index corresponds to. */
1439 size_t end_index;
1440 /* Index in buf of last character shown in return value. */
1441 size_t alloc_len;
1442 /* The length of memory allocated for converted. */
1443 char *converted;
1444 /* The string we return. */
1445 size_t index;
1446 /* Current position in converted. */
1447
1448 if (len == 0)
1449 return mallocstrcpy(NULL, "");
1450
1451 start_index = actual_x(buf, start_col);
1452 column = strnlenpt(buf, start_index);
1453 assert(column <= start_col);
1454 end_index = actual_x(buf, start_col + len - 1);
1455 alloc_len = strnlenpt(buf, end_index + 1) - column;
1456 if (len > alloc_len + column - start_col)
1457 len = alloc_len + column - start_col;
1458 converted = charalloc(alloc_len + 1);
1459 buf += start_index;
1460 index = 0;
1461
1462 for (; index < alloc_len; buf++) {
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00001463 if (*buf == '\t') {
1464 converted[index++] =
1465#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
1466 ISSET(WHITESPACE_DISPLAY) ? whitespace[0] :
1467#endif
1468 ' ';
1469 while ((column + index) % tabsize)
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001470 converted[index++] = ' ';
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00001471 } else if (is_cntrl_char(*buf)) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001472 converted[index++] = '^';
1473 if (*buf == '\n')
1474 /* Treat newlines embedded in a line as encoded nulls;
1475 * the line in question should be run through unsunder()
1476 * before reaching here. */
1477 converted[index++] = '@';
1478 else if (*buf == NANO_CONTROL_8)
1479 converted[index++] = '?';
1480 else
1481 converted[index++] = *buf + 64;
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00001482 } else if (*buf == ' ')
1483 converted[index++] =
1484#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
1485 ISSET(WHITESPACE_DISPLAY) ? whitespace[1] :
1486#endif
1487 ' ';
1488 else
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001489 converted[index++] = *buf;
1490 }
1491 assert(len <= alloc_len + column - start_col);
1492 charmove(converted, converted + start_col - column, len);
1493 null_at(&converted, len);
1494
1495 return charealloc(converted, len + 1);
1496}
1497
Chris Allegretta7662c862003-01-13 01:35:15 +00001498/* Repaint the statusbar when getting a character in nanogetstr(). buf
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001499 * should be no longer than max(0, COLS - 4).
Chris Allegretta6df90f52002-07-19 01:08:59 +00001500 *
Chris Allegretta7662c862003-01-13 01:35:15 +00001501 * Note that we must turn on A_REVERSE here, since do_help() turns it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001502 * off! */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001503void nanoget_repaint(const char *buf, const char *inputbuf, size_t x)
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001504{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001505 size_t x_real = strnlenpt(inputbuf, x);
1506 int wid = COLS - strlen(buf) - 2;
Chris Allegretta0d1e8d62000-11-02 15:30:24 +00001507
Chris Allegretta6df90f52002-07-19 01:08:59 +00001508 assert(0 <= x && x <= strlen(inputbuf));
1509
Chris Allegrettab3655b42001-10-22 03:15:31 +00001510 wattron(bottomwin, A_REVERSE);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001511 blank_statusbar();
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001512
Chris Allegretta6df90f52002-07-19 01:08:59 +00001513 mvwaddstr(bottomwin, 0, 0, buf);
1514 waddch(bottomwin, ':');
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001515
1516 if (COLS > 1)
1517 waddch(bottomwin, x_real < wid ? ' ' : '$');
1518 if (COLS > 2) {
1519 size_t page_start = x_real - x_real % wid;
1520 char *expanded = display_string(inputbuf, page_start, wid);
1521
1522 assert(wid > 0);
1523 assert(strlen(expanded) <= wid);
1524 waddstr(bottomwin, expanded);
1525 free(expanded);
1526 wmove(bottomwin, 0, COLS - wid + x_real - page_start);
1527 } else
1528 wmove(bottomwin, 0, COLS - 1);
Chris Allegrettab3655b42001-10-22 03:15:31 +00001529 wattroff(bottomwin, A_REVERSE);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001530}
1531
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001532/* Get the input from the keyboard; this should only be called from
Chris Allegretta6df90f52002-07-19 01:08:59 +00001533 * statusq(). */
Chris Allegrettaf717f982003-02-13 22:25:01 +00001534int nanogetstr(int allowtabs, const char *buf, const char *def,
Chris Allegretta5beed502003-01-05 20:41:21 +00001535#ifndef NANO_SMALL
1536 historyheadtype *history_list,
1537#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001538 const shortcut *s
Rocco Corsi06aca1c2001-01-11 05:30:31 +00001539#ifndef DISABLE_TABCOMP
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001540 , int *list
Chris Allegrettabe77c612000-11-24 14:00:16 +00001541#endif
Chris Allegretta65f075d2003-02-13 03:03:49 +00001542 )
Chris Allegretta6df90f52002-07-19 01:08:59 +00001543{
1544 int kbinput;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001545 int meta_key;
Chris Allegretta09fc4302003-01-16 22:16:38 +00001546 static int x = -1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001547 /* the cursor position in 'answer' */
1548 int xend;
1549 /* length of 'answer', the status bar text */
1550 int tabbed = 0;
1551 /* used by input_tab() */
1552 const shortcut *t;
Chris Allegretta598106e2002-01-19 01:59:37 +00001553
Chris Allegretta5beed502003-01-05 20:41:21 +00001554#ifndef NANO_SMALL
1555 /* for history */
1556 char *history = NULL;
Chris Allegretta8031f832003-01-09 05:29:58 +00001557 char *currentbuf = NULL;
Chris Allegretta5beed502003-01-05 20:41:21 +00001558 char *complete = NULL;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001559 int last_kbinput = 0;
1560
1561 /* This variable is used in the search history code. use_cb == 0
1562 means that we're using the existing history and ignoring
1563 currentbuf. use_cb == 1 means that the entry in answer should be
1564 moved to currentbuf or restored from currentbuf to answer.
1565 use_cb == 2 means that the entry in currentbuf should be moved to
1566 answer or restored from answer to currentbuf. */
1567 int use_cb = 0;
Chris Allegretta5beed502003-01-05 20:41:21 +00001568#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001569 xend = strlen(def);
Chris Allegretta09fc4302003-01-16 22:16:38 +00001570
1571 /* Only put x at the end of the string if it's uninitialized or if
1572 it would be past the end of the string as it is. Otherwise,
1573 leave it alone. This is so the cursor position stays at the same
1574 place if a prompt-changing toggle is pressed. */
Chris Allegretta65f075d2003-02-13 03:03:49 +00001575 if (x == -1 || x > xend || resetstatuspos)
Chris Allegretta09fc4302003-01-16 22:16:38 +00001576 x = xend;
1577
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00001578 answer = charealloc(answer, xend + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001579 if (xend > 0)
1580 strcpy(answer, def);
1581 else
1582 answer[0] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001583
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001584#if !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001585 currshortcut = s;
Chris Allegretta6fe61492001-05-21 12:56:25 +00001586#endif
1587
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001588 /* Get the input! */
Chris Allegretta31925e42000-11-02 04:40:39 +00001589
Chris Allegretta6df90f52002-07-19 01:08:59 +00001590 nanoget_repaint(buf, answer, x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001591
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001592 /* Make sure any editor screen updates are displayed before getting
1593 input */
Chris Allegretta022b96f2000-11-14 17:47:58 +00001594 wrefresh(edit);
1595
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00001596 /* If we're using restricted mode, we aren't allowed to change the
1597 * name of a file once it has one because that would allow writing
1598 * to files not specified on the command line. In this case,
1599 * disable all keys that would change the text if the filename isn't
1600 * blank and we're at the "Write File" prompt. */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001601 while ((kbinput = get_kbinput(bottomwin, &meta_key)) != NANO_ENTER_KEY) {
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001602 for (t = s; t != NULL; t = t->next) {
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001603#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001604 fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput, kbinput);
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001605#endif
1606
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001607 /* Temporary hack to interpret NANO_HELP_FKEY correctly. */
1608 if (kbinput == t->funcval)
1609 kbinput = t->ctrlval;
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00001610
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001611 if (kbinput == t->ctrlval && is_cntrl_char(kbinput)) {
Chris Allegretta5bf51d32000-11-16 06:01:10 +00001612
Chris Allegrettab3655b42001-10-22 03:15:31 +00001613#ifndef DISABLE_HELP
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001614 /* Have to do this here, it would be too late to do it
1615 in statusq() */
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00001616 if (kbinput == NANO_HELP_KEY) {
Chris Allegrettab3655b42001-10-22 03:15:31 +00001617 do_help();
1618 break;
1619 }
1620#endif
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001621#ifndef NANO_SMALL
1622 /* Have to handle these here too, for the time being */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001623 if (kbinput == NANO_PREVLINE_KEY || kbinput == NANO_NEXTLINE_KEY)
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001624 break;
1625#endif
Chris Allegretta5af58892003-01-17 21:07:38 +00001626
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001627 return t->ctrlval;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001628 }
1629 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001630 assert(0 <= x && x <= xend && xend == strlen(answer));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001631
Chris Allegretta04d848e2000-11-05 17:54:41 +00001632 if (kbinput != '\t')
1633 tabbed = 0;
1634
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001635 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001636#ifndef DISABLE_MOUSE
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001637 case KEY_MOUSE:
1638 do_mouse();
1639 break;
1640#endif
Chris Allegretta658399a2001-06-14 02:54:22 +00001641 case NANO_HOME_KEY:
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00001642#ifndef NANO_SMALL
1643 if (ISSET(SMART_HOME)) {
1644 int old_x = x;
1645
1646 for (x = 0; isblank(answer[x]) && x < xend; x++)
1647 ;
1648
1649 if (x == old_x || x == xend)
1650 x = 0;
1651 } else
1652#endif
1653 x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001654 break;
Chris Allegretta658399a2001-06-14 02:54:22 +00001655 case NANO_END_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001656 x = xend;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001657 break;
Chris Allegretta35dac582001-03-21 15:07:20 +00001658 case NANO_FORWARD_KEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001659 if (x < xend)
1660 x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001661 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001662 case NANO_DELETE_KEY:
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00001663 /* If we're using restricted mode, the filename isn't blank,
1664 * and we're at the "Write File" prompt, disable Delete. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001665 if (!ISSET(RESTRICTED) || filename[0] == '\0' || s != writefile_list) {
1666 if (x < xend) {
1667 charmove(answer + x, answer + x + 1, xend - x);
1668 xend--;
1669 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001670 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001671 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001672 case NANO_CUT_KEY:
1673 case NANO_UNCUT_KEY:
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00001674 /* If we're using restricted mode, the filename isn't blank,
1675 * and we're at the "Write File" prompt, disable Cut and
1676 * UnCut. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001677 if (!ISSET(RESTRICTED) || filename[0] == '\0' || s != writefile_list) {
1678 null_at(&answer, 0);
1679 xend = 0;
1680 x = 0;
1681 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001682 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001683 case NANO_BACKSPACE_KEY:
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00001684 /* If we're using restricted mode, the filename isn't blank,
1685 * and we're at the "Write File" prompt, disable
1686 * Backspace. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001687 if (!ISSET(RESTRICTED) || filename[0] == '\0' || s != writefile_list) {
1688 if (x > 0) {
1689 charmove(answer + x - 1, answer + x, xend - x + 1);
1690 x--;
1691 xend--;
1692 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001693 }
Chris Allegretta04d848e2000-11-05 17:54:41 +00001694 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001695 case NANO_TAB_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001696#ifndef NANO_SMALL
1697 /* tab history completion */
Chris Allegretta7662c862003-01-13 01:35:15 +00001698 if (history_list != NULL) {
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001699 if (!complete || last_kbinput != NANO_TAB_KEY) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001700 history_list->current = (historytype *)history_list;
1701 history_list->len = strlen(answer);
1702 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001703
Chris Allegretta7662c862003-01-13 01:35:15 +00001704 if (history_list->len > 0) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001705 complete = get_history_completion(history_list, answer);
1706 xend = strlen(complete);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001707 x = xend;
Chris Allegretta5beed502003-01-05 20:41:21 +00001708 answer = mallocstrcpy(answer, complete);
1709 }
Chris Allegretta7da4e9f2000-11-06 02:57:22 +00001710 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001711#ifndef DISABLE_TABCOMP
Chris Allegretta327abda2003-01-17 05:04:17 +00001712 else
1713#endif
Chris Allegrettabe77c612000-11-24 14:00:16 +00001714#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001715#ifndef DISABLE_TABCOMP
Chris Allegretta327abda2003-01-17 05:04:17 +00001716 if (allowtabs) {
1717 int shift = 0;
Chris Allegretta5beed502003-01-05 20:41:21 +00001718
Chris Allegretta327abda2003-01-17 05:04:17 +00001719 answer = input_tab(answer, x, &tabbed, &shift, list);
1720 xend = strlen(answer);
1721 x += shift;
1722 if (x > xend)
1723 x = xend;
Chris Allegretta5beed502003-01-05 20:41:21 +00001724 }
1725#endif
1726 break;
Chris Allegretta35dac582001-03-21 15:07:20 +00001727 case NANO_BACK_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001728 if (x > 0)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001729 x--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001730 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001731 case NANO_PREVLINE_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001732#ifndef NANO_SMALL
Chris Allegretta09fc4302003-01-16 22:16:38 +00001733 if (history_list != NULL) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001734
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001735 /* if currentbuf is NULL, or if use_cb is 1, currentbuf
1736 isn't NULL, and currentbuf is different from answer,
1737 it means that we're scrolling up at the top of the
1738 search history, and we need to save the current
1739 answer in currentbuf; do this and reset use_cb to
1740 0 */
1741 if (currentbuf == NULL || (use_cb == 1 && strcmp(currentbuf, answer))) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001742 currentbuf = mallocstrcpy(currentbuf, answer);
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001743 use_cb = 0;
Chris Allegretta8031f832003-01-09 05:29:58 +00001744 }
1745
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001746 /* if currentbuf isn't NULL, use_cb is 2, and currentbuf
1747 is different from answer, it means that we're
1748 scrolling up at the bottom of the search history, and
1749 we need to make the string in currentbuf the current
1750 answer; do this, blow away currentbuf since we don't
1751 need it anymore, and reset use_cb to 0 */
1752 if (currentbuf != NULL && use_cb == 2 && strcmp(currentbuf, answer)) {
1753 answer = mallocstrcpy(answer, currentbuf);
1754 free(currentbuf);
1755 currentbuf = NULL;
1756 xend = strlen(answer);
1757 use_cb = 0;
1758
1759 /* else get older search from the history list and save
1760 it in answer; if there is no older search, blank out
1761 answer */
1762 } else if ((history = get_history_older(history_list)) != NULL) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001763 answer = mallocstrcpy(answer, history);
1764 xend = strlen(history);
1765 } else {
1766 answer = mallocstrcpy(answer, "");
1767 xend = 0;
1768 }
1769 x = xend;
1770 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001771#endif
Chris Allegretta54abd942003-01-09 23:43:12 +00001772 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001773 case NANO_NEXTLINE_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001774#ifndef NANO_SMALL
Chris Allegretta09fc4302003-01-16 22:16:38 +00001775 if (history_list != NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001776
1777 /* get newer search from the history list and save it
1778 in answer */
Chris Allegretta7662c862003-01-13 01:35:15 +00001779 if ((history = get_history_newer(history_list)) != NULL) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001780 answer = mallocstrcpy(answer, history);
1781 xend = strlen(history);
Chris Allegretta8031f832003-01-09 05:29:58 +00001782
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001783 /* if there is no newer search, we're here */
1784
1785 /* if currentbuf isn't NULL and use_cb isn't 2, it means
1786 that we're scrolling down at the bottom of the search
1787 history and we need to make the string in currentbuf
1788 the current answer; do this, blow away currentbuf
1789 since we don't need it anymore, and set use_cb to
1790 1 */
1791 } else if (currentbuf != NULL && use_cb != 2) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001792 answer = mallocstrcpy(answer, currentbuf);
Chris Allegretta09fc4302003-01-16 22:16:38 +00001793 free(currentbuf);
1794 currentbuf = NULL;
1795 xend = strlen(answer);
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001796 use_cb = 1;
1797
1798 /* otherwise, if currentbuf is NULL and use_cb isn't 2,
1799 it means that we're scrolling down at the bottom of
Chris Allegrettac30fc242003-08-11 00:32:45 +00001800 the search history and the current answer (if it's
1801 not blank) needs to be saved in currentbuf; do this,
1802 blank out answer (if necessary), and set use_cb to
1803 2 */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001804 } else if (use_cb != 2) {
Chris Allegrettac30fc242003-08-11 00:32:45 +00001805 if (answer[0] != '\0') {
1806 currentbuf = mallocstrcpy(currentbuf, answer);
1807 answer = mallocstrcpy(answer, "");
1808 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001809 xend = 0;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001810 use_cb = 2;
Chris Allegretta5beed502003-01-05 20:41:21 +00001811 }
1812 x = xend;
1813 }
1814#endif
1815 break;
Chris Allegretta658399a2001-06-14 02:54:22 +00001816 default:
1817
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001818 for (t = s; t != NULL; t = t->next) {
Chris Allegretta658399a2001-06-14 02:54:22 +00001819#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001820 fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput,
Chris Allegretta598106e2002-01-19 01:59:37 +00001821 kbinput);
Chris Allegretta658399a2001-06-14 02:54:22 +00001822#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001823 if (meta_key == TRUE && (kbinput == t->metaval || kbinput == t->miscval))
David Lawrence Ramsey32613fa2004-05-24 18:40:41 +00001824 /* We hit a meta key. Do like above. We don't
David Lawrence Ramsey82138502003-12-24 08:03:54 +00001825 * just ungetch() the letter and let it get
1826 * caught above cause that screws the
1827 * keypad... */
1828 return kbinput;
Chris Allegretta658399a2001-06-14 02:54:22 +00001829 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001830
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00001831 /* If we're using restricted mode, the filename isn't blank,
1832 * and we're at the "Write File" prompt, act as though the
1833 * unhandled character we got is a control character and
1834 * throw it away. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001835 if (is_cntrl_char(kbinput) || (ISSET(RESTRICTED) && filename[0] != '\0' && s == writefile_list))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001836 break;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001837 answer = charealloc(answer, xend + 2);
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001838 charmove(answer + x + 1, answer + x, xend - x + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001839 xend++;
1840 answer[x] = kbinput;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001841 x++;
1842
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001843#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001844 fprintf(stderr, "input \'%c\' (%d)\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001845#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001846 } /* switch (kbinput) */
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001847#ifndef NANO_SMALL
Chris Allegretta5beed502003-01-05 20:41:21 +00001848 last_kbinput = kbinput;
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001849#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001850 nanoget_repaint(buf, answer, x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001851 wrefresh(bottomwin);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001852 } /* while (kbinput ...) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001853
Chris Allegretta5af58892003-01-17 21:07:38 +00001854 /* We finished putting in an answer; reset x */
1855 x = -1;
1856
Chris Allegretta7662c862003-01-13 01:35:15 +00001857 /* Just check for a blank answer here */
Chris Allegretta15c28f82003-01-05 21:47:06 +00001858 if (answer[0] == '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001859 return -2;
1860 else
1861 return 0;
1862}
1863
Chris Allegrettaf717f982003-02-13 22:25:01 +00001864void titlebar(const char *path)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001865{
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001866 size_t space;
1867 /* The space we have available for display. */
1868 size_t verlen = strlen(VERMSG) + 1;
1869 /* The length of the version message. */
1870 const char *prefix;
1871 /* "File:", "Dir:", or "New Buffer". Goes before filename. */
1872 size_t prefixlen;
1873 /* strlen(prefix) + 1. */
1874 const char *state;
1875 /* "Modified", "View", or spaces the length of "Modified".
1876 * Tells the state of this buffer. */
1877 size_t statelen = 0;
1878 /* strlen(state) + 1. */
1879 char *exppath = NULL;
1880 /* The file name, expanded for display. */
1881 size_t explen = 0;
1882 /* strlen(exppath) + 1. */
1883 int newbuffer = FALSE;
1884 /* Do we say "New Buffer"? */
1885 int dots = FALSE;
1886 /* Do we put an ellipsis before the path? */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001887
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001888 assert(path != NULL || filename != NULL);
1889 assert(COLS >= 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001890
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001891 wattron(topwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001892
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001893 blank_titlebar();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001894
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001895 if (COLS <= 5 || COLS - 5 < verlen)
1896 space = 0;
1897 else {
1898 space = COLS - 5 - verlen;
David Lawrence Ramsey8328fc22004-05-25 23:34:43 +00001899 /* Reserve 2/3 of the screen plus one column for after the
1900 * version message. */
1901 if (space < COLS - (COLS / 3) + 1)
1902 space = COLS - (COLS / 3) + 1;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001903 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001904
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001905 if (COLS > 4) {
David Lawrence Ramsey8328fc22004-05-25 23:34:43 +00001906 /* The version message should only take up 1/3 of the screen
1907 * minus one column. */
1908 mvwaddnstr(topwin, 0, 2, VERMSG, (COLS / 3) - 3);
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001909 waddstr(topwin, " ");
1910 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001911
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001912 if (ISSET(MODIFIED))
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001913 state = _("Modified");
1914 else if (path == NULL && ISSET(VIEW_MODE))
1915 state = _("View");
1916 else {
1917 if (space > 0)
1918 statelen = strnlen(_("Modified"), space - 1) + 1;
1919 state = &hblank[COLS - statelen];
1920 }
1921 statelen = strnlen(state, COLS);
1922 /* We need a space before state. */
1923 if ((ISSET(MODIFIED) || ISSET(VIEW_MODE)) && statelen < COLS)
1924 statelen++;
1925
1926 assert(space >= 0);
1927 if (space == 0 || statelen >= space)
1928 goto the_end;
1929
1930#ifndef DISABLE_BROWSER
1931 if (path != NULL)
1932 prefix = _("DIR:");
1933 else
1934#endif
1935 if (filename[0] == '\0') {
1936 prefix = _("New Buffer");
1937 newbuffer = TRUE;
1938 } else
1939 prefix = _("File:");
1940 assert(statelen < space);
1941 prefixlen = strnlen(prefix, space - statelen);
1942 /* If newbuffer is FALSE, we need a space after prefix. */
1943 if (!newbuffer && prefixlen + statelen < space)
1944 prefixlen++;
1945
1946 if (path == NULL)
1947 path = filename;
David Lawrence Ramsey1dcf36a2004-05-23 21:17:56 +00001948 space -= prefixlen + statelen;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001949 /* space is now the room we have for the file name. */
1950 if (!newbuffer) {
1951 size_t lenpt = strlenpt(path), start_col;
1952
1953 if (lenpt > space)
1954 start_col = actual_x(path, lenpt - space);
1955 else
1956 start_col = 0;
1957 exppath = display_string(path, start_col, space);
1958 dots = (lenpt > space);
1959 explen = strlen(exppath);
1960 }
1961
1962 if (!dots) {
1963 /* There is room for the whole filename, so we center it. */
1964 waddnstr(topwin, hblank, (space - explen) / 3);
1965 waddnstr(topwin, prefix, prefixlen);
1966 if (!newbuffer) {
1967 assert(strlen(prefix) + 1 == prefixlen);
1968 waddch(topwin, ' ');
1969 waddstr(topwin, exppath);
1970 }
1971 } else {
1972 /* We will say something like "File: ...ename". */
1973 waddnstr(topwin, prefix, prefixlen);
David Lawrence Ramsey1dcf36a2004-05-23 21:17:56 +00001974 if (space <= 0 || newbuffer)
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001975 goto the_end;
1976 waddch(topwin, ' ');
1977 waddnstr(topwin, "...", space);
1978 if (space <= 3)
1979 goto the_end;
1980 space -= 3;
1981 assert(explen = space + 3);
1982 waddnstr(topwin, exppath + 3, space);
1983 }
1984
1985 the_end:
1986
1987 free(exppath);
1988
1989 if (COLS <= 1 || statelen >= COLS - 1)
1990 mvwaddnstr(topwin, 0, 0, state, COLS);
1991 else {
1992 assert(COLS - statelen - 2 >= 0);
1993 mvwaddch(topwin, 0, COLS - statelen - 2, ' ');
1994 mvwaddnstr(topwin, 0, COLS - statelen - 1, state, statelen);
1995 }
Chris Allegretta8ce24132001-04-30 11:28:46 +00001996
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001997 wattroff(topwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001998
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001999 wnoutrefresh(topwin);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002000 reset_cursor();
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002001 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002002}
2003
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002004/* If modified is not already set, set it and update titlebar. */
2005void set_modified(void)
2006{
2007 if (!ISSET(MODIFIED)) {
2008 SET(MODIFIED);
2009 titlebar(NULL);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002010 }
2011}
2012
2013void statusbar(const char *msg, ...)
2014{
2015 va_list ap;
2016
2017 va_start(ap, msg);
2018
2019 /* Curses mode is turned off. If we use wmove() now, it will muck
2020 * up the terminal settings. So we just use vfprintf(). */
2021 if (curses_ended) {
2022 vfprintf(stderr, msg, ap);
2023 va_end(ap);
2024 return;
2025 }
2026
2027 /* Blank out the line. */
2028 blank_statusbar();
2029
2030 if (COLS >= 4) {
2031 char *bar;
2032 char *foo;
2033 size_t start_x = 0, foo_len;
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00002034#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
2035 int old_whitespace = ISSET(WHITESPACE_DISPLAY);
2036 UNSET(WHITESPACE_DISPLAY);
2037#endif
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002038 bar = charalloc(COLS - 3);
2039 vsnprintf(bar, COLS - 3, msg, ap);
2040 va_end(ap);
2041 foo = display_string(bar, 0, COLS - 4);
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00002042#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
2043 if (old_whitespace)
2044 SET(WHITESPACE_DISPLAY);
2045#endif
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002046 free(bar);
2047 foo_len = strlen(foo);
2048 start_x = (COLS - foo_len - 4) / 2;
2049
2050 wmove(bottomwin, 0, start_x);
2051 wattron(bottomwin, A_REVERSE);
2052
2053 waddstr(bottomwin, "[ ");
2054 waddstr(bottomwin, foo);
2055 free(foo);
2056 waddstr(bottomwin, " ]");
2057 wattroff(bottomwin, A_REVERSE);
2058 wnoutrefresh(bottomwin);
2059 reset_cursor();
2060 wrefresh(edit);
2061 /* Leave the cursor at its position in the edit window, not
2062 * in the statusbar. */
2063 }
2064
2065 SET(DISABLE_CURPOS);
2066 statblank = 26;
2067}
2068
Chris Allegretta6232d662002-05-12 19:52:15 +00002069void bottombars(const shortcut *s)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002070{
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002071 size_t i, colwidth, slen;
2072 char *keystr;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002073
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002074 if (ISSET(NO_HELP))
2075 return;
2076
Chris Allegretta6232d662002-05-12 19:52:15 +00002077 if (s == main_list) {
2078 slen = MAIN_VISIBLE;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002079 assert(slen <= length_of_list(s));
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002080 } else {
Chris Allegretta6232d662002-05-12 19:52:15 +00002081 slen = length_of_list(s);
2082
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002083 /* Don't show any more shortcuts than the main list does. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002084 if (slen > MAIN_VISIBLE)
2085 slen = MAIN_VISIBLE;
2086 }
2087
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002088 /* There will be this many characters per column. We need at least
2089 * 3 to display anything properly.*/
2090 colwidth = COLS / ((slen / 2) + (slen % 2));
2091 keystr = charalloc(colwidth);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002092
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002093 blank_bottombars();
Chris Allegretta658399a2001-06-14 02:54:22 +00002094
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002095 for (i = 0; i < slen; i++, s = s->next) {
2096 wmove(bottomwin, 1 + i % 2, (i / 2) * colwidth);
Chris Allegretta658399a2001-06-14 02:54:22 +00002097
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002098 /* Yucky sentinel values we can't handle a better way. */
Chris Allegrettaa65ba512003-01-05 20:57:07 +00002099#ifndef NANO_SMALL
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002100 if (s->ctrlval == NANO_HISTORY_KEY)
2101 strncpy(keystr, _("Up"), colwidth);
2102 else
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002103#endif
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002104 if (s->ctrlval == NANO_CONTROL_SPACE)
2105 strncpy(keystr, "^ ", colwidth);
2106 else if (s->ctrlval == NANO_CONTROL_8)
2107 strncpy(keystr, "^?", colwidth);
2108 /* Normal values. Assume that the shortcut has an equivalent
2109 * control key, meta key sequence, or both. */
2110 else if (s->ctrlval != NANO_NO_KEY)
2111 snprintf(keystr, colwidth, "^%c", s->ctrlval + 64);
2112 else if (s->metaval != NANO_NO_KEY)
2113 snprintf(keystr, colwidth, "M-%c", toupper(s->metaval));
Chris Allegretta658399a2001-06-14 02:54:22 +00002114
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002115 onekey(keystr, s->desc, colwidth);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002116 }
2117
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002118 free(keystr);
2119
2120 wnoutrefresh(bottomwin);
2121 reset_cursor();
2122 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002123}
2124
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002125/* Write a shortcut key to the help area at the bottom of the window.
2126 * keystroke is e.g. "^G" and desc is e.g. "Get Help". We are careful
2127 * to write at most len characters, even if len is very small and
2128 * keystroke and desc are long. Note that waddnstr(,,(size_t)-1) adds
2129 * the whole string! We do not bother padding the entry with blanks. */
2130void onekey(const char *keystroke, const char *desc, size_t len)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002131{
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002132 assert(keystroke != NULL && desc != NULL && len >= 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002133 wattron(bottomwin, A_REVERSE);
2134 waddnstr(bottomwin, keystroke, len);
2135 wattroff(bottomwin, A_REVERSE);
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002136 len -= strlen(keystroke) + 1;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002137 if (len > 0) {
2138 waddch(bottomwin, ' ');
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002139 waddnstr(bottomwin, desc, len);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002140 }
2141}
2142
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002143/* And so start the display update routines. */
2144
2145#ifndef NDEBUG
2146int check_linenumbers(const filestruct *fileptr)
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002147{
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002148 int check_line = 0;
2149 const filestruct *filetmp;
Robert Siemborskid8510b22000-06-06 23:04:06 +00002150
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002151 for (filetmp = edittop; filetmp != fileptr; filetmp = filetmp->next)
2152 check_line++;
2153 return check_line;
Robert Siemborskid8510b22000-06-06 23:04:06 +00002154}
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002155#endif
Robert Siemborskid8510b22000-06-06 23:04:06 +00002156
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00002157/* nano scrolls horizontally within a line in chunks. This function
2158 * returns the column number of the first character displayed in the
2159 * window when the cursor is at the given column. Note that
2160 * 0 <= column - get_page_start(column) < COLS. */
2161size_t get_page_start(size_t column)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002162{
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00002163 assert(COLS > 0);
2164 if (column == 0 || column < COLS - 1)
2165 return 0;
2166 else if (COLS > 9)
David Lawrence Ramsey66081d42004-01-22 07:25:31 +00002167 return column - 7 - (column - 7) % (COLS - 8);
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00002168 else if (COLS > 2)
2169 return column - (COLS - 2);
2170 else
2171 return column - (COLS - 1);
2172 /* The parentheses are necessary to avoid overflow. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002173}
2174
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002175/* Resets current_y, based on the position of current, and puts the
2176 * cursor at (current_y, current_x). */
2177void reset_cursor(void)
2178{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002179 /* Yuck. This condition can be true after open_file() when opening
2180 * the first file. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002181 if (edittop == NULL)
2182 return;
2183
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002184 current_y = current->lineno - edittop->lineno;
2185 if (current_y < editwinrows) {
2186 size_t x = xplustabs();
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002187
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002188 wmove(edit, current_y, x - get_page_start(x));
2189 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002190}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002191
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002192/* edit_add() takes care of the job of actually painting a line into the
2193 * edit window. fileptr is the line to be painted, at row yval of the
2194 * window. converted is the actual string to be written to the window,
2195 * with tabs and control characters replaced by strings of regular
David Lawrence Ramsey4178db02004-05-23 21:23:23 +00002196 * characters. start is the column number of the first character of
2197 * this page. That is, the first character of converted corresponds to
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002198 * character number actual_x(fileptr->data, start) of the line. */
David Lawrence Ramsey07d3feb2004-04-16 05:15:11 +00002199void edit_add(const filestruct *fileptr, const char *converted, int
2200 yval, size_t start)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002201{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002202#if defined(ENABLE_COLOR) || !defined(NANO_SMALL)
2203 size_t startpos = actual_x(fileptr->data, start);
2204 /* The position in fileptr->data of the leftmost character
2205 * that displays at least partially on the window. */
2206 size_t endpos = actual_x(fileptr->data, start + COLS - 1) + 1;
2207 /* The position in fileptr->data of the first character that is
2208 * completely off the window to the right.
2209 *
2210 * Note that endpos might be beyond the null terminator of the
2211 * string. */
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002212#endif
2213
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002214 assert(fileptr != NULL && converted != NULL);
2215 assert(strlen(converted) <= COLS);
2216
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002217 /* Just paint the string in any case (we'll add color or reverse on
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002218 * just the text that needs it). */
2219 mvwaddstr(edit, yval, 0, converted);
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002220
Chris Allegretta7dd77682001-12-08 19:52:28 +00002221#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002222 if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002223 const colortype *tmpcolor = colorstrings;
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002224
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002225 for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
2226 int x_start;
2227 /* Starting column for mvwaddnstr. Zero-based. */
2228 int paintlen;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002229 /* Number of chars to paint on this line. There are COLS
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002230 * characters on a whole line. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002231 regmatch_t startmatch; /* match position for start_regexp */
2232 regmatch_t endmatch; /* match position for end_regexp */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002233
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002234 if (tmpcolor->bright)
2235 wattron(edit, A_BOLD);
2236 wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002237 /* Two notes about regexec(). Return value 0 means there is
2238 * a match. Also, rm_eo is the first non-matching character
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002239 * after the match. */
2240
2241 /* First case, tmpcolor is a single-line expression. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002242 if (tmpcolor->end == NULL) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002243 size_t k = 0;
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002244
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002245 /* We increment k by rm_eo, to move past the end of the
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002246 * last match. Even though two matches may overlap, we
2247 * want to ignore them, so that we can highlight
2248 * C-strings correctly. */
2249 while (k < endpos) {
2250 /* Note the fifth parameter to regexec(). It says
2251 * not to match the beginning-of-line character
2252 * unless k is 0. If regexec() returns REG_NOMATCH,
2253 * there are no more matches in the line. */
Chris Allegrettace452fb2003-02-03 02:56:44 +00002254 if (regexec(&tmpcolor->start, &fileptr->data[k], 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002255 &startmatch, k == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002256 break;
2257 /* Translate the match to the beginning of the line. */
2258 startmatch.rm_so += k;
2259 startmatch.rm_eo += k;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002260 if (startmatch.rm_so == startmatch.rm_eo) {
2261 startmatch.rm_eo++;
Chris Allegretta7c27be42002-05-05 23:03:54 +00002262 statusbar(_("Refusing 0 length regex match"));
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002263 } else if (startmatch.rm_so < endpos &&
2264 startmatch.rm_eo > startpos) {
2265 if (startmatch.rm_so <= startpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002266 x_start = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002267 else
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002268 x_start = strnlenpt(fileptr->data,
2269 startmatch.rm_so) - start;
2270 paintlen = strnlenpt(fileptr->data,
2271 startmatch.rm_eo) - start - x_start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002272 if (paintlen > COLS - x_start)
2273 paintlen = COLS - x_start;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002274
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002275 assert(0 <= x_start && 0 < paintlen &&
2276 x_start + paintlen <= COLS);
2277 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002278 converted + x_start, paintlen);
2279 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002280 k = startmatch.rm_eo;
Chris Allegretta598106e2002-01-19 01:59:37 +00002281 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002282 } else {
2283 /* This is a multi-line regexp. There are two steps.
2284 * First, we have to see if the beginning of the line is
2285 * colored by a start on an earlier line, and an end on
2286 * this line or later.
2287 *
2288 * We find the first line before fileptr matching the
2289 * start. If every match on that line is followed by an
2290 * end, then go to step two. Otherwise, find the next line
2291 * after start_line matching the end. If that line is not
2292 * before fileptr, then paint the beginning of this line. */
Chris Allegretta3674c1d2002-05-12 20:43:49 +00002293
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002294 const filestruct *start_line = fileptr->prev;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002295 /* the first line before fileptr matching start */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002296 regoff_t start_col;
2297 /* where it starts in that line */
2298 const filestruct *end_line;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002299
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002300 while (start_line != NULL &&
Chris Allegrettace452fb2003-02-03 02:56:44 +00002301 regexec(&tmpcolor->start, start_line->data, 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002302 &startmatch, 0) == REG_NOMATCH) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002303 /* If there is an end on this line, there is no need
2304 * to look for starts on earlier lines. */
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002305 if (regexec(tmpcolor->end, start_line->data, 0,
2306 NULL, 0) == 0)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002307 goto step_two;
2308 start_line = start_line->prev;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002309 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002310 /* No start found, so skip to the next step. */
2311 if (start_line == NULL)
2312 goto step_two;
2313 /* Now start_line is the first line before fileptr
2314 * containing a start match. Is there a start on this
2315 * line not followed by an end on this line? */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002316
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002317 start_col = 0;
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002318 while (TRUE) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002319 start_col += startmatch.rm_so;
2320 startmatch.rm_eo -= startmatch.rm_so;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002321 if (regexec(tmpcolor->end,
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002322 start_line->data + start_col + startmatch.rm_eo,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002323 0, NULL, start_col + startmatch.rm_eo == 0 ? 0 :
2324 REG_NOTBOL) == REG_NOMATCH)
2325 /* No end found after this start. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002326 break;
2327 start_col++;
Chris Allegrettace452fb2003-02-03 02:56:44 +00002328 if (regexec(&tmpcolor->start,
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002329 start_line->data + start_col, 1,
2330 &startmatch, REG_NOTBOL) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002331 /* No later start on this line. */
2332 goto step_two;
2333 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002334 /* Indeed, there is a start not followed on this line by
2335 * an end. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002336
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002337 /* We have already checked that there is no end before
2338 * fileptr and after the start. Is there an end after
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002339 * the start at all? We don't paint unterminated
2340 * starts. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002341 end_line = fileptr;
Chris Allegrettace452fb2003-02-03 02:56:44 +00002342 while (end_line != NULL &&
2343 regexec(tmpcolor->end, end_line->data, 1, &endmatch, 0))
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002344 end_line = end_line->next;
2345
2346 /* No end found, or it is too early. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002347 if (end_line == NULL ||
2348 (end_line == fileptr && endmatch.rm_eo <= startpos))
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002349 goto step_two;
2350
2351 /* Now paint the start of fileptr. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002352 paintlen = end_line != fileptr ? COLS :
2353 strnlenpt(fileptr->data, endmatch.rm_eo) - start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002354 if (paintlen > COLS)
2355 paintlen = COLS;
2356
2357 assert(0 < paintlen && paintlen <= COLS);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002358 mvwaddnstr(edit, yval, 0, converted, paintlen);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002359
2360 /* We have already painted the whole line. */
2361 if (paintlen == COLS)
2362 goto skip_step_two;
2363
David Lawrence Ramsey94e70942004-05-13 18:04:31 +00002364 step_two:
2365 /* Second step, we look for starts on this line. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002366 start_col = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002367 while (start_col < endpos) {
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002368 if (regexec(&tmpcolor->start,
2369 fileptr->data + start_col, 1, &startmatch,
2370 start_col == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH ||
2371 start_col + startmatch.rm_so >= endpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002372 /* No more starts on this line. */
2373 break;
2374 /* Translate the match to be relative to the
2375 * beginning of the line. */
2376 startmatch.rm_so += start_col;
2377 startmatch.rm_eo += start_col;
2378
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002379 if (startmatch.rm_so <= startpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002380 x_start = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002381 else
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002382 x_start = strnlenpt(fileptr->data,
2383 startmatch.rm_so) - start;
2384 if (regexec(tmpcolor->end,
2385 fileptr->data + startmatch.rm_eo, 1, &endmatch,
2386 startmatch.rm_eo == 0 ? 0 : REG_NOTBOL) == 0) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002387 /* Translate the end match to be relative to the
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002388 * beginning of the line. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002389 endmatch.rm_so += startmatch.rm_eo;
2390 endmatch.rm_eo += startmatch.rm_eo;
2391 /* There is an end on this line. But does it
David Lawrence Ramsey94e70942004-05-13 18:04:31 +00002392 * appear on this page, and is the match more
2393 * than zero characters long? */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002394 if (endmatch.rm_eo > startpos &&
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002395 endmatch.rm_eo > startmatch.rm_so) {
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002396 paintlen = strnlenpt(fileptr->data,
2397 endmatch.rm_eo) - start - x_start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002398 if (x_start + paintlen > COLS)
2399 paintlen = COLS - x_start;
2400
2401 assert(0 <= x_start && 0 < paintlen &&
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002402 x_start + paintlen <= COLS);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002403 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002404 converted + x_start, paintlen);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002405 }
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002406 } else {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002407 /* There is no end on this line. But we haven't
2408 * yet looked for one on later lines. */
2409 end_line = fileptr->next;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002410 while (end_line != NULL &&
2411 regexec(tmpcolor->end, end_line->data, 0,
2412 NULL, 0) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002413 end_line = end_line->next;
2414 if (end_line != NULL) {
2415 assert(0 <= x_start && x_start < COLS);
2416 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002417 converted + x_start, COLS - x_start);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002418 /* We painted to the end of the line, so
2419 * don't bother checking any more starts. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002420 break;
Chris Allegretta3674c1d2002-05-12 20:43:49 +00002421 }
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002422 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002423 start_col = startmatch.rm_so + 1;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002424 } /* while start_col < endpos */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002425 } /* if (tmp_color->end != NULL) */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00002426
Chris Allegrettace452fb2003-02-03 02:56:44 +00002427 skip_step_two:
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002428 wattroff(edit, A_BOLD);
2429 wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
2430 } /* for tmpcolor in colorstrings */
2431 }
Chris Allegretta598106e2002-01-19 01:59:37 +00002432#endif /* ENABLE_COLOR */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002433
Chris Allegretta7dd77682001-12-08 19:52:28 +00002434#ifndef NANO_SMALL
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002435 if (ISSET(MARK_ISSET)
2436 && (fileptr->lineno <= mark_beginbuf->lineno
2437 || fileptr->lineno <= current->lineno)
2438 && (fileptr->lineno >= mark_beginbuf->lineno
2439 || fileptr->lineno >= current->lineno)) {
2440 /* fileptr is at least partially selected. */
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002441
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002442 const filestruct *top;
2443 /* Either current or mark_beginbuf, whichever is first. */
2444 size_t top_x;
2445 /* current_x or mark_beginx, corresponding to top. */
2446 const filestruct *bot;
2447 size_t bot_x;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002448 int x_start;
2449 /* Starting column for mvwaddnstr. Zero-based. */
2450 int paintlen;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002451 /* Number of chars to paint on this line. There are COLS
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002452 * characters on a whole line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002453
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002454 mark_order(&top, &top_x, &bot, &bot_x);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002455
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002456 if (top->lineno < fileptr->lineno || top_x < startpos)
2457 top_x = startpos;
2458 if (bot->lineno > fileptr->lineno || bot_x > endpos)
2459 bot_x = endpos;
2460
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00002461 /* The selected bit of fileptr is on this page. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002462 if (top_x < endpos && bot_x > startpos) {
2463 assert(startpos <= top_x);
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00002464
2465 /* x_start is the expanded location of the beginning of the
2466 * mark minus the beginning of the page. */
2467 x_start = strnlenpt(fileptr->data, top_x) - start;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002468
2469 if (bot_x >= endpos)
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00002470 /* If the end of the mark is off the page, paintlen is
2471 * -1, meaning that everything on the line gets
2472 * painted. */
2473 paintlen = -1;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002474 else
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00002475 /* Otherwise, paintlen is the expanded location of the
2476 * end of the mark minus the expanded location of the
2477 * beginning of the mark. */
David Lawrence Ramseye5b2f832004-04-29 06:30:36 +00002478 paintlen = strnlenpt(fileptr->data, bot_x)
2479 - (x_start + start);
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00002480
2481 /* If x_start is before the beginning of the page, shift
2482 * paintlen x_start characters to compensate, and put
2483 * x_start at the beginning of the page. */
2484 if (x_start < 0) {
2485 paintlen += x_start;
2486 x_start = 0;
2487 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002488
2489 assert(x_start >= 0 && x_start <= strlen(converted));
2490
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002491 wattron(edit, A_REVERSE);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002492 mvwaddnstr(edit, yval, x_start, converted + x_start, paintlen);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002493 wattroff(edit, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002494 }
Chris Allegretta08893e02001-11-29 02:42:27 +00002495 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002496#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002497}
2498
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002499/* Just update one line in the edit buffer. Basically a wrapper for
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002500 * edit_add().
2501 *
David Lawrence Ramsey07d3feb2004-04-16 05:15:11 +00002502 * If fileptr != current, then index is considered 0. The line will be
2503 * displayed starting with fileptr->data[index]. Likely args are
2504 * current_x or 0. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002505void update_line(const filestruct *fileptr, size_t index)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002506{
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002507 int line;
2508 /* line in the edit window for CURSES calls */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002509 char *converted;
2510 /* fileptr->data converted to have tabs and control characters
2511 * expanded. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002512 size_t page_start;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002513
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002514 assert(fileptr != NULL);
Robert Siemborski53154a72000-06-18 00:11:03 +00002515
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002516 line = fileptr->lineno - edittop->lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002517
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002518 /* We assume the line numbers are valid. Is that really true? */
2519 assert(line < 0 || line == check_linenumbers(fileptr));
2520
2521 if (line < 0 || line >= editwinrows)
2522 return;
2523
2524 /* First, blank out the line (at a minimum) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002525 mvwaddstr(edit, line, 0, hblank);
2526
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002527 /* Next, convert variables that index the line to their equivalent
2528 * positions in the expanded line. */
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00002529 index = (fileptr == current) ? strnlenpt(fileptr->data, index) : 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002530 page_start = get_page_start(index);
Chris Allegretta5beed502003-01-05 20:41:21 +00002531
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002532 /* Expand the line, replacing Tab by spaces, and control characters
2533 * by their display form. */
2534 converted = display_string(fileptr->data, page_start, COLS);
Robert Siemborski53875912000-06-16 04:25:30 +00002535
Chris Allegretta4dc03d52002-05-11 03:04:44 +00002536 /* Now, paint the line */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002537 edit_add(fileptr, converted, line, page_start);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002538 free(converted);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002539
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002540 if (page_start > 0)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002541 mvwaddch(edit, line, 0, '$');
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002542 if (strlenpt(fileptr->data) > page_start + COLS)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002543 mvwaddch(edit, line, COLS - 1, '$');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002544}
2545
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002546/* Return a nonzero value if we need an update after moving
2547 * horizontally. We need one if the mark is on or if old_pww and
David Lawrence Ramsey684b1932004-05-31 14:47:12 +00002548 * placewewant are on different pages. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002549int need_horizontal_update(int old_pww)
2550{
2551 return
2552#ifndef NANO_SMALL
2553 ISSET(MARK_ISSET) ||
2554#endif
2555 get_page_start(old_pww) != get_page_start(placewewant);
2556}
2557
2558/* Return a nonzero value if we need an update after moving vertically.
2559 * We need one if the mark is on or if old_pww and placewewant
David Lawrence Ramsey684b1932004-05-31 14:47:12 +00002560 * are on different pages. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002561int need_vertical_update(int old_pww)
2562{
2563 return
2564#ifndef NANO_SMALL
2565 ISSET(MARK_ISSET) ||
2566#endif
2567 get_page_start(old_pww) != get_page_start(placewewant);
2568}
2569
2570/* Scroll the edit window in the given direction and the given number
2571 * of lines, and draw new lines on the blank lines left after the
2572 * scrolling. direction is the direction to scroll, either UP or DOWN,
2573 * and nlines is the number of lines to scroll. Don't redraw the old
2574 * topmost or bottommost line (where we assume current is) before
2575 * scrolling or draw the new topmost or bottommost line after scrolling
2576 * (where we assume current will be), since we don't know where we are
David Lawrence Ramsey684b1932004-05-31 14:47:12 +00002577 * on the page or whether we'll stay there. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002578void edit_scroll(updown direction, int nlines)
2579{
2580 filestruct *foo;
2581 int i, scroll_rows = 0;
2582
2583 /* Scrolling less than one line or more than editwinrows lines is
2584 * redundant, so don't allow it. */
2585 if (nlines < 1 || nlines > editwinrows)
2586 return;
2587
2588 /* Move the top line of the edit window up or down (depending on the
2589 * value of direction) nlines lines. If there are fewer lines of
2590 * text than that left, move it to the top or bottom line of the
2591 * file (depending on the value of direction). Keep track of
2592 * how many lines we moved in scroll_rows. */
2593 for (i = nlines; i > 0; i--) {
2594 if (direction == UP) {
2595 if (edittop->prev == NULL)
2596 break;
2597 edittop = edittop->prev;
2598 scroll_rows--;
2599 } else {
2600 if (edittop->next == NULL)
2601 break;
2602 edittop = edittop->next;
2603 scroll_rows++;
2604 }
2605 }
2606
2607 /* Scroll the text on the screen up or down scroll_rows lines,
2608 * depending on the value of direction. */
2609 scrollok(edit, TRUE);
2610 wscrl(edit, scroll_rows);
2611 scrollok(edit, FALSE);
2612
2613 foo = edittop;
2614 if (direction != UP) {
2615 int slines = editwinrows - nlines;
2616 for (; slines > 0 && foo != NULL; slines--)
2617 foo = foo->next;
2618 }
2619
2620 /* And draw new lines on the blank top or bottom lines of the edit
2621 * window, depending on the value of direction. Don't draw the new
2622 * topmost or new bottommost line. */
2623 while (scroll_rows != 0 && foo != NULL) {
2624 if (foo->next != NULL)
2625 update_line(foo, 0);
2626 if (direction == UP)
2627 scroll_rows++;
2628 else
2629 scroll_rows--;
2630 foo = foo->next;
2631 }
2632}
2633
2634/* Update any lines between old_current and current that need to be
David Lawrence Ramsey684b1932004-05-31 14:47:12 +00002635 * updated. */
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00002636void edit_redraw(const filestruct *old_current, int old_pww)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002637{
David Lawrence Ramseyce1d7652004-06-01 18:32:36 +00002638 int do_refresh = need_vertical_update(0) ||
2639 need_vertical_update(old_pww);
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002640 const filestruct *foo;
2641
2642 /* If either old_current or current is offscreen, refresh the screen
2643 * and get out. */
2644 if (old_current->lineno < edittop->lineno || old_current->lineno >=
2645 edittop->lineno + editwinrows || current->lineno <
2646 edittop->lineno || current->lineno >= edittop->lineno +
2647 editwinrows) {
2648 edit_refresh();
2649 return;
2650 }
2651
David Lawrence Ramseyce1d7652004-06-01 18:32:36 +00002652 /* Update old_current and current if we're not on the first page
2653 * and/or we're not on the same page as before. If the mark is on,
2654 * update all the lines between old_current and current too. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002655 foo = old_current;
2656 while (foo != current) {
2657 if (do_refresh)
2658 update_line(foo, 0);
2659#ifndef NANO_SMALL
2660 if (!ISSET(MARK_ISSET))
2661#endif
2662 break;
2663 if (foo->lineno > current->lineno)
2664 foo = foo->prev;
2665 else
2666 foo = foo->next;
2667 }
2668 if (do_refresh)
2669 update_line(current, current_x);
2670}
2671
Chris Allegretta6df90f52002-07-19 01:08:59 +00002672/* Refresh the screen without changing the position of lines. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002673void edit_refresh(void)
2674{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002675 /* Neither of these conditions should occur, but they do. edittop
2676 * is NULL when you open an existing file on the command line, and
Chris Allegretta6df90f52002-07-19 01:08:59 +00002677 * ENABLE_COLOR is defined. Yuck. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002678 if (current == NULL)
2679 return;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002680 if (edittop == NULL)
2681 edittop = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002682
Chris Allegretta63d0b482003-01-26 19:47:10 +00002683 if (current->lineno < edittop->lineno ||
2684 current->lineno >= edittop->lineno + editwinrows)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002685 /* Note that edit_update() changes edittop so that
2686 * current->lineno = edittop->lineno + editwinrows / 2. Thus
2687 * when it then calls edit_refresh(), there is no danger of
2688 * getting an infinite loop. */
Chris Allegrettada721be2000-07-31 01:26:42 +00002689 edit_update(current, CENTER);
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002690 else {
2691 int nlines = 0;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002692 const filestruct *foo = edittop;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002693
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002694#ifdef DEBUG
2695 fprintf(stderr, "edit_refresh(): edittop->lineno = %ld\n", edittop->lineno);
2696#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002697
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002698 while (nlines < editwinrows) {
David Lawrence Ramsey9d325a02004-05-29 03:03:52 +00002699 update_line(foo, foo == current ? current_x : 0);
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002700 nlines++;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002701 if (foo->next == NULL)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002702 break;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002703 foo = foo->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002704 }
2705 while (nlines < editwinrows) {
2706 mvwaddstr(edit, nlines, 0, hblank);
2707 nlines++;
2708 }
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002709 reset_cursor();
David Lawrence Ramsey07d3feb2004-04-16 05:15:11 +00002710
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002711 /* What the hell are we expecting to update the screen if this
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002712 * isn't here? Luck? */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002713 wrefresh(edit);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002714 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002715}
2716
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002717/* Nice generic routine to update the edit buffer, given a pointer to the
2718 * file struct =) */
David Lawrence Ramsey1356a0a2003-09-10 20:31:02 +00002719void edit_update(filestruct *fileptr, topmidnone location)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002720{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002721 if (fileptr == NULL)
2722 return;
2723
Chris Allegretta6df90f52002-07-19 01:08:59 +00002724 if (location != TOP) {
David Lawrence Ramsey07d3feb2004-04-16 05:15:11 +00002725 int goal = (location == NONE) ? current_y : editwinrows / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002726
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00002727 for (; goal > 0 && fileptr->prev != NULL; goal--)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002728 fileptr = fileptr->prev;
2729 }
2730 edittop = fileptr;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002731 edit_refresh();
2732}
2733
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002734/* Ask a question on the statusbar. Answer will be stored in answer
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002735 * global. Returns -1 on aborted enter, -2 on a blank string, and 0
Chris Allegretta88520c92001-05-05 17:45:54 +00002736 * otherwise, the valid shortcut key caught. Def is any editable text we
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002737 * want to put up by default.
Chris Allegretta7da4e9f2000-11-06 02:57:22 +00002738 *
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002739 * New arg tabs tells whether or not to allow tab completion. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002740int statusq(int allowtabs, const shortcut *s, const char *def,
Chris Allegretta5beed502003-01-05 20:41:21 +00002741#ifndef NANO_SMALL
2742 historyheadtype *which_history,
2743#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002744 const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002745{
2746 va_list ap;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002747 char *foo = charalloc(COLS - 3);
Chris Allegretta9caa1932002-02-15 20:08:05 +00002748 int ret;
Chris Allegretta2084acc2001-11-29 03:43:08 +00002749#ifndef DISABLE_TABCOMP
Chris Allegrettaa16e4e92002-01-05 18:59:54 +00002750 int list = 0;
Chris Allegretta2084acc2001-11-29 03:43:08 +00002751#endif
2752
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002753 bottombars(s);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002754
2755 va_start(ap, msg);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002756 vsnprintf(foo, COLS - 4, msg, ap);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002757 va_end(ap);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002758 foo[COLS - 4] = '\0';
Chris Allegretta8ce24132001-04-30 11:28:46 +00002759
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002760 ret = nanogetstr(allowtabs, foo, def,
Chris Allegretta5beed502003-01-05 20:41:21 +00002761#ifndef NANO_SMALL
2762 which_history,
Chris Allegretta2084acc2001-11-29 03:43:08 +00002763#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00002764 s
2765#ifndef DISABLE_TABCOMP
2766 , &list
2767#endif
Chris Allegretta65f075d2003-02-13 03:03:49 +00002768 );
Chris Allegretta6df90f52002-07-19 01:08:59 +00002769 free(foo);
Chris Allegretta65f075d2003-02-13 03:03:49 +00002770 resetstatuspos = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002771
2772 switch (ret) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002773 case NANO_FIRSTLINE_KEY:
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00002774 case NANO_FIRSTLINE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002775 do_first_line();
Chris Allegretta65f075d2003-02-13 03:03:49 +00002776 resetstatuspos = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002777 break;
2778 case NANO_LASTLINE_KEY:
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00002779 case NANO_LASTLINE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002780 do_last_line();
Chris Allegretta65f075d2003-02-13 03:03:49 +00002781 resetstatuspos = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002782 break;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002783#ifndef DISABLE_JUSTIFY
2784 case NANO_PARABEGIN_KEY:
2785 do_para_begin();
2786 resetstatuspos = 1;
2787 break;
2788 case NANO_PARAEND_KEY:
2789 do_para_end();
2790 resetstatuspos = 1;
2791 break;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002792 case NANO_FULLJUSTIFY_KEY:
David Lawrence Ramseyd12fd4b2004-05-28 15:05:56 +00002793 if (!ISSET(VIEW_MODE))
2794 do_full_justify();
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002795 resetstatuspos = 1;
2796 break;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002797#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002798 case NANO_CANCEL_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002799 ret = -1;
Chris Allegretta65f075d2003-02-13 03:03:49 +00002800 resetstatuspos = 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002801 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002802 }
Chris Allegrettaa90d0cf2003-02-10 02:55:03 +00002803 blank_statusbar();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002804
2805#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00002806 fprintf(stderr, "I got \"%s\"\n", answer);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002807#endif
2808
Chris Allegretta6df90f52002-07-19 01:08:59 +00002809#ifndef DISABLE_TABCOMP
2810 /* if we've done tab completion, there might be a list of
2811 filename matches on the edit window at this point; make sure
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002812 they're cleared off. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002813 if (list)
2814 edit_refresh();
2815#endif
2816
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002817 return ret;
2818}
2819
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002820/* Ask a simple yes/no question on the statusbar. Returns 1 for Y, 0
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002821 * for N, 2 for All (if all is nonzero when passed in) and -1 for abort
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002822 * (^C). */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002823int do_yesno(int all, const char *msg)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002824{
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002825 int ok = -2, width = 16;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002826 const char *yesstr; /* String of yes characters accepted */
2827 const char *nostr; /* Same for no */
2828 const char *allstr; /* And all, surprise! */
Chris Allegretta235ab192001-04-12 13:24:40 +00002829
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002830 /* Yes, no and all are strings of any length. Each string consists
2831 * of all characters accepted as a valid character for that value.
2832 * The first value will be the one displayed in the shortcuts. */
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002833 yesstr = _("Yy");
2834 nostr = _("Nn");
2835 allstr = _("Aa");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002836
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002837 /* Remove gettext() call for keybindings until we clear the thing
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002838 * up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002839 if (!ISSET(NO_HELP)) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002840 char shortstr[3]; /* Temp string for Y, N, A. */
Chris Allegretta6232d662002-05-12 19:52:15 +00002841
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002842 if (COLS < 32)
2843 width = COLS / 2;
2844
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002845 /* Write the bottom of the screen. */
Chris Allegrettadb28e962003-01-28 01:23:40 +00002846 blank_bottombars();
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002847
Chris Allegretta6232d662002-05-12 19:52:15 +00002848 sprintf(shortstr, " %c", yesstr[0]);
Chris Allegrettadb28e962003-01-28 01:23:40 +00002849 wmove(bottomwin, 1, 0);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002850 onekey(shortstr, _("Yes"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002851
2852 if (all) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002853 wmove(bottomwin, 1, width);
Chris Allegretta6232d662002-05-12 19:52:15 +00002854 shortstr[1] = allstr[0];
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002855 onekey(shortstr, _("All"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002856 }
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002857
Chris Allegrettadb28e962003-01-28 01:23:40 +00002858 wmove(bottomwin, 2, 0);
Chris Allegretta6232d662002-05-12 19:52:15 +00002859 shortstr[1] = nostr[0];
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002860 onekey(shortstr, _("No"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002861
Chris Allegrettadb28e962003-01-28 01:23:40 +00002862 wmove(bottomwin, 2, 16);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002863 onekey("^C", _("Cancel"), width);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002864 }
Chris Allegrettadb28e962003-01-28 01:23:40 +00002865
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002866 wattron(bottomwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002867
2868 blank_statusbar();
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002869 mvwaddnstr(bottomwin, 0, 0, msg, COLS - 1);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002870
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002871 wattroff(bottomwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002872
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002873 wrefresh(bottomwin);
2874
Chris Allegrettadb28e962003-01-28 01:23:40 +00002875 do {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002876 int kbinput;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002877 int meta_key;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002878#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002879 int mouse_x, mouse_y;
Chris Allegretta235ab192001-04-12 13:24:40 +00002880#endif
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002881
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002882 kbinput = get_kbinput(edit, &meta_key);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002883
2884 if (kbinput == NANO_CANCEL_KEY)
Chris Allegrettadb28e962003-01-28 01:23:40 +00002885 ok = -1;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002886#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002887 /* Look ma! We get to duplicate lots of code from
2888 * do_mouse()!! */
2889 else if (kbinput == KEY_MOUSE) {
2890 kbinput = get_mouseinput(&mouse_x, &mouse_y, 0);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002891
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002892 if (mouse_x != -1 && mouse_y != -1 && !ISSET(NO_HELP) &&
2893 wenclose(bottomwin, mouse_y, mouse_x) && mouse_x <
2894 (width * 2) && mouse_y >= editwinrows + 3) {
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002895
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002896 int x = mouse_x / width;
2897 /* Did we click in the first column of shortcuts, or
2898 * the second? */
2899 int y = mouse_y - editwinrows - 3;
2900 /* Did we click in the first row of shortcuts? */
2901
2902 assert(0 <= x && x <= 1 && 0 <= y && y <= 1);
2903
2904 /* x = 0 means they clicked Yes or No.
2905 * y = 0 means Yes or All. */
2906 ok = -2 * x * y + x - y + 1;
2907
2908 if (ok == 2 && !all)
2909 ok = -2;
2910 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002911 }
Chris Allegrettadb28e962003-01-28 01:23:40 +00002912#endif
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002913 /* Look for the kbinput in the yes, no and (optionally) all
2914 * str. */
Chris Allegrettadb28e962003-01-28 01:23:40 +00002915 else if (strchr(yesstr, kbinput) != NULL)
2916 ok = 1;
2917 else if (strchr(nostr, kbinput) != NULL)
2918 ok = 0;
2919 else if (all && strchr(allstr, kbinput) != NULL)
2920 ok = 2;
2921 } while (ok == -2);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002922
Chris Allegrettadb28e962003-01-28 01:23:40 +00002923 return ok;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002924}
2925
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002926int total_refresh(void)
2927{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002928 clearok(topwin, TRUE);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002929 clearok(edit, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002930 clearok(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002931 wnoutrefresh(topwin);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002932 wnoutrefresh(edit);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002933 wnoutrefresh(bottomwin);
2934 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002935 clearok(topwin, FALSE);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002936 clearok(edit, FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002937 clearok(bottomwin, FALSE);
2938 edit_refresh();
2939 titlebar(NULL);
2940 return 1;
2941}
2942
2943void display_main_list(void)
2944{
2945 bottombars(main_list);
2946}
2947
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002948/* If constant is FALSE, the user typed ^C so we unconditionally display
Chris Allegrettad26ab912003-01-28 01:16:47 +00002949 * the cursor position. Otherwise, we display it only if the character
2950 * position changed, and DISABLE_CURPOS is not set.
2951 *
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002952 * If constant is TRUE and DISABLE_CURPOS is set, we unset it and update
2953 * old_i and old_totsize. That way, we leave the current statusbar
2954 * alone, but next time we will display. */
Chris Allegretta2084acc2001-11-29 03:43:08 +00002955int do_cursorpos(int constant)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002956{
Chris Allegrettad26ab912003-01-28 01:16:47 +00002957 const filestruct *fileptr;
2958 unsigned long i = 0;
2959 static unsigned long old_i = 0;
2960 static long old_totsize = -1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002961
Chris Allegrettad26ab912003-01-28 01:16:47 +00002962 assert(current != NULL && fileage != NULL && totlines != 0);
Chris Allegretta2084acc2001-11-29 03:43:08 +00002963
2964 if (old_totsize == -1)
2965 old_totsize = totsize;
2966
Chris Allegrettad26ab912003-01-28 01:16:47 +00002967 for (fileptr = fileage; fileptr != current; fileptr = fileptr->next) {
2968 assert(fileptr != NULL);
Chris Allegrettaf27c6972002-02-12 01:57:24 +00002969 i += strlen(fileptr->data) + 1;
Chris Allegrettad26ab912003-01-28 01:16:47 +00002970 }
Chris Allegrettaf27c6972002-02-12 01:57:24 +00002971 i += current_x;
Chris Allegretta14b3ca92002-01-25 21:59:02 +00002972
Chris Allegrettad26ab912003-01-28 01:16:47 +00002973 if (constant && ISSET(DISABLE_CURPOS)) {
2974 UNSET(DISABLE_CURPOS);
2975 old_i = i;
2976 old_totsize = totsize;
2977 return 0;
2978 }
Chris Allegretta14b3ca92002-01-25 21:59:02 +00002979
David Lawrence Ramsey4178db02004-05-23 21:23:23 +00002980 /* If constant is FALSE, display the position on the statusbar
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002981 * unconditionally; otherwise, only display the position when the
2982 * character values have changed. */
Chris Allegrettad26ab912003-01-28 01:16:47 +00002983 if (!constant || old_i != i || old_totsize != totsize) {
2984 unsigned long xpt = xplustabs() + 1;
2985 unsigned long cur_len = strlenpt(current->data) + 1;
2986 int linepct = 100 * current->lineno / totlines;
2987 int colpct = 100 * xpt / cur_len;
2988 int bytepct = totsize == 0 ? 0 : 100 * i / totsize;
2989
2990 statusbar(
2991 _("line %ld/%ld (%d%%), col %lu/%lu (%d%%), char %lu/%ld (%d%%)"),
2992 current->lineno, totlines, linepct,
2993 xpt, cur_len, colpct,
2994 i, totsize, bytepct);
2995 UNSET(DISABLE_CURPOS);
Chris Allegretta2084acc2001-11-29 03:43:08 +00002996 }
2997
2998 old_i = i;
2999 old_totsize = totsize;
3000
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003001 reset_cursor();
Chris Allegrettad26ab912003-01-28 01:16:47 +00003002 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003003}
3004
Chris Allegretta2084acc2001-11-29 03:43:08 +00003005int do_cursorpos_void(void)
3006{
3007 return do_cursorpos(0);
3008}
3009
Chris Allegretta4640fe32003-02-10 03:10:03 +00003010/* Calculate the next line of help_text, starting at ptr. */
3011int line_len(const char *ptr)
3012{
3013 int j = 0;
3014
3015 while (*ptr != '\n' && *ptr != '\0' && j < COLS - 5) {
3016 ptr++;
3017 j++;
3018 }
3019 if (j == COLS - 5) {
3020 /* Don't wrap at the first of two spaces following a period. */
3021 if (*ptr == ' ' && *(ptr + 1) == ' ')
3022 j++;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003023 /* Don't print half a word if we've run out of space. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00003024 while (*ptr != ' ' && j > 0) {
3025 ptr--;
3026 j--;
3027 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003028 /* Word longer than COLS - 5 chars just gets broken. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00003029 if (j == 0)
3030 j = COLS - 5;
3031 }
3032 assert(j >= 0 && j <= COLS - 4 && (j > 0 || *ptr == '\n'));
3033 return j;
3034}
3035
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003036#ifndef DISABLE_HELP
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003037/* Our shortcut-list-compliant help function, which is better than
3038 * nothing, and dynamic! */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003039int do_help(void)
3040{
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003041 int line = 0;
3042 /* The line number in help_text of the first displayed help line.
3043 * This variable is zero-based. */
3044 int no_more = 0;
3045 /* no_more means the end of the help text is shown, so don't go down
3046 * any more. */
3047 int kbinput = ERR, meta_key;
3048
David Lawrence Ramseye7638ea2004-06-01 19:49:38 +00003049 int old_no_help = ISSET(NO_HELP);
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003050#ifndef DISABLE_MOUSE
3051 const shortcut *oldshortcut = currshortcut;
3052 /* We will set currshortcut to allow clicking on the help
3053 screen shortcut list. */
3054#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003055
David Lawrence Ramseyae064bf2004-06-01 20:38:00 +00003056 curs_set(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003057 blank_edit();
Chris Allegrettab3655b42001-10-22 03:15:31 +00003058 wattroff(bottomwin, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003059 blank_statusbar();
3060
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003061 /* Set help_text as the string to display. */
Chris Allegrettab3655b42001-10-22 03:15:31 +00003062 help_init();
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003063 assert(help_text != NULL);
Chris Allegrettab3655b42001-10-22 03:15:31 +00003064
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003065#ifndef DISABLE_MOUSE
3066 /* Set currshortcut to allow clicking on the help screen shortcut
3067 * list, AFTER help_init(). */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003068 currshortcut = help_list;
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003069#endif
Chris Allegretta6fe61492001-05-21 12:56:25 +00003070
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003071 if (ISSET(NO_HELP)) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003072 /* Well, if we're going to do this, we should at least do it the
3073 * right way. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +00003074 UNSET(NO_HELP);
Chris Allegretta70444892001-01-07 23:02:02 +00003075 window_init();
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003076 }
3077 bottombars(help_list);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003078
3079 do {
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003080 int i;
3081 int old_line = line;
3082 /* We redisplay the help only if it moved. */
Chris Allegrettaf717f982003-02-13 22:25:01 +00003083 const char *ptr = help_text;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003084
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003085 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003086#ifndef DISABLE_MOUSE
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003087 case KEY_MOUSE:
3088 do_mouse();
3089 break;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003090#endif
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003091 case NANO_NEXTPAGE_KEY:
3092 case NANO_NEXTPAGE_FKEY:
3093 if (!no_more)
3094 line += editwinrows - 2;
3095 break;
3096 case NANO_PREVPAGE_KEY:
3097 case NANO_PREVPAGE_FKEY:
3098 if (line > 0) {
3099 line -= editwinrows - 2;
3100 if (line < 0)
3101 line = 0;
3102 }
3103 break;
3104 case NANO_PREVLINE_KEY:
3105 if (line > 0)
3106 line--;
3107 break;
3108 case NANO_NEXTLINE_KEY:
3109 if (!no_more)
3110 line++;
3111 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003112 }
3113
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003114 if (line == old_line && kbinput != ERR)
3115 goto skip_redisplay;
3116
3117 blank_edit();
3118
3119 assert(COLS > 5);
3120
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003121 /* Calculate where in the text we should be, based on the
3122 * page. */
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003123 for (i = 0; i < line; i++) {
Chris Allegretta4640fe32003-02-10 03:10:03 +00003124 ptr += line_len(ptr);
3125 if (*ptr == '\n')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003126 ptr++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003127 }
3128
Chris Allegretta4640fe32003-02-10 03:10:03 +00003129 for (i = 0; i < editwinrows && *ptr != '\0'; i++) {
3130 int j = line_len(ptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003131
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003132 mvwaddnstr(edit, i, 0, ptr, j);
Chris Allegretta4640fe32003-02-10 03:10:03 +00003133 ptr += j;
3134 if (*ptr == '\n')
3135 ptr++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003136 }
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003137 no_more = (*ptr == '\0');
Chris Allegretta4640fe32003-02-10 03:10:03 +00003138
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003139 skip_redisplay:
3140 kbinput = get_kbinput(edit, &meta_key);
3141 } while (kbinput != NANO_EXIT_KEY && kbinput != NANO_EXIT_FKEY);
Chris Allegrettad1627cf2000-12-18 05:03:16 +00003142
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003143#ifndef DISABLE_MOUSE
Chris Allegrettab3655b42001-10-22 03:15:31 +00003144 currshortcut = oldshortcut;
David Lawrence Ramseybe265612004-05-29 20:38:08 +00003145#endif
Chris Allegrettab3655b42001-10-22 03:15:31 +00003146
David Lawrence Ramseye7638ea2004-06-01 19:49:38 +00003147 if (old_no_help) {
Chris Allegretta70444892001-01-07 23:02:02 +00003148 blank_bottombars();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00003149 wrefresh(bottomwin);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003150 SET(NO_HELP);
Chris Allegretta70444892001-01-07 23:02:02 +00003151 window_init();
Chris Allegretta598106e2002-01-19 01:59:37 +00003152 } else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003153 bottombars(currshortcut);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003154
David Lawrence Ramseyae064bf2004-06-01 20:38:00 +00003155 curs_set(1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003156 edit_refresh();
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003157
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003158 /* The help_init() at the beginning allocated help_text, which has
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003159 * now been written to the screen. */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003160 free(help_text);
3161 help_text = NULL;
3162
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003163 return 1;
3164}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003165#endif /* !DISABLE_HELP */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003166
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003167/* Highlight the current word being replaced or spell checked. We
3168 * expect word to have tabs and control characters expanded. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003169void do_replace_highlight(int highlight_flag, const char *word)
Chris Allegrettafb62f732000-12-05 11:36:41 +00003170{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003171 int y = xplustabs();
3172 size_t word_len = strlen(word);
Chris Allegrettafb62f732000-12-05 11:36:41 +00003173
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003174 y = get_page_start(y) + COLS - y;
3175 /* Now y is the number of characters we can display on this
3176 * line. */
Chris Allegrettafb62f732000-12-05 11:36:41 +00003177
3178 reset_cursor();
Chris Allegretta598106e2002-01-19 01:59:37 +00003179
Chris Allegrettafb62f732000-12-05 11:36:41 +00003180 if (highlight_flag)
3181 wattron(edit, A_REVERSE);
3182
David Lawrence Ramsey2a4ab6d2003-12-24 08:29:49 +00003183#ifdef HAVE_REGEX_H
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00003184 /* This is so we can show zero-length regexes. */
3185 if (word_len == 0)
3186 waddstr(edit, " ");
3187 else
David Lawrence Ramsey2a4ab6d2003-12-24 08:29:49 +00003188#endif
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00003189 waddnstr(edit, word, y - 1);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003190
3191 if (word_len > y)
3192 waddch(edit, '$');
3193 else if (word_len == y)
3194 waddch(edit, word[word_len - 1]);
Chris Allegrettafb62f732000-12-05 11:36:41 +00003195
3196 if (highlight_flag)
3197 wattroff(edit, A_REVERSE);
Chris Allegrettafb62f732000-12-05 11:36:41 +00003198}
3199
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003200#ifdef DEBUG
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003201/* Dump the passed-in file structure to stderr. */
3202void dump_buffer(const filestruct *inptr)
3203{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003204 if (inptr == fileage)
Jordi Mallachf9390af2003-08-05 19:31:12 +00003205 fprintf(stderr, "Dumping file buffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003206 else if (inptr == cutbuffer)
Jordi Mallachf9390af2003-08-05 19:31:12 +00003207 fprintf(stderr, "Dumping cutbuffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003208 else
Jordi Mallachf9390af2003-08-05 19:31:12 +00003209 fprintf(stderr, "Dumping a buffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003210
3211 while (inptr != NULL) {
3212 fprintf(stderr, "(%d) %s\n", inptr->lineno, inptr->data);
3213 inptr = inptr->next;
3214 }
3215}
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003216
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003217/* Dump the file structure to stderr in reverse. */
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00003218void dump_buffer_reverse(void)
3219{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003220 const filestruct *fileptr = filebot;
3221
3222 while (fileptr != NULL) {
3223 fprintf(stderr, "(%d) %s\n", fileptr->lineno, fileptr->data);
3224 fileptr = fileptr->prev;
3225 }
3226}
3227#endif /* DEBUG */
3228
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003229#ifdef NANO_EXTRA
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00003230#define CREDIT_LEN 53
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00003231#define XLCREDIT_LEN 8
3232
David Lawrence Ramseyfdece462004-01-19 18:15:03 +00003233/* Easter egg: Display credits. Assume nodelay(edit) is FALSE. */
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003234void do_credits(void)
3235{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003236 int crpos = 0, xlpos = 0;
3237 const char *credits[CREDIT_LEN] = {
3238 NULL, /* "The nano text editor" */
3239 NULL, /* "version" */
Chris Allegretta598106e2002-01-19 01:59:37 +00003240 VERSION,
3241 "",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003242 NULL, /* "Brought to you by:" */
Chris Allegretta598106e2002-01-19 01:59:37 +00003243 "Chris Allegretta",
3244 "Jordi Mallach",
3245 "Adam Rogoyski",
3246 "Rob Siemborski",
3247 "Rocco Corsi",
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003248 "David Lawrence Ramsey",
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00003249 "David Benbennick",
Chris Allegretta598106e2002-01-19 01:59:37 +00003250 "Ken Tyler",
3251 "Sven Guckes",
3252 "Florian König",
3253 "Pauli Virtanen",
3254 "Daniele Medri",
3255 "Clement Laforet",
3256 "Tedi Heriyanto",
3257 "Bill Soudan",
3258 "Christian Weisgerber",
3259 "Erik Andersen",
3260 "Big Gaute",
3261 "Joshua Jensen",
3262 "Ryan Krebs",
3263 "Albert Chin",
Chris Allegretta598106e2002-01-19 01:59:37 +00003264 "",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003265 NULL, /* "Special thanks to:" */
Chris Allegretta598106e2002-01-19 01:59:37 +00003266 "Plattsburgh State University",
3267 "Benet Laboratories",
3268 "Amy Allegretta",
3269 "Linda Young",
3270 "Jeremy Robichaud",
3271 "Richard Kolb II",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003272 NULL, /* "The Free Software Foundation" */
Chris Allegretta598106e2002-01-19 01:59:37 +00003273 "Linus Torvalds",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003274 NULL, /* "For ncurses:" */
Chris Allegrettadce44ab2002-03-16 01:03:41 +00003275 "Thomas Dickey",
3276 "Pavel Curtis",
3277 "Zeyd Ben-Halim",
3278 "Eric S. Raymond",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003279 NULL, /* "and anyone else we forgot..." */
3280 NULL, /* "Thank you for using nano!" */
3281 "",
3282 "",
3283 "",
3284 "",
David Lawrence Ramsey6481c3f2004-01-09 23:06:54 +00003285 "(c) 1999-2004 Chris Allegretta",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003286 "",
3287 "",
3288 "",
3289 "",
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00003290 "http://www.nano-editor.org/"
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003291 };
3292
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003293 const char *xlcredits[XLCREDIT_LEN] = {
David Lawrence Ramsey837a02b2004-05-18 15:23:31 +00003294 "The nano text editor",
3295 "version",
3296 "Brought to you by:",
3297 "Special thanks to:",
3298 "The Free Software Foundation",
3299 "For ncurses:",
3300 "and anyone else we forgot...",
3301 "Thank you for using nano!"
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003302 };
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00003303
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003304 curs_set(0);
3305 nodelay(edit, TRUE);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003306 scrollok(edit, TRUE);
3307 blank_titlebar();
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00003308 blank_edit();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003309 blank_statusbar();
3310 blank_bottombars();
3311 wrefresh(topwin);
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00003312 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003313 wrefresh(bottomwin);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003314
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003315 for (crpos = 0; crpos < CREDIT_LEN + editwinrows / 2; crpos++) {
3316 if (wgetch(edit) != ERR)
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003317 break;
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003318 if (crpos < CREDIT_LEN) {
3319 const char *what = credits[crpos];
3320 size_t start_x;
3321
3322 if (what == NULL) {
3323 assert(0 <= xlpos && xlpos < XLCREDIT_LEN);
David Lawrence Ramsey837a02b2004-05-18 15:23:31 +00003324 what = _(xlcredits[xlpos]);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003325 xlpos++;
3326 }
3327 start_x = COLS / 2 - strlen(what) / 2 - 1;
3328 mvwaddstr(edit, editwinrows - 1 - editwinrows % 2, start_x, what);
3329 }
3330 napms(700);
3331 scroll(edit);
3332 wrefresh(edit);
3333 if (wgetch(edit) != ERR)
3334 break;
3335 napms(700);
3336 scroll(edit);
3337 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003338 }
3339
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003340 scrollok(edit, FALSE);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003341 nodelay(edit, FALSE);
3342 curs_set(1);
3343 display_main_list();
3344 total_refresh();
Chris Allegretta598106e2002-01-19 01:59:37 +00003345}
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003346#endif