blob: 09141b13600320b8df14c661a42067499c0c3098 [file] [log] [blame]
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001/**************************************************************************
Benno Schulenberg514cd9a2016-08-29 17:10:49 +02002 * winio.c -- This file is part of GNU nano. *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003 * *
Chris Allegretta8a07a962009-12-02 03:36:22 +00004 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
Benno Schulenberg7a9f4a42014-04-30 20:18:26 +00005 * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. *
Benno Schulenbergc1183972017-02-21 20:27:49 +01006 * Copyright (C) 2014, 2015, 2016, 2017 Benno Schulenberg *
Benno Schulenberg406e5242016-08-29 15:14:18 +02007 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +02008 * GNU nano is free software: you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published *
10 * by the Free Software Foundation, either version 3 of the License, *
11 * or (at your option) any later version. *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000012 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020013 * GNU nano is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty *
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
16 * See the GNU General Public License for more details. *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000017 * *
18 * You should have received a copy of the GNU General Public License *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020019 * along with this program. If not, see http://www.gnu.org/licenses/. *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000020 * *
21 **************************************************************************/
22
David Lawrence Ramsey034b9942005-12-08 02:47:10 +000023#include "proto.h"
Benno Schulenberg2ae490c2016-05-20 12:59:57 +020024#include "revision.h"
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +000025
Benno Schulenberg08cd1972016-09-08 21:00:51 +020026#ifdef __linux__
Benno Schulenberg290d2782016-07-29 09:15:07 +020027#include <sys/ioctl.h>
Benno Schulenberg928a24c2016-08-11 12:37:11 +020028#endif
Benno Schulenberg290d2782016-07-29 09:15:07 +020029
David Lawrence Ramsey143b8c72005-11-01 18:35:47 +000030#include <stdio.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000031#include <stdarg.h>
32#include <string.h>
Chris Allegretta8a0de3b2000-11-24 20:45:14 +000033#include <unistd.h>
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +000034#include <ctype.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000035
Benno Schulenberg2ae490c2016-05-20 12:59:57 +020036#ifdef REVISION
37#define BRANDING REVISION
38#else
39#define BRANDING PACKAGE_STRING
40#endif
41
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +000042static int *key_buffer = NULL;
David Lawrence Ramsey6335fb52007-01-01 05:15:32 +000043 /* The keystroke buffer, containing all the keystrokes we
44 * haven't handled yet at a given point. */
David Lawrence Ramsey74835712004-12-04 17:41:52 +000045static size_t key_buffer_len = 0;
David Lawrence Ramsey561db3a2006-05-26 03:22:44 +000046 /* The length of the keystroke buffer. */
Benno Schulenbergf2150d32016-07-11 14:21:38 +020047static bool solitary = FALSE;
48 /* Whether an Esc arrived by itself -- not as leader of a sequence. */
David Lawrence Ramseyfe7d53e2005-06-25 20:56:36 +000049static int statusblank = 0;
Benno Schulenberg2cd21da2016-05-15 11:17:55 +020050 /* The number of keystrokes left before we blank the statusbar. */
Benno Schulenberg9d6d5b62016-05-04 12:18:21 +020051static bool suppress_cursorpos = FALSE;
Benno Schulenberge0e788e2016-05-23 21:34:02 +020052 /* Should we skip constant position display for one keystroke? */
Benno Schulenberg8c7a3852016-07-12 21:05:09 +020053#ifdef USING_OLD_NCURSES
Benno Schulenberg954d04b2015-09-05 09:14:24 +000054static bool seen_wide = FALSE;
55 /* Whether we've seen a multicolumn character in the current line. */
Benno Schulenberg8c7a3852016-07-12 21:05:09 +020056#endif
Robert Siemborskid8510b22000-06-06 23:04:06 +000057
David Lawrence Ramsey0381c212004-05-01 01:21:38 +000058/* Control character compatibility:
59 *
Benno Schulenberg1c2d2a42016-07-22 15:57:20 +020060 * - Ctrl-H is Backspace under ASCII, ANSI, VT100, and VT220.
61 * - Ctrl-I is Tab under ASCII, ANSI, VT100, VT220, and VT320.
62 * - Ctrl-M is Enter under ASCII, ANSI, VT100, VT220, and VT320.
63 * - Ctrl-Q is XON under ASCII, ANSI, VT100, VT220, and VT320.
64 * - Ctrl-S is XOFF under ASCII, ANSI, VT100, VT220, and VT320.
Benno Schulenberg90a90362016-08-01 12:56:05 +020065 * - Ctrl-8 (Ctrl-?) is Delete under ASCII, ANSI, VT100, and VT220,
66 * but is Backspace under VT320.
David Lawrence Ramsey0381c212004-05-01 01:21:38 +000067 *
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +000068 * Note: VT220 and VT320 also generate Esc [ 3 ~ for Delete. By
David Lawrence Ramseya849ab12004-05-01 04:13:06 +000069 * default, xterm assumes it's running on a VT320 and generates Ctrl-8
70 * (Ctrl-?) for Backspace and Esc [ 3 ~ for Delete. This causes
David Lawrence Ramsey0381c212004-05-01 01:21:38 +000071 * problems for VT100-derived terminals such as the FreeBSD console,
David Lawrence Ramseya849ab12004-05-01 04:13:06 +000072 * which expect Ctrl-H for Backspace and Ctrl-8 (Ctrl-?) for Delete, and
David Lawrence Ramsey0381c212004-05-01 01:21:38 +000073 * on which the VT320 sequences are translated by the keypad to KEY_DC
74 * and [nothing]. We work around this conflict via the REBIND_DELETE
75 * flag: if it's not set, we assume VT320 compatibility, and if it is,
76 * we assume VT100 compatibility. Thanks to Lee Nelson and Wouter van
77 * Hemel for helping work this conflict out.
78 *
79 * Escape sequence compatibility:
80 *
81 * We support escape sequences for ANSI, VT100, VT220, VT320, the Linux
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +000082 * console, the FreeBSD console, the Mach console, xterm, rxvt, Eterm,
Benno Schulenberg1c2d2a42016-07-22 15:57:20 +020083 * and Terminal, and some for iTerm2. Among these, there are several
84 * conflicts and omissions, outlined as follows:
David Lawrence Ramsey0381c212004-05-01 01:21:38 +000085 *
86 * - Tab on ANSI == PageUp on FreeBSD console; the former is omitted.
87 * (Ctrl-I is also Tab on ANSI, which we already support.)
88 * - PageDown on FreeBSD console == Center (5) on numeric keypad with
89 * NumLock off on Linux console; the latter is omitted. (The editing
90 * keypad key is more important to have working than the numeric
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +000091 * keypad key, because the latter has no value when NumLock is off.)
David Lawrence Ramsey0381c212004-05-01 01:21:38 +000092 * - F1 on FreeBSD console == the mouse key on xterm/rxvt/Eterm; the
93 * latter is omitted. (Mouse input will only work properly if the
94 * extended keypad value KEY_MOUSE is generated on mouse events
95 * instead of the escape sequence.)
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +000096 * - F9 on FreeBSD console == PageDown on Mach console; the former is
David Lawrence Ramsey0381c212004-05-01 01:21:38 +000097 * omitted. (The editing keypad is more important to have working
98 * than the function keys, because the functions of the former are not
99 * arbitrary and the functions of the latter are.)
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +0000100 * - F10 on FreeBSD console == PageUp on Mach console; the former is
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000101 * omitted. (Same as above.)
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +0000102 * - F13 on FreeBSD console == End on Mach console; the former is
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000103 * omitted. (Same as above.)
David Lawrence Ramsey8381fdd2004-11-01 22:40:02 +0000104 * - F15 on FreeBSD console == Shift-Up on rxvt/Eterm; the former is
105 * omitted. (The arrow keys, with or without modifiers, are more
106 * important to have working than the function keys, because the
107 * functions of the former are not arbitrary and the functions of the
108 * latter are.)
109 * - F16 on FreeBSD console == Shift-Down on rxvt/Eterm; the former is
David Lawrence Ramsey25780252006-07-31 23:29:22 +0000110 * omitted. (Same as above.) */
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000111
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000112/* Read in a sequence of keystrokes from win and save them in the
David Lawrence Ramsey561db3a2006-05-26 03:22:44 +0000113 * keystroke buffer. This should only be called when the keystroke
114 * buffer is empty. */
David Lawrence Ramseydb958022005-07-13 20:18:46 +0000115void get_key_buffer(WINDOW *win)
David Lawrence Ramseydfca1c42004-08-25 16:37:06 +0000116{
David Lawrence Ramseyec8a0552006-03-19 19:26:52 +0000117 int input;
Benno Schulenberg5cbaf592016-05-17 22:12:28 +0200118 size_t errcount = 0;
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000119
120 /* If the keystroke buffer isn't empty, get out. */
121 if (key_buffer != NULL)
122 return;
123
David Lawrence Ramsey6d8e4952005-07-26 14:42:57 +0000124 /* Just before reading in the first character, display any pending
125 * screen updates. */
126 doupdate();
127
Benno Schulenbergf876ee12014-04-15 11:25:29 +0000128 /* Read in the first character using whatever mode we're in. */
Benno Schulenberg5cbaf592016-05-17 22:12:28 +0200129 input = wgetch(win);
David Lawrence Ramsey91493252006-03-19 19:25:29 +0000130
Benno Schulenberga878f5f2016-05-18 11:14:17 +0200131#ifndef NANO_TINY
Benno Schulenbergb77e6bd2016-12-14 20:37:03 +0100132 if (the_window_resized) {
Benno Schulenberg1d7c1772016-06-29 15:53:08 +0200133 ungetch(input);
Benno Schulenbergb77e6bd2016-12-14 20:37:03 +0100134 regenerate_screen();
Benno Schulenberga878f5f2016-05-18 11:14:17 +0200135 input = KEY_WINCH;
Benno Schulenberg1d7c1772016-06-29 15:53:08 +0200136 }
Benno Schulenberga878f5f2016-05-18 11:14:17 +0200137#endif
138
Benno Schulenberg5cbaf592016-05-17 22:12:28 +0200139 if (input == ERR && nodelay_mode)
140 return;
141
142 while (input == ERR) {
143 /* If we've failed to get a character MAX_BUF_SIZE times in a row,
144 * assume our input source is gone and die gracefully. We could
145 * check if errno is set to EIO ("Input/output error") and die in
146 * that case, but it's not always set properly. Argh. */
147 if (++errcount == MAX_BUF_SIZE)
148 handle_hupterm(0);
149
150#ifndef NANO_TINY
Benno Schulenbergb77e6bd2016-12-14 20:37:03 +0100151 if (the_window_resized) {
152 regenerate_screen();
Benno Schulenberg5cbaf592016-05-17 22:12:28 +0200153 input = KEY_WINCH;
154 break;
Chris Allegretta0dc26dc2009-01-24 22:40:41 +0000155 }
Benno Schulenberg5cbaf592016-05-17 22:12:28 +0200156#endif
157 input = wgetch(win);
Benno Schulenberg75d64e62015-05-28 13:02:29 +0000158 }
David Lawrence Ramsey369732f2004-02-16 20:32:40 +0000159
David Lawrence Ramsey14aa37c2007-05-25 16:54:06 +0000160 /* Increment the length of the keystroke buffer, and save the value
161 * of the keystroke at the end of it. */
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000162 key_buffer_len++;
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000163 key_buffer = (int *)nmalloc(sizeof(int));
164 key_buffer[0] = input;
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000165
Benno Schulenberg75d64e62015-05-28 13:02:29 +0000166#ifndef NANO_TINY
167 /* If we got SIGWINCH, get out immediately since the win argument is
168 * no longer valid. */
169 if (input == KEY_WINCH)
170 return;
171#endif
172
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000173 /* Read in the remaining characters using non-blocking input. */
174 nodelay(win, TRUE);
175
176 while (TRUE) {
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000177 input = wgetch(win);
David Lawrence Ramsey78ea5e42004-12-12 19:04:56 +0000178
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000179 /* If there aren't any more characters, stop reading. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000180 if (input == ERR)
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000181 break;
182
David Lawrence Ramsey14aa37c2007-05-25 16:54:06 +0000183 /* Otherwise, increment the length of the keystroke buffer, and
184 * save the value of the keystroke at the end of it. */
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000185 key_buffer_len++;
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000186 key_buffer = (int *)nrealloc(key_buffer, key_buffer_len *
187 sizeof(int));
188 key_buffer[key_buffer_len - 1] = input;
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000189 }
190
Benno Schulenbergc918c652016-05-05 21:44:45 +0200191 /* Restore waiting mode if it was on. */
192 if (!nodelay_mode)
193 nodelay(win, FALSE);
David Lawrence Ramseya17a1302005-03-16 14:39:42 +0000194
195#ifdef DEBUG
Benno Schulenberge00b3e82015-06-11 19:01:28 +0000196 {
197 size_t i;
Benno Schulenbergbd917852015-12-22 20:24:50 +0000198 fprintf(stderr, "\nget_key_buffer(): the sequence of hex codes:");
Benno Schulenberge00b3e82015-06-11 19:01:28 +0000199 for (i = 0; i < key_buffer_len; i++)
200 fprintf(stderr, " %3x", key_buffer[i]);
201 fprintf(stderr, "\n");
202 }
David Lawrence Ramseya17a1302005-03-16 14:39:42 +0000203#endif
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000204}
205
David Lawrence Ramsey561db3a2006-05-26 03:22:44 +0000206/* Return the length of the keystroke buffer. */
David Lawrence Ramseydb958022005-07-13 20:18:46 +0000207size_t get_key_buffer_len(void)
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000208{
209 return key_buffer_len;
210}
211
David Lawrence Ramsey561db3a2006-05-26 03:22:44 +0000212/* Add the keystrokes in input to the keystroke buffer. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000213void unget_input(int *input, size_t input_len)
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000214{
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000215 /* If input is empty, get out. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000216 if (input_len == 0)
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000217 return;
218
David Lawrence Ramsey561db3a2006-05-26 03:22:44 +0000219 /* If adding input would put the keystroke buffer beyond maximum
220 * capacity, only add enough of input to put it at maximum
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000221 * capacity. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000222 if (key_buffer_len + input_len < key_buffer_len)
223 input_len = (size_t)-1 - key_buffer_len;
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000224
David Lawrence Ramsey561db3a2006-05-26 03:22:44 +0000225 /* Add the length of input to the length of the keystroke buffer,
226 * and reallocate the keystroke buffer so that it has enough room
227 * for input. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000228 key_buffer_len += input_len;
229 key_buffer = (int *)nrealloc(key_buffer, key_buffer_len *
230 sizeof(int));
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000231
David Lawrence Ramsey561db3a2006-05-26 03:22:44 +0000232 /* If the keystroke buffer wasn't empty before, move its beginning
233 * forward far enough so that we can add input to its beginning. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000234 if (key_buffer_len > input_len)
235 memmove(key_buffer + input_len, key_buffer,
236 (key_buffer_len - input_len) * sizeof(int));
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000237
David Lawrence Ramsey561db3a2006-05-26 03:22:44 +0000238 /* Copy input to the beginning of the keystroke buffer. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000239 memcpy(key_buffer, input, input_len * sizeof(int));
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000240}
241
Benno Schulenberg91951ab2016-07-23 14:01:38 +0200242/* Put the character given in kbinput back into the input stream. If it
243 * is a Meta key, also insert an Escape character in front of it. */
244void unget_kbinput(int kbinput, bool metakey)
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000245{
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000246 unget_input(&kbinput, 1);
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000247
Benno Schulenberg7e5324d2014-06-30 18:04:33 +0000248 if (metakey) {
Benno Schulenberg90a90362016-08-01 12:56:05 +0200249 kbinput = ESC_CODE;
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000250 unget_input(&kbinput, 1);
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000251 }
252}
253
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200254/* Try to read input_len codes from the keystroke buffer. If the
David Lawrence Ramsey561db3a2006-05-26 03:22:44 +0000255 * keystroke buffer is empty and win isn't NULL, try to read in more
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200256 * codes from win and add them to the keystroke buffer before doing
Benno Schulenberge666f8c2016-05-02 21:58:43 +0200257 * anything else. If the keystroke buffer is (still) empty, return NULL. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000258int *get_input(WINDOW *win, size_t input_len)
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000259{
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000260 int *input;
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000261
Benno Schulenberge666f8c2016-05-02 21:58:43 +0200262 if (key_buffer_len == 0 && win != NULL)
263 get_key_buffer(win);
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000264
Benno Schulenberge666f8c2016-05-02 21:58:43 +0200265 if (key_buffer_len == 0)
266 return NULL;
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000267
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200268 /* Limit the request to the number of available codes in the buffer. */
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000269 if (input_len > key_buffer_len)
270 input_len = key_buffer_len;
271
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200272 /* Copy input_len codes from the head of the keystroke buffer. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000273 input = (int *)nmalloc(input_len * sizeof(int));
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000274 memcpy(input, key_buffer, input_len * sizeof(int));
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200275 key_buffer_len -= input_len;
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000276
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200277 /* If the keystroke buffer is now empty, mark it as such. */
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000278 if (key_buffer_len == 0) {
279 free(key_buffer);
280 key_buffer = NULL;
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000281 } else {
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200282 /* Trim from the buffer the codes that were copied. */
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000283 memmove(key_buffer, key_buffer + input_len, key_buffer_len *
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000284 sizeof(int));
285 key_buffer = (int *)nrealloc(key_buffer, key_buffer_len *
286 sizeof(int));
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000287 }
288
289 return input;
290}
291
Benno Schulenbergddd9c7a2016-06-24 22:45:41 +0200292/* Read in a single keystroke, ignoring any that are invalid. */
Benno Schulenberg7e5324d2014-06-30 18:04:33 +0000293int get_kbinput(WINDOW *win)
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000294{
Benno Schulenbergdb310ac2016-08-30 09:40:51 +0200295 int kbinput = ERR;
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000296
Benno Schulenbergddd9c7a2016-06-24 22:45:41 +0200297 /* Extract one keystroke from the input stream. */
Benno Schulenbergdb310ac2016-08-30 09:40:51 +0200298 while (kbinput == ERR)
Benno Schulenbergdb310ac2016-08-30 09:40:51 +0200299 kbinput = parse_kbinput(win);
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000300
Benno Schulenbergb9e83fe2016-07-13 17:38:28 +0200301#ifdef DEBUG
302 fprintf(stderr, "after parsing: kbinput = %d, meta_key = %s\n",
303 kbinput, meta_key ? "TRUE" : "FALSE");
304#endif
305
Benno Schulenbergddd9c7a2016-06-24 22:45:41 +0200306 /* If we read from the edit window, blank the statusbar if needed. */
David Lawrence Ramsey6b49e9e2006-05-22 01:29:30 +0000307 if (win == edit)
David Lawrence Ramseyce862362006-05-21 21:23:21 +0000308 check_statusblank();
309
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000310 return kbinput;
311}
312
Benno Schulenbergddd9c7a2016-06-24 22:45:41 +0200313/* Extract a single keystroke from the input stream. Translate escape
314 * sequences and extended keypad codes into their corresponding values.
Benno Schulenbergcb10b2b2016-07-13 16:22:56 +0200315 * Set meta_key to TRUE when appropriate. Supported extended keypad values
Benno Schulenbergddd9c7a2016-06-24 22:45:41 +0200316 * are: [arrow key], Ctrl-[arrow key], Shift-[arrow key], Enter, Backspace,
317 * the editing keypad (Insert, Delete, Home, End, PageUp, and PageDown),
318 * the function keys (F1-F16), and the numeric keypad with NumLock off. */
Benno Schulenberg7e5324d2014-06-30 18:04:33 +0000319int parse_kbinput(WINDOW *win)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000320{
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +0000321 static int escapes = 0, byte_digits = 0;
Mike Scalorad851ccd2016-04-02 12:13:24 +0200322 static bool double_esc = FALSE;
Benno Schulenberg19dfd202016-07-13 12:09:49 +0200323 int *kbinput, keycode, retval = ERR;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000324
Benno Schulenberg7e5324d2014-06-30 18:04:33 +0000325 meta_key = FALSE;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200326 shift_held = FALSE;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000327
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000328 /* Read in a character. */
Benno Schulenberga101b302016-04-16 11:57:05 +0200329 kbinput = get_input(win, 1);
330
331 if (kbinput == NULL && nodelay_mode)
332 return 0;
333
334 while (kbinput == NULL)
Chris Allegretta0dc26dc2009-01-24 22:40:41 +0000335 kbinput = get_input(win, 1);
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000336
Benno Schulenberg19dfd202016-07-13 12:09:49 +0200337 keycode = *kbinput;
338 free(kbinput);
339
Benno Schulenbergb9e83fe2016-07-13 17:38:28 +0200340#ifdef DEBUG
341 fprintf(stderr, "before parsing: keycode = %d, escapes = %d, byte_digits = %d\n",
342 keycode, escapes, byte_digits);
343#endif
344
Benno Schulenberg1af1f5c2016-07-13 18:08:44 +0200345 if (keycode == ERR)
346 return ERR;
347
Benno Schulenberg90a90362016-08-01 12:56:05 +0200348 if (keycode == ESC_CODE) {
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200349 /* Increment the escape counter, but trim an overabundance. */
350 escapes++;
351 if (escapes > 3)
352 escapes = 1;
353 /* Take note when an Esc arrived by itself. */
354 solitary = (escapes == 1 && key_buffer_len == 0);
355 return ERR;
Benno Schulenberg1af1f5c2016-07-13 18:08:44 +0200356 }
357
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200358 switch (escapes) {
359 case 0:
360 /* One non-escape: normal input mode. */
361 retval = keycode;
362 break;
363 case 1:
Benno Schulenberg8edb0962016-08-06 19:51:52 +0200364 if (keycode >= 0x80)
365 retval = keycode;
366 else if ((keycode != 'O' && keycode != 'o' && keycode != '[') ||
Benno Schulenberg90a90362016-08-01 12:56:05 +0200367 key_buffer_len == 0 || *key_buffer == ESC_CODE) {
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200368 /* One escape followed by a single non-escape:
369 * meta key sequence mode. */
370 if (!solitary || (keycode >= 0x20 && keycode < 0x7F))
371 meta_key = TRUE;
372 retval = tolower(keycode);
373 } else
374 /* One escape followed by a non-escape, and there
375 * are more codes waiting: escape sequence mode. */
376 retval = parse_escape_sequence(win, keycode);
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200377 escapes = 0;
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200378 break;
379 case 2:
380 if (double_esc) {
David Lawrence Ramsey059c8ef2016-11-18 14:14:36 +0100381 /* An "ESC ESC [ X" sequence from Option+arrow, or
382 * an "ESC ESC [ x" sequence from Shift+Alt+arrow. */
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200383 switch (keycode) {
384 case 'A':
385 retval = KEY_HOME;
386 break;
387 case 'B':
388 retval = KEY_END;
389 break;
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200390 case 'C':
Benno Schulenberg0333b872016-11-23 20:45:45 +0100391 retval = CONTROL_RIGHT;
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200392 break;
393 case 'D':
Benno Schulenberg0333b872016-11-23 20:45:45 +0100394 retval = CONTROL_LEFT;
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200395 break;
Benno Schulenberg74016702016-11-30 11:05:07 +0100396#ifndef NANO_TINY
David Lawrence Ramsey059c8ef2016-11-18 14:14:36 +0100397 case 'a':
398 retval = shiftaltup;
399 break;
400 case 'b':
401 retval = shiftaltdown;
402 break;
403 case 'c':
404 retval = shiftaltright;
405 break;
406 case 'd':
407 retval = shiftaltleft;
408 break;
Benno Schulenberg74016702016-11-30 11:05:07 +0100409#endif
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200410 }
411 double_esc = FALSE;
412 escapes = 0;
Benno Schulenbergf33d8ca2016-07-15 21:53:46 +0200413 } else if (key_buffer_len == 0) {
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200414 if (('0' <= keycode && keycode <= '2' &&
415 byte_digits == 0) || ('0' <= keycode &&
416 keycode <= '9' && byte_digits > 0)) {
417 /* Two escapes followed by one or more decimal
418 * digits, and there aren't any other codes
419 * waiting: byte sequence mode. If the range
420 * of the byte sequence is limited to 2XX (the
421 * first digit is between '0' and '2' and the
422 * others between '0' and '9', interpret it. */
423 int byte;
424
425 byte_digits++;
426 byte = get_byte_kbinput(keycode);
427
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200428 /* If the decimal byte value is complete, convert it and
429 * put the obtained byte(s) back into the input buffer. */
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200430 if (byte != ERR) {
431 char *byte_mb;
432 int byte_mb_len, *seq, i;
433
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200434 /* Convert the decimal code to one or two bytes. */
435 byte_mb = make_mbchar((long)byte, &byte_mb_len);
David Lawrence Ramsey95a02242004-12-06 04:14:42 +0000436
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200437 seq = (int *)nmalloc(byte_mb_len * sizeof(int));
David Lawrence Ramseyce9d2992005-06-14 23:38:08 +0000438
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200439 for (i = 0; i < byte_mb_len; i++)
440 seq[i] = (unsigned char)byte_mb[i];
David Lawrence Ramseya44ca782006-07-23 16:00:03 +0000441
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200442 /* Insert the byte(s) into the input buffer. */
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200443 unget_input(seq, byte_mb_len);
David Lawrence Ramseya44ca782006-07-23 16:00:03 +0000444
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200445 free(byte_mb);
446 free(seq);
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200447
448 byte_digits = 0;
449 escapes = 0;
David Lawrence Ramsey28889642006-05-30 20:51:15 +0000450 }
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200451 } else {
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200452 if (byte_digits == 0)
453 /* Two escapes followed by a non-decimal
454 * digit (or a decimal digit that would
455 * create a byte sequence greater than 2XX)
456 * and there aren't any other codes waiting:
457 * control character sequence mode. */
458 retval = get_control_kbinput(keycode);
459 else {
460 /* An invalid digit in the middle of a byte
461 * sequence: reset the byte sequence counter
462 * and save the code we got as the result. */
463 byte_digits = 0;
Benno Schulenberg19dfd202016-07-13 12:09:49 +0200464 retval = keycode;
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200465 }
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200466 escapes = 0;
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200467 }
468 } else if (keycode == '[' && key_buffer_len > 0 &&
David Lawrence Ramsey059c8ef2016-11-18 14:14:36 +0100469 (('A' <= *key_buffer && *key_buffer <= 'D') ||
470 ('a' <= *key_buffer && *key_buffer <= 'd'))) {
471 /* An iTerm2/Eterm/rxvt sequence: ^[ ^[ [ X. */
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200472 double_esc = TRUE;
473 } else {
474 /* Two escapes followed by a non-escape, and there are more
475 * codes waiting: combined meta and escape sequence mode. */
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200476 retval = parse_escape_sequence(win, keycode);
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200477 meta_key = TRUE;
478 escapes = 0;
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000479 }
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200480 break;
481 case 3:
Benno Schulenbergf33d8ca2016-07-15 21:53:46 +0200482 if (key_buffer_len == 0)
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200483 /* Three escapes followed by a non-escape, and no
484 * other codes are waiting: normal input mode. */
485 retval = keycode;
486 else
487 /* Three escapes followed by a non-escape, and more
488 * codes are waiting: combined control character and
489 * escape sequence mode. First interpret the escape
490 * sequence, then the result as a control sequence. */
491 retval = get_control_kbinput(
492 parse_escape_sequence(win, keycode));
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200493 escapes = 0;
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200494 break;
495 }
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000496
Benno Schulenberg1af1f5c2016-07-13 18:08:44 +0200497 if (retval == ERR)
498 return ERR;
499
Benno Schulenberge471e2d2016-07-31 18:29:57 +0200500 if (retval == controlleft)
Benno Schulenbergfdee0df2016-10-11 10:50:04 +0200501 return CONTROL_LEFT;
Benno Schulenberge471e2d2016-07-31 18:29:57 +0200502 else if (retval == controlright)
Benno Schulenbergfdee0df2016-10-11 10:50:04 +0200503 return CONTROL_RIGHT;
Benno Schulenberge471e2d2016-07-31 18:29:57 +0200504 else if (retval == controlup)
Benno Schulenbergfdee0df2016-10-11 10:50:04 +0200505 return CONTROL_UP;
Benno Schulenberge471e2d2016-07-31 18:29:57 +0200506 else if (retval == controldown)
Benno Schulenbergfdee0df2016-10-11 10:50:04 +0200507 return CONTROL_DOWN;
Benno Schulenberg08cd1972016-09-08 21:00:51 +0200508#ifndef NANO_TINY
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200509 else if (retval == shiftcontrolleft) {
510 shift_held = TRUE;
Benno Schulenberg026393a2016-12-22 11:42:13 +0100511 return CONTROL_LEFT;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200512 } else if (retval == shiftcontrolright) {
513 shift_held = TRUE;
Benno Schulenberg026393a2016-12-22 11:42:13 +0100514 return CONTROL_RIGHT;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200515 } else if (retval == shiftcontrolup) {
516 shift_held = TRUE;
Benno Schulenberg026393a2016-12-22 11:42:13 +0100517 return CONTROL_UP;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200518 } else if (retval == shiftcontroldown) {
519 shift_held = TRUE;
Benno Schulenberg026393a2016-12-22 11:42:13 +0100520 return CONTROL_DOWN;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200521 } else if (retval == shiftaltleft) {
522 shift_held = TRUE;
Benno Schulenberg026393a2016-12-22 11:42:13 +0100523 return KEY_HOME;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200524 } else if (retval == shiftaltright) {
525 shift_held = TRUE;
Benno Schulenberg026393a2016-12-22 11:42:13 +0100526 return KEY_END;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200527 } else if (retval == shiftaltup) {
528 shift_held = TRUE;
Benno Schulenberg026393a2016-12-22 11:42:13 +0100529 return KEY_PPAGE;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200530 } else if (retval == shiftaltdown) {
531 shift_held = TRUE;
Benno Schulenberg026393a2016-12-22 11:42:13 +0100532 return KEY_NPAGE;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200533 }
Benno Schulenberge471e2d2016-07-31 18:29:57 +0200534#endif
535
Benno Schulenberg08cd1972016-09-08 21:00:51 +0200536#ifdef __linux__
Benno Schulenberg290d2782016-07-29 09:15:07 +0200537 /* When not running under X, check for the bare arrow keys whether
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200538 * Shift/Ctrl/Alt are being held together with them. */
539 unsigned char modifiers = 6;
Benno Schulenberg290d2782016-07-29 09:15:07 +0200540
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200541 if (console && ioctl(0, TIOCLINUX, &modifiers) >= 0) {
Benno Schulenbergdb897b52016-12-22 10:42:49 +0100542#ifndef NANO_TINY
543 /* Is Shift being held? */
544 if (modifiers & 0x01)
545 shift_held = TRUE;
546#endif
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200547 /* Is Ctrl being held? */
548 if (modifiers & 0x04) {
Benno Schulenberg290d2782016-07-29 09:15:07 +0200549 if (retval == KEY_UP)
Benno Schulenberg026393a2016-12-22 11:42:13 +0100550 return CONTROL_UP;
Benno Schulenberg290d2782016-07-29 09:15:07 +0200551 else if (retval == KEY_DOWN)
Benno Schulenberg026393a2016-12-22 11:42:13 +0100552 return CONTROL_DOWN;
Benno Schulenberg290d2782016-07-29 09:15:07 +0200553 else if (retval == KEY_LEFT)
Benno Schulenberg026393a2016-12-22 11:42:13 +0100554 return CONTROL_LEFT;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200555 else if (retval == KEY_RIGHT)
Benno Schulenberg026393a2016-12-22 11:42:13 +0100556 return CONTROL_RIGHT;
Benno Schulenberg290d2782016-07-29 09:15:07 +0200557 }
Benno Schulenberg08cd1972016-09-08 21:00:51 +0200558#ifndef NANO_TINY
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200559 /* Are both Shift and Alt being held? */
560 if ((modifiers & 0x09) == 0x09) {
561 if (retval == KEY_UP)
Benno Schulenberg026393a2016-12-22 11:42:13 +0100562 return KEY_PPAGE;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200563 else if (retval == KEY_DOWN)
Benno Schulenberg026393a2016-12-22 11:42:13 +0100564 return KEY_NPAGE;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200565 else if (retval == KEY_LEFT)
Benno Schulenberg026393a2016-12-22 11:42:13 +0100566 return KEY_HOME;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200567 else if (retval == KEY_RIGHT)
Benno Schulenberg026393a2016-12-22 11:42:13 +0100568 return KEY_END;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200569 }
Benno Schulenberg08cd1972016-09-08 21:00:51 +0200570#endif
Benno Schulenberg290d2782016-07-29 09:15:07 +0200571 }
Benno Schulenberg08cd1972016-09-08 21:00:51 +0200572#endif /* __linux__ */
Benno Schulenberg290d2782016-07-29 09:15:07 +0200573
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200574 switch (retval) {
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000575#ifdef KEY_SLEFT
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200576 /* Slang doesn't support KEY_SLEFT. */
577 case KEY_SLEFT:
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200578 shift_held = TRUE;
Benno Schulenbergacd88092016-09-01 09:46:50 +0200579 return KEY_LEFT;
Benno Schulenbergb472f5a2016-07-11 16:22:30 +0200580#endif
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000581#ifdef KEY_SRIGHT
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200582 /* Slang doesn't support KEY_SRIGHT. */
583 case KEY_SRIGHT:
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200584 shift_held = TRUE;
Benno Schulenbergacd88092016-09-01 09:46:50 +0200585 return KEY_RIGHT;
Benno Schulenbergb472f5a2016-07-11 16:22:30 +0200586#endif
Benno Schulenberg272a9532016-08-30 10:11:29 +0200587#ifdef KEY_SR
Benno Schulenberg0c319f82016-07-10 20:49:52 +0200588#ifdef KEY_SUP
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200589 /* ncurses and Slang don't support KEY_SUP. */
590 case KEY_SUP:
Benno Schulenbergb472f5a2016-07-11 16:22:30 +0200591#endif
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200592 case KEY_SR: /* Scroll backward, on Xfce4-terminal. */
593 shift_held = TRUE;
Benno Schulenbergacd88092016-09-01 09:46:50 +0200594 return KEY_UP;
Benno Schulenberg272a9532016-08-30 10:11:29 +0200595#endif
596#ifdef KEY_SF
Benno Schulenberg0c319f82016-07-10 20:49:52 +0200597#ifdef KEY_SDOWN
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200598 /* ncurses and Slang don't support KEY_SDOWN. */
599 case KEY_SDOWN:
Benno Schulenbergb472f5a2016-07-11 16:22:30 +0200600#endif
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200601 case KEY_SF: /* Scroll forward, on Xfce4-terminal. */
602 shift_held = TRUE;
Benno Schulenbergacd88092016-09-01 09:46:50 +0200603 return KEY_DOWN;
Benno Schulenberg272a9532016-08-30 10:11:29 +0200604#endif
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000605#ifdef KEY_SHOME
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200606 /* HP-UX 10-11 and Slang don't support KEY_SHOME. */
607 case KEY_SHOME:
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000608#endif
Benno Schulenberg272a9532016-08-30 10:11:29 +0200609 case SHIFT_HOME:
610 shift_held = TRUE;
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200611 case KEY_A1: /* Home (7) on keypad with NumLock off. */
Benno Schulenbergacd88092016-09-01 09:46:50 +0200612 return KEY_HOME;
Benno Schulenberg0c319f82016-07-10 20:49:52 +0200613#ifdef KEY_SEND
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200614 /* HP-UX 10-11 and Slang don't support KEY_SEND. */
615 case KEY_SEND:
Benno Schulenberg0c319f82016-07-10 20:49:52 +0200616#endif
Benno Schulenberg272a9532016-08-30 10:11:29 +0200617 case SHIFT_END:
618 shift_held = TRUE;
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200619 case KEY_C1: /* End (1) on keypad with NumLock off. */
Benno Schulenbergacd88092016-09-01 09:46:50 +0200620 return KEY_END;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200621#ifndef NANO_TINY
Benno Schulenbergc9680b82016-12-01 16:51:40 +0100622#ifdef KEY_SPREVIOUS
623 case KEY_SPREVIOUS:
624#endif
625 case SHIFT_PAGEUP: /* Fake key, from Shift+Alt+Up. */
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200626 shift_held = TRUE;
627#endif
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200628 case KEY_A3: /* PageUp (9) on keypad with NumLock off. */
Benno Schulenbergacd88092016-09-01 09:46:50 +0200629 return KEY_PPAGE;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200630#ifndef NANO_TINY
Benno Schulenbergc9680b82016-12-01 16:51:40 +0100631#ifdef KEY_SNEXT
632 case KEY_SNEXT:
633#endif
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200634 case SHIFT_PAGEDOWN: /* Fake key, from Shift+Alt+Down. */
635 shift_held = TRUE;
636#endif
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200637 case KEY_C3: /* PageDown (3) on keypad with NumLock off. */
Benno Schulenbergacd88092016-09-01 09:46:50 +0200638 return KEY_NPAGE;
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000639#ifdef KEY_SDC
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200640 /* Slang doesn't support KEY_SDC. */
641 case KEY_SDC:
Benno Schulenbergd2b25122016-07-10 21:36:25 +0200642#endif
Benno Schulenberg90a90362016-08-01 12:56:05 +0200643 case DEL_CODE:
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200644 if (ISSET(REBIND_DELETE))
Benno Schulenberga9b5a0e2016-12-22 12:02:11 +0100645 return the_code_for(do_delete, KEY_DC);
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200646 else
Benno Schulenbergacd88092016-09-01 09:46:50 +0200647 return KEY_BACKSPACE;
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000648#ifdef KEY_SIC
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200649 /* Slang doesn't support KEY_SIC. */
650 case KEY_SIC:
Benno Schulenberga9b5a0e2016-12-22 12:02:11 +0100651 return the_code_for(do_insertfile_void, KEY_IC);
Chris Allegretta17436ce2008-03-11 03:03:53 +0000652#endif
Benno Schulenberg4fcc7602016-07-10 20:01:23 +0200653#ifdef KEY_SBEG
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200654 /* Slang doesn't support KEY_SBEG. */
655 case KEY_SBEG:
Benno Schulenberg4fcc7602016-07-10 20:01:23 +0200656#endif
David Lawrence Ramsey19f3bd62006-07-23 17:25:38 +0000657#ifdef KEY_BEG
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200658 /* Slang doesn't support KEY_BEG. */
659 case KEY_BEG:
Benno Schulenberg4fcc7602016-07-10 20:01:23 +0200660#endif
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200661 case KEY_B2: /* Center (5) on keypad with NumLock off. */
662 return ERR;
David Lawrence Ramsey6a8b3502007-04-18 14:06:34 +0000663#ifdef KEY_CANCEL
Chris Allegretta79a33bb2008-03-05 07:34:01 +0000664#ifdef KEY_SCANCEL
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200665 /* Slang doesn't support KEY_SCANCEL. */
666 case KEY_SCANCEL:
David Lawrence Ramsey6a8b3502007-04-18 14:06:34 +0000667#endif
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200668 /* Slang doesn't support KEY_CANCEL. */
669 case KEY_CANCEL:
Benno Schulenberga9b5a0e2016-12-22 12:02:11 +0100670 return the_code_for(do_cancel, 0x03);
David Lawrence Ramsey19f3bd62006-07-23 17:25:38 +0000671#endif
Benno Schulenberg4fcc7602016-07-10 20:01:23 +0200672#ifdef KEY_SUSPEND
David Lawrence Ramsey19f3bd62006-07-23 17:25:38 +0000673#ifdef KEY_SSUSPEND
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200674 /* Slang doesn't support KEY_SSUSPEND. */
675 case KEY_SSUSPEND:
David Lawrence Ramsey19f3bd62006-07-23 17:25:38 +0000676#endif
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200677 /* Slang doesn't support KEY_SUSPEND. */
678 case KEY_SUSPEND:
Benno Schulenberga9b5a0e2016-12-22 12:02:11 +0100679 return the_code_for(do_suspend_void, KEY_SUSPEND);
David Lawrence Ramsey19f3bd62006-07-23 17:25:38 +0000680#endif
681#ifdef PDCURSES
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200682 case KEY_SHIFT_L:
683 case KEY_SHIFT_R:
684 case KEY_CONTROL_L:
685 case KEY_CONTROL_R:
686 case KEY_ALT_L:
687 case KEY_ALT_R:
688 return ERR;
David Lawrence Ramsey19f3bd62006-07-23 17:25:38 +0000689#endif
Benno Schulenbergad83ed22016-09-06 12:05:22 +0200690#ifdef KEY_RESIZE
691 /* Slang and SunOS 5.7-5.9 don't support KEY_RESIZE. */
Benno Schulenbergfe38b782016-07-13 18:26:45 +0200692 case KEY_RESIZE:
693 return ERR;
David Lawrence Ramsey19f3bd62006-07-23 17:25:38 +0000694#endif
Benno Schulenberg5806bf52016-08-01 14:05:42 +0200695 }
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000696
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000697 return retval;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000698}
699
David Lawrence Ramsey58f6d832004-01-27 07:12:47 +0000700/* Translate escape sequences, most of which correspond to extended
David Lawrence Ramsey832db762004-11-27 23:28:39 +0000701 * keypad values, into their corresponding key values. These sequences
David Lawrence Ramsey1b4ae692006-07-25 19:23:35 +0000702 * are generated when the keypad doesn't support the needed keys.
703 * Assume that Escape has already been read in. */
Benno Schulenberg46082bd2015-12-22 19:00:25 +0000704int convert_sequence(const int *seq, size_t seq_len)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000705{
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000706 if (seq_len > 1) {
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000707 switch (seq[0]) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000708 case 'O':
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000709 switch (seq[1]) {
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000710 case '1':
Benno Schulenberg6d6f5bd2016-07-28 21:27:45 +0200711 if (seq_len > 4 && seq[2] == ';') {
712
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000713 switch (seq[3]) {
714 case '2':
Benno Schulenbergecef0932016-07-28 21:35:42 +0200715 switch (seq[4]) {
716 case 'A': /* Esc O 1 ; 2 A == Shift-Up on Terminal. */
717 case 'B': /* Esc O 1 ; 2 B == Shift-Down on Terminal. */
718 case 'C': /* Esc O 1 ; 2 C == Shift-Right on Terminal. */
719 case 'D': /* Esc O 1 ; 2 D == Shift-Left on Terminal. */
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200720 shift_held = TRUE;
Benno Schulenbergecef0932016-07-28 21:35:42 +0200721 return arrow_from_abcd(seq[4]);
722 case 'P': /* Esc O 1 ; 2 P == F13 on Terminal. */
723 return KEY_F(13);
724 case 'Q': /* Esc O 1 ; 2 Q == F14 on Terminal. */
725 return KEY_F(14);
726 case 'R': /* Esc O 1 ; 2 R == F15 on Terminal. */
727 return KEY_F(15);
728 case 'S': /* Esc O 1 ; 2 S == F16 on Terminal. */
729 return KEY_F(16);
730 }
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000731 break;
732 case '5':
Benno Schulenbergecef0932016-07-28 21:35:42 +0200733 switch (seq[4]) {
734 case 'A': /* Esc O 1 ; 5 A == Ctrl-Up on Terminal. */
735 return CONTROL_UP;
736 case 'B': /* Esc O 1 ; 5 B == Ctrl-Down on Terminal. */
737 return CONTROL_DOWN;
738 case 'C': /* Esc O 1 ; 5 C == Ctrl-Right on Terminal. */
739 return CONTROL_RIGHT;
740 case 'D': /* Esc O 1 ; 5 D == Ctrl-Left on Terminal. */
741 return CONTROL_LEFT;
742 }
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000743 break;
744 }
Benno Schulenberg6d6f5bd2016-07-28 21:27:45 +0200745
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000746 }
747 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000748 case '2':
David Lawrence Ramsey74835712004-12-04 17:41:52 +0000749 if (seq_len >= 3) {
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000750 switch (seq[2]) {
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000751 case 'P': /* Esc O 2 P == F13 on xterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000752 return KEY_F(13);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000753 case 'Q': /* Esc O 2 Q == F14 on xterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000754 return KEY_F(14);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000755 case 'R': /* Esc O 2 R == F15 on xterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000756 return KEY_F(15);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000757 case 'S': /* Esc O 2 S == F16 on xterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000758 return KEY_F(16);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000759 }
760 }
761 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000762 case 'A': /* Esc O A == Up on VT100/VT320/xterm. */
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000763 case 'B': /* Esc O B == Down on VT100/VT320/xterm. */
764 case 'C': /* Esc O C == Right on VT100/VT320/xterm. */
765 case 'D': /* Esc O D == Left on VT100/VT320/xterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000766 return arrow_from_abcd(seq[1]);
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000767 case 'E': /* Esc O E == Center (5) on numeric keypad
768 * with NumLock off on xterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000769 return KEY_B2;
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000770 case 'F': /* Esc O F == End on xterm/Terminal. */
Benno Schulenberg2225d542016-07-28 16:19:30 +0200771 return KEY_END;
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000772 case 'H': /* Esc O H == Home on xterm/Terminal. */
Benno Schulenberg2225d542016-07-28 16:19:30 +0200773 return KEY_HOME;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000774 case 'M': /* Esc O M == Enter on numeric keypad with
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000775 * NumLock off on VT100/VT220/VT320/xterm/
David Lawrence Ramsey28889642006-05-30 20:51:15 +0000776 * rxvt/Eterm. */
Benno Schulenberg2225d542016-07-28 16:19:30 +0200777 return KEY_ENTER;
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +0000778 case 'P': /* Esc O P == F1 on VT100/VT220/VT320/Mach
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000779 * console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000780 return KEY_F(1);
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +0000781 case 'Q': /* Esc O Q == F2 on VT100/VT220/VT320/Mach
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000782 * console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000783 return KEY_F(2);
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +0000784 case 'R': /* Esc O R == F3 on VT100/VT220/VT320/Mach
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000785 * console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000786 return KEY_F(3);
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +0000787 case 'S': /* Esc O S == F4 on VT100/VT220/VT320/Mach
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000788 * console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000789 return KEY_F(4);
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +0000790 case 'T': /* Esc O T == F5 on Mach console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000791 return KEY_F(5);
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +0000792 case 'U': /* Esc O U == F6 on Mach console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000793 return KEY_F(6);
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +0000794 case 'V': /* Esc O V == F7 on Mach console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000795 return KEY_F(7);
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +0000796 case 'W': /* Esc O W == F8 on Mach console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000797 return KEY_F(8);
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +0000798 case 'X': /* Esc O X == F9 on Mach console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000799 return KEY_F(9);
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +0000800 case 'Y': /* Esc O Y == F10 on Mach console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000801 return KEY_F(10);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000802 case 'a': /* Esc O a == Ctrl-Up on rxvt. */
Benno Schulenbergc6dbcf92016-06-25 15:16:52 +0200803 return CONTROL_UP;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000804 case 'b': /* Esc O b == Ctrl-Down on rxvt. */
Benno Schulenbergc6dbcf92016-06-25 15:16:52 +0200805 return CONTROL_DOWN;
Benno Schulenberg09dd0a42014-06-29 20:53:00 +0000806 case 'c': /* Esc O c == Ctrl-Right on rxvt. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000807 return CONTROL_RIGHT;
Benno Schulenberg09dd0a42014-06-29 20:53:00 +0000808 case 'd': /* Esc O d == Ctrl-Left on rxvt. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000809 return CONTROL_LEFT;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000810 case 'j': /* Esc O j == '*' on numeric keypad with
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000811 * NumLock off on VT100/VT220/VT320/xterm/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000812 * rxvt/Eterm/Terminal. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000813 return '*';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000814 case 'k': /* Esc O k == '+' on numeric keypad with
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000815 * NumLock off on VT100/VT220/VT320/xterm/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000816 * rxvt/Eterm/Terminal. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000817 return '+';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000818 case 'l': /* Esc O l == ',' on numeric keypad with
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000819 * NumLock off on VT100/VT220/VT320/xterm/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000820 * rxvt/Eterm/Terminal. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000821 return ',';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000822 case 'm': /* Esc O m == '-' on numeric keypad with
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000823 * NumLock off on VT100/VT220/VT320/xterm/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000824 * rxvt/Eterm/Terminal. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000825 return '-';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000826 case 'n': /* Esc O n == Delete (.) on numeric keypad
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000827 * with NumLock off on VT100/VT220/VT320/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000828 * xterm/rxvt/Eterm/Terminal. */
Benno Schulenberg2225d542016-07-28 16:19:30 +0200829 return KEY_DC;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000830 case 'o': /* Esc O o == '/' on numeric keypad with
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000831 * NumLock off on VT100/VT220/VT320/xterm/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000832 * rxvt/Eterm/Terminal. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000833 return '/';
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000834 case 'p': /* Esc O p == Insert (0) on numeric keypad
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000835 * with NumLock off on VT100/VT220/VT320/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000836 * rxvt/Eterm/Terminal. */
Benno Schulenberg2225d542016-07-28 16:19:30 +0200837 return KEY_IC;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000838 case 'q': /* Esc O q == End (1) on numeric keypad
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000839 * with NumLock off on VT100/VT220/VT320/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000840 * rxvt/Eterm/Terminal. */
Benno Schulenberg2225d542016-07-28 16:19:30 +0200841 return KEY_END;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000842 case 'r': /* Esc O r == Down (2) on numeric keypad
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000843 * with NumLock off on VT100/VT220/VT320/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000844 * rxvt/Eterm/Terminal. */
Benno Schulenberg2225d542016-07-28 16:19:30 +0200845 return KEY_DOWN;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000846 case 's': /* Esc O s == PageDown (3) on numeric
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000847 * keypad with NumLock off on VT100/VT220/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000848 * VT320/rxvt/Eterm/Terminal. */
Benno Schulenberg2225d542016-07-28 16:19:30 +0200849 return KEY_NPAGE;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000850 case 't': /* Esc O t == Left (4) on numeric keypad
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000851 * with NumLock off on VT100/VT220/VT320/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000852 * rxvt/Eterm/Terminal. */
Benno Schulenberg2225d542016-07-28 16:19:30 +0200853 return KEY_LEFT;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000854 case 'u': /* Esc O u == Center (5) on numeric keypad
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000855 * with NumLock off on VT100/VT220/VT320/
856 * rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000857 return KEY_B2;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000858 case 'v': /* Esc O v == Right (6) on numeric keypad
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000859 * with NumLock off on VT100/VT220/VT320/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000860 * rxvt/Eterm/Terminal. */
Benno Schulenberg2225d542016-07-28 16:19:30 +0200861 return KEY_RIGHT;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000862 case 'w': /* Esc O w == Home (7) on numeric keypad
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000863 * with NumLock off on VT100/VT220/VT320/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000864 * rxvt/Eterm/Terminal. */
Benno Schulenberg2225d542016-07-28 16:19:30 +0200865 return KEY_HOME;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000866 case 'x': /* Esc O x == Up (8) on numeric keypad
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000867 * with NumLock off on VT100/VT220/VT320/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000868 * rxvt/Eterm/Terminal. */
Benno Schulenberg2225d542016-07-28 16:19:30 +0200869 return KEY_UP;
David Lawrence Ramsey0a258082004-04-23 18:02:37 +0000870 case 'y': /* Esc O y == PageUp (9) on numeric keypad
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000871 * with NumLock off on VT100/VT220/VT320/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +0000872 * rxvt/Eterm/Terminal. */
Benno Schulenberg2225d542016-07-28 16:19:30 +0200873 return KEY_PPAGE;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000874 }
875 break;
876 case 'o':
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000877 switch (seq[1]) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000878 case 'a': /* Esc o a == Ctrl-Up on Eterm. */
Benno Schulenbergc6dbcf92016-06-25 15:16:52 +0200879 return CONTROL_UP;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000880 case 'b': /* Esc o b == Ctrl-Down on Eterm. */
Benno Schulenbergc6dbcf92016-06-25 15:16:52 +0200881 return CONTROL_DOWN;
Benno Schulenberg09dd0a42014-06-29 20:53:00 +0000882 case 'c': /* Esc o c == Ctrl-Right on Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000883 return CONTROL_RIGHT;
Benno Schulenberg09dd0a42014-06-29 20:53:00 +0000884 case 'd': /* Esc o d == Ctrl-Left on Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000885 return CONTROL_LEFT;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000886 }
887 break;
888 case '[':
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000889 switch (seq[1]) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000890 case '1':
Benno Schulenberge3dbffc2016-07-28 21:12:18 +0200891 if (seq_len > 3 && seq[3] == '~') {
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000892 switch (seq[2]) {
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000893 case '1': /* Esc [ 1 1 ~ == F1 on rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000894 return KEY_F(1);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000895 case '2': /* Esc [ 1 2 ~ == F2 on rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000896 return KEY_F(2);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000897 case '3': /* Esc [ 1 3 ~ == F3 on rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000898 return KEY_F(3);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000899 case '4': /* Esc [ 1 4 ~ == F4 on rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000900 return KEY_F(4);
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000901 case '5': /* Esc [ 1 5 ~ == F5 on xterm/
902 * rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000903 return KEY_F(5);
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000904 case '7': /* Esc [ 1 7 ~ == F6 on
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000905 * VT220/VT320/Linux console/
906 * xterm/rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000907 return KEY_F(6);
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000908 case '8': /* Esc [ 1 8 ~ == F7 on
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000909 * VT220/VT320/Linux console/
910 * xterm/rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000911 return KEY_F(7);
David Lawrence Ramsey0381c212004-05-01 01:21:38 +0000912 case '9': /* Esc [ 1 9 ~ == F8 on
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +0000913 * VT220/VT320/Linux console/
914 * xterm/rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000915 return KEY_F(8);
Benno Schulenberge3dbffc2016-07-28 21:12:18 +0200916 }
917 } else if (seq_len > 4 && seq[2] == ';') {
918
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000919 switch (seq[3]) {
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000920 case '2':
Benno Schulenbergecef0932016-07-28 21:35:42 +0200921 switch (seq[4]) {
922 case 'A': /* Esc [ 1 ; 2 A == Shift-Up on xterm. */
923 case 'B': /* Esc [ 1 ; 2 B == Shift-Down on xterm. */
924 case 'C': /* Esc [ 1 ; 2 C == Shift-Right on xterm. */
925 case 'D': /* Esc [ 1 ; 2 D == Shift-Left on xterm. */
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200926 shift_held = TRUE;
Benno Schulenbergecef0932016-07-28 21:35:42 +0200927 return arrow_from_abcd(seq[4]);
928 }
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000929 break;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200930#ifndef NANO_TINY
931 case '4':
932 /* When the arrow keys are held together with Shift+Meta,
933 * act as if they are Home/End/PgUp/PgDown with Shift. */
934 switch (seq[4]) {
935 case 'A': /* Esc [ 1 ; 4 A == Shift-Alt-Up on xterm. */
936 return SHIFT_PAGEUP;
937 case 'B': /* Esc [ 1 ; 4 B == Shift-Alt-Down on xterm. */
938 return SHIFT_PAGEDOWN;
939 case 'C': /* Esc [ 1 ; 4 C == Shift-Alt-Right on xterm. */
Benno Schulenberg272a9532016-08-30 10:11:29 +0200940 return SHIFT_END;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200941 case 'D': /* Esc [ 1 ; 4 D == Shift-Alt-Left on xterm. */
Benno Schulenberg272a9532016-08-30 10:11:29 +0200942 return SHIFT_HOME;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200943 }
944 break;
945#endif
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000946 case '5':
Benno Schulenbergecef0932016-07-28 21:35:42 +0200947 switch (seq[4]) {
948 case 'A': /* Esc [ 1 ; 5 A == Ctrl-Up on xterm. */
949 return CONTROL_UP;
950 case 'B': /* Esc [ 1 ; 5 B == Ctrl-Down on xterm. */
951 return CONTROL_DOWN;
952 case 'C': /* Esc [ 1 ; 5 C == Ctrl-Right on xterm. */
953 return CONTROL_RIGHT;
954 case 'D': /* Esc [ 1 ; 5 D == Ctrl-Left on xterm. */
955 return CONTROL_LEFT;
956 }
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000957 break;
Benno Schulenberg382c9d72016-04-24 11:28:28 +0200958#ifndef NANO_TINY
959 case '6':
960 switch (seq[4]) {
961 case 'A': /* Esc [ 1 ; 6 A == Shift-Ctrl-Up on xterm. */
962 return shiftcontrolup;
963 case 'B': /* Esc [ 1 ; 6 B == Shift-Ctrl-Down on xterm. */
964 return shiftcontroldown;
965 case 'C': /* Esc [ 1 ; 6 C == Shift-Ctrl-Right on xterm. */
966 return shiftcontrolright;
967 case 'D': /* Esc [ 1 ; 6 D == Shift-Ctrl-Left on xterm. */
968 return shiftcontrolleft;
969 }
970 break;
971#endif
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000972 }
Benno Schulenberge3dbffc2016-07-28 21:12:18 +0200973
974 } else if (seq_len > 2 && seq[2] == '~')
975 /* Esc [ 1 ~ == Home on VT320/Linux console. */
976 return KEY_HOME;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000977 break;
978 case '2':
Benno Schulenberge3dbffc2016-07-28 21:12:18 +0200979 if (seq_len > 3 && seq[3] == '~') {
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +0000980 switch (seq[2]) {
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000981 case '0': /* Esc [ 2 0 ~ == F9 on VT220/VT320/
982 * Linux console/xterm/rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000983 return KEY_F(9);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000984 case '1': /* Esc [ 2 1 ~ == F10 on VT220/VT320/
985 * Linux console/xterm/rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000986 return KEY_F(10);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000987 case '3': /* Esc [ 2 3 ~ == F11 on VT220/VT320/
988 * Linux console/xterm/rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000989 return KEY_F(11);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000990 case '4': /* Esc [ 2 4 ~ == F12 on VT220/VT320/
991 * Linux console/xterm/rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000992 return KEY_F(12);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000993 case '5': /* Esc [ 2 5 ~ == F13 on VT220/VT320/
994 * Linux console/rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000995 return KEY_F(13);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000996 case '6': /* Esc [ 2 6 ~ == F14 on VT220/VT320/
997 * Linux console/rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +0000998 return KEY_F(14);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +0000999 case '8': /* Esc [ 2 8 ~ == F15 on VT220/VT320/
1000 * Linux console/rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001001 return KEY_F(15);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +00001002 case '9': /* Esc [ 2 9 ~ == F16 on VT220/VT320/
1003 * Linux console/rxvt/Eterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001004 return KEY_F(16);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001005 }
Benno Schulenberge3dbffc2016-07-28 21:12:18 +02001006 } else if (seq_len > 2 && seq[2] == '~')
1007 /* Esc [ 2 ~ == Insert on VT220/VT320/
1008 * Linux console/xterm/Terminal. */
1009 return KEY_IC;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001010 break;
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +00001011 case '3': /* Esc [ 3 ~ == Delete on VT220/VT320/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +00001012 * Linux console/xterm/Terminal. */
David Lawrence Ramseyd48071b2016-11-26 13:33:31 -06001013 if (seq_len > 2 && seq[2] == '~')
1014 return KEY_DC;
1015 break;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +00001016 case '4': /* Esc [ 4 ~ == End on VT220/VT320/Linux
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001017 * console/xterm. */
David Lawrence Ramseyd48071b2016-11-26 13:33:31 -06001018 if (seq_len > 2 && seq[2] == '~')
1019 return KEY_END;
1020 break;
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +00001021 case '5': /* Esc [ 5 ~ == PageUp on VT220/VT320/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +00001022 * Linux console/xterm/Terminal;
1023 * Esc [ 5 ^ == PageUp on Eterm. */
David Lawrence Ramseyd48071b2016-11-26 13:33:31 -06001024 if (seq_len > 2 && (seq[2] == '~' || seq[2] == '^'))
1025 return KEY_PPAGE;
1026 break;
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +00001027 case '6': /* Esc [ 6 ~ == PageDown on VT220/VT320/
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +00001028 * Linux console/xterm/Terminal;
Benno Schulenberg1de337d2014-06-04 16:02:51 +00001029 * Esc [ 6 ^ == PageDown on Eterm. */
David Lawrence Ramseyd48071b2016-11-26 13:33:31 -06001030 if (seq_len > 2 && (seq[2] == '~' || seq[2] == '^'))
1031 return KEY_NPAGE;
1032 break;
Benno Schulenberg3cc561e2016-11-26 12:25:36 +01001033 case '7': /* Esc [ 7 ~ == Home on Eterm/rxvt,
1034 * Esc [ 7 $ == Shift-Home on Eterm/rxvt. */
1035 if (seq_len > 2 && seq[2] == '~')
1036 return KEY_HOME;
1037 else if (seq_len > 2 && seq[2] == '$')
1038 return SHIFT_HOME;
1039 break;
1040 case '8': /* Esc [ 8 ~ == End on Eterm/rxvt.
1041 * Esc [ 8 $ == Shift-End on Eterm/rxvt. */
1042 if (seq_len > 2 && seq[2] == '~')
1043 return KEY_END;
1044 else if (seq_len > 2 && seq[2] == '$')
1045 return SHIFT_END;
1046 break;
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +00001047 case '9': /* Esc [ 9 == Delete on Mach console. */
Benno Schulenberg2225d542016-07-28 16:19:30 +02001048 return KEY_DC;
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +00001049 case '@': /* Esc [ @ == Insert on Mach console. */
Benno Schulenberg2225d542016-07-28 16:19:30 +02001050 return KEY_IC;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +00001051 case 'A': /* Esc [ A == Up on ANSI/VT220/Linux
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +00001052 * console/FreeBSD console/Mach console/
David Lawrence Ramseya31d54e2007-04-18 13:48:37 +00001053 * rxvt/Eterm/Terminal. */
David Lawrence Ramsey0381c212004-05-01 01:21:38 +00001054 case 'B': /* Esc [ B == Down on ANSI/VT220/Linux
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +00001055 * console/FreeBSD console/Mach console/
David Lawrence Ramseya31d54e2007-04-18 13:48:37 +00001056 * rxvt/Eterm/Terminal. */
David Lawrence Ramsey0381c212004-05-01 01:21:38 +00001057 case 'C': /* Esc [ C == Right on ANSI/VT220/Linux
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +00001058 * console/FreeBSD console/Mach console/
David Lawrence Ramseya31d54e2007-04-18 13:48:37 +00001059 * rxvt/Eterm/Terminal. */
David Lawrence Ramsey0381c212004-05-01 01:21:38 +00001060 case 'D': /* Esc [ D == Left on ANSI/VT220/Linux
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +00001061 * console/FreeBSD console/Mach console/
David Lawrence Ramseya31d54e2007-04-18 13:48:37 +00001062 * rxvt/Eterm/Terminal. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001063 return arrow_from_abcd(seq[1]);
David Lawrence Ramsey0a258082004-04-23 18:02:37 +00001064 case 'E': /* Esc [ E == Center (5) on numeric keypad
David Lawrence Ramsey267daeb2007-04-04 20:36:56 +00001065 * with NumLock off on FreeBSD console/
1066 * Terminal. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001067 return KEY_B2;
Benno Schulenberg7f3bd262015-04-28 20:09:40 +00001068 case 'F': /* Esc [ F == End on FreeBSD console/Eterm. */
Benno Schulenberg2225d542016-07-28 16:19:30 +02001069 return KEY_END;
Benno Schulenberg7f3bd262015-04-28 20:09:40 +00001070 case 'G': /* Esc [ G == PageDown on FreeBSD console. */
Benno Schulenberg2225d542016-07-28 16:19:30 +02001071 return KEY_NPAGE;
David Lawrence Ramsey0381c212004-05-01 01:21:38 +00001072 case 'H': /* Esc [ H == Home on ANSI/VT220/FreeBSD
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +00001073 * console/Mach console/Eterm. */
Benno Schulenberg2225d542016-07-28 16:19:30 +02001074 return KEY_HOME;
Benno Schulenberg7f3bd262015-04-28 20:09:40 +00001075 case 'I': /* Esc [ I == PageUp on FreeBSD console. */
Benno Schulenberg2225d542016-07-28 16:19:30 +02001076 return KEY_PPAGE;
Benno Schulenberg7f3bd262015-04-28 20:09:40 +00001077 case 'L': /* Esc [ L == Insert on ANSI/FreeBSD console. */
Benno Schulenberg2225d542016-07-28 16:19:30 +02001078 return KEY_IC;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001079 case 'M': /* Esc [ M == F1 on FreeBSD console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001080 return KEY_F(1);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001081 case 'N': /* Esc [ N == F2 on FreeBSD console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001082 return KEY_F(2);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001083 case 'O':
Benno Schulenberge3dbffc2016-07-28 21:12:18 +02001084 if (seq_len > 2) {
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001085 switch (seq[2]) {
Benno Schulenberg7f3bd262015-04-28 20:09:40 +00001086 case 'P': /* Esc [ O P == F1 on xterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001087 return KEY_F(1);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +00001088 case 'Q': /* Esc [ O Q == F2 on xterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001089 return KEY_F(2);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +00001090 case 'R': /* Esc [ O R == F3 on xterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001091 return KEY_F(3);
Benno Schulenberg7f3bd262015-04-28 20:09:40 +00001092 case 'S': /* Esc [ O S == F4 on xterm. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001093 return KEY_F(4);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001094 }
David Lawrence Ramseyec729752005-09-25 18:42:05 +00001095 } else
David Lawrence Ramsey973a96b2004-06-22 14:30:18 +00001096 /* Esc [ O == F3 on FreeBSD console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001097 return KEY_F(3);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001098 break;
1099 case 'P': /* Esc [ P == F4 on FreeBSD console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001100 return KEY_F(4);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001101 case 'Q': /* Esc [ Q == F5 on FreeBSD console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001102 return KEY_F(5);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001103 case 'R': /* Esc [ R == F6 on FreeBSD console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001104 return KEY_F(6);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001105 case 'S': /* Esc [ S == F7 on FreeBSD console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001106 return KEY_F(7);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001107 case 'T': /* Esc [ T == F8 on FreeBSD console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001108 return KEY_F(8);
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +00001109 case 'U': /* Esc [ U == PageDown on Mach console. */
Benno Schulenberg2225d542016-07-28 16:19:30 +02001110 return KEY_NPAGE;
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +00001111 case 'V': /* Esc [ V == PageUp on Mach console. */
Benno Schulenberg2225d542016-07-28 16:19:30 +02001112 return KEY_PPAGE;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001113 case 'W': /* Esc [ W == F11 on FreeBSD console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001114 return KEY_F(11);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001115 case 'X': /* Esc [ X == F12 on FreeBSD console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001116 return KEY_F(12);
David Lawrence Ramseycc823ab2004-10-24 22:51:39 +00001117 case 'Y': /* Esc [ Y == End on Mach console. */
Benno Schulenberg2225d542016-07-28 16:19:30 +02001118 return KEY_END;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001119 case 'Z': /* Esc [ Z == F14 on FreeBSD console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001120 return KEY_F(14);
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +00001121 case 'a': /* Esc [ a == Shift-Up on rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +00001122 case 'b': /* Esc [ b == Shift-Down on rxvt/Eterm. */
Benno Schulenberg7f3bd262015-04-28 20:09:40 +00001123 case 'c': /* Esc [ c == Shift-Right on rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +00001124 case 'd': /* Esc [ d == Shift-Left on rxvt/Eterm. */
Benno Schulenberg382c9d72016-04-24 11:28:28 +02001125 shift_held = TRUE;
Benno Schulenbergbd917852015-12-22 20:24:50 +00001126 return arrow_from_abcd(seq[1]);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001127 case '[':
Benno Schulenberge3dbffc2016-07-28 21:12:18 +02001128 if (seq_len > 2 ) {
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001129 switch (seq[2]) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001130 case 'A': /* Esc [ [ A == F1 on Linux
1131 * console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001132 return KEY_F(1);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001133 case 'B': /* Esc [ [ B == F2 on Linux
1134 * console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001135 return KEY_F(2);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001136 case 'C': /* Esc [ [ C == F3 on Linux
1137 * console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001138 return KEY_F(3);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001139 case 'D': /* Esc [ [ D == F4 on Linux
1140 * console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001141 return KEY_F(4);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001142 case 'E': /* Esc [ [ E == F5 on Linux
1143 * console. */
Benno Schulenbergbd917852015-12-22 20:24:50 +00001144 return KEY_F(5);
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001145 }
1146 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001147 break;
1148 }
1149 break;
1150 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001151 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001152
Benno Schulenbergbd917852015-12-22 20:24:50 +00001153 return ERR;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001154}
1155
Benno Schulenberg2225d542016-07-28 16:19:30 +02001156/* Return the equivalent arrow-key value for the first four letters
1157 * in the alphabet, common to many escape sequences. */
Benno Schulenberg46082bd2015-12-22 19:00:25 +00001158int arrow_from_abcd(int kbinput)
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001159{
1160 switch (tolower(kbinput)) {
1161 case 'a':
Benno Schulenberg2225d542016-07-28 16:19:30 +02001162 return KEY_UP;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001163 case 'b':
Benno Schulenberg2225d542016-07-28 16:19:30 +02001164 return KEY_DOWN;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001165 case 'c':
Benno Schulenberg2225d542016-07-28 16:19:30 +02001166 return KEY_RIGHT;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001167 case 'd':
Benno Schulenberg2225d542016-07-28 16:19:30 +02001168 return KEY_LEFT;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001169 default:
1170 return ERR;
1171 }
1172}
1173
David Lawrence Ramsey1320d292006-05-25 22:10:27 +00001174/* Interpret the escape sequence in the keystroke buffer, the first
David Lawrence Ramsey5370b0c2006-07-23 17:54:35 +00001175 * character of which is kbinput. Assume that the keystroke buffer
1176 * isn't empty, and that the initial escape has already been read in. */
Benno Schulenberg46082bd2015-12-22 19:00:25 +00001177int parse_escape_sequence(WINDOW *win, int kbinput)
David Lawrence Ramsey1320d292006-05-25 22:10:27 +00001178{
1179 int retval, *seq;
1180 size_t seq_len;
David Lawrence Ramsey1320d292006-05-25 22:10:27 +00001181
1182 /* Put back the non-escape character, get the complete escape
1183 * sequence, translate the sequence into its corresponding key
1184 * value, and save that as the result. */
1185 unget_input(&kbinput, 1);
Benno Schulenbergf33d8ca2016-07-15 21:53:46 +02001186 seq_len = key_buffer_len;
David Lawrence Ramsey1320d292006-05-25 22:10:27 +00001187 seq = get_input(NULL, seq_len);
Benno Schulenberg46082bd2015-12-22 19:00:25 +00001188 retval = convert_sequence(seq, seq_len);
David Lawrence Ramsey1320d292006-05-25 22:10:27 +00001189
1190 free(seq);
1191
Benno Schulenberg46082bd2015-12-22 19:00:25 +00001192 /* If we got an unrecognized escape sequence, notify the user. */
David Lawrence Ramsey1b4ae692006-07-25 19:23:35 +00001193 if (retval == ERR) {
David Lawrence Ramsey8a723702006-07-23 18:00:50 +00001194 if (win == edit) {
Benno Schulenbergeb871e72016-05-01 10:02:49 +02001195 /* TRANSLATORS: This refers to a sequence of escape codes
1196 * (from the keyboard) that nano does not know about. */
Benno Schulenberg2535f512016-04-30 17:31:43 +02001197 statusline(ALERT, _("Unknown sequence"));
Benno Schulenberg73aa48b2016-05-14 22:14:37 +02001198 suppress_cursorpos = FALSE;
Benno Schulenbergc8f530a2016-05-19 20:43:08 +02001199 lastmessage = HUSH;
Benno Schulenberg73aa48b2016-05-14 22:14:37 +02001200 if (currmenu == MMAIN) {
1201 reset_cursor();
1202 curs_set(1);
1203 }
David Lawrence Ramsey5370b0c2006-07-23 17:54:35 +00001204 }
1205 }
1206
David Lawrence Ramsey1320d292006-05-25 22:10:27 +00001207#ifdef DEBUG
Benno Schulenberg46082bd2015-12-22 19:00:25 +00001208 fprintf(stderr, "parse_escape_sequence(): kbinput = %d, seq_len = %lu, retval = %d\n",
1209 kbinput, (unsigned long)seq_len, retval);
David Lawrence Ramsey1320d292006-05-25 22:10:27 +00001210#endif
1211
1212 return retval;
1213}
1214
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001215/* Translate a byte sequence: turn a three-digit decimal number (from
1216 * 000 to 255) into its corresponding byte value. */
David Lawrence Ramseyfc0f8f82006-05-10 13:41:53 +00001217int get_byte_kbinput(int kbinput)
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +00001218{
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001219 static int byte_digits = 0, byte = 0;
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +00001220 int retval = ERR;
1221
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +00001222 /* Increment the byte digit counter. */
1223 byte_digits++;
1224
1225 switch (byte_digits) {
1226 case 1:
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001227 /* First digit: This must be from zero to two. Put it in
1228 * the 100's position of the byte sequence holder. */
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +00001229 if ('0' <= kbinput && kbinput <= '2')
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001230 byte = (kbinput - '0') * 100;
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +00001231 else
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001232 /* This isn't the start of a byte sequence. Return this
1233 * character as the result. */
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +00001234 retval = kbinput;
1235 break;
1236 case 2:
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001237 /* Second digit: This must be from zero to five if the first
1238 * was two, and may be any decimal value if the first was
1239 * zero or one. Put it in the 10's position of the byte
1240 * sequence holder. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001241 if (('0' <= kbinput && kbinput <= '5') || (byte < 200 &&
1242 '6' <= kbinput && kbinput <= '9'))
1243 byte += (kbinput - '0') * 10;
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +00001244 else
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001245 /* This isn't the second digit of a byte sequence.
1246 * Return this character as the result. */
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +00001247 retval = kbinput;
1248 break;
1249 case 3:
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001250 /* Third digit: This must be from zero to five if the first
Benno Schulenbergf876ee12014-04-15 11:25:29 +00001251 * was two and the second was five, and may be any decimal
1252 * value otherwise. Put it in the 1's position of the byte
1253 * sequence holder. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001254 if (('0' <= kbinput && kbinput <= '5') || (byte < 250 &&
1255 '6' <= kbinput && kbinput <= '9')) {
David Lawrence Ramsey28889642006-05-30 20:51:15 +00001256 byte += kbinput - '0';
Benno Schulenbergf876ee12014-04-15 11:25:29 +00001257 /* The byte sequence is complete. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001258 retval = byte;
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +00001259 } else
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001260 /* This isn't the third digit of a byte sequence.
1261 * Return this character as the result. */
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +00001262 retval = kbinput;
1263 break;
1264 default:
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001265 /* If there are more than three digits, return this
1266 * character as the result. (Maybe we should produce an
1267 * error instead?) */
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +00001268 retval = kbinput;
1269 break;
1270 }
1271
1272 /* If we have a result, reset the byte digit counter and the byte
1273 * sequence holder. */
1274 if (retval != ERR) {
1275 byte_digits = 0;
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001276 byte = 0;
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +00001277 }
1278
1279#ifdef DEBUG
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001280 fprintf(stderr, "get_byte_kbinput(): kbinput = %d, byte_digits = %d, byte = %d, retval = %d\n", kbinput, byte_digits, byte, retval);
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +00001281#endif
1282
1283 return retval;
1284}
1285
David Lawrence Ramsey6fb66892006-05-27 17:39:19 +00001286#ifdef ENABLE_UTF8
David Lawrence Ramsey7f1b1192006-05-28 17:30:28 +00001287/* If the character in kbinput is a valid hexadecimal digit, multiply it
Benno Schulenberge679c512016-06-24 15:39:03 +02001288 * by factor and add the result to uni, and return ERR to signify okay. */
David Lawrence Ramsey7f1b1192006-05-28 17:30:28 +00001289long add_unicode_digit(int kbinput, long factor, long *uni)
1290{
David Lawrence Ramsey7f1b1192006-05-28 17:30:28 +00001291 if ('0' <= kbinput && kbinput <= '9')
1292 *uni += (kbinput - '0') * factor;
1293 else if ('a' <= tolower(kbinput) && tolower(kbinput) <= 'f')
1294 *uni += (tolower(kbinput) - 'a' + 10) * factor;
1295 else
Benno Schulenberge679c512016-06-24 15:39:03 +02001296 /* The character isn't hexadecimal; give it as the result. */
1297 return (long)kbinput;
David Lawrence Ramsey7f1b1192006-05-28 17:30:28 +00001298
Benno Schulenberge679c512016-06-24 15:39:03 +02001299 return ERR;
David Lawrence Ramsey7f1b1192006-05-28 17:30:28 +00001300}
1301
David Lawrence Ramsey8c7a5622005-08-08 23:47:28 +00001302/* Translate a Unicode sequence: turn a six-digit hexadecimal number
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001303 * (from 000000 to 10FFFF, case-insensitive) into its corresponding
David Lawrence Ramsey8c7a5622005-08-08 23:47:28 +00001304 * multibyte value. */
David Lawrence Ramseyfc0ddab2016-07-24 12:34:56 +02001305long get_unicode_kbinput(WINDOW *win, int kbinput)
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001306{
David Lawrence Ramsey8b006c22005-08-08 23:03:25 +00001307 static int uni_digits = 0;
1308 static long uni = 0;
1309 long retval = ERR;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001310
David Lawrence Ramsey8c7a5622005-08-08 23:47:28 +00001311 /* Increment the Unicode digit counter. */
David Lawrence Ramsey6a836472005-08-01 19:12:05 +00001312 uni_digits++;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001313
David Lawrence Ramsey6a836472005-08-01 19:12:05 +00001314 switch (uni_digits) {
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001315 case 1:
Benno Schulenberga472f482016-07-24 13:44:16 +02001316 /* The first digit must be zero or one. Put it in the
1317 * 0x100000's position of the Unicode sequence holder.
1318 * Otherwise, return the character itself as the result. */
1319 if (kbinput == '0' || kbinput == '1')
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001320 uni = (kbinput - '0') * 0x100000;
David Lawrence Ramsey8c7a5622005-08-08 23:47:28 +00001321 else
David Lawrence Ramsey8c7a5622005-08-08 23:47:28 +00001322 retval = kbinput;
1323 break;
1324 case 2:
Benno Schulenberga472f482016-07-24 13:44:16 +02001325 /* The second digit must be zero if the first was one, but
1326 * may be any hexadecimal value if the first was zero. */
1327 if (kbinput == '0' || uni == 0)
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001328 retval = add_unicode_digit(kbinput, 0x10000, &uni);
David Lawrence Ramsey8c7a5622005-08-08 23:47:28 +00001329 else
David Lawrence Ramsey8c7a5622005-08-08 23:47:28 +00001330 retval = kbinput;
1331 break;
1332 case 3:
Benno Schulenberga472f482016-07-24 13:44:16 +02001333 /* Later digits may be any hexadecimal value. */
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001334 retval = add_unicode_digit(kbinput, 0x1000, &uni);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001335 break;
David Lawrence Ramsey8c7a5622005-08-08 23:47:28 +00001336 case 4:
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001337 retval = add_unicode_digit(kbinput, 0x100, &uni);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001338 break;
David Lawrence Ramsey8c7a5622005-08-08 23:47:28 +00001339 case 5:
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001340 retval = add_unicode_digit(kbinput, 0x10, &uni);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001341 break;
David Lawrence Ramsey8c7a5622005-08-08 23:47:28 +00001342 case 6:
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001343 retval = add_unicode_digit(kbinput, 0x1, &uni);
Benno Schulenberga472f482016-07-24 13:44:16 +02001344 /* If also the sixth digit was a valid hexadecimal value, then
1345 * the Unicode sequence is complete, so return it. */
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001346 if (retval == ERR)
David Lawrence Ramsey6a836472005-08-01 19:12:05 +00001347 retval = uni;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001348 break;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001349 }
1350
David Lawrence Ramseyfc0ddab2016-07-24 12:34:56 +02001351 /* Show feedback only when editing, not when at a prompt. */
Benno Schulenberg4416d9c2016-07-24 13:15:45 +02001352 if (retval == ERR && win == edit) {
David Lawrence Ramseyfc0ddab2016-07-24 12:34:56 +02001353 char partial[7] = "......";
1354
1355 /* Construct the partial result, right-padding it with dots. */
1356 snprintf(partial, uni_digits + 1, "%06lX", uni);
1357 partial[uni_digits] = '.';
1358
1359 /* TRANSLATORS: This is shown while a six-digit hexadecimal
1360 * Unicode character code (%s) is being typed in. */
1361 statusline(HUSH, _("Unicode Input: %s"), partial);
1362 }
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001363
1364#ifdef DEBUG
Benno Schulenberg4416d9c2016-07-24 13:15:45 +02001365 fprintf(stderr, "get_unicode_kbinput(): kbinput = %d, uni_digits = %d, uni = %ld, retval = %ld\n",
1366 kbinput, uni_digits, uni, retval);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001367#endif
1368
Benno Schulenberg4416d9c2016-07-24 13:15:45 +02001369 /* If we have an end result, reset the Unicode digit counter. */
1370 if (retval != ERR)
1371 uni_digits = 0;
1372
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001373 return retval;
1374}
David Lawrence Ramsey6fb66892006-05-27 17:39:19 +00001375#endif /* ENABLE_UTF8 */
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001376
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001377/* Translate a control character sequence: turn an ASCII non-control
1378 * character into its corresponding control character. */
1379int get_control_kbinput(int kbinput)
1380{
1381 int retval;
1382
Benno Schulenbergcdcd3652016-05-17 11:33:21 +02001383 /* Ctrl-Space (Ctrl-2, Ctrl-@, Ctrl-`) */
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001384 if (kbinput == ' ' || kbinput == '2')
Benno Schulenberg90a90362016-08-01 12:56:05 +02001385 retval = 0;
David Lawrence Ramsey4d9ef692006-04-28 18:26:07 +00001386 /* Ctrl-/ (Ctrl-7, Ctrl-_) */
1387 else if (kbinput == '/')
Benno Schulenberg90a90362016-08-01 12:56:05 +02001388 retval = 31;
David Lawrence Ramsey4d9ef692006-04-28 18:26:07 +00001389 /* Ctrl-3 (Ctrl-[, Esc) to Ctrl-7 (Ctrl-/, Ctrl-_) */
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001390 else if ('3' <= kbinput && kbinput <= '7')
1391 retval = kbinput - 24;
1392 /* Ctrl-8 (Ctrl-?) */
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001393 else if (kbinput == '8' || kbinput == '?')
Benno Schulenberg90a90362016-08-01 12:56:05 +02001394 retval = DEL_CODE;
David Lawrence Ramsey51cb7fd2006-05-20 17:19:09 +00001395 /* Ctrl-@ (Ctrl-Space, Ctrl-2, Ctrl-`) to Ctrl-_ (Ctrl-/, Ctrl-7) */
1396 else if ('@' <= kbinput && kbinput <= '_')
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001397 retval = kbinput - '@';
David Lawrence Ramsey4d9ef692006-04-28 18:26:07 +00001398 /* Ctrl-` (Ctrl-2, Ctrl-Space, Ctrl-@) to Ctrl-~ (Ctrl-6, Ctrl-^) */
1399 else if ('`' <= kbinput && kbinput <= '~')
David Lawrence Ramsey12e37082006-05-27 15:52:26 +00001400 retval = kbinput - '`';
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001401 else
1402 retval = kbinput;
1403
1404#ifdef DEBUG
1405 fprintf(stderr, "get_control_kbinput(): kbinput = %d, retval = %d\n", kbinput, retval);
1406#endif
1407
1408 return retval;
1409}
1410
David Lawrence Ramsey561db3a2006-05-26 03:22:44 +00001411/* Put the output-formatted characters in output back into the keystroke
1412 * buffer, so that they can be parsed and displayed as output again. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001413void unparse_kbinput(char *output, size_t output_len)
David Lawrence Ramseyd9ad76b2005-01-02 22:35:31 +00001414{
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001415 int *input;
1416 size_t i;
David Lawrence Ramseyd9ad76b2005-01-02 22:35:31 +00001417
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001418 if (output_len == 0)
1419 return;
1420
1421 input = (int *)nmalloc(output_len * sizeof(int));
David Lawrence Ramseybd539802006-12-02 23:39:16 +00001422
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001423 for (i = 0; i < output_len; i++)
1424 input[i] = (int)output[i];
David Lawrence Ramseybd539802006-12-02 23:39:16 +00001425
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001426 unget_input(input, output_len);
David Lawrence Ramseybd539802006-12-02 23:39:16 +00001427
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001428 free(input);
David Lawrence Ramseyd9ad76b2005-01-02 22:35:31 +00001429}
1430
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001431/* Read in a stream of characters verbatim, and return the length of the
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001432 * string in kbinput_len. Assume nodelay(win) is FALSE. */
1433int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len)
1434{
1435 int *retval;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001436
1437 /* Turn off flow control characters if necessary so that we can type
David Lawrence Ramsey057edf72005-08-10 21:22:15 +00001438 * them in verbatim, and turn the keypad off if necessary so that we
1439 * don't get extended keypad values. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001440 if (ISSET(PRESERVE))
1441 disable_flow_control();
David Lawrence Ramsey057edf72005-08-10 21:22:15 +00001442 if (!ISSET(REBIND_KEYPAD))
1443 keypad(win, FALSE);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001444
Benno Schulenberg908663e2016-12-27 12:20:20 +01001445 /* Read in one keycode, or one or two escapes. */
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001446 retval = parse_verbatim_kbinput(win, kbinput_len);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001447
Benno Schulenberg908663e2016-12-27 12:20:20 +01001448 /* If the code is invalid in the current mode, discard it. */
1449 if ((*retval == '\n' && as_an_at) || (*retval == '\0' && !as_an_at)) {
1450 *kbinput_len = 0;
1451 beep();
1452 }
1453
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001454 /* Turn flow control characters back on if necessary and turn the
David Lawrence Ramsey057edf72005-08-10 21:22:15 +00001455 * keypad back on if necessary now that we're done. */
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001456 if (ISSET(PRESERVE))
1457 enable_flow_control();
Benno Schulenberg103dd062016-07-16 22:11:14 +02001458 /* Use the global window pointers, because a resize may have freed
1459 * the data that the win parameter points to. */
1460 if (!ISSET(REBIND_KEYPAD)) {
1461 keypad(edit, TRUE);
1462 keypad(bottomwin, TRUE);
1463 }
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001464
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001465 return retval;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001466}
1467
David Lawrence Ramsey059c8ef2016-11-18 14:14:36 +01001468/* Read in one control character (or an iTerm/Eterm/rxvt double Escape),
1469 * or convert a series of six digits into a Unicode codepoint. Return
1470 * in count either 1 (for a control character or the first byte of a
1471 * multibyte sequence), or 2 (for an iTerm/Eterm/rxvt double Escape). */
Benno Schulenberg08c51cf2016-07-16 19:44:24 +02001472int *parse_verbatim_kbinput(WINDOW *win, size_t *count)
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001473{
Benno Schulenberg08c51cf2016-07-16 19:44:24 +02001474 int *kbinput;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001475
Benno Schulenberg5806bf52016-08-01 14:05:42 +02001476 /* Read in the first code. */
Benno Schulenberg71c9a522014-05-13 20:14:01 +00001477 while ((kbinput = get_input(win, 1)) == NULL)
1478 ;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001479
Benno Schulenberg68cfb082016-07-25 17:28:54 +02001480#ifndef NANO_TINY
Benno Schulenberg103dd062016-07-16 22:11:14 +02001481 /* When the window was resized, abort and return nothing. */
1482 if (*kbinput == KEY_WINCH) {
Benno Schulenberg103dd062016-07-16 22:11:14 +02001483 free(kbinput);
Benno Schulenberg08c51cf2016-07-16 19:44:24 +02001484 *count = 0;
Benno Schulenberg103dd062016-07-16 22:11:14 +02001485 return NULL;
1486 }
Benno Schulenberg68cfb082016-07-25 17:28:54 +02001487#endif
Benno Schulenberg103dd062016-07-16 22:11:14 +02001488
David Lawrence Ramsey6fb66892006-05-27 17:39:19 +00001489#ifdef ENABLE_UTF8
David Lawrence Ramsey5c7d88d2006-05-28 16:25:15 +00001490 if (using_utf8()) {
Benno Schulenberg5806bf52016-08-01 14:05:42 +02001491 /* Check whether the first code is a valid starter digit: 0 or 1. */
David Lawrence Ramseyfc0ddab2016-07-24 12:34:56 +02001492 long uni = get_unicode_kbinput(win, *kbinput);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001493
Benno Schulenberg5806bf52016-08-01 14:05:42 +02001494 /* If the first code isn't the digit 0 nor 1, put it back. */
David Lawrence Ramsey5c7d88d2006-05-28 16:25:15 +00001495 if (uni != ERR)
1496 unget_input(kbinput, 1);
Benno Schulenberg5806bf52016-08-01 14:05:42 +02001497 /* Otherwise, continue reading in digits until we have a complete
1498 * Unicode value, and put back the corresponding byte(s). */
David Lawrence Ramsey5c7d88d2006-05-28 16:25:15 +00001499 else {
1500 char *uni_mb;
1501 int uni_mb_len, *seq, i;
David Lawrence Ramsey6fb66892006-05-27 17:39:19 +00001502
David Lawrence Ramsey5c7d88d2006-05-28 16:25:15 +00001503 while (uni == ERR) {
Benno Schulenberg1d4c1e02016-07-17 12:00:33 +02001504 free(kbinput);
Benno Schulenberg71c9a522014-05-13 20:14:01 +00001505 while ((kbinput = get_input(win, 1)) == NULL)
1506 ;
David Lawrence Ramseyfc0ddab2016-07-24 12:34:56 +02001507 uni = get_unicode_kbinput(win, *kbinput);
David Lawrence Ramsey5c7d88d2006-05-28 16:25:15 +00001508 }
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00001509
Benno Schulenberg5806bf52016-08-01 14:05:42 +02001510 /* Convert the Unicode value to a multibyte sequence. */
David Lawrence Ramsey5c7d88d2006-05-28 16:25:15 +00001511 uni_mb = make_mbchar(uni, &uni_mb_len);
1512
1513 seq = (int *)nmalloc(uni_mb_len * sizeof(int));
1514
1515 for (i = 0; i < uni_mb_len; i++)
1516 seq[i] = (unsigned char)uni_mb[i];
1517
Benno Schulenberg5806bf52016-08-01 14:05:42 +02001518 /* Insert the multibyte sequence into the input buffer. */
David Lawrence Ramsey5c7d88d2006-05-28 16:25:15 +00001519 unget_input(seq, uni_mb_len);
1520
1521 free(seq);
1522 free(uni_mb);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001523 }
David Lawrence Ramsey5c7d88d2006-05-28 16:25:15 +00001524 } else
David Lawrence Ramseya5b1ca22006-05-28 17:09:49 +00001525#endif /* ENABLE_UTF8 */
Benno Schulenberg5806bf52016-08-01 14:05:42 +02001526 /* Put back the first code. */
David Lawrence Ramsey5c7d88d2006-05-28 16:25:15 +00001527 unget_input(kbinput, 1);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001528
David Lawrence Ramseyad36bdc2006-12-02 17:22:21 +00001529 free(kbinput);
1530
Benno Schulenberg08c51cf2016-07-16 19:44:24 +02001531 *count = 1;
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001532
David Lawrence Ramsey059c8ef2016-11-18 14:14:36 +01001533 /* If this is an iTerm/Eterm/rxvt double escape, take both Escapes. */
Benno Schulenberg08c51cf2016-07-16 19:44:24 +02001534 if (key_buffer_len > 3 && *key_buffer == ESC_CODE &&
1535 key_buffer[1] == ESC_CODE && key_buffer[2] == '[')
1536 *count = 2;
1537
1538 return get_input(NULL, *count);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001539}
1540
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001541#ifndef DISABLE_MOUSE
David Lawrence Ramsey97a6ecb2007-12-08 04:21:15 +00001542/* Handle any mouse event that may have occurred. We currently handle
David Lawrence Ramsey3a504702007-05-29 17:01:12 +00001543 * releases/clicks of the first mouse button. If allow_shortcuts is
1544 * TRUE, releasing/clicking on a visible shortcut will put back the
1545 * keystroke associated with that shortcut. If NCURSES_MOUSE_VERSION is
1546 * at least 2, we also currently handle presses of the fourth mouse
1547 * button (upward rolls of the mouse wheel) by putting back the
1548 * keystrokes to move up, and presses of the fifth mouse button
1549 * (downward rolls of the mouse wheel) by putting back the keystrokes to
David Lawrence Ramsey97a6ecb2007-12-08 04:21:15 +00001550 * move down. We also store the coordinates of a mouse event that needs
1551 * to be handled in mouse_x and mouse_y, relative to the entire screen.
1552 * Return -1 on error, 0 if the mouse event needs to be handled, 1 if
1553 * it's been handled by putting back keystrokes that need to be handled.
1554 * or 2 if it's been ignored. Assume that KEY_MOUSE has already been
1555 * read in. */
David Lawrence Ramsey3a5eaeb2007-05-20 23:41:56 +00001556int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts)
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001557{
1558 MEVENT mevent;
David Lawrence Ramsey97a6ecb2007-12-08 04:21:15 +00001559 bool in_bottomwin;
Chris Allegretta79a33bb2008-03-05 07:34:01 +00001560 subnfunc *f;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001561
1562 *mouse_x = -1;
1563 *mouse_y = -1;
1564
1565 /* First, get the actual mouse event. */
1566 if (getmouse(&mevent) == ERR)
David Lawrence Ramsey3a5eaeb2007-05-20 23:41:56 +00001567 return -1;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001568
David Lawrence Ramsey3a5eaeb2007-05-20 23:41:56 +00001569 /* Save the screen coordinates where the mouse event took place. */
Faissal Bensefiade95ca62016-10-20 09:44:29 +01001570 *mouse_x = mevent.x - margin;
David Lawrence Ramsey3a5eaeb2007-05-20 23:41:56 +00001571 *mouse_y = mevent.y;
David Lawrence Ramsey98e4d4f2006-06-28 21:54:55 +00001572
David Lawrence Ramsey97a6ecb2007-12-08 04:21:15 +00001573 in_bottomwin = wenclose(bottomwin, *mouse_y, *mouse_x);
1574
David Lawrence Ramsey5fcf8bf2007-06-28 18:31:13 +00001575 /* Handle releases/clicks of the first mouse button. */
David Lawrence Ramsey3a504702007-05-29 17:01:12 +00001576 if (mevent.bstate & (BUTTON1_RELEASED | BUTTON1_CLICKED)) {
David Lawrence Ramseyb9fa1b12007-05-15 18:04:25 +00001577 /* If we're allowing shortcuts, the current shortcut list is
1578 * being displayed on the last two lines of the screen, and the
David Lawrence Ramsey3a504702007-05-29 17:01:12 +00001579 * first mouse button was released on/clicked inside it, we need
1580 * to figure out which shortcut was released on/clicked and put
1581 * back the equivalent keystroke(s) for it. */
David Lawrence Ramsey97a6ecb2007-12-08 04:21:15 +00001582 if (allow_shortcuts && !ISSET(NO_HELP) && in_bottomwin) {
David Lawrence Ramseybc653132007-05-22 17:20:28 +00001583 int i;
1584 /* The width of all the shortcuts, except for the last
1585 * two, in the shortcut list in bottomwin. */
1586 int j;
Benno Schulenberg59cd3e62014-05-09 11:44:17 +00001587 /* The calculated index number of the clicked item. */
Benno Schulenbergc05c9142016-08-27 10:12:05 +02001588 size_t number;
1589 /* The number of available shortcuts in the current menu. */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001590
David Lawrence Ramsey97a6ecb2007-12-08 04:21:15 +00001591 /* Translate the mouse event coordinates so that they're
1592 * relative to bottomwin. */
1593 wmouse_trafo(bottomwin, mouse_y, mouse_x, FALSE);
1594
1595 /* Handle releases/clicks of the first mouse button on the
1596 * statusbar elsewhere. */
1597 if (*mouse_y == 0) {
1598 /* Restore the untranslated mouse event coordinates, so
1599 * that they're relative to the entire screen again. */
Faissal Bensefiade95ca62016-10-20 09:44:29 +01001600 *mouse_x = mevent.x - margin;
David Lawrence Ramsey97a6ecb2007-12-08 04:21:15 +00001601 *mouse_y = mevent.y;
1602
1603 return 0;
1604 }
David Lawrence Ramseybc653132007-05-22 17:20:28 +00001605
Benno Schulenbergc19f0c72016-08-27 10:03:34 +02001606 /* Determine how many shortcuts are being shown. */
Benno Schulenbergc05c9142016-08-27 10:12:05 +02001607 number = length_of_list(currmenu);
David Lawrence Ramseyfe0d3662004-08-26 01:43:16 +00001608
Benno Schulenbergc05c9142016-08-27 10:12:05 +02001609 if (number > MAIN_VISIBLE)
1610 number = MAIN_VISIBLE;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001611
David Lawrence Ramseyb9fa1b12007-05-15 18:04:25 +00001612 /* Calculate the width of all of the shortcuts in the list
1613 * except for the last two, which are longer by (COLS % i)
1614 * columns so as to not waste space. */
Benno Schulenbergc05c9142016-08-27 10:12:05 +02001615 if (number < 2)
David Lawrence Ramseyb9fa1b12007-05-15 18:04:25 +00001616 i = COLS / (MAIN_VISIBLE / 2);
1617 else
Benno Schulenbergc05c9142016-08-27 10:12:05 +02001618 i = COLS / ((number / 2) + (number % 2));
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001619
Benno Schulenberg59cd3e62014-05-09 11:44:17 +00001620 /* Calculate the one-based index in the shortcut list. */
1621 j = (*mouse_x / i) * 2 + *mouse_y;
David Lawrence Ramseyb9fa1b12007-05-15 18:04:25 +00001622
Benno Schulenberg59cd3e62014-05-09 11:44:17 +00001623 /* Adjust the index if we hit the last two wider ones. */
Benno Schulenbergc05c9142016-08-27 10:12:05 +02001624 if ((j > number) && (*mouse_x % i < COLS % i))
David Lawrence Ramseyb9fa1b12007-05-15 18:04:25 +00001625 j -= 2;
Benno Schulenberg0d843012014-04-16 08:24:32 +00001626#ifdef DEBUG
1627 fprintf(stderr, "Calculated %i as index in shortcut list, currmenu = %x.\n", j, currmenu);
1628#endif
David Lawrence Ramsey3a504702007-05-29 17:01:12 +00001629 /* Ignore releases/clicks of the first mouse button beyond
1630 * the last shortcut. */
Benno Schulenbergc05c9142016-08-27 10:12:05 +02001631 if (j > number)
David Lawrence Ramsey3a5eaeb2007-05-20 23:41:56 +00001632 return 2;
David Lawrence Ramseyb9fa1b12007-05-15 18:04:25 +00001633
Benno Schulenberg0d843012014-04-16 08:24:32 +00001634 /* Go through the list of functions to determine which
1635 * shortcut in the current menu we released/clicked on. */
Benno Schulenberg59cd3e62014-05-09 11:44:17 +00001636 for (f = allfuncs; f != NULL; f = f->next) {
Benno Schulenberg26de2dd2014-06-27 20:01:27 +00001637 if ((f->menus & currmenu) == 0)
Benno Schulenberg59cd3e62014-05-09 11:44:17 +00001638 continue;
Benno Schulenberg59cd3e62014-05-09 11:44:17 +00001639 if (first_sc_for(currmenu, f->scfunc) == NULL)
Benno Schulenberg26de2dd2014-06-27 20:01:27 +00001640 continue;
Benno Schulenberg59cd3e62014-05-09 11:44:17 +00001641 /* Tick off an actually shown shortcut. */
1642 j -= 1;
Benno Schulenberg0d843012014-04-16 08:24:32 +00001643 if (j == 0)
1644 break;
Chris Allegrettac0b78722008-03-11 04:52:57 +00001645 }
Benno Schulenberg0d843012014-04-16 08:24:32 +00001646#ifdef DEBUG
Benno Schulenberg27a52a82014-04-21 13:07:18 +00001647 fprintf(stderr, "Stopped on func %ld present in menus %x\n", (long)f->scfunc, f->menus);
Benno Schulenberg0d843012014-04-16 08:24:32 +00001648#endif
Chris Allegrettac0b78722008-03-11 04:52:57 +00001649
Benno Schulenberg0d843012014-04-16 08:24:32 +00001650 /* And put the corresponding key into the keyboard buffer. */
Chris Allegretta79a33bb2008-03-05 07:34:01 +00001651 if (f != NULL) {
Benno Schulenberg26de2dd2014-06-27 20:01:27 +00001652 const sc *s = first_sc_for(currmenu, f->scfunc);
Benno Schulenberg1c9ab8b2016-07-24 21:49:07 +02001653 unget_kbinput(s->keycode, s->meta);
David Lawrence Ramseyb9fa1b12007-05-15 18:04:25 +00001654 }
Benno Schulenberga3f421c2014-06-11 18:04:36 +00001655 return 1;
David Lawrence Ramseyb9fa1b12007-05-15 18:04:25 +00001656 } else
David Lawrence Ramsey3a504702007-05-29 17:01:12 +00001657 /* Handle releases/clicks of the first mouse button that
1658 * aren't on the current shortcut list elsewhere. */
David Lawrence Ramsey3a5eaeb2007-05-20 23:41:56 +00001659 return 0;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001660 }
David Lawrence Ramseyb9fa1b12007-05-15 18:04:25 +00001661#if NCURSES_MOUSE_VERSION >= 2
1662 /* Handle presses of the fourth mouse button (upward rolls of the
David Lawrence Ramsey3a5eaeb2007-05-20 23:41:56 +00001663 * mouse wheel) and presses of the fifth mouse button (downward
1664 * rolls of the mouse wheel) . */
1665 else if (mevent.bstate & (BUTTON4_PRESSED | BUTTON5_PRESSED)) {
David Lawrence Ramseydef60912007-12-08 16:59:13 +00001666 bool in_edit = wenclose(edit, *mouse_y, *mouse_x);
David Lawrence Ramseybc653132007-05-22 17:20:28 +00001667
David Lawrence Ramsey97a6ecb2007-12-08 04:21:15 +00001668 if (in_bottomwin)
1669 /* Translate the mouse event coordinates so that they're
1670 * relative to bottomwin. */
1671 wmouse_trafo(bottomwin, mouse_y, mouse_x, FALSE);
David Lawrence Ramseyb9fa1b12007-05-15 18:04:25 +00001672
David Lawrence Ramsey97a6ecb2007-12-08 04:21:15 +00001673 if (in_edit || (in_bottomwin && *mouse_y == 0)) {
David Lawrence Ramseydef60912007-12-08 16:59:13 +00001674 int i;
1675
David Lawrence Ramsey3a5eaeb2007-05-20 23:41:56 +00001676 /* One upward roll of the mouse wheel is equivalent to
1677 * moving up three lines, and one downward roll of the mouse
1678 * wheel is equivalent to moving down three lines. */
1679 for (i = 0; i < 3; i++)
1680 unget_kbinput((mevent.bstate & BUTTON4_PRESSED) ?
Benno Schulenberg91951ab2016-07-23 14:01:38 +02001681 KEY_PPAGE : KEY_NPAGE, FALSE);
David Lawrence Ramseyb9fa1b12007-05-15 18:04:25 +00001682
David Lawrence Ramsey3a5eaeb2007-05-20 23:41:56 +00001683 return 1;
1684 } else
1685 /* Ignore presses of the fourth mouse button and presses of
1686 * the fifth mouse buttons that aren't on the edit window or
1687 * the statusbar. */
1688 return 2;
David Lawrence Ramseyb9fa1b12007-05-15 18:04:25 +00001689 }
1690#endif
David Lawrence Ramseyc8bde572007-06-28 16:38:00 +00001691
1692 /* Ignore all other mouse events. */
1693 return 2;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001694}
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00001695#endif /* !DISABLE_MOUSE */
1696
Benno Schulenberg7828a802014-04-14 09:22:29 +00001697/* Return the shortcut that corresponds to the values of kbinput (the
1698 * key itself) and meta_key (whether the key is a meta sequence). The
1699 * returned shortcut will be the first in the list that corresponds to
1700 * the given sequence. */
Benno Schulenberg49816fe2014-07-01 10:41:10 +00001701const sc *get_shortcut(int *kbinput)
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00001702{
Chris Allegretta79a33bb2008-03-05 07:34:01 +00001703 sc *s;
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00001704
David Lawrence Ramsey08eab722004-11-27 06:43:06 +00001705#ifdef DEBUG
Benno Schulenberg73a07212016-07-18 12:44:34 +02001706 fprintf(stderr, "get_shortcut(): kbinput = %d, meta_key = %s -- ",
1707 *kbinput, meta_key ? "TRUE" : "FALSE");
David Lawrence Ramsey08eab722004-11-27 06:43:06 +00001708#endif
1709
Chris Allegretta79a33bb2008-03-05 07:34:01 +00001710 for (s = sclist; s != NULL; s = s->next) {
Benno Schulenberg1c9ab8b2016-07-24 21:49:07 +02001711 if ((s->menus & currmenu) && *kbinput == s->keycode &&
Benno Schulenberge2950702016-07-23 14:42:40 +02001712 meta_key == s->meta) {
Chris Allegretta79a33bb2008-03-05 07:34:01 +00001713#ifdef DEBUG
Benno Schulenberg73a07212016-07-18 12:44:34 +02001714 fprintf (stderr, "matched seq '%s' (menu is %x from %x)\n",
1715 s->keystr, currmenu, s->menus);
Chris Allegretta79a33bb2008-03-05 07:34:01 +00001716#endif
David Lawrence Ramseyf4a799a2005-01-08 06:16:19 +00001717 return s;
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00001718 }
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00001719 }
Chris Allegretta79a33bb2008-03-05 07:34:01 +00001720#ifdef DEBUG
Benno Schulenberg73a07212016-07-18 12:44:34 +02001721 fprintf (stderr, "matched nothing\n");
Chris Allegretta79a33bb2008-03-05 07:34:01 +00001722#endif
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00001723
1724 return NULL;
1725}
1726
David Lawrence Ramseyb386a902005-07-10 02:37:38 +00001727/* Move to (x, y) in win, and display a line of n spaces with the
1728 * current attributes. */
Benno Schulenbergf7d320d2017-01-12 17:48:33 +01001729void blank_row(WINDOW *win, int y, int x, int n)
David Lawrence Ramseyb386a902005-07-10 02:37:38 +00001730{
1731 wmove(win, y, x);
David Lawrence Ramseyb94d51a2007-04-19 03:15:04 +00001732
David Lawrence Ramseyb386a902005-07-10 02:37:38 +00001733 for (; n > 0; n--)
1734 waddch(win, ' ');
1735}
1736
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001737/* Blank the first line of the top portion of the window. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001738void blank_titlebar(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001739{
Benno Schulenbergf7d320d2017-01-12 17:48:33 +01001740 blank_row(topwin, 0, 0, COLS);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001741}
1742
David Lawrence Ramseyb159f942006-07-28 17:06:27 +00001743/* Blank all the lines of the middle portion of the window, i.e. the
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001744 * edit window. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001745void blank_edit(void)
1746{
Benno Schulenbergf7d320d2017-01-12 17:48:33 +01001747 int row;
David Lawrence Ramseyb94d51a2007-04-19 03:15:04 +00001748
Benno Schulenbergf7d320d2017-01-12 17:48:33 +01001749 for (row = 0; row < editwinrows; row++)
1750 blank_row(edit, row, 0, COLS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001751}
1752
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001753/* Blank the first line of the bottom portion of the window. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001754void blank_statusbar(void)
1755{
Benno Schulenbergf7d320d2017-01-12 17:48:33 +01001756 blank_row(bottomwin, 0, 0, COLS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001757}
1758
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001759/* If the NO_HELP flag isn't set, blank the last two lines of the bottom
1760 * portion of the window. */
David Lawrence Ramseyb9ddb802005-03-17 17:56:48 +00001761void blank_bottombars(void)
1762{
Benno Schulenberg76a960d2016-08-15 19:44:49 +02001763 if (!ISSET(NO_HELP) && LINES > 4) {
Benno Schulenbergf7d320d2017-01-12 17:48:33 +01001764 blank_row(bottomwin, 1, 0, COLS);
1765 blank_row(bottomwin, 2, 0, COLS);
David Lawrence Ramseyb9ddb802005-03-17 17:56:48 +00001766 }
1767}
1768
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001769/* Check if the number of keystrokes needed to blank the statusbar has
1770 * been pressed. If so, blank the statusbar, unless constant cursor
Benno Schulenberg25035032016-05-15 11:36:51 +02001771 * position display is on and we are in the editing screen. */
David Lawrence Ramseye5d8f322004-09-30 22:07:21 +00001772void check_statusblank(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001773{
Benno Schulenberg25035032016-05-15 11:36:51 +02001774 if (statusblank == 0)
1775 return;
David Lawrence Ramseybf51aa42005-06-17 21:52:59 +00001776
Benno Schulenberg25035032016-05-15 11:36:51 +02001777 statusblank--;
1778
1779 /* When editing and 'constantshow' is active, skip the blanking. */
1780 if (currmenu == MMAIN && ISSET(CONST_UPDATE))
1781 return;
1782
1783 if (statusblank == 0) {
1784 blank_statusbar();
1785 wnoutrefresh(bottomwin);
1786 reset_cursor();
1787 wnoutrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001788 }
Benno Schulenberg76a960d2016-08-15 19:44:49 +02001789
1790 /* If the subwindows overlap, make sure to show the edit window now. */
1791 if (LINES == 1)
1792 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001793}
1794
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001795/* Convert buf into a string that can be displayed on screen. The
1796 * caller wants to display buf starting with column start_col, and
Benno Schulenberga37cd9f2016-06-14 19:56:16 +02001797 * extending for at most span columns. start_col is zero-based. span
1798 * is one-based, so span == 0 means you get "" returned. The returned
Benno Schulenbergeafae5d2016-12-18 09:40:09 +01001799 * string is dynamically allocated, and should be freed. If isdata is
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001800 * TRUE, the caller might put "$" at the beginning or end of the line if
1801 * it's too long. */
Benno Schulenberga37cd9f2016-06-14 19:56:16 +02001802char *display_string(const char *buf, size_t start_col, size_t span,
Benno Schulenbergeafae5d2016-12-18 09:40:09 +01001803 bool isdata)
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001804{
1805 size_t start_index;
David Lawrence Ramsey61a71402004-12-24 15:45:36 +00001806 /* Index in buf of the first character shown. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001807 size_t column;
David Lawrence Ramsey61a71402004-12-24 15:45:36 +00001808 /* Screen column that start_index corresponds to. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001809 char *converted;
1810 /* The string we return. */
1811 size_t index;
1812 /* Current position in converted. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001813
Benno Schulenbergeafae5d2016-12-18 09:40:09 +01001814 /* If this is data, make room for the "$" at the end of the line. */
1815 if (isdata && !ISSET(SOFTWRAP) && strlenpt(buf) > start_col + span)
Benno Schulenberga37cd9f2016-06-14 19:56:16 +02001816 span--;
David Lawrence Ramsey9dffac92005-01-05 06:09:34 +00001817
Benno Schulenberga37cd9f2016-06-14 19:56:16 +02001818 if (span == 0)
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001819 return mallocstrcpy(NULL, "");
1820
1821 start_index = actual_x(buf, start_col);
1822 column = strnlenpt(buf, start_index);
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001823
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001824 assert(column <= start_col);
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001825
Benno Schulenbergcf0eed62016-06-05 12:53:02 +02001826 /* Allocate enough space to hold the entire converted buffer. */
1827 converted = charalloc(strlen(buf) * (mb_cur_max() + tabsize) + 1);
David Lawrence Ramseybbd63e12005-01-05 16:59:49 +00001828
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001829 index = 0;
Benno Schulenberg8c7a3852016-07-12 21:05:09 +02001830#ifdef USING_OLD_NCURSES
Benno Schulenberg954d04b2015-09-05 09:14:24 +00001831 seen_wide = FALSE;
Benno Schulenberg8c7a3852016-07-12 21:05:09 +02001832#endif
Benno Schulenbergd6f43bd2016-06-05 21:10:07 +02001833 buf += start_index;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001834
Benno Schulenberg407f2d52017-02-17 12:01:25 +01001835 /* If the first character starts before the left edge, or would be
1836 * overwritten by a "$" token, then show spaces instead. */
1837 if (*buf != '\0' && *buf != '\t' && (column < start_col ||
1838 (column > 0 && isdata && !ISSET(SOFTWRAP)))) {
Benno Schulenbergd6f43bd2016-06-05 21:10:07 +02001839 if (is_cntrl_mbchar(buf)) {
David Lawrence Ramseyfe3627d2004-12-24 17:52:17 +00001840 if (column < start_col) {
Benno Schulenbergeafae5d2016-12-18 09:40:09 +01001841 converted[index++] = control_mbrep(buf, isdata);
Benno Schulenberg622995f2016-06-29 20:37:28 +02001842 start_col++;
Benno Schulenbergd6f43bd2016-06-05 21:10:07 +02001843 buf += parse_mbchar(buf, NULL, NULL);
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001844 }
David Lawrence Ramsey956da0d2005-01-03 06:56:38 +00001845 }
David Lawrence Ramsey7eb30a82005-07-17 02:40:07 +00001846#ifdef ENABLE_UTF8
Benno Schulenbergd6f43bd2016-06-05 21:10:07 +02001847 else if (using_utf8() && mbwidth(buf) == 2) {
David Lawrence Ramseyd99b0e12006-05-19 17:50:01 +00001848 if (column >= start_col) {
1849 converted[index++] = ' ';
1850 start_col++;
1851 }
1852
David Lawrence Ramsey9dffac92005-01-05 06:09:34 +00001853 converted[index++] = ' ';
David Lawrence Ramseya9b99132004-12-27 23:35:25 +00001854 start_col++;
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001855
Benno Schulenbergd6f43bd2016-06-05 21:10:07 +02001856 buf += parse_mbchar(buf, NULL, NULL);
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001857 }
David Lawrence Ramsey956da0d2005-01-03 06:56:38 +00001858#endif
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001859 }
1860
Benno Schulenbergd6f43bd2016-06-05 21:10:07 +02001861 while (*buf != '\0') {
Benno Schulenberge33a0b62016-06-06 13:20:04 +02001862 int charlength, charwidth = 1;
Benno Schulenberg08945872016-06-06 12:48:26 +02001863
Benno Schulenbergd6f43bd2016-06-05 21:10:07 +02001864 if (*buf == ' ') {
Benno Schulenberg3ac37642016-05-30 10:41:11 +02001865 /* Show a space as a visible character, or as a space. */
1866#ifndef NANO_TINY
1867 if (ISSET(WHITESPACE_DISPLAY)) {
1868 int i = whitespace_len[0];
1869
1870 while (i < whitespace_len[0] + whitespace_len[1])
1871 converted[index++] = whitespace[i++];
1872 } else
1873#endif
1874 converted[index++] = ' ';
1875 start_col++;
Benno Schulenberg08945872016-06-06 12:48:26 +02001876 buf++;
1877 continue;
Benno Schulenbergd6f43bd2016-06-05 21:10:07 +02001878 } else if (*buf == '\t') {
Benno Schulenberg5864d972016-05-30 10:45:46 +02001879 /* Show a tab as a visible character, or as as a space. */
Benno Schulenberg90798fb2015-08-09 16:05:50 +00001880#ifndef NANO_TINY
David Lawrence Ramsey6e60db62005-03-10 22:52:21 +00001881 if (ISSET(WHITESPACE_DISPLAY)) {
Benno Schulenberg5864d972016-05-30 10:45:46 +02001882 int i = 0;
David Lawrence Ramsey6e60db62005-03-10 22:52:21 +00001883
Benno Schulenberg5864d972016-05-30 10:45:46 +02001884 while (i < whitespace_len[0])
1885 converted[index++] = whitespace[i++];
David Lawrence Ramsey6e60db62005-03-10 22:52:21 +00001886 } else
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00001887#endif
David Lawrence Ramseyb94d51a2007-04-19 03:15:04 +00001888 converted[index++] = ' ';
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001889 start_col++;
Benno Schulenberg5864d972016-05-30 10:45:46 +02001890 /* Fill the tab up with the required number of spaces. */
David Lawrence Ramseyc1958202004-12-27 23:21:34 +00001891 while (start_col % tabsize != 0) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001892 converted[index++] = ' ';
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001893 start_col++;
1894 }
Benno Schulenberg08945872016-06-06 12:48:26 +02001895 buf++;
1896 continue;
1897 }
1898
Benno Schulenberge33a0b62016-06-06 13:20:04 +02001899 charlength = length_of_char(buf, &charwidth);
Benno Schulenberg08945872016-06-06 12:48:26 +02001900
Benno Schulenberg622995f2016-06-29 20:37:28 +02001901 /* If buf contains a control character, represent it. */
Benno Schulenberg08945872016-06-06 12:48:26 +02001902 if (is_cntrl_mbchar(buf)) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001903 converted[index++] = '^';
Benno Schulenbergeafae5d2016-12-18 09:40:09 +01001904 converted[index++] = control_mbrep(buf, isdata);
Benno Schulenberg622995f2016-06-29 20:37:28 +02001905 start_col += 2;
Benno Schulenberg08945872016-06-06 12:48:26 +02001906 buf += charlength;
1907 continue;
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001908 }
1909
Benno Schulenberg08945872016-06-06 12:48:26 +02001910 /* If buf contains a valid non-control character, simply copy it. */
1911 if (charlength > 0) {
Benno Schulenberg08945872016-06-06 12:48:26 +02001912 for (; charlength > 0; charlength--)
1913 converted[index++] = *(buf++);
1914
Benno Schulenberge33a0b62016-06-06 13:20:04 +02001915 start_col += charwidth;
Benno Schulenberg8c7a3852016-07-12 21:05:09 +02001916#ifdef USING_OLD_NCURSES
Benno Schulenberge33a0b62016-06-06 13:20:04 +02001917 if (charwidth > 1)
Benno Schulenberg08945872016-06-06 12:48:26 +02001918 seen_wide = TRUE;
Benno Schulenberg8c7a3852016-07-12 21:05:09 +02001919#endif
Benno Schulenberg08945872016-06-06 12:48:26 +02001920 continue;
1921 }
1922
1923 /* Represent an invalid sequence with the Replacement Character. */
1924 converted[index++] = '\xEF';
1925 converted[index++] = '\xBF';
1926 converted[index++] = '\xBD';
1927
1928 start_col += 1;
1929 buf++;
1930
1931 /* For invalid codepoints, skip extra bytes. */
1932 if (charlength < -1)
1933 buf += charlength + 7;
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001934 }
1935
David Lawrence Ramseye54f1c42006-10-29 21:14:53 +00001936 /* Null-terminate converted. */
David Lawrence Ramsey114cfb62006-02-03 03:58:49 +00001937 converted[index] = '\0';
David Lawrence Ramsey0251bdb2005-01-05 19:05:04 +00001938
Benno Schulenberga37cd9f2016-06-14 19:56:16 +02001939 /* Make sure converted takes up no more than span columns. */
1940 index = actual_x(converted, span);
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001941 null_at(&converted, index);
David Lawrence Ramsey0251bdb2005-01-05 19:05:04 +00001942
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001943 return converted;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001944}
1945
David Lawrence Ramsey4ea2eac2006-07-09 00:52:16 +00001946/* If path is NULL, we're in normal editing mode, so display the current
1947 * version of nano, the current filename, and whether the current file
1948 * has been modified on the titlebar. If path isn't NULL, we're in the
1949 * file browser, and path contains the directory to start the file
1950 * browser in, so display the current version of nano and the contents
1951 * of path on the titlebar. */
Chris Allegrettaf717f982003-02-13 22:25:01 +00001952void titlebar(const char *path)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001953{
Benno Schulenberg577f7fa2016-04-29 10:42:20 +02001954 size_t verlen, prefixlen, pathlen, statelen;
1955 /* The width of the different titlebar elements, in columns. */
1956 size_t pluglen = 0;
1957 /* The width that "Modified" would take up. */
1958 size_t offset = 0;
1959 /* The position at which the center part of the titlebar starts. */
1960 const char *prefix = "";
1961 /* What is shown before the path -- "File:", "DIR:", or "". */
1962 const char *state = "";
1963 /* The state of the current buffer -- "Modified", "View", or "". */
Benno Schulenbergdfff78d2016-12-17 21:54:36 +01001964 char *caption;
1965 /* The presentable form of the pathname. */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001966
Benno Schulenberg76a960d2016-08-15 19:44:49 +02001967 /* If the screen is too small, there is no titlebar. */
1968 if (topwin == NULL)
1969 return;
1970
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +00001971 assert(path != NULL || openfile->filename != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001972
Benno Schulenberg960e8482016-07-12 09:35:48 +02001973 wattron(topwin, interface_color_pair[TITLE_BAR]);
David Lawrence Ramsey85ffaee2006-07-02 18:29:49 +00001974
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001975 blank_titlebar();
Benno Schulenbergeef7d102016-12-20 19:27:41 +01001976 as_an_at = FALSE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001977
Benno Schulenberg577f7fa2016-04-29 10:42:20 +02001978 /* Do as Pico: if there is not enough width available for all items,
1979 * first sacrifice the version string, then eat up the side spaces,
1980 * then sacrifice the prefix, and only then start dottifying. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001981
Benno Schulenberg577f7fa2016-04-29 10:42:20 +02001982 /* Figure out the path, prefix and state strings. */
David Lawrence Ramseyb386a902005-07-10 02:37:38 +00001983#ifndef DISABLE_BROWSER
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001984 if (path != NULL)
1985 prefix = _("DIR:");
1986 else
1987#endif
Benno Schulenberg577f7fa2016-04-29 10:42:20 +02001988 {
1989 if (openfile->filename[0] == '\0')
1990 path = _("New Buffer");
David Lawrence Ramseyb386a902005-07-10 02:37:38 +00001991 else {
Benno Schulenberg577f7fa2016-04-29 10:42:20 +02001992 path = openfile->filename;
1993 prefix = _("File:");
1994 }
David Lawrence Ramseycb4f14b2005-03-24 22:28:25 +00001995
Benno Schulenberg577f7fa2016-04-29 10:42:20 +02001996 if (openfile->modified)
1997 state = _("Modified");
1998 else if (ISSET(VIEW_MODE))
1999 state = _("View");
2000
2001 pluglen = strlenpt(_("Modified")) + 1;
2002 }
2003
2004 /* Determine the widths of the four elements, including their padding. */
2005 verlen = strlenpt(BRANDING) + 3;
2006 prefixlen = strlenpt(prefix);
2007 if (prefixlen > 0)
2008 prefixlen++;
2009 pathlen= strlenpt(path);
2010 statelen = strlenpt(state) + 2;
2011 if (statelen > 2) {
2012 pathlen++;
2013 pluglen = 0;
2014 }
2015
2016 /* Only print the version message when there is room for it. */
2017 if (verlen + prefixlen + pathlen + pluglen + statelen <= COLS)
2018 mvwaddstr(topwin, 0, 2, BRANDING);
2019 else {
2020 verlen = 2;
2021 /* If things don't fit yet, give up the placeholder. */
2022 if (verlen + prefixlen + pathlen + pluglen + statelen > COLS)
2023 pluglen = 0;
2024 /* If things still don't fit, give up the side spaces. */
2025 if (verlen + prefixlen + pathlen + pluglen + statelen > COLS) {
2026 verlen = 0;
2027 statelen -= 2;
David Lawrence Ramseyb386a902005-07-10 02:37:38 +00002028 }
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002029 }
Chris Allegretta8ce24132001-04-30 11:28:46 +00002030
Benno Schulenberg577f7fa2016-04-29 10:42:20 +02002031 /* If we have side spaces left, center the path name. */
2032 if (verlen > 0)
2033 offset = verlen + (COLS - (verlen + pluglen + statelen) -
2034 (prefixlen + pathlen)) / 2;
2035
2036 /* Only print the prefix when there is room for it. */
2037 if (verlen + prefixlen + pathlen + pluglen + statelen <= COLS) {
2038 mvwaddstr(topwin, 0, offset, prefix);
2039 if (prefixlen > 0)
2040 waddstr(topwin, " ");
2041 } else
2042 wmove(topwin, 0, offset);
2043
2044 /* Print the full path if there's room; otherwise, dottify it. */
Benno Schulenbergdfff78d2016-12-17 21:54:36 +01002045 if (pathlen + pluglen + statelen <= COLS) {
2046 caption = display_string(path, 0, pathlen, FALSE);
2047 waddstr(topwin, caption);
2048 free(caption);
2049 } else if (5 + statelen <= COLS) {
Benno Schulenberg577f7fa2016-04-29 10:42:20 +02002050 waddstr(topwin, "...");
Benno Schulenbergdfff78d2016-12-17 21:54:36 +01002051 caption = display_string(path, 3 + pathlen - COLS + statelen,
Benno Schulenberg577f7fa2016-04-29 10:42:20 +02002052 COLS - statelen, FALSE);
Benno Schulenbergdfff78d2016-12-17 21:54:36 +01002053 waddstr(topwin, caption);
2054 free(caption);
Benno Schulenberg577f7fa2016-04-29 10:42:20 +02002055 }
2056
2057 /* Right-align the state if there's room; otherwise, trim it. */
2058 if (statelen > 0 && statelen <= COLS)
2059 mvwaddstr(topwin, 0, COLS - statelen, state);
2060 else if (statelen > 0)
2061 mvwaddnstr(topwin, 0, 0, state, actual_x(state, COLS));
2062
Benno Schulenberg960e8482016-07-12 09:35:48 +02002063 wattroff(topwin, interface_color_pair[TITLE_BAR]);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002064
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002065 wnoutrefresh(topwin);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002066 reset_cursor();
David Lawrence Ramsey6d8e4952005-07-26 14:42:57 +00002067 wnoutrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002068}
2069
Benno Schulenberg2535f512016-04-30 17:31:43 +02002070/* Display a normal message on the statusbar, quietly. */
2071void statusbar(const char *msg)
2072{
2073 statusline(HUSH, msg);
2074}
2075
David Lawrence Ramseye4d45242016-11-27 15:01:54 -06002076/* Warn the user on the statusbar and pause for a moment, so that the
2077 * message can be noticed and read. */
2078void warn_and_shortly_pause(const char *msg)
2079{
2080 statusbar(msg);
2081 beep();
2082 napms(1800);
David Lawrence Ramseye4d45242016-11-27 15:01:54 -06002083}
2084
Benno Schulenberg9d6d5b62016-05-04 12:18:21 +02002085/* Display a message on the statusbar, and set suppress_cursorpos to
David Lawrence Ramsey5593e202005-06-28 19:49:15 +00002086 * TRUE, so that the message won't be immediately overwritten if
2087 * constant cursor position display is on. */
Benno Schulenbergc8f530a2016-05-19 20:43:08 +02002088void statusline(message_type importance, const char *msg, ...)
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002089{
2090 va_list ap;
Benno Schulenberg23c3fd92017-02-21 12:57:11 +01002091 static int alerts = 0;
Benno Schulenberg21cb01e2016-08-22 10:50:51 +02002092 char *compound, *message;
Benno Schulenberg8f21d252017-01-08 12:05:42 +01002093 size_t start_col;
Benno Schulenbergea9aaee2016-08-15 22:25:52 +02002094 bool bracketed;
Benno Schulenberg90798fb2015-08-09 16:05:50 +00002095#ifndef NANO_TINY
2096 bool old_whitespace = ISSET(WHITESPACE_DISPLAY);
2097
2098 UNSET(WHITESPACE_DISPLAY);
David Lawrence Ramsey874703b2005-10-27 03:35:42 +00002099#endif
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002100
2101 va_start(ap, msg);
2102
2103 /* Curses mode is turned off. If we use wmove() now, it will muck
2104 * up the terminal settings. So we just use vfprintf(). */
David Lawrence Ramseyf70f67b2006-06-03 17:31:52 +00002105 if (isendwin()) {
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002106 vfprintf(stderr, msg, ap);
2107 va_end(ap);
2108 return;
2109 }
2110
Benno Schulenbergc8f530a2016-05-19 20:43:08 +02002111 /* If there already was an alert message, ignore lesser ones. */
2112 if ((lastmessage == ALERT && importance != ALERT) ||
2113 (lastmessage == MILD && importance == HUSH))
2114 return;
Benno Schulenberg2535f512016-04-30 17:31:43 +02002115
Benno Schulenberg23c3fd92017-02-21 12:57:11 +01002116 /* If the ALERT status has been reset, reset the counter. */
2117 if (lastmessage == HUSH)
2118 alerts = 0;
2119
2120 /* Shortly pause after each of the first three alert messages,
2121 * to give the user time to read them. */
2122 if (lastmessage == ALERT && alerts < 4)
Benno Schulenbergc8f530a2016-05-19 20:43:08 +02002123 napms(1200);
2124
Benno Schulenberg23c3fd92017-02-21 12:57:11 +01002125 if (importance == ALERT) {
2126 if (++alerts > 3)
2127 msg = "Some warnings were suppressed";
Benno Schulenberg2535f512016-04-30 17:31:43 +02002128 beep();
Benno Schulenberg23c3fd92017-02-21 12:57:11 +01002129 }
Benno Schulenbergc8f530a2016-05-19 20:43:08 +02002130
2131 lastmessage = importance;
Benno Schulenberg2535f512016-04-30 17:31:43 +02002132
Benno Schulenberg97dcd372016-02-06 11:18:27 +00002133 /* Turn the cursor off while fiddling in the statusbar. */
2134 curs_set(0);
2135
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002136 blank_statusbar();
2137
Benno Schulenberg21cb01e2016-08-22 10:50:51 +02002138 /* Construct the message out of all the arguments. */
2139 compound = charalloc(mb_cur_max() * (COLS + 1));
2140 vsnprintf(compound, mb_cur_max() * (COLS + 1), msg, ap);
David Lawrence Ramsey874703b2005-10-27 03:35:42 +00002141 va_end(ap);
Benno Schulenberg21cb01e2016-08-22 10:50:51 +02002142 message = display_string(compound, 0, COLS, FALSE);
2143 free(compound);
Benno Schulenberg90798fb2015-08-09 16:05:50 +00002144
Benno Schulenberg8f21d252017-01-08 12:05:42 +01002145 start_col = (COLS - strlenpt(message)) / 2;
2146 bracketed = (start_col > 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002147
Benno Schulenberg8f21d252017-01-08 12:05:42 +01002148 wmove(bottomwin, 0, (bracketed ? start_col - 2 : start_col));
Benno Schulenberg960e8482016-07-12 09:35:48 +02002149 wattron(bottomwin, interface_color_pair[STATUS_BAR]);
Benno Schulenbergea9aaee2016-08-15 22:25:52 +02002150 if (bracketed)
2151 waddstr(bottomwin, "[ ");
Benno Schulenberg21cb01e2016-08-22 10:50:51 +02002152 waddstr(bottomwin, message);
2153 free(message);
Benno Schulenbergea9aaee2016-08-15 22:25:52 +02002154 if (bracketed)
2155 waddstr(bottomwin, " ]");
Benno Schulenberg960e8482016-07-12 09:35:48 +02002156 wattroff(bottomwin, interface_color_pair[STATUS_BAR]);
Benno Schulenbergf5eb3162016-02-23 12:37:10 +00002157
Benno Schulenberge0e788e2016-05-23 21:34:02 +02002158 /* Push the message to the screen straightaway. */
David Lawrence Ramsey874703b2005-10-27 03:35:42 +00002159 wnoutrefresh(bottomwin);
Benno Schulenberge0e788e2016-05-23 21:34:02 +02002160 doupdate();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002161
Benno Schulenberg9d6d5b62016-05-04 12:18:21 +02002162 suppress_cursorpos = TRUE;
David Lawrence Ramseyc6618532005-06-17 22:33:15 +00002163
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002164#ifndef NANO_TINY
Benno Schulenberg21cb01e2016-08-22 10:50:51 +02002165 if (old_whitespace)
2166 SET(WHITESPACE_DISPLAY);
2167
2168 /* If doing quick blanking, blank the statusbar after just one keystroke.
2169 * Otherwise, blank it after twenty-six keystrokes, as Pico does. */
Benno Schulenberg681f0422016-05-15 10:57:25 +02002170 if (ISSET(QUICK_BLANK))
2171 statusblank = 1;
2172 else
David Lawrence Ramseye29111f2005-06-17 19:06:25 +00002173#endif
Benno Schulenberg681f0422016-05-15 10:57:25 +02002174 statusblank = 26;
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002175}
2176
Benno Schulenbergf2da4662015-12-04 21:11:10 +00002177/* Display the shortcut list corresponding to menu on the last two rows
2178 * of the bottom portion of the window. */
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002179void bottombars(int menu)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002180{
Benno Schulenbergc05c9142016-08-27 10:12:05 +02002181 size_t number, itemwidth, i;
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002182 subnfunc *f;
2183 const sc *s;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002184
Benno Schulenbergd8b6dbf2015-04-07 14:16:07 +00002185 /* Set the global variable to the given menu. */
2186 currmenu = menu;
2187
Benno Schulenberg76a960d2016-08-15 19:44:49 +02002188 if (ISSET(NO_HELP) || LINES < 5)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002189 return;
2190
Benno Schulenbergc19f0c72016-08-27 10:03:34 +02002191 /* Determine how many shortcuts there are to show. */
Benno Schulenbergc05c9142016-08-27 10:12:05 +02002192 number = length_of_list(menu);
Benno Schulenbergc19f0c72016-08-27 10:03:34 +02002193
Benno Schulenbergc05c9142016-08-27 10:12:05 +02002194 if (number > MAIN_VISIBLE)
2195 number = MAIN_VISIBLE;
David Lawrence Ramsey31b159c2005-05-26 05:17:13 +00002196
Benno Schulenberg0dd2a552016-08-15 12:55:03 +02002197 /* Compute the width of each keyname-plus-explanation pair. */
Benno Schulenbergc05c9142016-08-27 10:12:05 +02002198 itemwidth = COLS / ((number / 2) + (number % 2));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002199
Benno Schulenberg0dd2a552016-08-15 12:55:03 +02002200 /* If there is no room, don't print anything. */
Benno Schulenbergc05c9142016-08-27 10:12:05 +02002201 if (itemwidth == 0)
Benno Schulenberg0dd2a552016-08-15 12:55:03 +02002202 return;
2203
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002204 blank_bottombars();
Chris Allegretta658399a2001-06-14 02:54:22 +00002205
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002206#ifdef DEBUG
Benno Schulenbergc05c9142016-08-27 10:12:05 +02002207 fprintf(stderr, "In bottombars, number of items == \"%d\"\n", (int) number);
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002208#endif
Chris Allegretta658399a2001-06-14 02:54:22 +00002209
Benno Schulenbergc05c9142016-08-27 10:12:05 +02002210 for (f = allfuncs, i = 0; i < number && f != NULL; f = f->next) {
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002211#ifdef DEBUG
Benno Schulenberg26de2dd2014-06-27 20:01:27 +00002212 fprintf(stderr, "Checking menu items....");
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002213#endif
Benno Schulenberg26de2dd2014-06-27 20:01:27 +00002214 if ((f->menus & menu) == 0)
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002215 continue;
David Lawrence Ramsey0ff01a92004-10-25 15:00:38 +00002216
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002217#ifdef DEBUG
Benno Schulenberg26de2dd2014-06-27 20:01:27 +00002218 fprintf(stderr, "found one! f->menus = %x, desc = \"%s\"\n", f->menus, f->desc);
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002219#endif
Benno Schulenberg26de2dd2014-06-27 20:01:27 +00002220 s = first_sc_for(menu, f->scfunc);
2221 if (s == NULL) {
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002222#ifdef DEBUG
2223 fprintf(stderr, "Whoops, guess not, no shortcut key found for func!\n");
2224#endif
Benno Schulenberg26de2dd2014-06-27 20:01:27 +00002225 continue;
2226 }
Benno Schulenbergc05c9142016-08-27 10:12:05 +02002227
2228 wmove(bottomwin, 1 + i % 2, (i / 2) * itemwidth);
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002229#ifdef DEBUG
Benno Schulenberg26de2dd2014-06-27 20:01:27 +00002230 fprintf(stderr, "Calling onekey with keystr \"%s\" and desc \"%s\"\n", s->keystr, f->desc);
Chris Allegretta79a33bb2008-03-05 07:34:01 +00002231#endif
Benno Schulenbergc05c9142016-08-27 10:12:05 +02002232 onekey(s->keystr, _(f->desc), itemwidth + (COLS % itemwidth));
Benno Schulenberg26de2dd2014-06-27 20:01:27 +00002233 i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002234 }
2235
Benno Schulenberg0a18d892016-10-12 13:56:48 +02002236 /* Defeat a VTE bug by moving the cursor and forcing a screen update. */
2237 wmove(bottomwin, 0, 0);
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002238 wnoutrefresh(bottomwin);
Benno Schulenberg0a18d892016-10-12 13:56:48 +02002239 doupdate();
2240
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002241 reset_cursor();
David Lawrence Ramsey6d8e4952005-07-26 14:42:57 +00002242 wnoutrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002243}
2244
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002245/* Write a shortcut key to the help area at the bottom of the window.
2246 * keystroke is e.g. "^G" and desc is e.g. "Get Help". We are careful
Benno Schulenberg7f3dc2d2016-03-23 20:21:36 +00002247 * to write at most length characters, even if length is very small and
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002248 * keystroke and desc are long. Note that waddnstr(,,(size_t)-1) adds
2249 * the whole string! We do not bother padding the entry with blanks. */
Benno Schulenberg7f3dc2d2016-03-23 20:21:36 +00002250void onekey(const char *keystroke, const char *desc, int length)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002251{
David Lawrence Ramsey12054fe2005-01-07 22:37:01 +00002252 assert(keystroke != NULL && desc != NULL);
2253
Benno Schulenberg960e8482016-07-12 09:35:48 +02002254 wattron(bottomwin, interface_color_pair[KEY_COMBO]);
Benno Schulenberg7f3dc2d2016-03-23 20:21:36 +00002255 waddnstr(bottomwin, keystroke, actual_x(keystroke, length));
Benno Schulenberg960e8482016-07-12 09:35:48 +02002256 wattroff(bottomwin, interface_color_pair[KEY_COMBO]);
David Lawrence Ramsey1903ace2004-12-24 00:43:41 +00002257
Benno Schulenberg7f3dc2d2016-03-23 20:21:36 +00002258 length -= strlenpt(keystroke) + 1;
David Lawrence Ramsey1903ace2004-12-24 00:43:41 +00002259
Benno Schulenberg7f3dc2d2016-03-23 20:21:36 +00002260 if (length > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002261 waddch(bottomwin, ' ');
Benno Schulenberg960e8482016-07-12 09:35:48 +02002262 wattron(bottomwin, interface_color_pair[FUNCTION_TAG]);
Benno Schulenberg7f3dc2d2016-03-23 20:21:36 +00002263 waddnstr(bottomwin, desc, actual_x(desc, length));
Benno Schulenberg960e8482016-07-12 09:35:48 +02002264 wattroff(bottomwin, interface_color_pair[FUNCTION_TAG]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002265 }
2266}
2267
Benno Schulenberg344fe552016-03-23 20:04:33 +00002268/* Redetermine current_y from the position of current relative to edittop,
2269 * and put the cursor in the edit window at (current_y, current_x). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002270void reset_cursor(void)
2271{
Benno Schulenberg6fc70cc2016-03-23 19:48:44 +00002272 size_t xpt = xplustabs();
David Lawrence Ramsey964722a2006-05-26 03:02:50 +00002273
Benno Schulenberg1102aaa2014-06-09 20:26:54 +00002274#ifndef NANO_TINY
Chris Allegretta05417a22009-08-17 07:52:10 +00002275 if (ISSET(SOFTWRAP)) {
Benno Schulenberg344fe552016-03-23 20:04:33 +00002276 filestruct *line = openfile->edittop;
Chris Allegretta6f083322009-11-11 06:00:33 +00002277 openfile->current_y = 0;
Chris Allegretta05417a22009-08-17 07:52:10 +00002278
Benno Schulenberg344fe552016-03-23 20:04:33 +00002279 while (line != NULL && line != openfile->current) {
Faissal Bensefiade95ca62016-10-20 09:44:29 +01002280 openfile->current_y += strlenpt(line->data) / editwincols + 1;
Benno Schulenberg344fe552016-03-23 20:04:33 +00002281 line = line->next;
2282 }
Faissal Bensefiade95ca62016-10-20 09:44:29 +01002283 openfile->current_y += xpt / editwincols;
Benno Schulenberg344fe552016-03-23 20:04:33 +00002284
Chris Allegretta05417a22009-08-17 07:52:10 +00002285 if (openfile->current_y < editwinrows)
Faissal Bensefiade95ca62016-10-20 09:44:29 +01002286 wmove(edit, openfile->current_y, xpt % editwincols + margin);
Benno Schulenberg1102aaa2014-06-09 20:26:54 +00002287 } else
2288#endif
2289 {
Chris Allegretta05417a22009-08-17 07:52:10 +00002290 openfile->current_y = openfile->current->lineno -
Benno Schulenberg344fe552016-03-23 20:04:33 +00002291 openfile->edittop->lineno;
Chris Allegretta05417a22009-08-17 07:52:10 +00002292
2293 if (openfile->current_y < editwinrows)
Faissal Bensefiade95ca62016-10-20 09:44:29 +01002294 wmove(edit, openfile->current_y, xpt - get_page_start(xpt) + margin);
Chris Allegretta05417a22009-08-17 07:52:10 +00002295 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002296}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002297
David Lawrence Ramseya0aff672005-10-27 20:10:45 +00002298/* edit_draw() takes care of the job of actually painting a line into
Benno Schulenberg892762d2017-01-12 18:00:54 +01002299 * the edit window. fileptr is the line to be painted, at row row of
David Lawrence Ramseya0aff672005-10-27 20:10:45 +00002300 * the window. converted is the actual string to be written to the
2301 * window, with tabs and control characters replaced by strings of
Benno Schulenberg6103c472017-01-08 10:20:57 +01002302 * regular characters. from_col is the column number of the first
David Lawrence Ramseya0aff672005-10-27 20:10:45 +00002303 * character of this page. That is, the first character of converted
Benno Schulenberg6103c472017-01-08 10:20:57 +01002304 * corresponds to character number actual_x(fileptr->data, from_col) of the
David Lawrence Ramseya0aff672005-10-27 20:10:45 +00002305 * line. */
Benno Schulenbergc0aa5ad2017-01-09 18:25:25 +01002306void edit_draw(filestruct *fileptr, const char *converted,
Benno Schulenberg892762d2017-01-12 18:00:54 +01002307 int row, size_t from_col)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002308{
Benno Schulenberg00389922014-04-04 11:59:03 +00002309#if !defined(NANO_TINY) || !defined(DISABLE_COLOR)
Benno Schulenberg6103c472017-01-08 10:20:57 +01002310 size_t from_x = actual_x(fileptr->data, from_col);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002311 /* The position in fileptr->data of the leftmost character
2312 * that displays at least partially on the window. */
Benno Schulenberg6103c472017-01-08 10:20:57 +01002313 size_t till_x = actual_x(fileptr->data, from_col + editwincols - 1) + 1;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002314 /* The position in fileptr->data of the first character that is
Benno Schulenberg26683a92017-01-08 21:31:49 +01002315 * completely off the window to the right. Note that till_x
2316 * might be beyond the null terminator of the string. */
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002317#endif
2318
David Lawrence Ramseydb958022005-07-13 20:18:46 +00002319 assert(openfile != NULL && fileptr != NULL && converted != NULL);
Faissal Bensefiade95ca62016-10-20 09:44:29 +01002320 assert(strlenpt(converted) <= editwincols);
2321
2322#ifdef ENABLE_LINENUMBERS
Benno Schulenberg26683a92017-01-08 21:31:49 +01002323 /* If line numbering is switched on, put a line number in front of
Benno Schulenberg023edff2016-10-21 14:31:37 +02002324 * the text -- but only for the parts that are not softwrapped. */
2325 if (margin > 0) {
Benno Schulenbergde2aa4f2016-10-20 10:07:48 +02002326 wattron(edit, interface_color_pair[LINE_NUMBER]);
David Lawrence Ramseyc9f743f2016-12-09 11:51:41 -06002327#ifndef NANO_TINY
Benno Schulenberg08cfdbc2017-01-08 11:49:59 +01002328 if (ISSET(SOFTWRAP) && from_x != 0)
Benno Schulenberg892762d2017-01-12 18:00:54 +01002329 mvwprintw(edit, row, 0, "%*s", margin - 1, " ");
David Lawrence Ramseyc9f743f2016-12-09 11:51:41 -06002330 else
2331#endif
Benno Schulenberg892762d2017-01-12 18:00:54 +01002332 mvwprintw(edit, row, 0, "%*ld", margin - 1, (long)fileptr->lineno);
Benno Schulenbergde2aa4f2016-10-20 10:07:48 +02002333 wattroff(edit, interface_color_pair[LINE_NUMBER]);
Faissal Bensefiade95ca62016-10-20 09:44:29 +01002334 }
2335#endif
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002336
Benno Schulenberg892762d2017-01-12 18:00:54 +01002337 /* First simply write the converted line -- afterward we'll add colors
2338 * and the marking highlight on just the pieces that need it. */
2339 mvwaddstr(edit, row, margin, converted);
Benno Schulenberg1de337d2014-06-04 16:02:51 +00002340
Benno Schulenberg8c7a3852016-07-12 21:05:09 +02002341#ifdef USING_OLD_NCURSES
Benno Schulenberg1de337d2014-06-04 16:02:51 +00002342 /* Tell ncurses to really redraw the line without trying to optimize
2343 * for what it thinks is already there, because it gets it wrong in
2344 * the case of a wide character in column zero. See bug #31743. */
Benno Schulenberg954d04b2015-09-05 09:14:24 +00002345 if (seen_wide)
Benno Schulenberg892762d2017-01-12 18:00:54 +01002346 wredrawln(edit, row, 1);
Chris Allegrettacfa29762014-05-28 01:35:51 +00002347#endif
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002348
Benno Schulenberg00389922014-04-04 11:59:03 +00002349#ifndef DISABLE_COLOR
Benno Schulenberg26683a92017-01-08 21:31:49 +01002350 /* If color syntaxes are available and turned on, apply them. */
David Lawrence Ramseydb958022005-07-13 20:18:46 +00002351 if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX)) {
Benno Schulenberg8fea3472016-03-13 20:13:16 +00002352 const colortype *varnish = openfile->colorstrings;
Chris Allegretta2fa11b82001-12-02 04:55:44 +00002353
Benno Schulenbergee335032015-11-29 13:20:08 +00002354 /* If there are multiline regexes, make sure there is a cache. */
2355 if (openfile->syntax->nmultis > 0)
2356 alloc_multidata_if_needed(fileptr);
2357
Benno Schulenberg26683a92017-01-08 21:31:49 +01002358 /* Iterate through all the coloring regexes. */
Benno Schulenberg8fea3472016-03-13 20:13:16 +00002359 for (; varnish != NULL; varnish = varnish->next) {
Benno Schulenberg38d73622017-01-08 22:04:43 +01002360 size_t index = 0;
2361 /* Where in the line we currently begin looking for a match. */
Benno Schulenberg5dbd2882017-01-08 12:32:24 +01002362 int start_col;
Benno Schulenberg26683a92017-01-08 21:31:49 +01002363 /* The starting column of a piece to paint. Zero-based. */
Benno Schulenberg26ae9db2015-06-14 18:06:36 +00002364 int paintlen = 0;
Benno Schulenberg26683a92017-01-08 21:31:49 +01002365 /* The number of characters to paint. */
2366 const char *thetext;
2367 /* The place in converted from where painting starts. */
Benno Schulenbergaf7201f2017-01-20 21:32:43 +01002368 regmatch_t match;
2369 /* The match positions of a single-line regex. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002370
David Lawrence Ramseyb0e04c02005-12-08 07:24:54 +00002371 /* Two notes about regexec(). A return value of zero means
2372 * that there is a match. Also, rm_eo is the first
2373 * non-matching character after the match. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002374
Benno Schulenberg26683a92017-01-08 21:31:49 +01002375 wattron(edit, varnish->attributes);
2376
Benno Schulenberg8fea3472016-03-13 20:13:16 +00002377 /* First case: varnish is a single-line expression. */
2378 if (varnish->end == NULL) {
Benno Schulenberg38d73622017-01-08 22:04:43 +01002379 /* We increment index by rm_eo, to move past the end of the
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002380 * last match. Even though two matches may overlap, we
David Lawrence Ramsey2ef7dae2006-05-26 11:58:37 +00002381 * want to ignore them, so that we can highlight e.g. C
2382 * strings correctly. */
Benno Schulenberg38d73622017-01-08 22:04:43 +01002383 while (index < till_x) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002384 /* Note the fifth parameter to regexec(). It says
2385 * not to match the beginning-of-line character
Benno Schulenberg38d73622017-01-08 22:04:43 +01002386 * unless index is zero. If regexec() returns
David Lawrence Ramsey2ef7dae2006-05-26 11:58:37 +00002387 * REG_NOMATCH, there are no more matches in the
2388 * line. */
Benno Schulenberg38d73622017-01-08 22:04:43 +01002389 if (regexec(varnish->start, &fileptr->data[index], 1,
Benno Schulenberg23595c82017-01-20 19:44:46 +01002390 &match, (index == 0) ? 0 : REG_NOTBOL) != 0)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002391 break;
Benno Schulenberg26683a92017-01-08 21:31:49 +01002392
Benno Schulenberg66945352017-01-20 19:20:30 +01002393 /* If the match is of length zero, skip it. */
Benno Schulenberg23595c82017-01-20 19:44:46 +01002394 if (match.rm_so == match.rm_eo) {
Benno Schulenberg66945352017-01-20 19:20:30 +01002395 index = move_mbright(fileptr->data,
Benno Schulenberg23595c82017-01-20 19:44:46 +01002396 index + match.rm_eo);
Benno Schulenberg38d73622017-01-08 22:04:43 +01002397 continue;
2398 }
2399
2400 /* Translate the match to the beginning of the line. */
Benno Schulenberg23595c82017-01-20 19:44:46 +01002401 match.rm_so += index;
2402 match.rm_eo += index;
2403 index = match.rm_eo;
Benno Schulenberg38d73622017-01-08 22:04:43 +01002404
Benno Schulenberg23595c82017-01-20 19:44:46 +01002405 /* If the matching part is not visible, skip it. */
2406 if (match.rm_eo <= from_x || match.rm_so >= till_x)
Benno Schulenberg38d73622017-01-08 22:04:43 +01002407 continue;
2408
Benno Schulenberg23595c82017-01-20 19:44:46 +01002409 start_col = (match.rm_so <= from_x) ?
2410 0 : strnlenpt(fileptr->data,
2411 match.rm_so) - from_col;
David Lawrence Ramsey14ace172005-01-24 21:51:07 +00002412
Benno Schulenberg26683a92017-01-08 21:31:49 +01002413 thetext = converted + actual_x(converted, start_col);
David Lawrence Ramsey14ace172005-01-24 21:51:07 +00002414
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002415 paintlen = actual_x(thetext, strnlenpt(fileptr->data,
Benno Schulenberg23595c82017-01-20 19:44:46 +01002416 match.rm_eo) - from_col - start_col);
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002417
Benno Schulenberg892762d2017-01-12 18:00:54 +01002418 mvwaddnstr(edit, row, margin + start_col,
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002419 thetext, paintlen);
2420 }
2421 goto tail_of_loop;
2422 }
2423
2424 /* Second case: varnish is a multiline expression. */
2425 const filestruct *start_line = fileptr->prev;
2426 /* The first line before fileptr that matches 'start'. */
2427 const filestruct *end_line = fileptr;
2428 /* The line that matches 'end'. */
Benno Schulenbergaf7201f2017-01-20 21:32:43 +01002429 regmatch_t startmatch, endmatch;
2430 /* The match positions of the start and end regexes. */
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002431
Benno Schulenbergfccfccc2017-02-13 17:28:38 +01002432 /* Assume nothing gets painted until proven otherwise below. */
2433 fileptr->multidata[varnish->id] = CNONE;
2434
Benno Schulenbergb3bcc8e2017-01-23 14:41:25 +01002435 /* First check the multidata of the preceding line -- it tells
2436 * us about the situation so far, and thus what to do here. */
2437 if (start_line != NULL && start_line->multidata != NULL) {
2438 if (start_line->multidata[varnish->id] == CWHOLELINE ||
Benno Schulenbergfccfccc2017-02-13 17:28:38 +01002439 start_line->multidata[varnish->id] == CENDAFTER ||
2440 start_line->multidata[varnish->id] == CWOULDBE)
Benno Schulenbergb3bcc8e2017-01-23 14:41:25 +01002441 goto seek_an_end;
Benno Schulenbergb3bcc8e2017-01-23 14:41:25 +01002442 if (start_line->multidata[varnish->id] == CNONE ||
2443 start_line->multidata[varnish->id] == CBEGINBEFORE ||
Benno Schulenbergfccfccc2017-02-13 17:28:38 +01002444 start_line->multidata[varnish->id] == CSTARTENDHERE)
Benno Schulenbergb3bcc8e2017-01-23 14:41:25 +01002445 goto step_two;
Benno Schulenbergb3bcc8e2017-01-23 14:41:25 +01002446 }
2447
Benno Schulenberg6bd94042017-02-12 20:28:14 +01002448 /* The preceding line has no precalculated multidata. So, do
2449 * some backtracking to find out what to paint. */
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002450
Benno Schulenbergfccfccc2017-02-13 17:28:38 +01002451 /* First step: see if there is a line before current that
2452 * matches 'start' and is not complemented by an 'end'. */
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002453 while (start_line != NULL && regexec(varnish->start,
2454 start_line->data, 1, &startmatch, 0) == REG_NOMATCH) {
Benno Schulenbergfccfccc2017-02-13 17:28:38 +01002455 /* There is no start on this line; but if there is an end,
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002456 * there is no need to look for starts on earlier lines. */
2457 if (regexec(varnish->end, start_line->data, 0, NULL, 0) == 0)
2458 goto step_two;
2459 start_line = start_line->prev;
2460 }
2461
2462 /* If no start was found, skip to the next step. */
2463 if (start_line == NULL)
2464 goto step_two;
2465
2466 /* If a found start has been qualified as an end earlier,
2467 * believe it and skip to the next step. */
2468 if (start_line->multidata != NULL &&
2469 (start_line->multidata[varnish->id] == CBEGINBEFORE ||
2470 start_line->multidata[varnish->id] == CSTARTENDHERE))
2471 goto step_two;
2472
Benno Schulenbergfccfccc2017-02-13 17:28:38 +01002473 /* Is there an uncomplemented start on the found line? */
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002474 while (TRUE) {
Benno Schulenberg94907aa2017-01-20 13:31:18 +01002475 /* Begin searching for an end after the start match. */
Benno Schulenberg7e5524b2017-01-20 10:58:15 +01002476 index += startmatch.rm_eo;
Benno Schulenberg94907aa2017-01-20 13:31:18 +01002477 /* If there is no end after this last start, good. */
Benno Schulenberg1d10d792017-01-22 10:12:27 +01002478 if (regexec(varnish->end, start_line->data + index, 1, &endmatch,
2479 (index == 0) ? 0 : REG_NOTBOL) == REG_NOMATCH)
Benno Schulenberg94907aa2017-01-20 13:31:18 +01002480 break;
Benno Schulenberg9a4a5452017-01-21 11:58:00 +01002481 /* Begin searching for a new start after the end match. */
2482 index += endmatch.rm_eo;
Benno Schulenberg84418872017-01-21 19:35:11 +01002483 /* If both start and end match are mere anchors, advance. */
2484 if (startmatch.rm_so == startmatch.rm_eo &&
2485 endmatch.rm_so == endmatch.rm_eo) {
Benno Schulenberg775f0072017-01-21 18:18:34 +01002486 if (start_line->data[index] == '\0')
Benno Schulenberg9a4a5452017-01-21 11:58:00 +01002487 break;
Benno Schulenberg775f0072017-01-21 18:18:34 +01002488 index = move_mbright(start_line->data, index);
Benno Schulenberg9a4a5452017-01-21 11:58:00 +01002489 }
Benno Schulenberg94907aa2017-01-20 13:31:18 +01002490 /* If there is no later start on this line, next step. */
2491 if (regexec(varnish->start, start_line->data + index,
2492 1, &startmatch, REG_NOTBOL) == REG_NOMATCH)
2493 goto step_two;
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002494 }
2495 /* Indeed, there is a start without an end on that line. */
2496
Benno Schulenbergb3bcc8e2017-01-23 14:41:25 +01002497 seek_an_end:
Benno Schulenbergc0aa5ad2017-01-09 18:25:25 +01002498 /* We've already checked that there is no end between the start
2499 * and the current line. But is there an end after the start
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002500 * at all? We don't paint unterminated starts. */
2501 while (end_line != NULL && regexec(varnish->end, end_line->data,
2502 1, &endmatch, 0) == REG_NOMATCH)
2503 end_line = end_line->next;
2504
Benno Schulenberga898fa52017-01-09 19:14:51 +01002505 /* If there is no end, there is nothing to paint. */
Benno Schulenberg7ef5c532017-02-12 22:34:31 +01002506 if (end_line == NULL) {
2507 fileptr->multidata[varnish->id] = CWOULDBE;
Benno Schulenberga898fa52017-01-09 19:14:51 +01002508 goto tail_of_loop;
Benno Schulenberg7ef5c532017-02-12 22:34:31 +01002509 }
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002510
Benno Schulenberg2f801932017-01-20 21:27:49 +01002511 /* If the end is on a later line, paint whole line, and be done. */
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002512 if (end_line != fileptr) {
Benno Schulenberg892762d2017-01-12 18:00:54 +01002513 mvwaddnstr(edit, row, margin, converted, -1);
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002514 fileptr->multidata[varnish->id] = CWHOLELINE;
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002515 goto tail_of_loop;
Benno Schulenberg2f801932017-01-20 21:27:49 +01002516 }
2517
2518 /* Only if it is visible, paint the part to be coloured. */
2519 if (endmatch.rm_eo > from_x) {
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002520 paintlen = actual_x(converted, strnlenpt(fileptr->data,
2521 endmatch.rm_eo) - from_col);
Benno Schulenberg892762d2017-01-12 18:00:54 +01002522 mvwaddnstr(edit, row, margin, converted, paintlen);
Benno Schulenberg2f801932017-01-20 21:27:49 +01002523 }
2524 fileptr->multidata[varnish->id] = CBEGINBEFORE;
Benno Schulenberg03148802017-02-13 17:09:17 +01002525
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002526 step_two:
2527 /* Second step: look for starts on this line, but begin
2528 * looking only after an end match, if there is one. */
2529 index = (paintlen == 0) ? 0 : endmatch.rm_eo;
2530
2531 while (regexec(varnish->start, fileptr->data + index,
2532 1, &startmatch, (index == 0) ?
Benno Schulenberg07e806e2015-12-01 13:33:45 +00002533 0 : REG_NOTBOL) == 0) {
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002534 /* Translate the match to be relative to the
2535 * beginning of the line. */
2536 startmatch.rm_so += index;
2537 startmatch.rm_eo += index;
2538
2539 start_col = (startmatch.rm_so <= from_x) ?
2540 0 : strnlenpt(fileptr->data,
2541 startmatch.rm_so) - from_col;
2542
2543 thetext = converted + actual_x(converted, start_col);
2544
2545 if (regexec(varnish->end, fileptr->data + startmatch.rm_eo,
2546 1, &endmatch, (startmatch.rm_eo == 0) ?
2547 0 : REG_NOTBOL) == 0) {
2548 /* Translate the end match to be relative to
2549 * the beginning of the line. */
2550 endmatch.rm_so += startmatch.rm_eo;
2551 endmatch.rm_eo += startmatch.rm_eo;
Benno Schulenbergc0aa5ad2017-01-09 18:25:25 +01002552 /* Only paint the match if it is visible on screen and
2553 * it is more than zero characters long. */
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002554 if (endmatch.rm_eo > from_x &&
Benno Schulenberg88cf22f2017-01-07 20:42:37 +01002555 endmatch.rm_eo > startmatch.rm_so) {
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002556 paintlen = actual_x(thetext, strnlenpt(fileptr->data,
Benno Schulenberg5dbd2882017-01-08 12:32:24 +01002557 endmatch.rm_eo) - from_col - start_col);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002558
Benno Schulenberg892762d2017-01-12 18:00:54 +01002559 mvwaddnstr(edit, row, margin + start_col,
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002560 thetext, paintlen);
Benno Schulenberg8177e622017-01-03 21:18:24 +01002561
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002562 fileptr->multidata[varnish->id] = CSTARTENDHERE;
Benno Schulenberg38d73622017-01-08 22:04:43 +01002563 }
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002564 index = endmatch.rm_eo;
Benno Schulenberg84418872017-01-21 19:35:11 +01002565 /* If both start and end match are anchors, advance. */
2566 if (startmatch.rm_so == startmatch.rm_eo &&
2567 endmatch.rm_so == endmatch.rm_eo) {
Benno Schulenberg775f0072017-01-21 18:18:34 +01002568 if (fileptr->data[index] == '\0')
Benno Schulenberg66945352017-01-20 19:20:30 +01002569 break;
Benno Schulenberg775f0072017-01-21 18:18:34 +01002570 index = move_mbright(fileptr->data, index);
Benno Schulenberg66945352017-01-20 19:20:30 +01002571 }
2572 continue;
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002573 }
Benno Schulenberg38d73622017-01-08 22:04:43 +01002574
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002575 /* There is no end on this line. But maybe on later lines? */
2576 end_line = fileptr->next;
David Lawrence Ramsey68e30162005-01-03 22:23:00 +00002577
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002578 while (end_line != NULL && regexec(varnish->end, end_line->data,
2579 0, NULL, 0) == REG_NOMATCH)
2580 end_line = end_line->next;
David Lawrence Ramsey14ace172005-01-24 21:51:07 +00002581
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002582 /* If there is no end, we're done with this regex. */
Benno Schulenberg7ef5c532017-02-12 22:34:31 +01002583 if (end_line == NULL) {
2584 fileptr->multidata[varnish->id] = CWOULDBE;
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002585 break;
Benno Schulenberg7ef5c532017-02-12 22:34:31 +01002586 }
David Lawrence Ramsey68e30162005-01-03 22:23:00 +00002587
Benno Schulenberg03148802017-02-13 17:09:17 +01002588 /* Paint the rest of the line, and we're done. */
Benno Schulenberg892762d2017-01-12 18:00:54 +01002589 mvwaddnstr(edit, row, margin + start_col, thetext, -1);
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002590 fileptr->multidata[varnish->id] = CENDAFTER;
Benno Schulenbergf6fbc152017-01-09 11:49:35 +01002591 break;
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00002592 }
Benno Schulenbergeee07d52015-12-01 12:49:17 +00002593 tail_of_loop:
Rishabh Dave4c566c72016-07-17 18:59:07 +05302594 wattroff(edit, varnish->attributes);
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00002595 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002596 }
Benno Schulenberg00389922014-04-04 11:59:03 +00002597#endif /* !DISABLE_COLOR */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002598
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002599#ifndef NANO_TINY
Benno Schulenberg95f417f2016-06-14 11:06:04 +02002600 /* If the mark is on, and fileptr is at least partially selected, we
2601 * need to paint it. */
2602 if (openfile->mark_set &&
2603 (fileptr->lineno <= openfile->mark_begin->lineno ||
2604 fileptr->lineno <= openfile->current->lineno) &&
2605 (fileptr->lineno >= openfile->mark_begin->lineno ||
2606 fileptr->lineno >= openfile->current->lineno)) {
2607 const filestruct *top, *bot;
2608 /* The lines where the marked region begins and ends. */
2609 size_t top_x, bot_x;
2610 /* The x positions where the marked region begins and ends. */
Benno Schulenberg5dbd2882017-01-08 12:32:24 +01002611 int start_col;
Benno Schulenberga8943722017-01-08 13:01:45 +01002612 /* The column where painting starts. Zero-based. */
2613 const char *thetext;
2614 /* The place in converted from where painting starts. */
2615 int paintlen = -1;
2616 /* The number of characters to paint. Negative means "all". */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002617
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002618 mark_order(&top, &top_x, &bot, &bot_x, NULL);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002619
Benno Schulenberg6103c472017-01-08 10:20:57 +01002620 if (top->lineno < fileptr->lineno || top_x < from_x)
2621 top_x = from_x;
2622 if (bot->lineno > fileptr->lineno || bot_x > till_x)
2623 bot_x = till_x;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002624
Benno Schulenberg5dbd2882017-01-08 12:32:24 +01002625 /* Only paint if the marked part of the line is on this page. */
Benno Schulenberg6103c472017-01-08 10:20:57 +01002626 if (top_x < till_x && bot_x > from_x) {
Benno Schulenberg5dbd2882017-01-08 12:32:24 +01002627 /* Compute on which screen column to start painting. */
2628 start_col = strnlenpt(fileptr->data, top_x) - from_col;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002629
Benno Schulenberga8943722017-01-08 13:01:45 +01002630 thetext = converted + actual_x(converted, start_col);
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00002631
Benno Schulenberga8943722017-01-08 13:01:45 +01002632 /* If the end of the mark is onscreen, compute how many
2633 * characters to paint. Otherwise, just paint all. */
2634 if (bot_x < till_x) {
2635 size_t end_col = strnlenpt(fileptr->data, bot_x) - from_col;
2636 paintlen = actual_x(thetext, end_col - start_col);
2637 }
David Lawrence Ramsey68e30162005-01-03 22:23:00 +00002638
Benno Schulenbergc9700352014-05-04 08:53:06 +00002639 wattron(edit, hilite_attribute);
Benno Schulenberg892762d2017-01-12 18:00:54 +01002640 mvwaddnstr(edit, row, margin + start_col, thetext, paintlen);
Benno Schulenbergc9700352014-05-04 08:53:06 +00002641 wattroff(edit, hilite_attribute);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002642 }
Chris Allegretta08893e02001-11-29 02:42:27 +00002643 }
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002644#endif /* !NANO_TINY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002645}
2646
David Lawrence Ramseyc67c4312017-01-12 17:55:22 -06002647/* Redraw the line at fileptr. The line will be displayed so that the
2648 * character with the given index is visible -- if necessary, the line
2649 * will be horizontally scrolled. In softwrap mode, however, the entire
2650 * line will be displayed. Likely values of index are current_x or zero.
2651 * Return the number of additional rows consumed (when softwrapping). */
Chris Allegretta05417a22009-08-17 07:52:10 +00002652int update_line(filestruct *fileptr, size_t index)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002653{
Benno Schulenberg892762d2017-01-12 18:00:54 +01002654 int row = 0;
Benno Schulenbergc0aa5ad2017-01-09 18:25:25 +01002655 /* The row in the edit window we will be updating. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002656 char *converted;
Benno Schulenbergc0aa5ad2017-01-09 18:25:25 +01002657 /* The data of the line with tabs and control characters expanded. */
Benno Schulenbergb7c25132017-01-12 18:25:50 +01002658 size_t from_col = 0;
2659 /* From which column a horizontally scrolled line is displayed. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002660
Benno Schulenberg1102aaa2014-06-09 20:26:54 +00002661#ifndef NANO_TINY
Chris Allegretta05417a22009-08-17 07:52:10 +00002662 if (ISSET(SOFTWRAP)) {
Benno Schulenbergb7c25132017-01-12 18:25:50 +01002663 filestruct *line = openfile->edittop;
Benno Schulenberg1102aaa2014-06-09 20:26:54 +00002664
Benno Schulenberg9bb64fc2017-01-13 17:47:55 +01002665 /* Find out on which screen row the target line should be shown. */
Benno Schulenbergb7c25132017-01-12 18:25:50 +01002666 while (line != fileptr && line != NULL) {
2667 row += (strlenpt(line->data) / editwincols) + 1;
2668 line = line->next;
2669 }
Chris Allegretta05417a22009-08-17 07:52:10 +00002670 } else
Benno Schulenberg1102aaa2014-06-09 20:26:54 +00002671#endif
Benno Schulenberg892762d2017-01-12 18:00:54 +01002672 row = fileptr->lineno - openfile->edittop->lineno;
Chris Allegretta05417a22009-08-17 07:52:10 +00002673
David Lawrence Ramsey6e3adf32016-12-28 10:22:05 -06002674 /* If the line is offscreen, don't even try to display it. */
Benno Schulenberg892762d2017-01-12 18:00:54 +01002675 if (row < 0 || row >= editwinrows)
David Lawrence Ramsey6e3adf32016-12-28 10:22:05 -06002676 return 0;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00002677
Benno Schulenberg980e3342017-01-13 19:11:11 +01002678#ifndef NANO_TINY
Benno Schulenberg5d5666f2017-01-13 19:18:08 +01002679 if (ISSET(SOFTWRAP)) {
Benno Schulenberg53435b02014-06-10 19:07:47 +00002680 size_t full_length = strlenpt(fileptr->data);
Benno Schulenberg9f884812017-01-13 19:25:16 +01002681 int starting_row = row;
Benno Schulenbergb7c25132017-01-12 18:25:50 +01002682
Benno Schulenberg980e3342017-01-13 19:11:11 +01002683 for (from_col = 0; from_col <= full_length &&
2684 row < editwinrows; from_col += editwincols) {
David Lawrence Ramseyc67c4312017-01-12 17:55:22 -06002685 /* First, blank out the row. */
Benno Schulenberg980e3342017-01-13 19:11:11 +01002686 blank_row(edit, row, 0, COLS);
Chris Allegretta05417a22009-08-17 07:52:10 +00002687
2688 /* Expand the line, replacing tabs with spaces, and control
Benno Schulenberg71c9a522014-05-13 20:14:01 +00002689 * characters with their displayed forms. */
Benno Schulenbergb7c25132017-01-12 18:25:50 +01002690 converted = display_string(fileptr->data, from_col, editwincols, TRUE);
Benno Schulenberg9bb64fc2017-01-13 17:47:55 +01002691
Benno Schulenberg892762d2017-01-12 18:00:54 +01002692 /* Draw the line. */
Benno Schulenberg980e3342017-01-13 19:11:11 +01002693 edit_draw(fileptr, converted, row++, from_col);
Benno Schulenberg71c9a522014-05-13 20:14:01 +00002694 free(converted);
Chris Allegretta05417a22009-08-17 07:52:10 +00002695 }
Benno Schulenberg980e3342017-01-13 19:11:11 +01002696
Benno Schulenberg9f884812017-01-13 19:25:16 +01002697 return (row - starting_row);
Chris Allegretta05417a22009-08-17 07:52:10 +00002698 }
Benno Schulenberg9bb64fc2017-01-13 17:47:55 +01002699#endif
David Lawrence Ramseyc67c4312017-01-12 17:55:22 -06002700
Benno Schulenberg5d5666f2017-01-13 19:18:08 +01002701 /* First, blank out the row. */
2702 blank_row(edit, row, 0, COLS);
2703
2704 /* Next, find out from which column to start displaying the line. */
2705 from_col = get_page_start(strnlenpt(fileptr->data, index));
2706
2707 /* Expand the line, replacing tabs with spaces, and control
2708 * characters with their displayed forms. */
2709 converted = display_string(fileptr->data, from_col, editwincols, TRUE);
2710
2711 /* Draw the line. */
2712 edit_draw(fileptr, converted, row, from_col);
2713 free(converted);
2714
2715 if (from_col > 0)
2716 mvwaddch(edit, row, margin, '$');
2717 if (strlenpt(fileptr->data) > from_col + editwincols)
2718 mvwaddch(edit, row, COLS - 1, '$');
2719
Benno Schulenberg9f884812017-01-13 19:25:16 +01002720 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002721}
2722
Benno Schulenberg2f664762016-07-26 19:47:00 +02002723/* Check whether old_column and new_column are on different "pages" (or that
2724 * the mark is on), which means that the relevant line needs to be redrawn. */
2725bool need_horizontal_scroll(const size_t old_column, const size_t new_column)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002726{
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002727#ifndef NANO_TINY
Benno Schulenberg2f664762016-07-26 19:47:00 +02002728 if (openfile->mark_set)
2729 return TRUE;
2730 else
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002731#endif
Benno Schulenberg2f664762016-07-26 19:47:00 +02002732 return (get_page_start(old_column) != get_page_start(new_column));
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002733}
2734
Benno Schulenbergbf0268d2017-01-12 21:31:08 +01002735/* Determine how many file lines we can display, accounting for softwraps. */
Benno Schulenberg0208ae72017-01-12 17:33:46 +01002736void compute_maxlines(void)
Chris Allegretta99c8d402009-11-13 13:48:56 +00002737{
David Lawrence Ramseyc8c63402016-12-08 09:56:16 -06002738#ifndef NANO_TINY
2739 if (ISSET(SOFTWRAP)) {
Benno Schulenberg2fa93ae2016-12-09 12:47:00 +01002740 filestruct *line = openfile->edittop;
Benno Schulenbergbf0268d2017-01-12 21:31:08 +01002741 int row = 0;
Chris Allegretta99c8d402009-11-13 13:48:56 +00002742
Benno Schulenberg0208ae72017-01-12 17:33:46 +01002743 maxlines = 0;
Benno Schulenberg2fa93ae2016-12-09 12:47:00 +01002744
Benno Schulenbergbf0268d2017-01-12 21:31:08 +01002745 while (row < editwinrows && line != NULL) {
2746 row += (strlenpt(line->data) / editwincols) + 1;
Benno Schulenberg2fa93ae2016-12-09 12:47:00 +01002747 line = line->next;
Benno Schulenberg0208ae72017-01-12 17:33:46 +01002748 maxlines++;
David Lawrence Ramseyc8c63402016-12-08 09:56:16 -06002749 }
Chris Allegretta8c1edd12009-11-16 04:28:40 +00002750
Benno Schulenbergbf0268d2017-01-12 21:31:08 +01002751 if (row < editwinrows)
2752 maxlines += (editwinrows - row);
Chris Allegretta99c8d402009-11-13 13:48:56 +00002753#ifdef DEBUG
Benno Schulenberg0208ae72017-01-12 17:33:46 +01002754 fprintf(stderr, "recomputed: maxlines = %d\n", maxlines);
Chris Allegretta99c8d402009-11-13 13:48:56 +00002755#endif
David Lawrence Ramseyc8c63402016-12-08 09:56:16 -06002756 } else
2757#endif /* !NANO_TINY */
Benno Schulenberg0208ae72017-01-12 17:33:46 +01002758 maxlines = editwinrows;
Chris Allegretta99c8d402009-11-13 13:48:56 +00002759}
2760
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002761/* Scroll the edit window in the given direction and the given number of rows,
2762 * and draw new lines on the blank lines left after the scrolling. We change
2763 * edittop, and assume that current and current_x are up to date. */
2764void edit_scroll(scroll_dir direction, int nrows)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002765{
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002766 int i;
David Lawrence Ramsey78037832016-12-30 02:09:14 -06002767 filestruct *line;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002768
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002769 /* Part 1: nrows is the number of rows we're going to scroll the text of
2770 * the edit window. */
David Lawrence Ramseyc0097592005-07-22 23:17:19 +00002771
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002772 /* Move the top line of the edit window up or down (depending on the value
2773 * of direction) nrows rows, or as many rows as we can if there are fewer
2774 * than nrows rows available. */
2775 for (i = nrows; i > 0; i--) {
Benno Schulenbergce0ea442014-06-23 18:20:12 +00002776 if (direction == UPWARD) {
David Lawrence Ramseye99223d2005-11-10 04:27:30 +00002777 if (openfile->edittop == openfile->fileage)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002778 break;
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +00002779 openfile->edittop = openfile->edittop->prev;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002780 } else {
David Lawrence Ramseye99223d2005-11-10 04:27:30 +00002781 if (openfile->edittop == openfile->filebot)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002782 break;
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +00002783 openfile->edittop = openfile->edittop->next;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002784 }
Benno Schulenberg1102aaa2014-06-09 20:26:54 +00002785
2786#ifndef NANO_TINY
Benno Schulenbergf876ee12014-04-15 11:25:29 +00002787 /* Don't over-scroll on long lines. */
Benno Schulenbergce0ea442014-06-23 18:20:12 +00002788 if (ISSET(SOFTWRAP) && direction == UPWARD) {
Faissal Bensefiade95ca62016-10-20 09:44:29 +01002789 ssize_t len = strlenpt(openfile->edittop->data) / editwincols;
Benno Schulenberg52e35332014-05-16 11:03:04 +00002790 i -= len;
Chris Allegretta1a7a91b2010-01-13 03:21:19 +00002791 if (len > 0)
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +02002792 refresh_needed = TRUE;
Chris Allegretta1a7a91b2010-01-13 03:21:19 +00002793 }
Benno Schulenberg1102aaa2014-06-09 20:26:54 +00002794#endif
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002795 }
2796
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002797 /* Limit nrows to the number of rows we could scroll. */
2798 nrows -= i;
David Lawrence Ramsey258497f2005-08-01 21:17:38 +00002799
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002800 /* Don't bother scrolling zero rows, nor more than the window can hold. */
2801 if (nrows == 0)
David Lawrence Ramsey258497f2005-08-01 21:17:38 +00002802 return;
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002803 if (nrows >= editwinrows)
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +02002804 refresh_needed = TRUE;
Benno Schulenberg22460292016-04-13 13:14:36 +02002805
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +02002806 if (refresh_needed == TRUE)
Benno Schulenberg22460292016-04-13 13:14:36 +02002807 return;
David Lawrence Ramseyc0097592005-07-22 23:17:19 +00002808
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002809 /* Scroll the text of the edit window a number of rows up or down. */
David Lawrence Ramsey47bb8882005-07-22 22:56:03 +00002810 scrollok(edit, TRUE);
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002811 wscrl(edit, (direction == UPWARD) ? -nrows : nrows);
David Lawrence Ramsey47bb8882005-07-22 22:56:03 +00002812 scrollok(edit, FALSE);
2813
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002814 /* Part 2: nrows is now the number of rows in the scrolled region of the
2815 * edit window that we need to draw. */
David Lawrence Ramseyc0097592005-07-22 23:17:19 +00002816
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002817 /* If the scrolled region contains only one row, and the row before it is
2818 * visible in the edit window, we need to draw it too. If the scrolled
2819 * region is more than one row, and the rows before and after it are
2820 * visible in the edit window, we need to draw them too. */
2821 nrows += (nrows == 1) ? 1 : 2;
David Lawrence Ramseyc25ed532005-08-01 21:53:54 +00002822
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002823 if (nrows > editwinrows)
2824 nrows = editwinrows;
David Lawrence Ramsey4d464372005-07-16 22:50:30 +00002825
Benno Schulenbergc0aa5ad2017-01-09 18:25:25 +01002826 /* If we scrolled up, we're on the line before the scrolled region. */
David Lawrence Ramsey78037832016-12-30 02:09:14 -06002827 line = openfile->edittop;
David Lawrence Ramsey14588912005-07-14 20:37:01 +00002828
Benno Schulenbergc0aa5ad2017-01-09 18:25:25 +01002829 /* If we scrolled down, move down to the line before the scrolled region. */
Benno Schulenbergce0ea442014-06-23 18:20:12 +00002830 if (direction == DOWNWARD) {
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002831 for (i = editwinrows - nrows; i > 0 && line != NULL; i--)
David Lawrence Ramsey78037832016-12-30 02:09:14 -06002832 line = line->next;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002833 }
2834
David Lawrence Ramseyb1b97702017-01-15 12:17:19 -06002835 /* Draw new lines on any blank rows before or inside the scrolled region.
2836 * If we scrolled down and we're on the top row, or if we scrolled up and
2837 * we're on the bottom row, the row won't be blank, so we don't need to
2838 * draw it unless the mark is on or we're not on the first "page". */
2839 for (i = nrows; i > 0 && line != NULL; i--) {
2840 if ((i == nrows && direction == DOWNWARD) ||
Benno Schulenbergc0aa5ad2017-01-09 18:25:25 +01002841 (i == 1 && direction == UPWARD)) {
Benno Schulenberg2f664762016-07-26 19:47:00 +02002842 if (need_horizontal_scroll(openfile->placewewant, 0))
David Lawrence Ramsey78037832016-12-30 02:09:14 -06002843 update_line(line, (line == openfile->current) ?
David Lawrence Ramsey27865302005-07-23 20:39:41 +00002844 openfile->current_x : 0);
2845 } else
David Lawrence Ramsey78037832016-12-30 02:09:14 -06002846 update_line(line, (line == openfile->current) ?
David Lawrence Ramsey4d464372005-07-16 22:50:30 +00002847 openfile->current_x : 0);
David Lawrence Ramsey78037832016-12-30 02:09:14 -06002848 line = line->next;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002849 }
Benno Schulenbergc0aa5ad2017-01-09 18:25:25 +01002850
Benno Schulenberg0208ae72017-01-12 17:33:46 +01002851 compute_maxlines();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002852}
2853
2854/* Update any lines between old_current and current that need to be
David Lawrence Ramsey75a29b72005-07-26 14:26:47 +00002855 * updated. Use this if we've moved without changing any text. */
Benno Schulenbergaa1ae0a2016-04-10 21:16:19 +02002856void edit_redraw(filestruct *old_current)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002857{
Benno Schulenbergaa1ae0a2016-04-10 21:16:19 +02002858 size_t was_pww = openfile->placewewant;
2859
2860 openfile->placewewant = xplustabs();
2861
Benno Schulenbergb8d32d82016-01-24 15:32:13 +00002862 /* If the current line is offscreen, scroll until it's onscreen. */
Benno Schulenberg0208ae72017-01-12 17:33:46 +01002863 if (openfile->current->lineno >= openfile->edittop->lineno + maxlines ||
Benno Schulenbergfc9c7b42016-09-13 10:26:08 +02002864#ifndef NANO_TINY
Benno Schulenberg0208ae72017-01-12 17:33:46 +01002865 (openfile->current->lineno == openfile->edittop->lineno + maxlines - 1 &&
Faissal Bensefiade95ca62016-10-20 09:44:29 +01002866 ISSET(SOFTWRAP) && strlenpt(openfile->current->data) >= editwincols) ||
Benno Schulenbergfc9c7b42016-09-13 10:26:08 +02002867#endif
Benno Schulenbergb97c36c2016-04-25 20:05:21 +02002868 openfile->current->lineno < openfile->edittop->lineno) {
Benno Schulenberg01bbf7e2016-10-20 21:11:11 +02002869 adjust_viewport((focusing || !ISSET(SMOOTH_SCROLL)) ? CENTERING : FLOWING);
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +02002870 refresh_needed = TRUE;
Benno Schulenberg9d5ee162016-10-20 21:18:17 +02002871 return;
Benno Schulenbergb97c36c2016-04-25 20:05:21 +02002872 }
David Lawrence Ramsey107e8162005-08-01 21:05:29 +00002873
David Lawrence Ramseyd5228b32006-05-26 03:04:24 +00002874#ifndef NANO_TINY
Benno Schulenbergb8d32d82016-01-24 15:32:13 +00002875 /* If the mark is on, update all lines between old_current and current. */
2876 if (openfile->mark_set) {
David Lawrence Ramsey34e086f2017-01-19 01:15:43 -06002877 filestruct *line = old_current;
David Lawrence Ramseyd5228b32006-05-26 03:04:24 +00002878
David Lawrence Ramsey34e086f2017-01-19 01:15:43 -06002879 while (line != openfile->current) {
2880 update_line(line, 0);
David Lawrence Ramseye5806be2005-07-16 02:12:18 +00002881
David Lawrence Ramsey34e086f2017-01-19 01:15:43 -06002882 line = (line->lineno > openfile->current->lineno) ?
2883 line->prev : line->next;
Benno Schulenbergb8d32d82016-01-24 15:32:13 +00002884 }
Benno Schulenbergb26aaa72016-04-27 17:45:36 +02002885 } else
2886#endif
2887 /* Otherwise, update old_current only if it differs from current
2888 * and was horizontally scrolled. */
2889 if (old_current != openfile->current && get_page_start(was_pww) > 0)
2890 update_line(old_current, 0);
Benno Schulenberg4b5b66a2016-04-11 20:40:21 +02002891
David Lawrence Ramseyf2ac2012016-12-28 09:43:23 -06002892 /* Update current if the mark is on or it has changed "page", or if it
2893 * differs from old_current and needs to be horizontally scrolled. */
Benno Schulenberg2f664762016-07-26 19:47:00 +02002894 if (need_horizontal_scroll(was_pww, openfile->placewewant) ||
Benno Schulenbergc9e99642016-07-26 11:47:53 +02002895 (old_current != openfile->current &&
Benno Schulenberg4b5b66a2016-04-11 20:40:21 +02002896 get_page_start(openfile->placewewant) > 0))
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +00002897 update_line(openfile->current, openfile->current_x);
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002898}
2899
David Lawrence Ramsey75a29b72005-07-26 14:26:47 +00002900/* Refresh the screen without changing the position of lines. Use this
2901 * if we've moved and changed text. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002902void edit_refresh(void)
2903{
Benno Schulenbergc92b9be2016-12-23 12:51:04 +01002904 filestruct *line;
2905 int row = 0;
David Lawrence Ramsey5b44f372005-07-16 22:47:12 +00002906
Benno Schulenberg0208ae72017-01-12 17:33:46 +01002907 /* Figure out what maxlines should really be. */
2908 compute_maxlines();
Chris Allegretta99c8d402009-11-13 13:48:56 +00002909
Benno Schulenberg55b14032016-10-20 22:04:38 +02002910 /* If the current line is out of view, get it back on screen. */
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +00002911 if (openfile->current->lineno < openfile->edittop->lineno ||
Benno Schulenberg0208ae72017-01-12 17:33:46 +01002912 openfile->current->lineno >= openfile->edittop->lineno + maxlines) {
Chris Allegretta8c1edd12009-11-16 04:28:40 +00002913#ifdef DEBUG
Benno Schulenberg0208ae72017-01-12 17:33:46 +01002914 fprintf(stderr, "edit-refresh: line = %ld, edittop = %ld and maxlines = %d\n",
2915 (long)openfile->current->lineno, (long)openfile->edittop->lineno, maxlines);
Chris Allegretta8c1edd12009-11-16 04:28:40 +00002916#endif
Benno Schulenberg01bbf7e2016-10-20 21:11:11 +02002917 adjust_viewport((focusing || !ISSET(SMOOTH_SCROLL)) ? CENTERING : STATIONARY);
Chris Allegretta8c1edd12009-11-16 04:28:40 +00002918 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002919
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002920#ifdef DEBUG
Benno Schulenberg0f3e3032016-12-02 17:37:11 +01002921 fprintf(stderr, "edit-refresh: now edittop = %ld\n", (long)openfile->edittop->lineno);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00002922#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002923
Benno Schulenbergc92b9be2016-12-23 12:51:04 +01002924 line = openfile->edittop;
2925
2926 while (row < editwinrows && line != NULL) {
2927 if (line == openfile->current)
Benno Schulenberg9f884812017-01-13 19:25:16 +01002928 row += update_line(line, openfile->current_x);
Benno Schulenbergc92b9be2016-12-23 12:51:04 +01002929 else
Benno Schulenberg9f884812017-01-13 19:25:16 +01002930 row += update_line(line, 0);
Benno Schulenbergc92b9be2016-12-23 12:51:04 +01002931 line = line->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002932 }
David Lawrence Ramsey5b44f372005-07-16 22:47:12 +00002933
Benno Schulenbergc92b9be2016-12-23 12:51:04 +01002934 while (row < editwinrows)
Benno Schulenbergf7d320d2017-01-12 17:48:33 +01002935 blank_row(edit, row++, 0, COLS);
David Lawrence Ramsey5b44f372005-07-16 22:47:12 +00002936
2937 reset_cursor();
David Lawrence Ramsey6d8e4952005-07-26 14:42:57 +00002938 wnoutrefresh(edit);
Benno Schulenberg2789bb02016-10-21 13:52:40 +02002939
2940 refresh_needed = FALSE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002941}
2942
Benno Schulenbergcb177322016-04-07 13:58:51 +02002943/* Move edittop so that current is on the screen. manner says how it
2944 * should be moved: CENTERING means that current should end up in the
2945 * middle of the screen, STATIONARY means that it should stay at the
2946 * same vertical position, and FLOWING means that it should scroll no
2947 * more than needed to bring current into view. */
Benno Schulenberg01bbf7e2016-10-20 21:11:11 +02002948void adjust_viewport(update_type manner)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002949{
Benno Schulenberg0bffd992016-04-16 11:38:39 +02002950 int goal = 0;
David Lawrence Ramsey20b83502004-08-26 18:07:58 +00002951
David Lawrence Ramseyf2ac2012016-12-28 09:43:23 -06002952 /* If manner is CENTERING, move edittop half the number of window rows
2953 * back from current. If manner is FLOWING, move edittop back 0 rows
2954 * or (editwinrows - 1) rows, depending on where current has moved.
2955 * This puts the cursor on the first or the last row. If manner is
2956 * STATIONARY, move edittop back current_y rows if current_y is in range
2957 * of the screen, 0 rows if current_y is below zero, or (editwinrows - 1)
2958 * rows if current_y is too big. This puts current at the same place on
2959 * the screen as before, or... at some undefined place. */
Benno Schulenbergcb177322016-04-07 13:58:51 +02002960 if (manner == CENTERING)
Chris Allegretta374216f2010-01-04 19:00:55 +00002961 goal = editwinrows / 2;
Benno Schulenbergcb177322016-04-07 13:58:51 +02002962 else if (manner == FLOWING) {
Benno Schulenberg598e0af2016-09-15 10:43:49 +02002963 if (openfile->current->lineno >= openfile->edittop->lineno) {
Benno Schulenbergcb177322016-04-07 13:58:51 +02002964 goal = editwinrows - 1;
Benno Schulenberg598e0af2016-09-15 10:43:49 +02002965#ifndef NANO_TINY
2966 if (ISSET(SOFTWRAP))
Faissal Bensefiade95ca62016-10-20 09:44:29 +01002967 goal -= strlenpt(openfile->current->data) / editwincols;
Benno Schulenberg598e0af2016-09-15 10:43:49 +02002968#endif
2969 }
Benno Schulenbergcb177322016-04-07 13:58:51 +02002970 } else {
David Lawrence Ramsey5b44f372005-07-16 22:47:12 +00002971 goal = openfile->current_y;
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002972
David Lawrence Ramseyf2ac2012016-12-28 09:43:23 -06002973 /* Limit goal to (editwinrows - 1) rows maximum. */
Chris Allegretta374216f2010-01-04 19:00:55 +00002974 if (goal > editwinrows - 1)
2975 goal = editwinrows - 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002976 }
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002977
Benno Schulenberg0bffd992016-04-16 11:38:39 +02002978 openfile->edittop = openfile->current;
2979
2980 while (goal > 0 && openfile->edittop->prev != NULL) {
2981 openfile->edittop = openfile->edittop->prev;
Benno Schulenberg55b14032016-10-20 22:04:38 +02002982 goal--;
Benno Schulenberg1102aaa2014-06-09 20:26:54 +00002983#ifndef NANO_TINY
Benno Schulenberg598e0af2016-09-15 10:43:49 +02002984 if (ISSET(SOFTWRAP)) {
Faissal Bensefiade95ca62016-10-20 09:44:29 +01002985 goal -= strlenpt(openfile->edittop->data) / editwincols;
Benno Schulenberg598e0af2016-09-15 10:43:49 +02002986 if (goal < 0)
2987 openfile->edittop = openfile->edittop->next;
2988 }
Benno Schulenberg1102aaa2014-06-09 20:26:54 +00002989#endif
Chris Allegretta35afab52009-09-13 04:50:44 +00002990 }
Chris Allegretta1a7a91b2010-01-13 03:21:19 +00002991#ifdef DEBUG
Benno Schulenberg01bbf7e2016-10-20 21:11:11 +02002992 fprintf(stderr, "adjust_viewport(): setting edittop to lineno %ld\n", (long)openfile->edittop->lineno);
Chris Allegretta1a7a91b2010-01-13 03:21:19 +00002993#endif
Benno Schulenberg0208ae72017-01-12 17:33:46 +01002994 compute_maxlines();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002995}
2996
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002997/* Unconditionally redraw the entire screen. */
David Lawrence Ramseyc54c4d12005-06-18 15:49:17 +00002998void total_redraw(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002999{
David Lawrence Ramseyf78bc852007-12-18 15:55:48 +00003000#ifdef USE_SLANG
3001 /* Slang curses emulation brain damage, part 4: Slang doesn't define
3002 * curscr. */
3003 SLsmg_touch_screen();
3004 SLsmg_refresh();
3005#else
David Lawrence Ramseyb386a902005-07-10 02:37:38 +00003006 wrefresh(curscr);
David Lawrence Ramseyf78bc852007-12-18 15:55:48 +00003007#endif
David Lawrence Ramseyb9ddb802005-03-17 17:56:48 +00003008}
3009
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00003010/* Unconditionally redraw the entire screen, and then refresh it using
3011 * the current file. */
David Lawrence Ramseyb9ddb802005-03-17 17:56:48 +00003012void total_refresh(void)
3013{
David Lawrence Ramseyc54c4d12005-06-18 15:49:17 +00003014 total_redraw();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003015 titlebar(NULL);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003016 edit_refresh();
Chris Allegretta79a33bb2008-03-05 07:34:01 +00003017 bottombars(currmenu);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003018}
3019
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00003020/* Display the main shortcut list on the last two rows of the bottom
3021 * portion of the window. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003022void display_main_list(void)
3023{
Benno Schulenberg00389922014-04-04 11:59:03 +00003024#ifndef DISABLE_COLOR
Benno Schulenberg17cf8332016-05-30 09:09:36 +02003025 if (openfile->syntax &&
3026 (openfile->syntax->formatter || openfile->syntax->linter))
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003027 set_lint_or_format_shortcuts();
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003028 else
3029 set_spell_shortcuts();
3030#endif
3031
Chris Allegretta79a33bb2008-03-05 07:34:01 +00003032 bottombars(MMAIN);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003033}
3034
David Lawrence Ramsey4e05b752005-06-28 20:04:14 +00003035/* If constant is TRUE, we display the current cursor position only if
Benno Schulenberg9d6d5b62016-05-04 12:18:21 +02003036 * suppress_cursorpos is FALSE. If constant is FALSE, we display the
3037 * position always. In any case we reset suppress_cursorpos to FALSE. */
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003038void do_cursorpos(bool constant)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003039{
Benno Schulenberga7721942016-12-11 11:24:48 +01003040 char saved_byte;
3041 size_t sum, cur_xpt = xplustabs() + 1;
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +00003042 size_t cur_lenpt = strlenpt(openfile->current->data) + 1;
David Lawrence Ramsey4e05b752005-06-28 20:04:14 +00003043 int linepct, colpct, charpct;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003044
David Lawrence Ramsey4ab80152005-07-31 18:51:51 +00003045 assert(openfile->fileage != NULL && openfile->current != NULL);
Chris Allegretta2084acc2001-11-29 03:43:08 +00003046
Benno Schulenberg9d6d5b62016-05-04 12:18:21 +02003047 /* Determine the size of the file up to the cursor. */
Benno Schulenberga7721942016-12-11 11:24:48 +01003048 saved_byte = openfile->current->data[openfile->current_x];
David Lawrence Ramsey15d68572005-07-31 20:15:01 +00003049 openfile->current->data[openfile->current_x] = '\0';
David Lawrence Ramsey04f65f22005-08-01 02:18:05 +00003050
Benno Schulenberga7721942016-12-11 11:24:48 +01003051 sum = get_totsize(openfile->fileage, openfile->current);
David Lawrence Ramsey04f65f22005-08-01 02:18:05 +00003052
Benno Schulenberga7721942016-12-11 11:24:48 +01003053 openfile->current->data[openfile->current_x] = saved_byte;
Benno Schulenbergfaf77fb2016-12-11 11:18:28 +01003054
3055 /* When not at EOF, subtract 1 for an overcounted newline. */
3056 if (openfile->current != openfile->filebot)
Benno Schulenberga7721942016-12-11 11:24:48 +01003057 sum--;
Chris Allegretta14b3ca92002-01-25 21:59:02 +00003058
Benno Schulenberg9d6d5b62016-05-04 12:18:21 +02003059 /* If the position needs to be suppressed, don't suppress it next time. */
Benno Schulenberg66986592016-05-14 21:49:19 +02003060 if (suppress_cursorpos && constant) {
Benno Schulenberg9d6d5b62016-05-04 12:18:21 +02003061 suppress_cursorpos = FALSE;
Benno Schulenberg66986592016-05-14 21:49:19 +02003062 return;
Chris Allegrettad26ab912003-01-28 01:16:47 +00003063 }
Chris Allegretta14b3ca92002-01-25 21:59:02 +00003064
Benno Schulenberg9d6d5b62016-05-04 12:18:21 +02003065 /* Display the current cursor position on the statusbar. */
Benno Schulenberg08d9f572015-07-10 17:25:51 +00003066 linepct = 100 * openfile->current->lineno / openfile->filebot->lineno;
David Lawrence Ramsey4e05b752005-06-28 20:04:14 +00003067 colpct = 100 * cur_xpt / cur_lenpt;
Benno Schulenberga7721942016-12-11 11:24:48 +01003068 charpct = (openfile->totsize == 0) ? 0 : 100 * sum / openfile->totsize;
Chris Allegrettad26ab912003-01-28 01:16:47 +00003069
Benno Schulenberg2535f512016-04-30 17:31:43 +02003070 statusline(HUSH,
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00003071 _("line %ld/%ld (%d%%), col %lu/%lu (%d%%), char %lu/%lu (%d%%)"),
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +00003072 (long)openfile->current->lineno,
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00003073 (long)openfile->filebot->lineno, linepct,
David Lawrence Ramsey4e05b752005-06-28 20:04:14 +00003074 (unsigned long)cur_xpt, (unsigned long)cur_lenpt, colpct,
Benno Schulenberga7721942016-12-11 11:24:48 +01003075 (unsigned long)sum, (unsigned long)openfile->totsize, charpct);
Benno Schulenberg66986592016-05-14 21:49:19 +02003076
3077 /* Displaying the cursor position should not suppress it next time. */
3078 suppress_cursorpos = FALSE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003079}
3080
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00003081/* Unconditionally display the current cursor position. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003082void do_cursorpos_void(void)
Chris Allegretta2084acc2001-11-29 03:43:08 +00003083{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003084 do_cursorpos(FALSE);
Chris Allegretta2084acc2001-11-29 03:43:08 +00003085}
3086
Chris Allegretta0dc26dc2009-01-24 22:40:41 +00003087void enable_nodelay(void)
3088{
Benno Schulenberg492e9f62014-06-20 10:48:26 +00003089 nodelay_mode = TRUE;
3090 nodelay(edit, TRUE);
Chris Allegretta0dc26dc2009-01-24 22:40:41 +00003091}
3092
3093void disable_nodelay(void)
3094{
Benno Schulenberg492e9f62014-06-20 10:48:26 +00003095 nodelay_mode = FALSE;
3096 nodelay(edit, FALSE);
Chris Allegretta0dc26dc2009-01-24 22:40:41 +00003097}
3098
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003099/* Highlight the current word being replaced or spell checked. We
3100 * expect word to have tabs and control characters expanded. */
Benno Schulenbergc98afde2016-03-30 12:09:39 +00003101void spotlight(bool active, const char *word)
Chris Allegrettafb62f732000-12-05 11:36:41 +00003102{
Benno Schulenberg29cac042016-03-30 12:18:22 +00003103 size_t word_len = strlenpt(word), room;
Chris Allegrettafb62f732000-12-05 11:36:41 +00003104
Benno Schulenberg17cf8332016-05-30 09:09:36 +02003105 /* Compute the number of columns that are available for the word. */
Faissal Bensefiade95ca62016-10-20 09:44:29 +01003106 room = editwincols + get_page_start(xplustabs()) - xplustabs();
Chris Allegrettafb62f732000-12-05 11:36:41 +00003107
Benno Schulenberg29cac042016-03-30 12:18:22 +00003108 assert(room > 0);
David Lawrence Ramsey913db832005-01-05 05:08:14 +00003109
Benno Schulenberg29cac042016-03-30 12:18:22 +00003110 if (word_len > room)
3111 room--;
David Lawrence Ramsey913db832005-01-05 05:08:14 +00003112
Chris Allegrettafb62f732000-12-05 11:36:41 +00003113 reset_cursor();
Chris Allegretta598106e2002-01-19 01:59:37 +00003114
Benno Schulenbergc98afde2016-03-30 12:09:39 +00003115 if (active)
Benno Schulenbergc9700352014-05-04 08:53:06 +00003116 wattron(edit, hilite_attribute);
Chris Allegrettafb62f732000-12-05 11:36:41 +00003117
David Lawrence Ramsey21b946e2006-11-10 20:13:38 +00003118 /* This is so we can show zero-length matches. */
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00003119 if (word_len == 0)
David Lawrence Ramsey5b9f5222005-06-13 02:22:44 +00003120 waddch(edit, ' ');
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00003121 else
Benno Schulenberg29cac042016-03-30 12:18:22 +00003122 waddnstr(edit, word, actual_x(word, room));
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003123
Benno Schulenberg29cac042016-03-30 12:18:22 +00003124 if (word_len > room)
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00003125 waddch(edit, '$');
Chris Allegrettafb62f732000-12-05 11:36:41 +00003126
Benno Schulenbergc98afde2016-03-30 12:09:39 +00003127 if (active)
Benno Schulenbergc9700352014-05-04 08:53:06 +00003128 wattroff(edit, hilite_attribute);
Benno Schulenbergc6512a92016-12-01 15:14:41 +01003129
3130 wnoutrefresh(edit);
Chris Allegrettafb62f732000-12-05 11:36:41 +00003131}
3132
Benno Schulenbergd17438b2014-04-03 20:57:44 +00003133#ifndef DISABLE_EXTRA
Benno Schulenberg8d53aa32015-02-01 09:19:58 +00003134#define CREDIT_LEN 54
3135#define XLCREDIT_LEN 9
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00003136
David Lawrence Ramsey8ad58bc2005-08-16 03:02:46 +00003137/* Easter egg: Display credits. Assume nodelay(edit) and scrollok(edit)
3138 * are FALSE. */
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003139void do_credits(void)
3140{
David Lawrence Ramsey31de1052005-08-14 19:25:16 +00003141 bool old_more_space = ISSET(MORE_SPACE);
3142 bool old_no_help = ISSET(NO_HELP);
David Lawrence Ramsey3925bda2005-06-07 03:20:35 +00003143 int kbinput = ERR, crpos = 0, xlpos = 0;
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003144 const char *credits[CREDIT_LEN] = {
3145 NULL, /* "The nano text editor" */
3146 NULL, /* "version" */
Chris Allegretta598106e2002-01-19 01:59:37 +00003147 VERSION,
3148 "",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003149 NULL, /* "Brought to you by:" */
Chris Allegretta598106e2002-01-19 01:59:37 +00003150 "Chris Allegretta",
3151 "Jordi Mallach",
3152 "Adam Rogoyski",
3153 "Rob Siemborski",
3154 "Rocco Corsi",
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003155 "David Lawrence Ramsey",
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00003156 "David Benbennick",
Benno Schulenberga44def02014-12-28 22:27:56 +00003157 "Mark Majeres",
David Lawrence Ramsey47daf022005-08-29 18:29:02 +00003158 "Mike Frysinger",
Chris Allegretta34b7f1c2014-02-24 15:15:51 +00003159 "Benno Schulenberg",
Chris Allegretta598106e2002-01-19 01:59:37 +00003160 "Ken Tyler",
3161 "Sven Guckes",
Chris Allegretta598106e2002-01-19 01:59:37 +00003162 "Bill Soudan",
3163 "Christian Weisgerber",
3164 "Erik Andersen",
3165 "Big Gaute",
3166 "Joshua Jensen",
3167 "Ryan Krebs",
3168 "Albert Chin",
Chris Allegretta598106e2002-01-19 01:59:37 +00003169 "",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003170 NULL, /* "Special thanks to:" */
Chris Allegretta34b7f1c2014-02-24 15:15:51 +00003171 "Monique, Brielle & Joseph",
Chris Allegretta598106e2002-01-19 01:59:37 +00003172 "Plattsburgh State University",
3173 "Benet Laboratories",
3174 "Amy Allegretta",
3175 "Linda Young",
3176 "Jeremy Robichaud",
3177 "Richard Kolb II",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003178 NULL, /* "The Free Software Foundation" */
Chris Allegretta598106e2002-01-19 01:59:37 +00003179 "Linus Torvalds",
Benno Schulenberg8d53aa32015-02-01 09:19:58 +00003180 NULL, /* "the many translators and the TP" */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003181 NULL, /* "For ncurses:" */
Chris Allegrettadce44ab2002-03-16 01:03:41 +00003182 "Thomas Dickey",
3183 "Pavel Curtis",
3184 "Zeyd Ben-Halim",
3185 "Eric S. Raymond",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003186 NULL, /* "and anyone else we forgot..." */
3187 NULL, /* "Thank you for using nano!" */
3188 "",
3189 "",
3190 "",
3191 "",
Benno Schulenberg1b293ff2016-01-10 16:18:43 +00003192 "(C) 1999 - 2016",
David Lawrence Ramseyd8a1d372007-10-11 05:01:32 +00003193 "Free Software Foundation, Inc.",
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003194 "",
3195 "",
3196 "",
3197 "",
Jordi Mallachc2b199e2016-06-20 19:44:56 +02003198 "https://nano-editor.org/"
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003199 };
3200
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003201 const char *xlcredits[XLCREDIT_LEN] = {
David Lawrence Ramsey576bf332004-07-12 03:10:30 +00003202 N_("The nano text editor"),
3203 N_("version"),
3204 N_("Brought to you by:"),
3205 N_("Special thanks to:"),
3206 N_("The Free Software Foundation"),
Benno Schulenberg8d53aa32015-02-01 09:19:58 +00003207 N_("the many translators and the TP"),
David Lawrence Ramsey576bf332004-07-12 03:10:30 +00003208 N_("For ncurses:"),
3209 N_("and anyone else we forgot..."),
3210 N_("Thank you for using nano!")
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003211 };
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00003212
David Lawrence Ramsey31de1052005-08-14 19:25:16 +00003213 if (!old_more_space || !old_no_help) {
3214 SET(MORE_SPACE);
3215 SET(NO_HELP);
3216 window_init();
3217 }
3218
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003219 curs_set(0);
3220 nodelay(edit, TRUE);
David Lawrence Ramsey31de1052005-08-14 19:25:16 +00003221
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003222 blank_titlebar();
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00003223 blank_edit();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003224 blank_statusbar();
David Lawrence Ramseyc71e0312005-08-14 21:17:37 +00003225
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003226 wrefresh(topwin);
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00003227 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003228 wrefresh(bottomwin);
David Lawrence Ramseyc71e0312005-08-14 21:17:37 +00003229 napms(700);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003230
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003231 for (crpos = 0; crpos < CREDIT_LEN + editwinrows / 2; crpos++) {
David Lawrence Ramsey3925bda2005-06-07 03:20:35 +00003232 if ((kbinput = wgetch(edit)) != ERR)
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003233 break;
David Lawrence Ramsey0099a8f2005-03-15 06:34:09 +00003234
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003235 if (crpos < CREDIT_LEN) {
David Lawrence Ramsey9905b6a2005-06-28 07:26:11 +00003236 const char *what;
Benno Schulenberg8f21d252017-01-08 12:05:42 +01003237 size_t start_col;
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003238
David Lawrence Ramsey4dc58382005-03-15 06:58:02 +00003239 if (credits[crpos] == NULL) {
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003240 assert(0 <= xlpos && xlpos < XLCREDIT_LEN);
David Lawrence Ramsey4dc58382005-03-15 06:58:02 +00003241
David Lawrence Ramsey9905b6a2005-06-28 07:26:11 +00003242 what = _(xlcredits[xlpos]);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003243 xlpos++;
David Lawrence Ramsey4dc58382005-03-15 06:58:02 +00003244 } else
David Lawrence Ramsey9905b6a2005-06-28 07:26:11 +00003245 what = credits[crpos];
David Lawrence Ramsey4dc58382005-03-15 06:58:02 +00003246
Benno Schulenberg8f21d252017-01-08 12:05:42 +01003247 start_col = COLS / 2 - strlenpt(what) / 2 - 1;
David Lawrence Ramsey4dc58382005-03-15 06:58:02 +00003248 mvwaddstr(edit, editwinrows - 1 - (editwinrows % 2),
Benno Schulenberg8f21d252017-01-08 12:05:42 +01003249 start_col, what);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003250 }
David Lawrence Ramsey0099a8f2005-03-15 06:34:09 +00003251
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003252 wrefresh(edit);
David Lawrence Ramseyc71e0312005-08-14 21:17:37 +00003253
David Lawrence Ramsey3925bda2005-06-07 03:20:35 +00003254 if ((kbinput = wgetch(edit)) != ERR)
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003255 break;
3256 napms(700);
David Lawrence Ramseyc71e0312005-08-14 21:17:37 +00003257
David Lawrence Ramsey31de1052005-08-14 19:25:16 +00003258 scrollok(edit, TRUE);
David Lawrence Ramseyc71e0312005-08-14 21:17:37 +00003259 wscrl(edit, 1);
3260 scrollok(edit, FALSE);
3261 wrefresh(edit);
3262
3263 if ((kbinput = wgetch(edit)) != ERR)
3264 break;
3265 napms(700);
3266
3267 scrollok(edit, TRUE);
3268 wscrl(edit, 1);
David Lawrence Ramsey31de1052005-08-14 19:25:16 +00003269 scrollok(edit, FALSE);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003270 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003271 }
3272
David Lawrence Ramsey3925bda2005-06-07 03:20:35 +00003273 if (kbinput != ERR)
3274 ungetch(kbinput);
3275
Benno Schulenbergc916ca82016-01-02 16:33:03 +00003276 if (!old_more_space)
David Lawrence Ramsey31de1052005-08-14 19:25:16 +00003277 UNSET(MORE_SPACE);
Benno Schulenbergc916ca82016-01-02 16:33:03 +00003278 if (!old_no_help)
David Lawrence Ramsey31de1052005-08-14 19:25:16 +00003279 UNSET(NO_HELP);
Benno Schulenbergc916ca82016-01-02 16:33:03 +00003280 window_init();
David Lawrence Ramsey31de1052005-08-14 19:25:16 +00003281
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003282 nodelay(edit, FALSE);
David Lawrence Ramsey31de1052005-08-14 19:25:16 +00003283
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00003284 total_refresh();
Chris Allegretta598106e2002-01-19 01:59:37 +00003285}
Benno Schulenbergd17438b2014-04-03 20:57:44 +00003286#endif /* !DISABLE_EXTRA */