1 /* $Id: winio.c 4527 2011-02-07 14:45:56Z astyanax $ */
2 /**************************************************************************
5 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
6 * 2008, 2009 Free Software Foundation, Inc. *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 3, or (at your option) *
10 * any later version. *
12 * This program is distributed in the hope that it will be useful, but *
13 * WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
15 * General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
22 **************************************************************************/
32 static int *key_buffer = NULL;
33 /* The keystroke buffer, containing all the keystrokes we
34 * haven't handled yet at a given point. */
35 static size_t key_buffer_len = 0;
36 /* The length of the keystroke buffer. */
37 static int statusblank = 0;
38 /* The number of keystrokes left after we call statusbar(),
39 * before we actually blank the statusbar. */
40 static bool disable_cursorpos = FALSE;
41 /* Should we temporarily disable constant cursor position
44 /* Control character compatibility:
46 * - NANO_BACKSPACE_KEY is Ctrl-H, which is Backspace under ASCII, ANSI,
48 * - NANO_TAB_KEY is Ctrl-I, which is Tab under ASCII, ANSI, VT100,
50 * - NANO_ENTER_KEY is Ctrl-M, which is Enter under ASCII, ANSI, VT100,
52 * - NANO_XON_KEY is Ctrl-Q, which is XON under ASCII, ANSI, VT100,
54 * - NANO_XOFF_KEY is Ctrl-S, which is XOFF under ASCII, ANSI, VT100,
56 * - NANO_CONTROL_8 is Ctrl-8 (Ctrl-?), which is Delete under ASCII,
57 * ANSI, VT100, and VT220, and which is Backspace under VT320.
59 * Note: VT220 and VT320 also generate Esc [ 3 ~ for Delete. By
60 * default, xterm assumes it's running on a VT320 and generates Ctrl-8
61 * (Ctrl-?) for Backspace and Esc [ 3 ~ for Delete. This causes
62 * problems for VT100-derived terminals such as the FreeBSD console,
63 * which expect Ctrl-H for Backspace and Ctrl-8 (Ctrl-?) for Delete, and
64 * on which the VT320 sequences are translated by the keypad to KEY_DC
65 * and [nothing]. We work around this conflict via the REBIND_DELETE
66 * flag: if it's not set, we assume VT320 compatibility, and if it is,
67 * we assume VT100 compatibility. Thanks to Lee Nelson and Wouter van
68 * Hemel for helping work this conflict out.
70 * Escape sequence compatibility:
72 * We support escape sequences for ANSI, VT100, VT220, VT320, the Linux
73 * console, the FreeBSD console, the Mach console, xterm, rxvt, Eterm,
74 * and Terminal. Among these, there are several conflicts and
75 * omissions, outlined as follows:
77 * - Tab on ANSI == PageUp on FreeBSD console; the former is omitted.
78 * (Ctrl-I is also Tab on ANSI, which we already support.)
79 * - PageDown on FreeBSD console == Center (5) on numeric keypad with
80 * NumLock off on Linux console; the latter is omitted. (The editing
81 * keypad key is more important to have working than the numeric
82 * keypad key, because the latter has no value when NumLock is off.)
83 * - F1 on FreeBSD console == the mouse key on xterm/rxvt/Eterm; the
84 * latter is omitted. (Mouse input will only work properly if the
85 * extended keypad value KEY_MOUSE is generated on mouse events
86 * instead of the escape sequence.)
87 * - F9 on FreeBSD console == PageDown on Mach console; the former is
88 * omitted. (The editing keypad is more important to have working
89 * than the function keys, because the functions of the former are not
90 * arbitrary and the functions of the latter are.)
91 * - F10 on FreeBSD console == PageUp on Mach console; the former is
92 * omitted. (Same as above.)
93 * - F13 on FreeBSD console == End on Mach console; the former is
94 * omitted. (Same as above.)
95 * - F15 on FreeBSD console == Shift-Up on rxvt/Eterm; the former is
96 * omitted. (The arrow keys, with or without modifiers, are more
97 * important to have working than the function keys, because the
98 * functions of the former are not arbitrary and the functions of the
100 * - F16 on FreeBSD console == Shift-Down on rxvt/Eterm; the former is
101 * omitted. (Same as above.) */
103 /* Read in a sequence of keystrokes from win and save them in the
104 * keystroke buffer. This should only be called when the keystroke
105 * buffer is empty. */
106 void get_key_buffer(WINDOW *win)
111 /* If the keystroke buffer isn't empty, get out. */
112 if (key_buffer != NULL)
115 /* Read in the first character using blocking input. */
117 allow_pending_sigwinch(TRUE);
120 /* Just before reading in the first character, display any pending
126 if ((input = wgetch(win)) == ERR)
129 while ((input = wgetch(win)) == ERR) {
132 /* If we've failed to get a character MAX_BUF_SIZE times in a
133 * row, assume that the input source we were using is gone and
134 * die gracefully. We could check if errno is set to EIO
135 * ("Input/output error") and die gracefully in that case, but
136 * it's not always set properly. Argh. */
137 if (errcount == MAX_BUF_SIZE)
142 allow_pending_sigwinch(FALSE);
145 /* Increment the length of the keystroke buffer, and save the value
146 * of the keystroke at the end of it. */
148 key_buffer = (int *)nmalloc(sizeof(int));
149 key_buffer[0] = input;
151 /* Read in the remaining characters using non-blocking input. */
156 allow_pending_sigwinch(TRUE);
161 /* If there aren't any more characters, stop reading. */
165 /* Otherwise, increment the length of the keystroke buffer, and
166 * save the value of the keystroke at the end of it. */
168 key_buffer = (int *)nrealloc(key_buffer, key_buffer_len *
170 key_buffer[key_buffer_len - 1] = input;
173 allow_pending_sigwinch(FALSE);
177 /* Switch back to non-blocking input. */
181 fprintf(stderr, "get_key_buffer(): key_buffer_len = %lu\n", (unsigned long)key_buffer_len);
185 /* Return the length of the keystroke buffer. */
186 size_t get_key_buffer_len(void)
188 return key_buffer_len;
191 /* Add the keystrokes in input to the keystroke buffer. */
192 void unget_input(int *input, size_t input_len)
195 allow_pending_sigwinch(TRUE);
196 allow_pending_sigwinch(FALSE);
199 /* If input is empty, get out. */
203 /* If adding input would put the keystroke buffer beyond maximum
204 * capacity, only add enough of input to put it at maximum
206 if (key_buffer_len + input_len < key_buffer_len)
207 input_len = (size_t)-1 - key_buffer_len;
209 /* Add the length of input to the length of the keystroke buffer,
210 * and reallocate the keystroke buffer so that it has enough room
212 key_buffer_len += input_len;
213 key_buffer = (int *)nrealloc(key_buffer, key_buffer_len *
216 /* If the keystroke buffer wasn't empty before, move its beginning
217 * forward far enough so that we can add input to its beginning. */
218 if (key_buffer_len > input_len)
219 memmove(key_buffer + input_len, key_buffer,
220 (key_buffer_len - input_len) * sizeof(int));
222 /* Copy input to the beginning of the keystroke buffer. */
223 memcpy(key_buffer, input, input_len * sizeof(int));
226 /* Put back the character stored in kbinput, putting it in byte range
227 * beforehand. If meta_key is TRUE, put back the Escape character after
228 * putting back kbinput. If func_key is TRUE, put back the function key
229 * (a value outside byte range) without putting it in byte range. */
230 void unget_kbinput(int kbinput, bool meta_key, bool func_key)
233 kbinput = (char)kbinput;
235 unget_input(&kbinput, 1);
238 kbinput = NANO_CONTROL_3;
239 unget_input(&kbinput, 1);
243 /* Try to read input_len characters from the keystroke buffer. If the
244 * keystroke buffer is empty and win isn't NULL, try to read in more
245 * characters from win and add them to the keystroke buffer before doing
246 * anything else. If the keystroke buffer is empty and win is NULL,
248 int *get_input(WINDOW *win, size_t input_len)
253 allow_pending_sigwinch(TRUE);
254 allow_pending_sigwinch(FALSE);
257 if (key_buffer_len == 0) {
261 if (key_buffer_len == 0)
267 /* If input_len is greater than the length of the keystroke buffer,
268 * only read the number of characters in the keystroke buffer. */
269 if (input_len > key_buffer_len)
270 input_len = key_buffer_len;
272 /* Subtract input_len from the length of the keystroke buffer, and
273 * allocate input so that it has enough room for input_len
275 key_buffer_len -= input_len;
276 input = (int *)nmalloc(input_len * sizeof(int));
278 /* Copy input_len keystrokes from the beginning of the keystroke
279 * buffer into input. */
280 memcpy(input, key_buffer, input_len * sizeof(int));
282 /* If the keystroke buffer is empty, mark it as such. */
283 if (key_buffer_len == 0) {
286 /* If the keystroke buffer isn't empty, move its beginning forward
287 * far enough so that the keystrokes in input are no longer at its
290 memmove(key_buffer, key_buffer + input_len, key_buffer_len *
292 key_buffer = (int *)nrealloc(key_buffer, key_buffer_len *
299 /* Read in a single character. If it's ignored, swallow it and go on.
300 * Otherwise, try to translate it from ASCII, meta key sequences, escape
301 * sequences, and/or extended keypad values. Set meta_key to TRUE when
302 * we get a meta key sequence, and set func_key to TRUE when we get an
303 * extended keypad value. Supported extended keypad values consist of
304 * [arrow key], Ctrl-[arrow key], Shift-[arrow key], Enter, Backspace,
305 * the editing keypad (Insert, Delete, Home, End, PageUp, and PageDown),
306 * the function keypad (F1-F16), and the numeric keypad with NumLock
307 * off. Assume nodelay(win) is FALSE. */
308 int get_kbinput(WINDOW *win, bool *meta_key, bool *func_key)
312 /* Read in a character and interpret it. Continue doing this until
313 * we get a recognized value or sequence. */
314 while ((kbinput = parse_kbinput(win, meta_key, func_key)) == ERR);
316 /* If we read from the edit window, blank the statusbar if we need
324 /* Translate ASCII characters, extended keypad values, and escape
325 * sequences into their corresponding key values. Set meta_key to TRUE
326 * when we get a meta key sequence, and set func_key to TRUE when we get
327 * a function key. Assume nodelay(win) is FALSE. */
328 int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key)
330 static int escapes = 0, byte_digits = 0;
331 int *kbinput, retval = ERR;
336 /* Read in a character. */
338 kbinput = get_input(win, 1);
342 while ((kbinput = get_input(win, 1)) == NULL);
348 /* Increment the escape counter. */
352 /* One escape: wait for more input. */
354 /* Two escapes: wait for more input. */
356 /* Three escapes: wait for more input. */
359 /* More than three escapes: limit the escape counter
360 * to no more than two, and wait for more input. */
367 /* One non-escape: normal input mode. Save the
368 * non-escape character as the result. */
372 /* Reset the escape counter. */
374 if (get_key_buffer_len() == 0) {
375 /* One escape followed by a non-escape, and
376 * there aren't any other keystrokes waiting:
377 * meta key sequence mode. Set meta_key to
378 * TRUE, and save the lowercase version of the
379 * non-escape character as the result. */
381 retval = tolower(*kbinput);
383 /* One escape followed by a non-escape, and
384 * there are other keystrokes waiting: escape
385 * sequence mode. Interpret the escape
387 retval = parse_escape_seq_kbinput(win,
391 if (get_key_buffer_len() == 0) {
392 if (('0' <= *kbinput && *kbinput <= '2' &&
393 byte_digits == 0) || ('0' <= *kbinput &&
394 *kbinput <= '9' && byte_digits > 0)) {
395 /* Two escapes followed by one or more
396 * decimal digits, and there aren't any
397 * other keystrokes waiting: byte sequence
398 * mode. If the byte sequence's range is
399 * limited to 2XX (the first digit is in the
400 * '0' to '2' range and it's the first
401 * digit, or it's in the '0' to '9' range
402 * and it's not the first digit), increment
403 * the byte sequence counter and interpret
404 * the digit. If the byte sequence's range
405 * is not limited to 2XX, fall through. */
409 byte = get_byte_kbinput(*kbinput);
413 int byte_mb_len, *seq, i;
415 /* If we've read in a complete byte
416 * sequence, reset the escape counter
417 * and the byte sequence counter, and
418 * put back the corresponding byte
423 /* Put back the multibyte equivalent of
425 byte_mb = make_mbchar((long)byte,
428 seq = (int *)nmalloc(byte_mb_len *
431 for (i = 0; i < byte_mb_len; i++)
432 seq[i] = (unsigned char)byte_mb[i];
434 unget_input(seq, byte_mb_len);
440 /* Reset the escape counter. */
442 if (byte_digits == 0)
443 /* Two escapes followed by a non-decimal
444 * digit or a decimal digit that would
445 * create a byte sequence greater than
446 * 2XX, we're not in the middle of a
447 * byte sequence, and there aren't any
448 * other keystrokes waiting: control
449 * character sequence mode. Interpret
450 * the control sequence and save the
451 * corresponding control character as
453 retval = get_control_kbinput(*kbinput);
455 /* If we're in the middle of a byte
456 * sequence, reset the byte sequence
457 * counter and save the character we got
464 /* Two escapes followed by a non-escape, and
465 * there are other keystrokes waiting: combined
466 * meta and escape sequence mode. Reset the
467 * escape counter, set meta_key to TRUE, and
468 * interpret the escape sequence. */
471 retval = parse_escape_seq_kbinput(win,
476 /* Reset the escape counter. */
478 if (get_key_buffer_len() == 0)
479 /* Three escapes followed by a non-escape, and
480 * there aren't any other keystrokes waiting:
481 * normal input mode. Save the non-escape
482 * character as the result. */
485 /* Three escapes followed by a non-escape, and
486 * there are other keystrokes waiting: combined
487 * control character and escape sequence mode.
488 * Interpret the escape sequence, and interpret
489 * the result as a control sequence. */
490 retval = get_control_kbinput(
491 parse_escape_seq_kbinput(win,
500 retval = ISSET(REBIND_DELETE) ? sc_seq_or(do_delete, 0) :
501 sc_seq_or(do_backspace, 0);
505 /* ncurses and Slang don't support KEY_SDOWN. */
508 retval = sc_seq_or(do_down_void, *kbinput);
512 /* ncurses and Slang don't support KEY_SUP. */
515 retval = sc_seq_or(do_up_void, *kbinput);
519 /* Slang doesn't support KEY_SLEFT. */
522 retval = sc_seq_or(do_left, *kbinput);
526 /* Slang doesn't support KEY_SRIGHT. */
529 retval = sc_seq_or(do_right, *kbinput);
532 /* HP-UX 10-11 and Slang don't support KEY_SHOME. */
535 case KEY_A1: /* Home (7) on numeric keypad with
537 retval = sc_seq_or(do_home, *kbinput);
540 retval = sc_seq_or(do_backspace, *kbinput);
543 /* Slang doesn't support KEY_SDC. */
545 if (ISSET(REBIND_DELETE))
546 retval = sc_seq_or(do_delete, *kbinput);
548 retval = sc_seq_or(do_backspace, *kbinput);
552 /* Slang doesn't support KEY_SIC. */
554 retval = sc_seq_or(do_insertfile_void, *kbinput);
557 case KEY_C3: /* PageDown (4) on numeric keypad with
559 retval = sc_seq_or(do_page_down, *kbinput);
561 case KEY_A3: /* PageUp (9) on numeric keypad with
563 retval = sc_seq_or(do_page_up, *kbinput);
566 retval = sc_seq_or(do_enter_void, *kbinput);
568 case KEY_B2: /* Center (5) on numeric keypad with
572 case KEY_C1: /* End (1) on numeric keypad with
575 /* HP-UX 10-11 and Slang don't support KEY_SEND. */
578 retval = sc_seq_or(do_end, *kbinput);
581 /* Slang doesn't support KEY_BEG. */
582 case KEY_BEG: /* Center (5) on numeric keypad with
588 /* Slang doesn't support KEY_CANCEL. */
591 /* Slang doesn't support KEY_SCANCEL. */
594 retval = first_sc_for(currmenu, do_cancel)->seq;
598 /* Slang doesn't support KEY_SBEG. */
599 case KEY_SBEG: /* Center (5) on numeric keypad with
605 /* Slang doesn't support KEY_SSUSPEND. */
607 retval = sc_seq_or(do_suspend_void, 0);
611 /* Slang doesn't support KEY_SUSPEND. */
613 retval = sc_seq_or(do_suspend_void, 0);
626 #if !defined(NANO_TINY) && defined(KEY_RESIZE)
627 /* Since we don't change the default SIGWINCH handler when
628 * NANO_TINY is defined, KEY_RESIZE is never generated.
629 * Also, Slang and SunOS 5.7-5.9 don't support
637 /* If our result is an extended keypad value (i.e. a value
638 * outside of byte range), set func_key to TRUE. */
640 *func_key = !is_byte(retval);
644 fprintf(stderr, "parse_kbinput(): kbinput = %d, meta_key = %s, func_key = %s, escapes = %d, byte_digits = %d, retval = %d\n", *kbinput, *meta_key ? "TRUE" : "FALSE", *func_key ? "TRUE" : "FALSE", escapes, byte_digits, retval);
649 /* Return the result. */
653 /* Translate escape sequences, most of which correspond to extended
654 * keypad values, into their corresponding key values. These sequences
655 * are generated when the keypad doesn't support the needed keys.
656 * Assume that Escape has already been read in. */
657 int get_escape_seq_kbinput(const int *seq, size_t seq_len)
674 case 'A': /* Esc O 1 ; 2 A == Shift-Up on
676 case 'B': /* Esc O 1 ; 2 B == Shift-Down on
678 case 'C': /* Esc O 1 ; 2 C == Shift-Right on
680 case 'D': /* Esc O 1 ; 2 D == Shift-Left on
682 retval = get_escape_seq_abcd(seq[4]);
684 case 'P': /* Esc O 1 ; 2 P == F13 on
688 case 'Q': /* Esc O 1 ; 2 Q == F14 on
692 case 'R': /* Esc O 1 ; 2 R == F15 on
696 case 'S': /* Esc O 1 ; 2 S == F16 on
706 case 'A': /* Esc O 1 ; 5 A == Ctrl-Up on
708 case 'B': /* Esc O 1 ; 5 B == Ctrl-Down on
710 case 'C': /* Esc O 1 ; 5 C == Ctrl-Right on
712 case 'D': /* Esc O 1 ; 5 D == Ctrl-Left on
714 retval = get_escape_seq_abcd(seq[4]);
728 case 'P': /* Esc O 2 P == F13 on
732 case 'Q': /* Esc O 2 Q == F14 on
736 case 'R': /* Esc O 2 R == F15 on
740 case 'S': /* Esc O 2 S == F16 on
747 case 'A': /* Esc O A == Up on VT100/VT320/xterm. */
748 case 'B': /* Esc O B == Down on
749 * VT100/VT320/xterm. */
750 case 'C': /* Esc O C == Right on
751 * VT100/VT320/xterm. */
752 case 'D': /* Esc O D == Left on
753 * VT100/VT320/xterm. */
754 retval = get_escape_seq_abcd(seq[1]);
756 case 'E': /* Esc O E == Center (5) on numeric keypad
757 * with NumLock off on xterm. */
760 case 'F': /* Esc O F == End on xterm/Terminal. */
761 retval = sc_seq_or(do_end, 0);
763 case 'H': /* Esc O H == Home on xterm/Terminal. */
764 retval = sc_seq_or(do_home, 0);;
766 case 'M': /* Esc O M == Enter on numeric keypad with
767 * NumLock off on VT100/VT220/VT320/xterm/
769 retval = sc_seq_or(do_home, 0);;
771 case 'P': /* Esc O P == F1 on VT100/VT220/VT320/Mach
775 case 'Q': /* Esc O Q == F2 on VT100/VT220/VT320/Mach
779 case 'R': /* Esc O R == F3 on VT100/VT220/VT320/Mach
783 case 'S': /* Esc O S == F4 on VT100/VT220/VT320/Mach
787 case 'T': /* Esc O T == F5 on Mach console. */
790 case 'U': /* Esc O U == F6 on Mach console. */
793 case 'V': /* Esc O V == F7 on Mach console. */
796 case 'W': /* Esc O W == F8 on Mach console. */
799 case 'X': /* Esc O X == F9 on Mach console. */
802 case 'Y': /* Esc O Y == F10 on Mach console. */
805 case 'a': /* Esc O a == Ctrl-Up on rxvt. */
806 case 'b': /* Esc O b == Ctrl-Down on rxvt. */
807 case 'c': /* Esc O c == Ctrl-Right on rxvt. */
808 case 'd': /* Esc O d == Ctrl-Left on rxvt. */
809 retval = get_escape_seq_abcd(seq[1]);
811 case 'j': /* Esc O j == '*' on numeric keypad with
812 * NumLock off on VT100/VT220/VT320/xterm/
813 * rxvt/Eterm/Terminal. */
816 case 'k': /* Esc O k == '+' on numeric keypad with
817 * NumLock off on VT100/VT220/VT320/xterm/
818 * rxvt/Eterm/Terminal. */
821 case 'l': /* Esc O l == ',' on numeric keypad with
822 * NumLock off on VT100/VT220/VT320/xterm/
823 * rxvt/Eterm/Terminal. */
826 case 'm': /* Esc O m == '-' on numeric keypad with
827 * NumLock off on VT100/VT220/VT320/xterm/
828 * rxvt/Eterm/Terminal. */
831 case 'n': /* Esc O n == Delete (.) on numeric keypad
832 * with NumLock off on VT100/VT220/VT320/
833 * xterm/rxvt/Eterm/Terminal. */
834 retval = sc_seq_or(do_delete, 0);;
836 case 'o': /* Esc O o == '/' on numeric keypad with
837 * NumLock off on VT100/VT220/VT320/xterm/
838 * rxvt/Eterm/Terminal. */
841 case 'p': /* Esc O p == Insert (0) on numeric keypad
842 * with NumLock off on VT100/VT220/VT320/
843 * rxvt/Eterm/Terminal. */
844 retval = sc_seq_or(do_insertfile_void, 0);;
846 case 'q': /* Esc O q == End (1) on numeric keypad
847 * with NumLock off on VT100/VT220/VT320/
848 * rxvt/Eterm/Terminal. */
849 retval = sc_seq_or(do_end, 0);;
851 case 'r': /* Esc O r == Down (2) on numeric keypad
852 * with NumLock off on VT100/VT220/VT320/
853 * rxvt/Eterm/Terminal. */
854 retval = sc_seq_or(do_down_void, 0);;
856 case 's': /* Esc O s == PageDown (3) on numeric
857 * keypad with NumLock off on VT100/VT220/
858 * VT320/rxvt/Eterm/Terminal. */
859 retval = sc_seq_or(do_page_down, 0);;
861 case 't': /* Esc O t == Left (4) on numeric keypad
862 * with NumLock off on VT100/VT220/VT320/
863 * rxvt/Eterm/Terminal. */
864 retval = sc_seq_or(do_left, 0);;
866 case 'u': /* Esc O u == Center (5) on numeric keypad
867 * with NumLock off on VT100/VT220/VT320/
871 case 'v': /* Esc O v == Right (6) on numeric keypad
872 * with NumLock off on VT100/VT220/VT320/
873 * rxvt/Eterm/Terminal. */
874 retval = sc_seq_or(do_right, 0);
876 case 'w': /* Esc O w == Home (7) on numeric keypad
877 * with NumLock off on VT100/VT220/VT320/
878 * rxvt/Eterm/Terminal. */
879 retval = sc_seq_or(do_home, 0);
881 case 'x': /* Esc O x == Up (8) on numeric keypad
882 * with NumLock off on VT100/VT220/VT320/
883 * rxvt/Eterm/Terminal. */
884 retval = sc_seq_or(do_up_void, 0);
886 case 'y': /* Esc O y == PageUp (9) on numeric keypad
887 * with NumLock off on VT100/VT220/VT320/
888 * rxvt/Eterm/Terminal. */
889 retval = sc_seq_or(do_page_up, 0);
895 case 'a': /* Esc o a == Ctrl-Up on Eterm. */
896 case 'b': /* Esc o b == Ctrl-Down on Eterm. */
897 case 'c': /* Esc o c == Ctrl-Right on Eterm. */
898 case 'd': /* Esc o d == Ctrl-Left on Eterm. */
899 retval = get_escape_seq_abcd(seq[1]);
908 case '1': /* Esc [ 1 1 ~ == F1 on rxvt/
912 case '2': /* Esc [ 1 2 ~ == F2 on rxvt/
916 case '3': /* Esc [ 1 3 ~ == F3 on rxvt/
920 case '4': /* Esc [ 1 4 ~ == F4 on rxvt/
924 case '5': /* Esc [ 1 5 ~ == F5 on xterm/
928 case '7': /* Esc [ 1 7 ~ == F6 on
929 * VT220/VT320/Linux console/
930 * xterm/rxvt/Eterm. */
933 case '8': /* Esc [ 1 8 ~ == F7 on
934 * VT220/VT320/Linux console/
935 * xterm/rxvt/Eterm. */
938 case '9': /* Esc [ 1 9 ~ == F8 on
939 * VT220/VT320/Linux console/
940 * xterm/rxvt/Eterm. */
949 case 'A': /* Esc [ 1 ; 2 A == Shift-Up on
951 case 'B': /* Esc [ 1 ; 2 B == Shift-Down on
953 case 'C': /* Esc [ 1 ; 2 C == Shift-Right on
955 case 'D': /* Esc [ 1 ; 2 D == Shift-Left on
957 retval = get_escape_seq_abcd(seq[4]);
965 case 'A': /* Esc [ 1 ; 5 A == Ctrl-Up on
967 case 'B': /* Esc [ 1 ; 5 B == Ctrl-Down on
969 case 'C': /* Esc [ 1 ; 5 C == Ctrl-Right on
971 case 'D': /* Esc [ 1 ; 5 D == Ctrl-Left on
973 retval = get_escape_seq_abcd(seq[4]);
981 default: /* Esc [ 1 ~ == Home on
982 * VT320/Linux console. */
983 retval = sc_seq_or(do_home, 0);;
991 case '0': /* Esc [ 2 0 ~ == F9 on
992 * VT220/VT320/Linux console/
993 * xterm/rxvt/Eterm. */
996 case '1': /* Esc [ 2 1 ~ == F10 on
997 * VT220/VT320/Linux console/
998 * xterm/rxvt/Eterm. */
1001 case '3': /* Esc [ 2 3 ~ == F11 on
1002 * VT220/VT320/Linux console/
1003 * xterm/rxvt/Eterm. */
1006 case '4': /* Esc [ 2 4 ~ == F12 on
1007 * VT220/VT320/Linux console/
1008 * xterm/rxvt/Eterm. */
1011 case '5': /* Esc [ 2 5 ~ == F13 on
1012 * VT220/VT320/Linux console/
1016 case '6': /* Esc [ 2 6 ~ == F14 on
1017 * VT220/VT320/Linux console/
1021 case '8': /* Esc [ 2 8 ~ == F15 on
1022 * VT220/VT320/Linux console/
1026 case '9': /* Esc [ 2 9 ~ == F16 on
1027 * VT220/VT320/Linux console/
1031 default: /* Esc [ 2 ~ == Insert on
1032 * VT220/VT320/Linux console/
1033 * xterm/Terminal. */
1034 retval = sc_seq_or(do_insertfile_void, 0);;
1039 case '3': /* Esc [ 3 ~ == Delete on VT220/VT320/
1040 * Linux console/xterm/Terminal. */
1041 retval = sc_seq_or(do_delete, 0);;
1043 case '4': /* Esc [ 4 ~ == End on VT220/VT320/Linux
1045 retval = sc_seq_or(do_end, 0);;
1047 case '5': /* Esc [ 5 ~ == PageUp on VT220/VT320/
1048 * Linux console/xterm/Terminal;
1049 * Esc [ 5 ^ == PageUp on Eterm. */
1050 retval = sc_seq_or(do_page_up, 0);;
1052 case '6': /* Esc [ 6 ~ == PageDown on VT220/VT320/
1053 * Linux console/xterm/Terminal;
1054 * Esc [ 6 ^ == PageDown on Eterm. */
1055 retval = sc_seq_or(do_page_down, 0);;
1057 case '7': /* Esc [ 7 ~ == Home on rxvt. */
1058 retval = sc_seq_or(do_home, 0);
1060 case '8': /* Esc [ 8 ~ == End on rxvt. */
1061 retval = sc_seq_or(do_end, 0);
1063 case '9': /* Esc [ 9 == Delete on Mach console. */
1064 retval = sc_seq_or(do_delete, 0);;
1066 case '@': /* Esc [ @ == Insert on Mach console. */
1067 retval = sc_seq_or(do_insertfile_void, 0);;
1069 case 'A': /* Esc [ A == Up on ANSI/VT220/Linux
1070 * console/FreeBSD console/Mach console/
1071 * rxvt/Eterm/Terminal. */
1072 case 'B': /* Esc [ B == Down on ANSI/VT220/Linux
1073 * console/FreeBSD console/Mach console/
1074 * rxvt/Eterm/Terminal. */
1075 case 'C': /* Esc [ C == Right on ANSI/VT220/Linux
1076 * console/FreeBSD console/Mach console/
1077 * rxvt/Eterm/Terminal. */
1078 case 'D': /* Esc [ D == Left on ANSI/VT220/Linux
1079 * console/FreeBSD console/Mach console/
1080 * rxvt/Eterm/Terminal. */
1081 retval = get_escape_seq_abcd(seq[1]);
1083 case 'E': /* Esc [ E == Center (5) on numeric keypad
1084 * with NumLock off on FreeBSD console/
1088 case 'F': /* Esc [ F == End on FreeBSD
1090 retval = sc_seq_or(do_end, 0);
1092 case 'G': /* Esc [ G == PageDown on FreeBSD
1094 retval = sc_seq_or(do_page_down, 0);
1096 case 'H': /* Esc [ H == Home on ANSI/VT220/FreeBSD
1097 * console/Mach console/Eterm. */
1098 retval = sc_seq_or(do_home, 0);
1100 case 'I': /* Esc [ I == PageUp on FreeBSD
1102 retval = sc_seq_or(do_page_up, 0);
1104 case 'L': /* Esc [ L == Insert on ANSI/FreeBSD
1106 retval = sc_seq_or(do_insertfile_void, 0);
1108 case 'M': /* Esc [ M == F1 on FreeBSD console. */
1111 case 'N': /* Esc [ N == F2 on FreeBSD console. */
1117 case 'P': /* Esc [ O P == F1 on
1121 case 'Q': /* Esc [ O Q == F2 on
1125 case 'R': /* Esc [ O R == F3 on
1129 case 'S': /* Esc [ O S == F4 on
1135 /* Esc [ O == F3 on FreeBSD console. */
1138 case 'P': /* Esc [ P == F4 on FreeBSD console. */
1141 case 'Q': /* Esc [ Q == F5 on FreeBSD console. */
1144 case 'R': /* Esc [ R == F6 on FreeBSD console. */
1147 case 'S': /* Esc [ S == F7 on FreeBSD console. */
1150 case 'T': /* Esc [ T == F8 on FreeBSD console. */
1153 case 'U': /* Esc [ U == PageDown on Mach console. */
1154 retval = sc_seq_or(do_page_down, 0);
1156 case 'V': /* Esc [ V == PageUp on Mach console. */
1157 retval = sc_seq_or(do_page_up, 0);
1159 case 'W': /* Esc [ W == F11 on FreeBSD console. */
1162 case 'X': /* Esc [ X == F12 on FreeBSD console. */
1165 case 'Y': /* Esc [ Y == End on Mach console. */
1166 retval = sc_seq_or(do_end, 0);
1168 case 'Z': /* Esc [ Z == F14 on FreeBSD console. */
1171 case 'a': /* Esc [ a == Shift-Up on rxvt/Eterm. */
1172 case 'b': /* Esc [ b == Shift-Down on rxvt/Eterm. */
1173 case 'c': /* Esc [ c == Shift-Right on rxvt/
1175 case 'd': /* Esc [ d == Shift-Left on rxvt/Eterm. */
1176 retval = get_escape_seq_abcd(seq[1]);
1181 case 'A': /* Esc [ [ A == F1 on Linux
1185 case 'B': /* Esc [ [ B == F2 on Linux
1189 case 'C': /* Esc [ [ C == F3 on Linux
1193 case 'D': /* Esc [ [ D == F4 on Linux
1197 case 'E': /* Esc [ [ E == F5 on Linux
1210 fprintf(stderr, "get_escape_seq_kbinput(): retval = %d\n", retval);
1216 /* Return the equivalent arrow key value for the case-insensitive
1217 * letters A (up), B (down), C (right), and D (left). These are common
1218 * to many escape sequences. */
1219 int get_escape_seq_abcd(int kbinput)
1221 switch (tolower(kbinput)) {
1223 return sc_seq_or(do_up_void, 0);;
1225 return sc_seq_or(do_down_void, 0);;
1227 return sc_seq_or(do_right, 0);;
1229 return sc_seq_or(do_left, 0);;
1235 /* Interpret the escape sequence in the keystroke buffer, the first
1236 * character of which is kbinput. Assume that the keystroke buffer
1237 * isn't empty, and that the initial escape has already been read in. */
1238 int parse_escape_seq_kbinput(WINDOW *win, int kbinput)
1243 /* Put back the non-escape character, get the complete escape
1244 * sequence, translate the sequence into its corresponding key
1245 * value, and save that as the result. */
1246 unget_input(&kbinput, 1);
1247 seq_len = get_key_buffer_len();
1248 seq = get_input(NULL, seq_len);
1249 retval = get_escape_seq_kbinput(seq, seq_len);
1253 /* If we got an unrecognized escape sequence, throw it out. */
1254 if (retval == ERR) {
1256 statusbar(_("Unknown Command"));
1262 fprintf(stderr, "parse_escape_seq_kbinput(): kbinput = %d, seq_len = %lu, retval = %d\n", kbinput, (unsigned long)seq_len, retval);
1268 /* Translate a byte sequence: turn a three-digit decimal number (from
1269 * 000 to 255) into its corresponding byte value. */
1270 int get_byte_kbinput(int kbinput)
1272 static int byte_digits = 0, byte = 0;
1275 /* Increment the byte digit counter. */
1278 switch (byte_digits) {
1280 /* First digit: This must be from zero to two. Put it in
1281 * the 100's position of the byte sequence holder. */
1282 if ('0' <= kbinput && kbinput <= '2')
1283 byte = (kbinput - '0') * 100;
1285 /* This isn't the start of a byte sequence. Return this
1286 * character as the result. */
1290 /* Second digit: This must be from zero to five if the first
1291 * was two, and may be any decimal value if the first was
1292 * zero or one. Put it in the 10's position of the byte
1293 * sequence holder. */
1294 if (('0' <= kbinput && kbinput <= '5') || (byte < 200 &&
1295 '6' <= kbinput && kbinput <= '9'))
1296 byte += (kbinput - '0') * 10;
1298 /* This isn't the second digit of a byte sequence.
1299 * Return this character as the result. */
1303 /* Third digit: This must be from zero to five if the first
1304 * was two and the second was between zero and five, and may
1305 * be any decimal value if the first was zero or one and the
1306 * second was between six and nine. Put it in the 1's
1307 * position of the byte sequence holder. */
1308 if (('0' <= kbinput && kbinput <= '5') || (byte < 250 &&
1309 '6' <= kbinput && kbinput <= '9')) {
1310 byte += kbinput - '0';
1311 /* If this character is a valid decimal value, then the
1312 * byte sequence is complete. */
1315 /* This isn't the third digit of a byte sequence.
1316 * Return this character as the result. */
1320 /* If there are more than three digits, return this
1321 * character as the result. (Maybe we should produce an
1322 * error instead?) */
1327 /* If we have a result, reset the byte digit counter and the byte
1328 * sequence holder. */
1329 if (retval != ERR) {
1335 fprintf(stderr, "get_byte_kbinput(): kbinput = %d, byte_digits = %d, byte = %d, retval = %d\n", kbinput, byte_digits, byte, retval);
1342 /* If the character in kbinput is a valid hexadecimal digit, multiply it
1343 * by factor and add the result to uni. */
1344 long add_unicode_digit(int kbinput, long factor, long *uni)
1348 if ('0' <= kbinput && kbinput <= '9')
1349 *uni += (kbinput - '0') * factor;
1350 else if ('a' <= tolower(kbinput) && tolower(kbinput) <= 'f')
1351 *uni += (tolower(kbinput) - 'a' + 10) * factor;
1353 /* If this character isn't a valid hexadecimal value, save it as
1360 /* Translate a Unicode sequence: turn a six-digit hexadecimal number
1361 * (from 000000 to 10FFFF, case-insensitive) into its corresponding
1362 * multibyte value. */
1363 long get_unicode_kbinput(int kbinput)
1365 static int uni_digits = 0;
1366 static long uni = 0;
1369 /* Increment the Unicode digit counter. */
1372 switch (uni_digits) {
1374 /* First digit: This must be zero or one. Put it in the
1375 * 0x100000's position of the Unicode sequence holder. */
1376 if ('0' <= kbinput && kbinput <= '1')
1377 uni = (kbinput - '0') * 0x100000;
1379 /* This isn't the first digit of a Unicode sequence.
1380 * Return this character as the result. */
1384 /* Second digit: This must be zero if the first was one, and
1385 * may be any hexadecimal value if the first was zero. Put
1386 * it in the 0x10000's position of the Unicode sequence
1388 if (uni == 0 || '0' == kbinput)
1389 retval = add_unicode_digit(kbinput, 0x10000, &uni);
1391 /* This isn't the second digit of a Unicode sequence.
1392 * Return this character as the result. */
1396 /* Third digit: This may be any hexadecimal value. Put it
1397 * in the 0x1000's position of the Unicode sequence
1399 retval = add_unicode_digit(kbinput, 0x1000, &uni);
1402 /* Fourth digit: This may be any hexadecimal value. Put it
1403 * in the 0x100's position of the Unicode sequence
1405 retval = add_unicode_digit(kbinput, 0x100, &uni);
1408 /* Fifth digit: This may be any hexadecimal value. Put it
1409 * in the 0x10's position of the Unicode sequence holder. */
1410 retval = add_unicode_digit(kbinput, 0x10, &uni);
1413 /* Sixth digit: This may be any hexadecimal value. Put it
1414 * in the 0x1's position of the Unicode sequence holder. */
1415 retval = add_unicode_digit(kbinput, 0x1, &uni);
1416 /* If this character is a valid hexadecimal value, then the
1417 * Unicode sequence is complete. */
1422 /* If there are more than six digits, return this character
1423 * as the result. (Maybe we should produce an error
1429 /* If we have a result, reset the Unicode digit counter and the
1430 * Unicode sequence holder. */
1431 if (retval != ERR) {
1437 fprintf(stderr, "get_unicode_kbinput(): kbinput = %d, uni_digits = %d, uni = %ld, retval = %ld\n", kbinput, uni_digits, uni, retval);
1442 #endif /* ENABLE_UTF8 */
1444 /* Translate a control character sequence: turn an ASCII non-control
1445 * character into its corresponding control character. */
1446 int get_control_kbinput(int kbinput)
1450 /* Ctrl-Space (Ctrl-2, Ctrl-@, Ctrl-`) */
1451 if (kbinput == ' ' || kbinput == '2')
1452 retval = NANO_CONTROL_SPACE;
1453 /* Ctrl-/ (Ctrl-7, Ctrl-_) */
1454 else if (kbinput == '/')
1455 retval = NANO_CONTROL_7;
1456 /* Ctrl-3 (Ctrl-[, Esc) to Ctrl-7 (Ctrl-/, Ctrl-_) */
1457 else if ('3' <= kbinput && kbinput <= '7')
1458 retval = kbinput - 24;
1459 /* Ctrl-8 (Ctrl-?) */
1460 else if (kbinput == '8' || kbinput == '?')
1461 retval = NANO_CONTROL_8;
1462 /* Ctrl-@ (Ctrl-Space, Ctrl-2, Ctrl-`) to Ctrl-_ (Ctrl-/, Ctrl-7) */
1463 else if ('@' <= kbinput && kbinput <= '_')
1464 retval = kbinput - '@';
1465 /* Ctrl-` (Ctrl-2, Ctrl-Space, Ctrl-@) to Ctrl-~ (Ctrl-6, Ctrl-^) */
1466 else if ('`' <= kbinput && kbinput <= '~')
1467 retval = kbinput - '`';
1472 fprintf(stderr, "get_control_kbinput(): kbinput = %d, retval = %d\n", kbinput, retval);
1478 /* Put the output-formatted characters in output back into the keystroke
1479 * buffer, so that they can be parsed and displayed as output again. */
1480 void unparse_kbinput(char *output, size_t output_len)
1485 if (output_len == 0)
1488 input = (int *)nmalloc(output_len * sizeof(int));
1490 for (i = 0; i < output_len; i++)
1491 input[i] = (int)output[i];
1493 unget_input(input, output_len);
1498 /* Read in a stream of characters verbatim, and return the length of the
1499 * string in kbinput_len. Assume nodelay(win) is FALSE. */
1500 int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len)
1504 /* Turn off flow control characters if necessary so that we can type
1505 * them in verbatim, and turn the keypad off if necessary so that we
1506 * don't get extended keypad values. */
1507 if (ISSET(PRESERVE))
1508 disable_flow_control();
1509 if (!ISSET(REBIND_KEYPAD))
1512 /* Read in a stream of characters and interpret it if possible. */
1513 retval = parse_verbatim_kbinput(win, kbinput_len);
1515 /* Turn flow control characters back on if necessary and turn the
1516 * keypad back on if necessary now that we're done. */
1517 if (ISSET(PRESERVE))
1518 enable_flow_control();
1519 if (!ISSET(REBIND_KEYPAD))
1525 /* Read in a stream of all available characters, and return the length
1526 * of the string in kbinput_len. Translate the first few characters of
1527 * the input into the corresponding multibyte value if possible. After
1528 * that, leave the input as-is. */
1529 int *parse_verbatim_kbinput(WINDOW *win, size_t *kbinput_len)
1531 int *kbinput, *retval;
1533 /* Read in the first keystroke. */
1534 while ((kbinput = get_input(win, 1)) == NULL);
1538 /* Check whether the first keystroke is a valid hexadecimal
1540 long uni = get_unicode_kbinput(*kbinput);
1542 /* If the first keystroke isn't a valid hexadecimal digit, put
1543 * back the first keystroke. */
1545 unget_input(kbinput, 1);
1547 /* Otherwise, read in keystrokes until we have a complete
1548 * Unicode sequence, and put back the corresponding Unicode
1552 int uni_mb_len, *seq, i;
1555 /* TRANSLATORS: This is displayed during the input of a
1556 * six-digit hexadecimal Unicode character code. */
1557 statusbar(_("Unicode Input"));
1559 while (uni == ERR) {
1560 while ((kbinput = get_input(win, 1)) == NULL);
1562 uni = get_unicode_kbinput(*kbinput);
1565 /* Put back the multibyte equivalent of the Unicode
1567 uni_mb = make_mbchar(uni, &uni_mb_len);
1569 seq = (int *)nmalloc(uni_mb_len * sizeof(int));
1571 for (i = 0; i < uni_mb_len; i++)
1572 seq[i] = (unsigned char)uni_mb[i];
1574 unget_input(seq, uni_mb_len);
1580 #endif /* ENABLE_UTF8 */
1582 /* Put back the first keystroke. */
1583 unget_input(kbinput, 1);
1587 /* Get the complete sequence, and save the characters in it as the
1589 *kbinput_len = get_key_buffer_len();
1590 retval = get_input(NULL, *kbinput_len);
1595 #ifndef DISABLE_MOUSE
1596 /* Handle any mouse event that may have occurred. We currently handle
1597 * releases/clicks of the first mouse button. If allow_shortcuts is
1598 * TRUE, releasing/clicking on a visible shortcut will put back the
1599 * keystroke associated with that shortcut. If NCURSES_MOUSE_VERSION is
1600 * at least 2, we also currently handle presses of the fourth mouse
1601 * button (upward rolls of the mouse wheel) by putting back the
1602 * keystrokes to move up, and presses of the fifth mouse button
1603 * (downward rolls of the mouse wheel) by putting back the keystrokes to
1604 * move down. We also store the coordinates of a mouse event that needs
1605 * to be handled in mouse_x and mouse_y, relative to the entire screen.
1606 * Return -1 on error, 0 if the mouse event needs to be handled, 1 if
1607 * it's been handled by putting back keystrokes that need to be handled.
1608 * or 2 if it's been ignored. Assume that KEY_MOUSE has already been
1610 int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts)
1619 /* First, get the actual mouse event. */
1620 if (getmouse(&mevent) == ERR)
1623 /* Save the screen coordinates where the mouse event took place. */
1624 *mouse_x = mevent.x;
1625 *mouse_y = mevent.y;
1627 in_bottomwin = wenclose(bottomwin, *mouse_y, *mouse_x);
1629 /* Handle releases/clicks of the first mouse button. */
1630 if (mevent.bstate & (BUTTON1_RELEASED | BUTTON1_CLICKED)) {
1631 /* If we're allowing shortcuts, the current shortcut list is
1632 * being displayed on the last two lines of the screen, and the
1633 * first mouse button was released on/clicked inside it, we need
1634 * to figure out which shortcut was released on/clicked and put
1635 * back the equivalent keystroke(s) for it. */
1636 if (allow_shortcuts && !ISSET(NO_HELP) && in_bottomwin) {
1638 /* The width of all the shortcuts, except for the last
1639 * two, in the shortcut list in bottomwin. */
1641 /* The y-coordinate relative to the beginning of the
1642 * shortcut list in bottomwin. */
1644 /* The number of shortcuts in the current shortcut
1647 /* Translate the mouse event coordinates so that they're
1648 * relative to bottomwin. */
1649 wmouse_trafo(bottomwin, mouse_y, mouse_x, FALSE);
1651 /* Handle releases/clicks of the first mouse button on the
1652 * statusbar elsewhere. */
1653 if (*mouse_y == 0) {
1654 /* Restore the untranslated mouse event coordinates, so
1655 * that they're relative to the entire screen again. */
1656 *mouse_x = mevent.x;
1657 *mouse_y = mevent.y;
1662 /* Calculate the y-coordinate relative to the beginning of
1663 * the shortcut list in bottomwin. */
1666 /* Get the shortcut lists' length. */
1667 if (currmenu == MMAIN)
1668 currslen = MAIN_VISIBLE;
1670 currslen = length_of_list(currmenu);
1672 /* We don't show any more shortcuts than the main list
1674 if (currslen > MAIN_VISIBLE)
1675 currslen = MAIN_VISIBLE;
1678 /* Calculate the width of all of the shortcuts in the list
1679 * except for the last two, which are longer by (COLS % i)
1680 * columns so as to not waste space. */
1682 i = COLS / (MAIN_VISIBLE / 2);
1684 i = COLS / ((currslen / 2) + (currslen % 2));
1686 /* Calculate the x-coordinate relative to the beginning of
1687 * the shortcut list in bottomwin, and add it to j. j
1688 * should now be the index in the shortcut list of the
1689 * shortcut we released/clicked on. */
1690 j = (*mouse_x / i) * 2 + j;
1692 /* Adjust j if we released on the last two shortcuts. */
1693 if ((j >= currslen) && (*mouse_x % i < COLS % i))
1696 /* Ignore releases/clicks of the first mouse button beyond
1697 * the last shortcut. */
1701 /* Go through the shortcut list to determine which shortcut
1702 * we released/clicked on. */
1705 for (; j > 0; j--) {
1706 if (f->next != NULL)
1709 while (f->next != NULL && ((f->menus & currmenu) == 0
1710 #ifndef DISABLE_HELP
1711 || strlen(f->help) == 0
1718 /* And put back the equivalent key. */
1720 const sc *s = first_sc_for(currmenu, f->scfunc);
1722 unget_kbinput(s->seq, s->type == META, FALSE);
1725 /* Handle releases/clicks of the first mouse button that
1726 * aren't on the current shortcut list elsewhere. */
1729 #if NCURSES_MOUSE_VERSION >= 2
1730 /* Handle presses of the fourth mouse button (upward rolls of the
1731 * mouse wheel) and presses of the fifth mouse button (downward
1732 * rolls of the mouse wheel) . */
1733 else if (mevent.bstate & (BUTTON4_PRESSED | BUTTON5_PRESSED)) {
1734 bool in_edit = wenclose(edit, *mouse_y, *mouse_x);
1737 /* Translate the mouse event coordinates so that they're
1738 * relative to bottomwin. */
1739 wmouse_trafo(bottomwin, mouse_y, mouse_x, FALSE);
1741 if (in_edit || (in_bottomwin && *mouse_y == 0)) {
1744 /* One upward roll of the mouse wheel is equivalent to
1745 * moving up three lines, and one downward roll of the mouse
1746 * wheel is equivalent to moving down three lines. */
1747 for (i = 0; i < 3; i++)
1748 unget_kbinput((mevent.bstate & BUTTON4_PRESSED) ?
1749 sc_seq_or(up_void, 0) : sc_seq_or(DO_DOWN_VOID, 0), FALSE,
1754 /* Ignore presses of the fourth mouse button and presses of
1755 * the fifth mouse buttons that aren't on the edit window or
1761 /* Ignore all other mouse events. */
1764 #endif /* !DISABLE_MOUSE */
1766 /* Return the shortcut corresponding to the values of kbinput (the key
1767 * itself), meta_key (whether the key is a meta sequence), and func_key
1768 * (whether the key is a function key), if any. The shortcut will be
1769 * the first one in the list (control key, meta key sequence, function
1770 * key, other meta key sequence) for the corresponding function. For
1771 * example, passing in a meta key sequence that corresponds to a
1772 * function with a control key, a function key, and a meta key sequence
1773 * will return the control key corresponding to that function. */
1774 const sc *get_shortcut(int menu, int *kbinput, bool
1775 *meta_key, bool *func_key)
1780 fprintf(stderr, "get_shortcut(): kbinput = %d, meta_key = %s, func_key = %s\n", *kbinput, *meta_key ? "TRUE" : "FALSE", *func_key ? "TRUE" : "FALSE");
1783 /* Check for shortcuts. */
1784 for (s = sclist; s != NULL; s = s->next) {
1785 if ((menu & s->menu)
1786 && ((s->type == META && *meta_key == TRUE && *kbinput == s->seq)
1787 || (s->type != META && *kbinput == s->seq))) {
1789 fprintf (stderr, "matched seq \"%s\" and btw meta was %d (menus %d = %d)\n", s->keystr, *meta_key, menu, s->menu);
1795 fprintf (stderr, "matched nothing btw meta was %d\n", *meta_key);
1802 /* Try to get a function back from a window. Just a wrapper so
1803 functions to need to create function_key meta_key blah blah
1804 mmenu - what menu name to look through for valid funcs */
1805 const subnfunc *getfuncfromkey(WINDOW *win)
1808 bool func_key = FALSE, meta_key = FALSE;
1812 kbinput = parse_kbinput(win, &meta_key, &func_key);
1816 s = get_shortcut(currmenu, &kbinput, &meta_key, &func_key);
1820 f = sctofunc((sc *) s);
1827 /* Move to (x, y) in win, and display a line of n spaces with the
1828 * current attributes. */
1829 void blank_line(WINDOW *win, int y, int x, int n)
1837 /* Blank the first line of the top portion of the window. */
1838 void blank_titlebar(void)
1840 blank_line(topwin, 0, 0, COLS);
1843 /* If the MORE_SPACE flag isn't set, blank the second line of the top
1844 * portion of the window. */
1845 void blank_topbar(void)
1847 if (!ISSET(MORE_SPACE))
1848 blank_line(topwin, 1, 0, COLS);
1851 /* Blank all the lines of the middle portion of the window, i.e. the
1853 void blank_edit(void)
1857 for (i = 0; i < editwinrows; i++)
1858 blank_line(edit, i, 0, COLS);
1861 /* Blank the first line of the bottom portion of the window. */
1862 void blank_statusbar(void)
1864 blank_line(bottomwin, 0, 0, COLS);
1867 /* If the NO_HELP flag isn't set, blank the last two lines of the bottom
1868 * portion of the window. */
1869 void blank_bottombars(void)
1871 if (!ISSET(NO_HELP)) {
1872 blank_line(bottomwin, 1, 0, COLS);
1873 blank_line(bottomwin, 2, 0, COLS);
1877 /* Check if the number of keystrokes needed to blank the statusbar has
1878 * been pressed. If so, blank the statusbar, unless constant cursor
1879 * position display is on. */
1880 void check_statusblank(void)
1882 if (statusblank > 0) {
1885 if (statusblank == 0 && !ISSET(CONST_UPDATE)) {
1887 wnoutrefresh(bottomwin);
1894 /* Convert buf into a string that can be displayed on screen. The
1895 * caller wants to display buf starting with column start_col, and
1896 * extending for at most len columns. start_col is zero-based. len is
1897 * one-based, so len == 0 means you get "" returned. The returned
1898 * string is dynamically allocated, and should be freed. If dollars is
1899 * TRUE, the caller might put "$" at the beginning or end of the line if
1901 char *display_string(const char *buf, size_t start_col, size_t len, bool
1905 /* Index in buf of the first character shown. */
1907 /* Screen column that start_index corresponds to. */
1909 /* The length of memory allocated for converted. */
1911 /* The string we return. */
1913 /* Current position in converted. */
1917 /* If dollars is TRUE, make room for the "$" at the end of the
1919 if (dollars && len > 0 && strlenpt(buf) > start_col + len)
1923 return mallocstrcpy(NULL, "");
1925 buf_mb = charalloc(mb_cur_max());
1927 start_index = actual_x(buf, start_col);
1928 column = strnlenpt(buf, start_index);
1930 assert(column <= start_col);
1932 /* Make sure there's enough room for the initial character, whether
1933 * it's a multibyte control character, a non-control multibyte
1934 * character, a tab character, or a null terminator. Rationale:
1936 * multibyte control character followed by a null terminator:
1937 * 1 byte ('^') + mb_cur_max() bytes + 1 byte ('\0')
1938 * multibyte non-control character followed by a null terminator:
1939 * mb_cur_max() bytes + 1 byte ('\0')
1940 * tab character followed by a null terminator:
1941 * mb_cur_max() bytes + (tabsize - 1) bytes + 1 byte ('\0')
1943 * Since tabsize has a minimum value of 1, it can substitute for 1
1945 alloc_len = (mb_cur_max() + tabsize + 1) * MAX_BUF_SIZE;
1946 converted = charalloc(alloc_len);
1950 if (buf[start_index] != '\0' && buf[start_index] != '\t' &&
1951 (column < start_col || (dollars && column > 0))) {
1952 /* We don't display all of buf[start_index] since it starts to
1953 * the left of the screen. */
1954 buf_mb_len = parse_mbchar(buf + start_index, buf_mb, NULL);
1956 if (is_cntrl_mbchar(buf_mb)) {
1957 if (column < start_col) {
1958 char *ctrl_buf_mb = charalloc(mb_cur_max());
1959 int ctrl_buf_mb_len, i;
1961 ctrl_buf_mb = control_mbrep(buf_mb, ctrl_buf_mb,
1964 for (i = 0; i < ctrl_buf_mb_len; i++)
1965 converted[index++] = ctrl_buf_mb[i];
1967 start_col += mbwidth(ctrl_buf_mb);
1971 start_index += buf_mb_len;
1975 else if (using_utf8() && mbwidth(buf_mb) == 2) {
1976 if (column >= start_col) {
1977 converted[index++] = ' ';
1981 converted[index++] = ' ';
1984 start_index += buf_mb_len;
1989 while (buf[start_index] != '\0') {
1990 buf_mb_len = parse_mbchar(buf + start_index, buf_mb, NULL);
1992 /* Make sure there's enough room for the next character, whether
1993 * it's a multibyte control character, a non-control multibyte
1994 * character, a tab character, or a null terminator. */
1995 if (index + mb_cur_max() + tabsize + 1 >= alloc_len - 1) {
1996 alloc_len += (mb_cur_max() + tabsize + 1) * MAX_BUF_SIZE;
1997 converted = charealloc(converted, alloc_len);
2000 /* If buf contains a tab character, interpret it. */
2001 if (*buf_mb == '\t') {
2002 #if !defined(NANO_TINY) && defined(ENABLE_NANORC)
2003 if (ISSET(WHITESPACE_DISPLAY)) {
2006 for (i = 0; i < whitespace_len[0]; i++)
2007 converted[index++] = whitespace[i];
2010 converted[index++] = ' ';
2012 while (start_col % tabsize != 0) {
2013 converted[index++] = ' ';
2016 /* If buf contains a control character, interpret it. If buf
2017 * contains an invalid multibyte control character, display it
2019 } else if (is_cntrl_mbchar(buf_mb)) {
2020 char *ctrl_buf_mb = charalloc(mb_cur_max());
2021 int ctrl_buf_mb_len, i;
2023 converted[index++] = '^';
2026 ctrl_buf_mb = control_mbrep(buf_mb, ctrl_buf_mb,
2029 for (i = 0; i < ctrl_buf_mb_len; i++)
2030 converted[index++] = ctrl_buf_mb[i];
2032 start_col += mbwidth(ctrl_buf_mb);
2035 /* If buf contains a space character, interpret it. */
2036 } else if (*buf_mb == ' ') {
2037 #if !defined(NANO_TINY) && defined(ENABLE_NANORC)
2038 if (ISSET(WHITESPACE_DISPLAY)) {
2041 for (i = whitespace_len[0]; i < whitespace_len[0] +
2042 whitespace_len[1]; i++)
2043 converted[index++] = whitespace[i];
2046 converted[index++] = ' ';
2048 /* If buf contains a non-control character, interpret it. If
2049 * buf contains an invalid multibyte non-control character,
2050 * display it as such. */
2052 char *nctrl_buf_mb = charalloc(mb_cur_max());
2053 int nctrl_buf_mb_len, i;
2055 nctrl_buf_mb = mbrep(buf_mb, nctrl_buf_mb,
2058 for (i = 0; i < nctrl_buf_mb_len; i++)
2059 converted[index++] = nctrl_buf_mb[i];
2061 start_col += mbwidth(nctrl_buf_mb);
2066 start_index += buf_mb_len;
2071 assert(alloc_len >= index + 1);
2073 /* Null-terminate converted. */
2074 converted[index] = '\0';
2076 /* Make sure converted takes up no more than len columns. */
2077 index = actual_x(converted, len);
2078 null_at(&converted, index);
2083 /* If path is NULL, we're in normal editing mode, so display the current
2084 * version of nano, the current filename, and whether the current file
2085 * has been modified on the titlebar. If path isn't NULL, we're in the
2086 * file browser, and path contains the directory to start the file
2087 * browser in, so display the current version of nano and the contents
2088 * of path on the titlebar. */
2089 void titlebar(const char *path)
2092 /* The space we have available for display. */
2093 size_t verlen = strlenpt(PACKAGE_STRING) + 1;
2094 /* The length of the version message in columns, plus one for
2097 /* "DIR:", "File:", or "New Buffer". Goes before filename. */
2099 /* The length of the prefix in columns, plus one for padding. */
2101 /* "Modified", "View", or "". Shows the state of this
2103 size_t statelen = 0;
2104 /* The length of the state in columns, or the length of
2105 * "Modified" if the state is blank and we're not in the file
2107 char *exppath = NULL;
2108 /* The filename, expanded for display. */
2109 bool newfie = FALSE;
2110 /* Do we say "New Buffer"? */
2112 /* Do we put an ellipsis before the path? */
2114 assert(path != NULL || openfile->filename != NULL);
2116 wattron(topwin, reverse_attr);
2120 /* space has to be at least 4: two spaces before the version message,
2121 * at least one character of the version message, and one space
2122 * after the version message. */
2126 /* Limit verlen to 1/3 the length of the screen in columns,
2127 * minus three columns for spaces. */
2128 if (verlen > (COLS / 3) - 3)
2129 verlen = (COLS / 3) - 3;
2133 /* Add a space after the version message, and account for both
2134 * it and the two spaces before it. */
2135 mvwaddnstr(topwin, 0, 2, PACKAGE_STRING,
2136 actual_x(PACKAGE_STRING, verlen));
2139 /* Account for the full length of the version message. */
2143 #ifndef DISABLE_BROWSER
2144 /* Don't display the state if we're in the file browser. */
2149 state = openfile->modified ? _("Modified") : ISSET(VIEW_MODE) ?
2152 statelen = strlenpt((*state == '\0' && path == NULL) ?
2153 _("Modified") : state);
2155 /* If possible, add a space before state. */
2156 if (space > 0 && statelen < space)
2161 #ifndef DISABLE_BROWSER
2162 /* path should be a directory if we're in the file browser. */
2167 if (openfile->filename[0] == '\0') {
2168 prefix = _("New Buffer");
2171 prefix = _("File:");
2173 prefixlen = strnlenpt(prefix, space - statelen) + 1;
2175 /* If newfie is FALSE, add a space after prefix. */
2176 if (!newfie && prefixlen + statelen < space)
2179 /* If we're not in the file browser, set path to the current
2182 path = openfile->filename;
2184 /* Account for the full lengths of the prefix and the state. */
2185 if (space >= prefixlen + statelen)
2186 space -= prefixlen + statelen;
2189 /* space is now the room we have for the filename. */
2192 size_t lenpt = strlenpt(path), start_col;
2194 /* Don't set dots to TRUE if we have fewer than eight columns
2195 * (i.e. one column for padding, plus seven columns for a
2197 dots = (space >= 8 && lenpt >= space);
2200 start_col = lenpt - space + 3;
2205 exppath = display_string(path, start_col, space, FALSE);
2208 /* If dots is TRUE, we will display something like "File:
2211 mvwaddnstr(topwin, 0, verlen - 1, prefix, actual_x(prefix,
2213 if (space <= -3 || newfie)
2215 waddch(topwin, ' ');
2216 waddnstr(topwin, "...", space + 3);
2219 waddstr(topwin, exppath);
2221 size_t exppathlen = newfie ? 0 : strlenpt(exppath);
2222 /* The length of the expanded filename. */
2224 /* There is room for the whole filename, so we center it. */
2225 mvwaddnstr(topwin, 0, verlen + ((space - exppathlen) / 3),
2226 prefix, actual_x(prefix, prefixlen));
2228 waddch(topwin, ' ');
2229 waddstr(topwin, exppath);
2236 if (state[0] != '\0') {
2237 if (statelen >= COLS - 1)
2238 mvwaddnstr(topwin, 0, 0, state, actual_x(state, COLS));
2240 assert(COLS - statelen - 1 >= 0);
2242 mvwaddnstr(topwin, 0, COLS - statelen - 1, state,
2243 actual_x(state, statelen));
2247 wattroff(topwin, reverse_attr);
2249 wnoutrefresh(topwin);
2254 /* Mark the current file as modified if it isn't already, and then
2255 * update the titlebar to display the file's new status. */
2256 void set_modified(void)
2258 if (!openfile->modified) {
2259 openfile->modified = TRUE;
2264 /* Display a message on the statusbar, and set disable_cursorpos to
2265 * TRUE, so that the message won't be immediately overwritten if
2266 * constant cursor position display is on. */
2267 void statusbar(const char *msg, ...)
2271 size_t start_x, foo_len;
2272 #if !defined(NANO_TINY) && defined(ENABLE_NANORC)
2273 bool old_whitespace;
2278 /* Curses mode is turned off. If we use wmove() now, it will muck
2279 * up the terminal settings. So we just use vfprintf(). */
2281 vfprintf(stderr, msg, ap);
2288 #if !defined(NANO_TINY) && defined(ENABLE_NANORC)
2289 old_whitespace = ISSET(WHITESPACE_DISPLAY);
2290 UNSET(WHITESPACE_DISPLAY);
2292 bar = charalloc(mb_cur_max() * (COLS - 3));
2293 vsnprintf(bar, mb_cur_max() * (COLS - 3), msg, ap);
2295 foo = display_string(bar, 0, COLS - 4, FALSE);
2296 #if !defined(NANO_TINY) && defined(ENABLE_NANORC)
2298 SET(WHITESPACE_DISPLAY);
2301 foo_len = strlenpt(foo);
2302 start_x = (COLS - foo_len - 4) / 2;
2304 wmove(bottomwin, 0, start_x);
2305 wattron(bottomwin, reverse_attr);
2306 waddstr(bottomwin, "[ ");
2307 waddstr(bottomwin, foo);
2309 waddstr(bottomwin, " ]");
2310 wattroff(bottomwin, reverse_attr);
2311 wnoutrefresh(bottomwin);
2314 /* Leave the cursor at its position in the edit window, not in
2317 disable_cursorpos = TRUE;
2319 /* If we're doing quick statusbar blanking, and constant cursor
2320 * position display is off, blank the statusbar after only one
2321 * keystroke. Otherwise, blank it after twenty-six keystrokes, as
2325 ISSET(QUICK_BLANK) && !ISSET(CONST_UPDATE) ? 1 :
2330 /* Display the shortcut list in s on the last two rows of the bottom
2331 * portion of the window. */
2332 void bottombars(int menu)
2334 size_t i, colwidth, slen;
2341 if (menu == MMAIN) {
2342 slen = MAIN_VISIBLE;
2344 assert(slen <= length_of_list(menu));
2346 slen = length_of_list(menu);
2348 /* Don't show any more shortcuts than the main list does. */
2349 if (slen > MAIN_VISIBLE)
2350 slen = MAIN_VISIBLE;
2353 /* There will be this many characters per column, except for the
2354 * last two, which will be longer by (COLS % colwidth) columns so as
2355 * to not waste space. We need at least three columns to display
2356 * anything properly. */
2357 colwidth = COLS / ((slen / 2) + (slen % 2));
2362 fprintf(stderr, "In bottombars, and slen == \"%d\"\n", (int) slen);
2365 for (f = allfuncs, i = 0; i < slen && f != NULL; f = f->next) {
2368 fprintf(stderr, "Checking menu items....");
2370 if ((f->menus & menu) == 0)
2373 if (!f->desc || strlen(f->desc) == 0)
2377 fprintf(stderr, "found one! f->menus = %d, desc = \"%s\"\n", f->menus, f->desc);
2379 s = first_sc_for(menu, f->scfunc);
2382 fprintf(stderr, "Whoops, guess not, no shortcut key found for func!\n");
2386 wmove(bottomwin, 1 + i % 2, (i / 2) * colwidth);
2388 fprintf(stderr, "Calling onekey with keystr \"%s\" and desc \"%s\"\n", s->keystr, f->desc);
2390 onekey(s->keystr, _(f->desc), colwidth + (COLS % colwidth));
2394 wnoutrefresh(bottomwin);
2399 /* Write a shortcut key to the help area at the bottom of the window.
2400 * keystroke is e.g. "^G" and desc is e.g. "Get Help". We are careful
2401 * to write at most len characters, even if len is very small and
2402 * keystroke and desc are long. Note that waddnstr(,,(size_t)-1) adds
2403 * the whole string! We do not bother padding the entry with blanks. */
2404 void onekey(const char *keystroke, const char *desc, size_t len)
2406 size_t keystroke_len = strlenpt(keystroke) + 1;
2408 assert(keystroke != NULL && desc != NULL);
2410 wattron(bottomwin, reverse_attr);
2411 waddnstr(bottomwin, keystroke, actual_x(keystroke, len));
2412 wattroff(bottomwin, reverse_attr);
2414 if (len > keystroke_len)
2415 len -= keystroke_len;
2420 waddch(bottomwin, ' ');
2421 waddnstr(bottomwin, desc, actual_x(desc, len));
2425 /* Reset current_y, based on the position of current, and put the cursor
2426 * in the edit window at (current_y, current_x). */
2427 void reset_cursor(void)
2430 /* If we haven't opened any files yet, put the cursor in the top
2431 * left corner of the edit window and get out. */
2432 if (openfile == NULL) {
2439 if (ISSET(SOFTWRAP)) {
2441 openfile->current_y = 0;
2443 for (tmp = openfile->edittop; tmp && tmp != openfile->current; tmp = tmp->next)
2444 openfile->current_y += 1 + strlenpt(tmp->data) / COLS;
2446 openfile->current_y += xplustabs() / COLS;
2447 if (openfile->current_y < editwinrows)
2448 wmove(edit, openfile->current_y, xpt % COLS);
2450 openfile->current_y = openfile->current->lineno -
2451 openfile->edittop->lineno;
2453 if (openfile->current_y < editwinrows)
2454 wmove(edit, openfile->current_y, xpt - get_page_start(xpt));
2458 /* edit_draw() takes care of the job of actually painting a line into
2459 * the edit window. fileptr is the line to be painted, at row line of
2460 * the window. converted is the actual string to be written to the
2461 * window, with tabs and control characters replaced by strings of
2462 * regular characters. start is the column number of the first
2463 * character of this page. That is, the first character of converted
2464 * corresponds to character number actual_x(fileptr->data, start) of the
2466 void edit_draw(filestruct *fileptr, const char *converted, int
2469 #if !defined(NANO_TINY) || defined(ENABLE_COLOR)
2470 size_t startpos = actual_x(fileptr->data, start);
2471 /* The position in fileptr->data of the leftmost character
2472 * that displays at least partially on the window. */
2473 size_t endpos = actual_x(fileptr->data, start + COLS - 1) + 1;
2474 /* The position in fileptr->data of the first character that is
2475 * completely off the window to the right.
2477 * Note that endpos might be beyond the null terminator of the
2481 assert(openfile != NULL && fileptr != NULL && converted != NULL);
2482 assert(strlenpt(converted) <= COLS);
2484 /* Just paint the string in any case (we'll add color or reverse on
2485 * just the text that needs it). */
2486 mvwaddstr(edit, line, 0, converted);
2489 /* If color syntaxes are available and turned on, we need to display
2491 if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX)) {
2492 const colortype *tmpcolor = openfile->colorstrings;
2494 /* Set up multi-line color data for this line if it's not yet calculated */
2495 if (fileptr->multidata == NULL && openfile->syntax
2496 && openfile->syntax->nmultis > 0) {
2498 fileptr->multidata = (short *) nmalloc(openfile->syntax->nmultis * sizeof(short));
2499 for (i = 0; i < openfile->syntax->nmultis; i++)
2500 fileptr->multidata[i] = -1; /* Assue this applies until we know otherwise */
2502 for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
2504 /* Starting column for mvwaddnstr. Zero-based. */
2506 /* Number of chars to paint on this line. There are
2507 * COLS characters on a whole line. */
2509 /* Index in converted where we paint. */
2510 regmatch_t startmatch;
2511 /* Match position for start_regex. */
2512 regmatch_t endmatch;
2513 /* Match position for end_regex. */
2515 if (tmpcolor->bright)
2516 wattron(edit, A_BOLD);
2517 wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
2518 /* Two notes about regexec(). A return value of zero means
2519 * that there is a match. Also, rm_eo is the first
2520 * non-matching character after the match. */
2522 /* First case, tmpcolor is a single-line expression. */
2523 if (tmpcolor->end == NULL) {
2526 /* We increment k by rm_eo, to move past the end of the
2527 * last match. Even though two matches may overlap, we
2528 * want to ignore them, so that we can highlight e.g. C
2529 * strings correctly. */
2530 while (k < endpos) {
2531 /* Note the fifth parameter to regexec(). It says
2532 * not to match the beginning-of-line character
2533 * unless k is zero. If regexec() returns
2534 * REG_NOMATCH, there are no more matches in the
2536 if (regexec(tmpcolor->start, &fileptr->data[k], 1,
2537 &startmatch, (k == 0) ? 0 : REG_NOTBOL) ==
2540 /* Translate the match to the beginning of the
2542 startmatch.rm_so += k;
2543 startmatch.rm_eo += k;
2545 /* Skip over a zero-length regex match. */
2546 if (startmatch.rm_so == startmatch.rm_eo)
2548 else if (startmatch.rm_so < endpos &&
2549 startmatch.rm_eo > startpos) {
2550 x_start = (startmatch.rm_so <= startpos) ? 0 :
2551 strnlenpt(fileptr->data,
2552 startmatch.rm_so) - start;
2554 index = actual_x(converted, x_start);
2556 paintlen = actual_x(converted + index,
2557 strnlenpt(fileptr->data,
2558 startmatch.rm_eo) - start - x_start);
2560 assert(0 <= x_start && 0 <= paintlen);
2562 mvwaddnstr(edit, line, x_start, converted +
2565 k = startmatch.rm_eo;
2567 } else if (fileptr->multidata != NULL && fileptr->multidata[tmpcolor->id] != CNONE) {
2568 /* This is a multi-line regex. There are two steps.
2569 * First, we have to see if the beginning of the line is
2570 * colored by a start on an earlier line, and an end on
2571 * this line or later.
2573 * We find the first line before fileptr matching the
2574 * start. If every match on that line is followed by an
2575 * end, then go to step two. Otherwise, find the next
2576 * line after start_line matching the end. If that line
2577 * is not before fileptr, then paint the beginning of
2579 const filestruct *start_line = fileptr->prev;
2580 /* The first line before fileptr matching start. */
2582 /* Where it starts in that line. */
2583 const filestruct *end_line;
2584 short md = fileptr->multidata[tmpcolor->id];
2587 fileptr->multidata[tmpcolor->id] = CNONE; /* until we find out otherwise */
2588 else if (md == CNONE)
2590 else if (md == CWHOLELINE) {
2591 mvwaddnstr(edit, line, 0, converted, -1);
2593 } else if (md == CBEGINBEFORE) {
2594 regexec(tmpcolor->end, fileptr->data, 1, &endmatch, 0);
2595 paintlen = actual_x(converted, strnlenpt(fileptr->data,
2596 endmatch.rm_eo) - start);
2597 mvwaddnstr(edit, line, 0, converted, paintlen);
2601 while (start_line != NULL && regexec(tmpcolor->start,
2602 start_line->data, 1, &startmatch, 0) ==
2604 /* If there is an end on this line, there is no need
2605 * to look for starts on earlier lines. */
2606 if (regexec(tmpcolor->end, start_line->data, 0,
2609 start_line = start_line->prev;
2612 /* Skip over a zero-length regex match. */
2613 if (startmatch.rm_so == startmatch.rm_eo)
2616 /* No start found, so skip to the next step. */
2617 if (start_line == NULL)
2619 /* Now start_line is the first line before fileptr
2620 * containing a start match. Is there a start on
2621 * this line not followed by an end on this line? */
2624 start_col += startmatch.rm_so;
2625 startmatch.rm_eo -= startmatch.rm_so;
2626 if (regexec(tmpcolor->end, start_line->data +
2627 start_col + startmatch.rm_eo, 0, NULL,
2628 (start_col + startmatch.rm_eo == 0) ?
2629 0 : REG_NOTBOL) == REG_NOMATCH)
2630 /* No end found after this start. */
2633 if (regexec(tmpcolor->start, start_line->data +
2634 start_col, 1, &startmatch,
2635 REG_NOTBOL) == REG_NOMATCH)
2636 /* No later start on this line. */
2639 /* Indeed, there is a start not followed on this
2640 * line by an end. */
2642 /* We have already checked that there is no end
2643 * before fileptr and after the start. Is there an
2644 * end after the start at all? We don't paint
2645 * unterminated starts. */
2647 while (end_line != NULL && regexec(tmpcolor->end,
2648 end_line->data, 1, &endmatch, 0) == REG_NOMATCH)
2649 end_line = end_line->next;
2651 /* No end found, or it is too early. */
2652 if (end_line == NULL || (end_line == fileptr &&
2653 endmatch.rm_eo <= startpos))
2656 /* Now paint the start of fileptr. If the start of
2657 * fileptr is on a different line from the end,
2658 * paintlen is -1, meaning that everything on the
2659 * line gets painted. Otherwise, paintlen is the
2660 * expanded location of the end of the match minus
2661 * the expanded location of the beginning of the
2663 if (end_line != fileptr) {
2665 fileptr->multidata[tmpcolor->id] = CWHOLELINE;
2667 paintlen = actual_x(converted,
2668 strnlenpt(fileptr->data,
2669 endmatch.rm_eo) - start);
2670 fileptr->multidata[tmpcolor->id] = CBEGINBEFORE;
2672 mvwaddnstr(edit, line, 0, converted, paintlen);
2674 /* Second step, we look for starts on this line. */
2677 while (start_col < endpos) {
2678 if (regexec(tmpcolor->start, fileptr->data +
2679 start_col, 1, &startmatch, (start_col ==
2680 0) ? 0 : REG_NOTBOL) == REG_NOMATCH ||
2681 start_col + startmatch.rm_so >= endpos)
2682 /* No more starts on this line. */
2684 /* Translate the match to be relative to the
2685 * beginning of the line. */
2686 startmatch.rm_so += start_col;
2687 startmatch.rm_eo += start_col;
2689 x_start = (startmatch.rm_so <= startpos) ? 0 :
2690 strnlenpt(fileptr->data,
2691 startmatch.rm_so) - start;
2693 index = actual_x(converted, x_start);
2695 if (regexec(tmpcolor->end, fileptr->data +
2696 startmatch.rm_eo, 1, &endmatch,
2697 (startmatch.rm_eo == 0) ? 0 :
2699 /* Translate the end match to be relative to
2700 * the beginning of the line. */
2701 endmatch.rm_so += startmatch.rm_eo;
2702 endmatch.rm_eo += startmatch.rm_eo;
2703 /* There is an end on this line. But does
2704 * it appear on this page, and is the match
2705 * more than zero characters long? */
2706 if (endmatch.rm_eo > startpos &&
2707 endmatch.rm_eo > startmatch.rm_so) {
2708 paintlen = actual_x(converted + index,
2709 strnlenpt(fileptr->data,
2710 endmatch.rm_eo) - start -
2713 assert(0 <= x_start && x_start < COLS);
2715 mvwaddnstr(edit, line, x_start,
2716 converted + index, paintlen);
2718 fileptr->multidata[tmpcolor->id] = CSTARTENDHERE;
2722 /* There is no end on this line. But we
2723 * haven't yet looked for one on later
2725 end_line = fileptr->next;
2727 while (end_line != NULL &&
2728 regexec(tmpcolor->end, end_line->data,
2729 0, NULL, 0) == REG_NOMATCH)
2730 end_line = end_line->next;
2732 if (end_line != NULL) {
2733 assert(0 <= x_start && x_start < COLS);
2735 mvwaddnstr(edit, line, x_start,
2736 converted + index, -1);
2737 /* We painted to the end of the line, so
2738 * don't bother checking any more
2740 fileptr->multidata[tmpcolor->id] = CENDAFTER;
2744 start_col = startmatch.rm_so + 1;
2749 wattroff(edit, A_BOLD);
2750 wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
2753 #endif /* ENABLE_COLOR */
2756 /* If the mark is on, we need to display it. */
2757 if (openfile->mark_set && (fileptr->lineno <=
2758 openfile->mark_begin->lineno || fileptr->lineno <=
2759 openfile->current->lineno) && (fileptr->lineno >=
2760 openfile->mark_begin->lineno || fileptr->lineno >=
2761 openfile->current->lineno)) {
2762 /* fileptr is at least partially selected. */
2763 const filestruct *top;
2764 /* Either current or mark_begin, whichever is first. */
2766 /* current_x or mark_begin_x, corresponding to top. */
2767 const filestruct *bot;
2770 /* Starting column for mvwaddnstr(). Zero-based. */
2772 /* Number of characters to paint on this line. There are
2773 * COLS characters on a whole line. */
2775 /* Index in converted where we paint. */
2777 mark_order(&top, &top_x, &bot, &bot_x, NULL);
2779 if (top->lineno < fileptr->lineno || top_x < startpos)
2781 if (bot->lineno > fileptr->lineno || bot_x > endpos)
2784 /* The selected bit of fileptr is on this page. */
2785 if (top_x < endpos && bot_x > startpos) {
2786 assert(startpos <= top_x);
2788 /* x_start is the expanded location of the beginning of the
2789 * mark minus the beginning of the page. */
2790 x_start = strnlenpt(fileptr->data, top_x) - start;
2792 /* If the end of the mark is off the page, paintlen is -1,
2793 * meaning that everything on the line gets painted.
2794 * Otherwise, paintlen is the expanded location of the end
2795 * of the mark minus the expanded location of the beginning
2797 if (bot_x >= endpos)
2800 paintlen = strnlenpt(fileptr->data, bot_x) - (x_start +
2803 /* If x_start is before the beginning of the page, shift
2804 * paintlen x_start characters to compensate, and put
2805 * x_start at the beginning of the page. */
2807 paintlen += x_start;
2811 assert(x_start >= 0 && x_start <= strlen(converted));
2813 index = actual_x(converted, x_start);
2816 paintlen = actual_x(converted + index, paintlen);
2818 wattron(edit, reverse_attr);
2819 mvwaddnstr(edit, line, x_start, converted + index,
2821 wattroff(edit, reverse_attr);
2824 #endif /* !NANO_TINY */
2827 /* Just update one line in the edit buffer. This is basically a wrapper
2828 * for edit_draw(). The line will be displayed starting with
2829 * fileptr->data[index]. Likely arguments are current_x or zero.
2830 * Returns: Number of additiona lines consumed (needed for SOFTWRAP)
2832 int update_line(filestruct *fileptr, size_t index)
2835 int extralinesused = 0;
2836 /* The line in the edit window that we want to update. */
2838 /* fileptr->data converted to have tabs and control characters
2843 assert(fileptr != NULL);
2845 if (ISSET(SOFTWRAP)) {
2846 for (tmp = openfile->edittop; tmp && tmp != fileptr; tmp = tmp->next) {
2847 line += 1 + (strlenpt(tmp->data) / COLS);
2850 line = fileptr->lineno - openfile->edittop->lineno;
2852 if (line < 0 || line >= editwinrows)
2855 /* First, blank out the line. */
2856 blank_line(edit, line, 0, COLS);
2858 /* Next, convert variables that index the line to their equivalent
2859 * positions in the expanded line. */
2860 if (ISSET(SOFTWRAP))
2863 index = strnlenpt(fileptr->data, index);
2864 page_start = get_page_start(index);
2866 /* Expand the line, replacing tabs with spaces, and control
2867 * characters with their displayed forms. */
2868 converted = display_string(fileptr->data, page_start, COLS, !ISSET(SOFTWRAP));
2871 if (ISSET(SOFTWRAP) && strlen(converted) >= COLS - 2)
2872 fprintf(stderr, "update_line(): converted(1) line = %s\n", converted);
2876 /* Paint the line. */
2877 edit_draw(fileptr, converted, line, page_start);
2880 if (!ISSET(SOFTWRAP)) {
2882 mvwaddch(edit, line, 0, '$');
2883 if (strlenpt(fileptr->data) > page_start + COLS)
2884 mvwaddch(edit, line, COLS - 1, '$');
2886 int full_length = strlenpt(fileptr->data);
2887 for (index += COLS; index <= full_length && line < editwinrows; index += COLS) {
2890 fprintf(stderr, "update_line(): Softwrap code, moving to %d index %lu\n", line, (unsigned long) index);
2892 blank_line(edit, line, 0, COLS);
2894 /* Expand the line, replacing tabs with spaces, and control
2895 * characters with their displayed forms. */
2896 converted = display_string(fileptr->data, index, COLS, !ISSET(SOFTWRAP));
2898 if (ISSET(SOFTWRAP) && strlen(converted) >= COLS - 2)
2899 fprintf(stderr, "update_line(): converted(2) line = %s\n", converted);
2902 /* Paint the line. */
2903 edit_draw(fileptr, converted, line, index);
2908 return extralinesused;
2911 /* Return TRUE if we need an update after moving horizontally, and FALSE
2912 * otherwise. We need one if the mark is on or if pww_save and
2913 * placewewant are on different pages. */
2914 bool need_horizontal_update(size_t pww_save)
2918 openfile->mark_set ||
2920 get_page_start(pww_save) !=
2921 get_page_start(openfile->placewewant);
2924 /* Return TRUE if we need an update after moving vertically, and FALSE
2925 * otherwise. We need one if the mark is on or if pww_save and
2926 * placewewant are on different pages. */
2927 bool need_vertical_update(size_t pww_save)
2931 openfile->mark_set ||
2933 get_page_start(pww_save) !=
2934 get_page_start(openfile->placewewant);
2937 /* When edittop changes, try and figure out how many lines
2938 * we really have to work with (i.e. set maxrows)
2940 void compute_maxrows(void)
2943 filestruct *foo = openfile->edittop;
2945 if (!ISSET(SOFTWRAP)) {
2946 maxrows = editwinrows;
2951 for (n = 0; n < editwinrows && foo; n++) {
2953 n += strlenpt(foo->data) / COLS;
2957 if (n < editwinrows)
2958 maxrows += editwinrows - n;
2961 fprintf(stderr, "compute_maxrows(): maxrows = %ld\n", maxrows);
2965 /* Scroll the edit window in the given direction and the given number
2966 * of lines, and draw new lines on the blank lines left after the
2967 * scrolling. direction is the direction to scroll, either UP_DIR or
2968 * DOWN_DIR, and nlines is the number of lines to scroll. We change
2969 * edittop, and assume that current and current_x are up to date. We
2970 * also assume that scrollok(edit) is FALSE. */
2971 void edit_scroll(scroll_dir direction, ssize_t nlines)
2974 ssize_t i, extracuzsoft = 0;
2975 bool do_redraw = FALSE;
2977 /* Don't bother scrolling less than one line. */
2981 if (need_vertical_update(0))
2985 /* If using soft wrapping, we want to scroll down enough to display the entire next
2986 line, if possible... */
2987 if (ISSET(SOFTWRAP) && direction == DOWN_DIR) {
2989 fprintf(stderr, "Softwrap: Entering check for extracuzsoft\n");
2991 for (i = maxrows, foo = openfile->edittop; foo && i > 0; i--, foo = foo->next)
2995 extracuzsoft += strlenpt(foo->data) / COLS;
2997 fprintf(stderr, "Setting extracuzsoft to %lu due to strlen %lu of line %lu\n", (unsigned long) extracuzsoft,
2998 (unsigned long) strlenpt(foo->data), (unsigned long) foo->lineno);
3001 /* Now account for whether the edittop line itself is >COLS, if scrolling down */
3002 for (foo = openfile->edittop; foo && extracuzsoft > 0; nlines++) {
3003 extracuzsoft -= 1 + strlenpt(foo->data) / COLS;
3005 fprintf(stderr, "Edittop adjustment, setting nlines to %lu\n", (unsigned long) nlines);
3007 if (foo == openfile->filebot)
3014 /* Part 1: nlines is the number of lines we're going to scroll the
3015 * text of the edit window. */
3017 /* Move the top line of the edit window up or down (depending on the
3018 * value of direction) nlines lines, or as many lines as we can if
3019 * there are fewer than nlines lines available. */
3020 for (i = nlines; i > 0; i--) {
3021 if (direction == UP_DIR) {
3022 if (openfile->edittop == openfile->fileage)
3024 openfile->edittop = openfile->edittop->prev;
3026 if (openfile->edittop == openfile->filebot)
3028 openfile->edittop = openfile->edittop->next;
3030 /* Don't over-scroll on long lines */
3031 if (ISSET(SOFTWRAP)) {
3032 ssize_t len = strlenpt(openfile->edittop->data) / COLS;
3039 /* Limit nlines to the number of lines we could scroll. */
3042 /* Don't bother scrolling zero lines or more than the number of
3043 * lines in the edit window minus one; in both cases, get out, and
3044 * call edit_refresh() beforehand if we need to. */
3045 if (nlines == 0 || do_redraw || nlines >= editwinrows) {
3046 if (do_redraw || nlines >= editwinrows)
3047 edit_refresh_needed = TRUE;
3051 /* Scroll the text of the edit window up or down nlines lines,
3052 * depending on the value of direction. */
3053 scrollok(edit, TRUE);
3054 wscrl(edit, (direction == UP_DIR) ? -nlines : nlines);
3055 scrollok(edit, FALSE);
3057 /* Part 2: nlines is the number of lines in the scrolled region of
3058 * the edit window that we need to draw. */
3060 /* If the top or bottom line of the file is now visible in the edit
3061 * window, we need to draw the entire edit window. */
3062 if ((direction == UP_DIR && openfile->edittop ==
3063 openfile->fileage) || (direction == DOWN_DIR &&
3064 openfile->edittop->lineno + editwinrows - 1 >=
3065 openfile->filebot->lineno))
3066 nlines = editwinrows;
3068 /* If the scrolled region contains only one line, and the line
3069 * before it is visible in the edit window, we need to draw it too.
3070 * If the scrolled region contains more than one line, and the lines
3071 * before and after the scrolled region are visible in the edit
3072 * window, we need to draw them too. */
3073 nlines += (nlines == 1) ? 1 : 2;
3075 if (nlines > editwinrows)
3076 nlines = editwinrows;
3078 /* If we scrolled up, we're on the line before the scrolled
3080 foo = openfile->edittop;
3082 /* If we scrolled down, move down to the line before the scrolled
3084 if (direction == DOWN_DIR) {
3085 for (i = editwinrows - nlines; i > 0 && foo != NULL; i--)
3089 /* Draw new lines on any blank lines before or inside the scrolled
3090 * region. If we scrolled down and we're on the top line, or if we
3091 * scrolled up and we're on the bottom line, the line won't be
3092 * blank, so we don't need to draw it unless the mark is on or we're
3093 * not on the first page. */
3094 for (i = nlines; i > 0 && foo != NULL; i--) {
3095 if ((i == nlines && direction == DOWN_DIR) || (i == 1 &&
3096 direction == UP_DIR)) {
3098 update_line(foo, (foo == openfile->current) ?
3099 openfile->current_x : 0);
3101 update_line(foo, (foo == openfile->current) ?
3102 openfile->current_x : 0);
3107 /* Update any lines between old_current and current that need to be
3108 * updated. Use this if we've moved without changing any text. */
3109 void edit_redraw(filestruct *old_current, size_t pww_save)
3111 bool do_redraw = need_vertical_update(0) ||
3112 need_vertical_update(pww_save);
3113 filestruct *foo = NULL;
3115 /* If either old_current or current is offscreen, scroll the edit
3116 * window until it's onscreen and get out. */
3117 if (old_current->lineno < openfile->edittop->lineno ||
3118 old_current->lineno >= openfile->edittop->lineno +
3119 maxrows || openfile->current->lineno <
3120 openfile->edittop->lineno || openfile->current->lineno >=
3121 openfile->edittop->lineno + maxrows) {
3124 fprintf(stderr, "edit_redraw(): line %lu was offscreen, oldcurrent = %lu edittop = %lu", openfile->current->lineno,
3125 old_current->lineno, openfile->edittop->lineno);
3127 filestruct *old_edittop = openfile->edittop;
3130 /* If the mark is on, update all the lines between old_current
3131 * and either the old first line or old last line (depending on
3132 * whether we've scrolled up or down) of the edit window. */
3133 if (openfile->mark_set) {
3136 if (old_edittop->lineno < openfile->edittop->lineno)
3137 old_lineno = old_edittop->lineno;
3139 old_lineno = (old_edittop->lineno + maxrows <=
3140 openfile->filebot->lineno) ?
3141 old_edittop->lineno + editwinrows :
3142 openfile->filebot->lineno;
3146 while (foo->lineno != old_lineno) {
3147 update_line(foo, 0);
3149 foo = (foo->lineno > old_lineno) ? foo->prev :
3153 #endif /* !NANO_TINY */
3155 /* Put edittop in range of current, get the difference in lines
3156 * between the original edittop and the current edittop, and
3157 * then restore the original edittop. */
3158 edit_update(CENTER);
3160 /* Update old_current if we're not on the same page as
3163 update_line(old_current, 0);
3166 /* If the mark is on, update all the lines between the old first
3167 * line or old last line of the edit window (depending on
3168 * whether we've scrolled up or down) and current. */
3169 if (openfile->mark_set) {
3170 while (foo->lineno != openfile->current->lineno) {
3171 update_line(foo, 0);
3173 foo = (foo->lineno > openfile->current->lineno) ?
3174 foo->prev : foo->next;
3177 #endif /* !NANO_TINY */
3182 /* Update old_current and current if we're not on the same page as
3183 * before. If the mark is on, update all the lines between
3184 * old_current and current too. */
3187 while (foo != openfile->current) {
3189 update_line(foo, 0);
3192 if (!openfile->mark_set)
3197 foo = (foo->lineno > openfile->current->lineno) ? foo->prev :
3203 update_line(openfile->current, openfile->current_x);
3206 /* Refresh the screen without changing the position of lines. Use this
3207 * if we've moved and changed text. */
3208 void edit_refresh(void)
3213 /* Figure out what maxrows should really be */
3216 if (openfile->current->lineno < openfile->edittop->lineno ||
3217 openfile->current->lineno >= openfile->edittop->lineno +
3221 fprintf(stderr, "edit_refresh(): line = %d, edittop %d + maxrows %d\n", openfile->current->lineno, openfile->edittop->lineno, maxrows);
3224 /* Put the top line of the edit window in range of the current
3226 edit_update(CENTER);
3229 foo = openfile->edittop;
3232 fprintf(stderr, "edit_refresh(): edittop->lineno = %ld\n", (long)openfile->edittop->lineno);
3235 for (nlines = 0; nlines < editwinrows && foo != NULL; nlines++) {
3236 nlines += update_line(foo, (foo == openfile->current) ?
3237 openfile->current_x : 0);
3241 for (; nlines < editwinrows; nlines++)
3242 blank_line(edit, nlines, 0, COLS);
3248 /* Move edittop to put it in range of current, keeping current in the
3249 * same place. location determines how we move it: if it's CENTER, we
3250 * center current, and if it's NONE, we put current current_y lines
3252 void edit_update(update_type location)
3254 filestruct *foo = openfile->current;
3257 /* If location is CENTER, we move edittop up (editwinrows / 2)
3258 * lines. This puts current at the center of the screen. If
3259 * location is NONE, we move edittop up current_y lines if current_y
3260 * is in range of the screen, 0 lines if current_y is less than 0,
3261 * or (editwinrows - 1) lines if current_y is greater than
3262 * (editwinrows - 1). This puts current at the same place on the
3263 * screen as before, or at the top or bottom of the screen if
3264 * edittop is beyond either. */
3265 if (location == CENTER)
3266 goal = editwinrows / 2;
3268 goal = openfile->current_y;
3270 /* Limit goal to (editwinrows - 1) lines maximum. */
3271 if (goal > editwinrows - 1)
3272 goal = editwinrows - 1;
3275 for (; goal > 0 && foo->prev != NULL; goal--) {
3277 if (ISSET(SOFTWRAP) && foo)
3278 goal -= strlenpt(foo->data) / COLS;
3280 openfile->edittop = foo;
3282 fprintf(stderr, "edit_udpate(), setting edittop to lineno %d\n", openfile->edittop->lineno);
3285 edit_refresh_needed = TRUE;
3288 /* Unconditionally redraw the entire screen. */
3289 void total_redraw(void)
3292 /* Slang curses emulation brain damage, part 4: Slang doesn't define
3294 SLsmg_touch_screen();
3301 /* Unconditionally redraw the entire screen, and then refresh it using
3302 * the current file. */
3303 void total_refresh(void)
3308 bottombars(currmenu);
3311 /* Display the main shortcut list on the last two rows of the bottom
3312 * portion of the window. */
3313 void display_main_list(void)
3318 /* If constant is TRUE, we display the current cursor position only if
3319 * disable_cursorpos is FALSE. Otherwise, we display it
3320 * unconditionally and set disable_cursorpos to FALSE. If constant is
3321 * TRUE and disable_cursorpos is TRUE, we also set disable_cursorpos to
3322 * FALSE, so that we leave the current statusbar alone this time, and
3323 * display the current cursor position next time. */
3324 void do_cursorpos(bool constant)
3328 size_t i, cur_xpt = xplustabs() + 1;
3329 size_t cur_lenpt = strlenpt(openfile->current->data) + 1;
3330 int linepct, colpct, charpct;
3332 assert(openfile->fileage != NULL && openfile->current != NULL);
3334 f = openfile->current->next;
3335 c = openfile->current->data[openfile->current_x];
3337 openfile->current->next = NULL;
3338 openfile->current->data[openfile->current_x] = '\0';
3340 i = get_totsize(openfile->fileage, openfile->current);
3342 openfile->current->data[openfile->current_x] = c;
3343 openfile->current->next = f;
3345 if (constant && disable_cursorpos) {
3346 disable_cursorpos = FALSE;
3350 /* Display the current cursor position on the statusbar, and set
3351 * disable_cursorpos to FALSE. */
3352 linepct = 100 * openfile->current->lineno /
3353 openfile->filebot->lineno;
3354 colpct = 100 * cur_xpt / cur_lenpt;
3355 charpct = (openfile->totsize == 0) ? 0 : 100 * i /
3359 _("line %ld/%ld (%d%%), col %lu/%lu (%d%%), char %lu/%lu (%d%%)"),
3360 (long)openfile->current->lineno,
3361 (long)openfile->filebot->lineno, linepct,
3362 (unsigned long)cur_xpt, (unsigned long)cur_lenpt, colpct,
3363 (unsigned long)i, (unsigned long)openfile->totsize, charpct);
3365 disable_cursorpos = FALSE;
3368 /* Unconditionally display the current cursor position. */
3369 void do_cursorpos_void(void)
3371 do_cursorpos(FALSE);
3374 void enable_nodelay(void)
3376 nodelay_mode = TRUE;
3377 nodelay(edit, TRUE);
3380 void disable_nodelay(void)
3382 nodelay_mode = FALSE;
3383 nodelay(edit, FALSE);
3387 /* Highlight the current word being replaced or spell checked. We
3388 * expect word to have tabs and control characters expanded. */
3389 void do_replace_highlight(bool highlight, const char *word)
3391 size_t y = xplustabs(), word_len = strlenpt(word);
3393 y = get_page_start(y) + COLS - y;
3394 /* Now y is the number of columns that we can display on this
3406 wattron(edit, reverse_attr);
3408 /* This is so we can show zero-length matches. */
3412 waddnstr(edit, word, actual_x(word, y));
3418 wattroff(edit, reverse_attr);
3422 #define CREDIT_LEN 55
3423 #define XLCREDIT_LEN 8
3425 /* Easter egg: Display credits. Assume nodelay(edit) and scrollok(edit)
3427 void do_credits(void)
3429 bool old_more_space = ISSET(MORE_SPACE);
3430 bool old_no_help = ISSET(NO_HELP);
3431 int kbinput = ERR, crpos = 0, xlpos = 0;
3432 const char *credits[CREDIT_LEN] = {
3433 NULL, /* "The nano text editor" */
3434 NULL, /* "version" */
3437 NULL, /* "Brought to you by:" */
3443 "David Lawrence Ramsey",
3448 NULL, /* credits[15], handled below. */
3454 "Christian Weisgerber",
3461 NULL, /* "Special thanks to:" */
3462 "Plattsburgh State University",
3463 "Benet Laboratories",
3468 NULL, /* "The Free Software Foundation" */
3470 NULL, /* "For ncurses:" */
3475 NULL, /* "and anyone else we forgot..." */
3476 NULL, /* "Thank you for using nano!" */
3481 "(C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007",
3482 "Free Software Foundation, Inc.",
3487 "http://www.nano-editor.org/"
3490 const char *xlcredits[XLCREDIT_LEN] = {
3491 N_("The nano text editor"),
3493 N_("Brought to you by:"),
3494 N_("Special thanks to:"),
3495 N_("The Free Software Foundation"),
3497 N_("and anyone else we forgot..."),
3498 N_("Thank you for using nano!")
3501 /* credits[15]: Make sure this name is displayed properly, since we
3502 * can't dynamically assign it above, using Unicode 00F6 (Latin
3503 * Small Letter O with Diaresis) if applicable. */
3506 using_utf8() ? "Florian K\xC3\xB6nig" :
3510 if (!old_more_space || !old_no_help) {
3517 nodelay(edit, TRUE);
3527 wrefresh(bottomwin);
3530 for (crpos = 0; crpos < CREDIT_LEN + editwinrows / 2; crpos++) {
3531 if ((kbinput = wgetch(edit)) != ERR)
3534 if (crpos < CREDIT_LEN) {
3538 if (credits[crpos] == NULL) {
3539 assert(0 <= xlpos && xlpos < XLCREDIT_LEN);
3541 what = _(xlcredits[xlpos]);
3544 what = credits[crpos];
3546 start_x = COLS / 2 - strlenpt(what) / 2 - 1;
3547 mvwaddstr(edit, editwinrows - 1 - (editwinrows % 2),
3553 if ((kbinput = wgetch(edit)) != ERR)
3557 scrollok(edit, TRUE);
3559 scrollok(edit, FALSE);
3562 if ((kbinput = wgetch(edit)) != ERR)
3566 scrollok(edit, TRUE);
3568 scrollok(edit, FALSE);
3575 if (!old_more_space || !old_no_help) {
3582 nodelay(edit, FALSE);
3586 #endif /* NANO_EXTRA */