blob: a4cfdf131b2b55bb5361a62dfe004015b6be9086 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * winio.c *
4 * *
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +00005 * Copyright (C) 1999-2004 Chris Allegretta *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00006 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
Chris Allegretta3a24f3f2001-10-24 11:33:54 +00008 * the Free Software Foundation; either version 2, or (at your option) *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00009 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +000022#include "config.h"
23
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000024#include <stdarg.h>
25#include <string.h>
Chris Allegrettadba37ae2000-07-07 05:13:09 +000026#include <stdlib.h>
Chris Allegretta8a0de3b2000-11-24 20:45:14 +000027#include <unistd.h>
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +000028#include <ctype.h>
Chris Allegretta6232d662002-05-12 19:52:15 +000029#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000030#include "proto.h"
31#include "nano.h"
32
David Lawrence Ramseyf5300af2004-02-24 20:48:12 +000033#ifdef NANO_EXTRA
34#include <time.h>
35#endif
36
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000037static int statblank = 0; /* Number of keystrokes left after
Chris Allegretta88520c92001-05-05 17:45:54 +000038 we call statusbar(), before we
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000039 actually blank the statusbar */
Robert Siemborskid8510b22000-06-06 23:04:06 +000040
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000041/* Read in a single input character. If it's ignored, swallow it and go
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +000042 * on. Otherwise, try to translate it from ASCII, extended keypad
43 * values, and/or escape sequences. Supported extended keypad values
44 * consist of [arrow key], Ctrl-[arrow key], Shift-[arrow key], Enter,
45 * Backspace, Insert, Delete, Home, End, PageUp, PageDown, and F1-F14.
46 * Assume nodelay(win) is FALSE. */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +000047int get_kbinput(WINDOW *win, int *meta_key)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000048{
49 int kbinput, retval;
50
David Lawrence Ramsey369732f2004-02-16 20:32:40 +000051#ifndef NANO_SMALL
52 allow_pending_sigwinch(TRUE);
53#endif
54
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000055 kbinput = get_ignored_kbinput(win);
David Lawrence Ramsey1576d532004-03-19 21:46:34 +000056 retval = get_accepted_kbinput(win, kbinput, meta_key);
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000057
David Lawrence Ramsey369732f2004-02-16 20:32:40 +000058#ifndef NANO_SMALL
59 allow_pending_sigwinch(FALSE);
60#endif
61
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000062 return retval;
63}
64
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +000065/* Read in a string of input characters (e.g. an escape sequence)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000066 * verbatim, and return the length of the string in kbinput_len. Assume
67 * nodelay(win) is FALSE. */
David Lawrence Ramseyee383db2004-02-06 03:07:10 +000068int *get_verbatim_kbinput(WINDOW *win, int *kbinput_len, int
69 allow_ascii)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000070{
David Lawrence Ramseyee383db2004-02-06 03:07:10 +000071 int kbinput, *verbatim_kbinput;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000072
David Lawrence Ramsey369732f2004-02-16 20:32:40 +000073#ifndef NANO_SMALL
74 allow_pending_sigwinch(TRUE);
75#endif
76
David Lawrence Ramseyedc1ea42004-04-07 01:07:50 +000077 /* Switch to raw mode if necessary so that we can type ^C, ^Q, ^S,
78 * ^Z, and ^\ (and ^Y on systems supporting delayed suspend) without
79 * getting interrupts, and turn the keypad off so that we don't get
80 * extended keypad values, all of which are outside the ASCII
81 * range. */
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +000082#ifdef _POSIX_VDISABLE
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +000083 raw();
84#endif
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +000085 keypad(win, FALSE);
David Lawrence Ramsey58f6d832004-01-27 07:12:47 +000086
87 kbinput = wgetch(win);
David Lawrence Ramseyee383db2004-02-06 03:07:10 +000088 verbatim_kbinput = (int *)nmalloc(sizeof(int));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000089 verbatim_kbinput[0] = kbinput;
90 *kbinput_len = 1;
91
David Lawrence Ramseyf4276942003-12-24 03:33:09 +000092 if (allow_ascii && kbinput >= '0' && kbinput <= '2')
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000093 /* Entering a three-digit decimal ASCII code from 000-255 in
94 * verbatim mode will produce the corresponding ASCII
95 * character. */
David Lawrence Ramseyee383db2004-02-06 03:07:10 +000096 verbatim_kbinput[0] = get_ascii_kbinput(win, kbinput);
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000097 else {
98 nodelay(win, TRUE);
David Lawrence Ramseye1e7cb22004-04-15 06:15:55 +000099#ifdef DEBUG
100 fprintf(stderr, "get_verbatim_kbinput(): kbinput = %d\n", kbinput);
101#endif
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000102 while ((kbinput = wgetch(win)) != ERR) {
David Lawrence Ramseyda8fd8f2003-09-16 01:22:31 +0000103 (*kbinput_len)++;
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000104 verbatim_kbinput = realloc(verbatim_kbinput, *kbinput_len * sizeof(int));
105 verbatim_kbinput[*kbinput_len - 1] = kbinput;
David Lawrence Ramseye1e7cb22004-04-15 06:15:55 +0000106#ifdef DEBUG
107 fprintf(stderr, "get_verbatim_kbinput(): kbinput = %d\n", kbinput);
108#endif
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000109 }
110 nodelay(win, FALSE);
111 }
112
David Lawrence Ramseyedc1ea42004-04-07 01:07:50 +0000113 /* Switch back to cbreak mode if necessary and turn the keypad back
114 * on now that we're done. */
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +0000115#ifdef _POSIX_VDISABLE
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +0000116 cbreak();
117#endif
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000118 keypad(win, TRUE);
David Lawrence Ramsey58f6d832004-01-27 07:12:47 +0000119
David Lawrence Ramsey369732f2004-02-16 20:32:40 +0000120#ifndef NANO_SMALL
121 allow_pending_sigwinch(FALSE);
122#endif
123
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000124 return verbatim_kbinput;
125}
126
127/* Swallow input characters that should be quietly ignored, and return
128 * the first input character that shouldn't be. */
129int get_ignored_kbinput(WINDOW *win)
130{
131 int kbinput;
132
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000133 while (TRUE) {
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000134 kbinput = wgetch(win);
135 switch (kbinput) {
136 case ERR:
137 case KEY_RESIZE:
138#ifdef PDCURSES
139 case KEY_SHIFT_L:
140 case KEY_SHIFT_R:
141 case KEY_CONTROL_L:
142 case KEY_CONTROL_R:
143 case KEY_ALT_L:
144 case KEY_ALT_R:
145#endif
146#ifdef DEBUG
147 fprintf(stderr, "get_ignored_kbinput(): kbinput = %d\n", kbinput);
148#endif
149 break;
150 default:
151 return kbinput;
152 }
153 }
154}
155
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000156/* Translate acceptable ASCII, extended keypad values, and/or escape
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000157 * sequences. Set meta_key to 1 if we get a Meta sequence. Assume
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000158 * nodelay(win) is FALSE. */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000159int get_accepted_kbinput(WINDOW *win, int kbinput, int *meta_key)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000160{
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000161 *meta_key = FALSE;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000162
163 switch (kbinput) {
164 case NANO_CONTROL_3: /* Escape */
David Lawrence Ramsey25061362004-01-16 19:12:46 +0000165 kbinput = wgetch(win);
166 switch (kbinput) {
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000167 case NANO_CONTROL_3: /* Escape */
168 kbinput = wgetch(win);
169 /* Esc Esc [three-digit decimal ASCII code from
170 * 000-255] == [corresponding ASCII character];
David Lawrence Ramseyd390dd82004-02-07 03:38:02 +0000171 * Esc Esc 2 obviously can't be Ctrl-2 here */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000172 if (kbinput >= '0' && kbinput <= '2')
173 kbinput = get_ascii_kbinput(win, kbinput);
174 /* Esc Esc [character] == Ctrl-[character];
175 * Ctrl-Space (Ctrl-2) == Ctrl-@ == Ctrl-` */
176 else if (kbinput == ' ' || kbinput == '@' || kbinput == '`')
177 kbinput = NANO_CONTROL_SPACE;
178 /* Ctrl-3 (Ctrl-[, Esc) to Ctrl-7 (Ctrl-_) */
179 else if (kbinput >= '3' && kbinput <= '7')
180 kbinput -= 24;
181 /* Ctrl-8 (Ctrl-?) */
182 else if (kbinput == '8' || kbinput == '?')
183 kbinput = NANO_CONTROL_8;
184 /* Ctrl-A to Ctrl-_ */
185 else if (kbinput >= 'A' && kbinput <= '_')
186 kbinput -= 64;
David Lawrence Ramseyda8fd8f2003-09-16 01:22:31 +0000187 /* Ctrl-A to Ctrl-~ */
188 else if (kbinput >= 'a' && kbinput <= '~')
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000189 kbinput -= 96;
190 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000191 case 'O':
192 case 'o':
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000193 /* Terminal breakage, part 1: We shouldn't get an escape
194 * sequence here for terminals that support Delete, but
195 * we do sometimes on FreeBSD. Thank you, Wouter van
196 * Hemel. */
197 case '[':
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000198 {
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000199 int old_kbinput = kbinput, *escape_seq, escape_seq_len;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000200 nodelay(win, TRUE);
201 kbinput = wgetch(win);
202 switch (kbinput) {
203 case ERR:
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000204 kbinput = tolower(old_kbinput);
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000205 *meta_key = TRUE;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000206 break;
207 default:
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000208 ungetch(kbinput);
209 ungetch(old_kbinput);
210 escape_seq = get_verbatim_kbinput(win, &escape_seq_len, 0);
211 kbinput = get_escape_seq_kbinput(win, escape_seq, escape_seq_len);
212 free(escape_seq);
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000213 }
214 nodelay(win, FALSE);
215 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000216 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000217 default:
218 /* Esc [character] == Meta-[character] */
David Lawrence Ramseyda8fd8f2003-09-16 01:22:31 +0000219 kbinput = tolower(kbinput);
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000220 *meta_key = TRUE;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000221 }
222 break;
David Lawrence Ramsey7776ef92003-11-04 18:32:35 +0000223 case NANO_CONTROL_8:
224 /* Terminal breakage, part 2: We shouldn't get Ctrl-8
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000225 * (Ctrl-?) for Backspace or Delete, but we do sometimes. */
226 kbinput = ISSET(REBIND_DELETE) ? NANO_DELETE_KEY : NANO_BACKSPACE_KEY;
David Lawrence Ramsey7776ef92003-11-04 18:32:35 +0000227 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000228 case KEY_DOWN:
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000229 kbinput = NANO_NEXTLINE_KEY;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000230 break;
231 case KEY_UP:
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000232 kbinput = NANO_PREVLINE_KEY;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000233 break;
234 case KEY_LEFT:
235 kbinput = NANO_BACK_KEY;
236 break;
237 case KEY_RIGHT:
238 kbinput = NANO_FORWARD_KEY;
239 break;
240 case KEY_HOME:
241 kbinput = NANO_HOME_KEY;
242 break;
243 case KEY_BACKSPACE:
244 kbinput = NANO_BACKSPACE_KEY;
245 break;
246 case KEY_DC:
David Lawrence Ramsey7776ef92003-11-04 18:32:35 +0000247 /* Terminal breakage, part 3: We should only get KEY_DC when
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000248 * hitting Delete, but we get it when hitting Backspace
249 * sometimes on FreeBSD. Thank you, Lee Nelson. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000250 kbinput = ISSET(REBIND_DELETE) ? NANO_BACKSPACE_KEY : NANO_DELETE_KEY;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000251 break;
252 case KEY_IC:
253 kbinput = NANO_INSERTFILE_KEY;
254 break;
255 case KEY_NPAGE:
256 kbinput = NANO_NEXTPAGE_KEY;
257 break;
258 case KEY_PPAGE:
259 kbinput = NANO_PREVPAGE_KEY;
260 break;
261 case KEY_ENTER:
262 kbinput = NANO_ENTER_KEY;
263 break;
264 case KEY_END:
265 kbinput = NANO_END_KEY;
266 break;
267 case KEY_SUSPEND:
268 kbinput = NANO_SUSPEND_KEY;
269 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000270 case KEY_SLEFT:
271 kbinput = NANO_BACK_KEY;
272 break;
273 case KEY_SRIGHT:
274 kbinput = NANO_FORWARD_KEY;
275 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000276 }
277#ifdef DEBUG
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000278 fprintf(stderr, "get_accepted_kbinput(): kbinput = %d, meta_key = %d\n", kbinput, *meta_key);
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000279#endif
280 return kbinput;
281}
282
283/* Translate a three-digit decimal ASCII code from 000-255 into the
284 * corresponding ASCII character. */
285int get_ascii_kbinput(WINDOW *win, int kbinput)
286{
287 int retval;
288
289 switch (kbinput) {
290 case '0':
291 case '1':
292 case '2':
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000293 retval = (kbinput - '0') * 100;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000294 break;
295 default:
296 return kbinput;
297 }
298
299 kbinput = wgetch(win);
300 switch (kbinput) {
301 case '0':
302 case '1':
303 case '2':
304 case '3':
305 case '4':
306 case '5':
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000307 retval += (kbinput - '0') * 10;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000308 break;
309 case '6':
310 case '7':
311 case '8':
312 case '9':
313 if (retval < 200) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000314 retval += (kbinput - '0') * 10;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000315 break;
316 }
317 default:
318 return kbinput;
319 }
320
321 kbinput = wgetch(win);
322 switch (kbinput) {
323 case '0':
324 case '1':
325 case '2':
326 case '3':
327 case '4':
328 case '5':
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000329 retval += kbinput - '0';
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000330 break;
331 case '6':
332 case '7':
333 case '8':
334 case '9':
335 if (retval < 250) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000336 retval += kbinput - '0';
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000337 break;
338 }
339 default:
340 return kbinput;
341 }
342
343#ifdef DEBUG
344 fprintf(stderr, "get_ascii_kbinput(): kbinput = %d\n", kbinput);
345#endif
346 return retval;
347}
348
David Lawrence Ramsey58f6d832004-01-27 07:12:47 +0000349/* Translate escape sequences, most of which correspond to extended
350 * keypad values. These sequences are generated when the terminal
351 * doesn't support the needed keys. Assume that Escape has already been
352 * read in, and that nodelay(win) is TRUE.
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000353 *
354 * The supported terminals are the Linux console, the FreeBSD console,
355 * the Hurd console (a.k.a. the Mach console), xterm, rxvt, and Eterm.
356 * There are several escape sequence conflicts and omissions, outlined
357 * as follows:
358 *
359 * - F1 on FreeBSD console == kmous on xterm/rxvt/Eterm; the latter is
360 * omitted. (Mouse input will only work properly if the extended
361 * keypad value KEY_MOUSE is generated on mouse events instead of the
362 * kmous escape sequence.)
363 * - F9 on FreeBSD console == PageDown on Hurd console; the former is
David Lawrence Ramsey0ee54d92004-01-26 20:18:52 +0000364 * omitted. (The editing keypad, consisting of Insert, Delete, Home,
365 * End, PageUp, and PageDown, is more important to have working than
366 * the function keys, because the functions of the former are not
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000367 * arbitrary and the functions of the latter are.)
368 * - F10 on FreeBSD console == PageUp on Hurd console; the former is
369 * omitted. (Same as above.)
370 * - F13 on FreeBSD console == End on Hurd console; the former is
371 * omitted. (Same as above.)
372 * - The Hurd console has no escape sequences for F11, F12, F13, or
373 * F14. */
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000374int get_escape_seq_kbinput(WINDOW *win, int *escape_seq, int
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000375 escape_seq_len)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000376{
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000377 int kbinput = ERR;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000378
379 if (escape_seq_len > 1) {
380 switch (escape_seq[0]) {
381 case 'O':
382 switch (escape_seq[1]) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000383 case '2':
384 if (escape_seq_len >= 3) {
385 switch (escape_seq[2]) {
386 case 'P': /* Esc O 2 P == F13 on
387 * xterm. */
388 kbinput = KEY_F(13);
389 break;
390 case 'Q': /* Esc O 2 Q == F14 on
391 * xterm. */
392 kbinput = KEY_F(14);
393 break;
394 }
395 }
396 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000397 case 'A': /* Esc O A == Up on xterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000398 case 'B': /* Esc O B == Down on xterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000399 case 'C': /* Esc O C == Right on xterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000400 case 'D': /* Esc O D == Left on xterm. */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000401 kbinput = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000402 break;
403 case 'F': /* Esc O F == End on xterm. */
404 kbinput = NANO_END_KEY;
405 break;
406 case 'H': /* Esc O H == Home on xterm. */
407 kbinput = NANO_HOME_KEY;
408 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000409 case 'P': /* Esc O P == F1 on Hurd console. */
410 kbinput = KEY_F(1);
411 break;
412 case 'Q': /* Esc O Q == F2 on Hurd console. */
413 kbinput = KEY_F(2);
414 break;
415 case 'R': /* Esc O R == F3 on Hurd console. */
416 kbinput = KEY_F(3);
417 break;
418 case 'S': /* Esc O S == F4 on Hurd console. */
419 kbinput = KEY_F(4);
420 break;
421 case 'T': /* Esc O T == F5 on Hurd console. */
422 kbinput = KEY_F(5);
423 break;
424 case 'U': /* Esc O U == F6 on Hurd console. */
425 kbinput = KEY_F(6);
426 break;
427 case 'V': /* Esc O V == F7 on Hurd console. */
428 kbinput = KEY_F(7);
429 break;
430 case 'W': /* Esc O W == F8 on Hurd console. */
431 kbinput = KEY_F(8);
432 break;
433 case 'X': /* Esc O X == F9 on Hurd console. */
434 kbinput = KEY_F(9);
435 break;
436 case 'Y': /* Esc O Y == F10 on Hurd console. */
437 kbinput = KEY_F(10);
438 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000439 case 'a': /* Esc O a == Ctrl-Up on rxvt. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000440 case 'b': /* Esc O b == Ctrl-Down on rxvt. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000441 case 'c': /* Esc O c == Ctrl-Right on rxvt. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000442 case 'd': /* Esc O d == Ctrl-Left on rxvt. */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000443 kbinput = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000444 break;
445 }
446 break;
447 case 'o':
448 switch (escape_seq[1]) {
449 case 'a': /* Esc o a == Ctrl-Up on Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000450 case 'b': /* Esc o b == Ctrl-Down on Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000451 case 'c': /* Esc o c == Ctrl-Right on Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000452 case 'd': /* Esc o d == Ctrl-Left on Eterm. */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000453 kbinput = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000454 break;
455 }
456 break;
457 case '[':
458 switch (escape_seq[1]) {
459 case '1':
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000460 if (escape_seq_len >= 3) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000461 switch (escape_seq[2]) {
462 case '1': /* Esc [ 1 1 ~ == F1 on
463 * rxvt/Eterm. */
464 kbinput = KEY_F(1);
465 break;
466 case '2': /* Esc [ 1 2 ~ == F2 on
467 * rxvt/Eterm. */
468 kbinput = KEY_F(2);
469 break;
470 case '3': /* Esc [ 1 3 ~ == F3 on
471 * rxvt/Eterm. */
472 kbinput = KEY_F(3);
473 break;
474 case '4': /* Esc [ 1 4 ~ == F4 on
475 * rxvt/Eterm. */
476 kbinput = KEY_F(4);
477 break;
478 case '5': /* Esc [ 1 5 ~ == F5 on
479 * xterm/rxvt/Eterm. */
480 kbinput = KEY_F(5);
481 break;
482 case '7': /* Esc [ 1 7 ~ == F6 on Linux
483 * console/xterm/rxvt/Eterm. */
484 kbinput = KEY_F(6);
485 break;
486 case '8': /* Esc [ 1 8 ~ == F7 on Linux
487 * console/xterm/rxvt/Eterm. */
488 kbinput = KEY_F(7);
489 break;
490 case '9': /* Esc [ 1 9 ~ == F8 on Linux
491 * console/xterm/rxvt/Eterm. */
492 kbinput = KEY_F(8);
493 break;
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000494 case ';':
495 if (escape_seq_len >= 4) {
496 switch (escape_seq[3]) {
497 case '2':
498 if (escape_seq_len >= 5) {
499 switch (escape_seq[4]) {
500 case 'A': /* Esc [ 1 ; 2 A == Shift-Up on
501 * xterm. */
502 case 'B': /* Esc [ 1 ; 2 B == Shift-Down on
503 * xterm. */
504 case 'C': /* Esc [ 1 ; 2 C == Shift-Right on
505 * xterm. */
506 case 'D': /* Esc [ 1 ; 2 D == Shift-Left on
507 * xterm. */
508 kbinput = get_escape_seq_abcd(escape_seq[4]);
509 break;
510 }
511 }
512 break;
513 case '5':
514 if (escape_seq_len >= 5) {
515 switch (escape_seq[4]) {
516 case 'A': /* Esc [ 1 ; 5 A == Ctrl-Up on
517 * xterm. */
518 case 'B': /* Esc [ 1 ; 5 B == Ctrl-Down on
519 * xterm. */
520 case 'C': /* Esc [ 1 ; 5 C == Ctrl-Right on
521 * xterm. */
522 case 'D': /* Esc [ 1 ; 5 D == Ctrl-Left on
523 * xterm. */
524 kbinput = get_escape_seq_abcd(escape_seq[4]);
525 break;
526 }
527 }
528 break;
529 }
530 }
531 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000532 default: /* Esc [ 1 ~ == Home on Linux
533 * console. */
534 kbinput = NANO_HOME_KEY;
535 break;
536 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000537 }
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000538 break;
539 case '2':
540 if (escape_seq_len >= 3) {
541 switch (escape_seq[2]) {
542 case '0': /* Esc [ 2 0 ~ == F9 on Linux
543 * console/xterm/rxvt/Eterm. */
544 kbinput = KEY_F(9);
545 break;
546 case '1': /* Esc [ 2 1 ~ == F10 on Linux
547 * console/xterm/rxvt/Eterm. */
548 kbinput = KEY_F(10);
549 break;
550 case '3': /* Esc [ 2 3 ~ == F11 on Linux
551 * console/xterm/rxvt/Eterm. */
552 kbinput = KEY_F(11);
553 break;
554 case '4': /* Esc [ 2 4 ~ == F12 on Linux
555 * console/xterm/rxvt/Eterm. */
556 kbinput = KEY_F(12);
557 break;
558 case '5': /* Esc [ 2 5 ~ == F13 on Linux
559 * console/rxvt/Eterm. */
560 kbinput = KEY_F(13);
561 break;
562 case '6': /* Esc [ 2 6 ~ == F14 on Linux
563 * console/rxvt/Eterm. */
564 kbinput = KEY_F(14);
565 break;
566 default: /* Esc [ 2 ~ == Insert on Linux
567 * console/xterm. */
568 kbinput = NANO_INSERTFILE_KEY;
569 break;
570 }
571 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000572 break;
573 case '3': /* Esc [ 3 ~ == Delete on Linux
574 * console/xterm. */
575 kbinput = NANO_DELETE_KEY;
576 break;
577 case '4': /* Esc [ 4 ~ == End on Linux
578 * console/xterm. */
579 kbinput = NANO_END_KEY;
580 break;
581 case '5': /* Esc [ 5 ~ == PageUp on Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000582 * console/xterm; Esc [ 5 ^ == PageUp on
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000583 * Eterm. */
584 kbinput = NANO_PREVPAGE_KEY;
585 break;
586 case '6': /* Esc [ 6 ~ == PageDown on Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000587 * console/xterm; Esc [ 6 ^ == PageDown on
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000588 * Eterm. */
589 kbinput = NANO_NEXTPAGE_KEY;
590 break;
591 case '7': /* Esc [ 7 ~ == Home on rxvt. */
592 kbinput = NANO_HOME_KEY;
593 break;
594 case '8': /* Esc [ 8 ~ == End on rxvt. */
595 kbinput = NANO_END_KEY;
596 break;
597 case '9': /* Esc [ 9 == Delete on Hurd console. */
598 kbinput = NANO_DELETE_KEY;
599 break;
600 case '@': /* Esc [ @ == Insert on Hurd console. */
601 kbinput = NANO_INSERTFILE_KEY;
602 break;
603 case 'A': /* Esc [ A == Up on Linux console/FreeBSD
604 * console/Hurd console/rxvt/Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000605 case 'B': /* Esc [ B == Down on Linux
606 * console/FreeBSD console/Hurd
607 * console/rxvt/Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000608 case 'C': /* Esc [ C == Right on Linux
609 * console/FreeBSD console/Hurd
610 * console/rxvt/Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000611 case 'D': /* Esc [ D == Left on Linux
612 * console/FreeBSD console/Hurd
613 * console/rxvt/Eterm. */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000614 kbinput = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000615 break;
616 case 'F': /* Esc [ F == End on FreeBSD
617 * console/Eterm. */
618 kbinput = NANO_END_KEY;
619 break;
620 case 'G': /* Esc [ G == PageDown on FreeBSD
621 * console. */
622 kbinput = NANO_NEXTPAGE_KEY;
623 break;
624 case 'H': /* Esc [ H == Home on FreeBSD
625 * console/Hurd console/Eterm. */
626 kbinput = NANO_HOME_KEY;
627 break;
628 case 'I': /* Esc [ I == PageUp on FreeBSD
629 * console. */
630 kbinput = NANO_PREVPAGE_KEY;
631 break;
632 case 'L': /* Esc [ L == Insert on FreeBSD
633 * console. */
634 kbinput = NANO_INSERTFILE_KEY;
635 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000636 case 'M': /* Esc [ M == F1 on FreeBSD console. */
637 kbinput = KEY_F(1);
638 break;
639 case 'N': /* Esc [ N == F2 on FreeBSD console. */
640 kbinput = KEY_F(2);
641 break;
642 case 'O':
643 if (escape_seq_len >= 3) {
644 switch (escape_seq[2]) {
645 case 'P': /* Esc [ O P == F1 on
646 * xterm. */
647 kbinput = KEY_F(1);
648 break;
649 case 'Q': /* Esc [ O Q == F2 on
650 * xterm. */
651 kbinput = KEY_F(2);
652 break;
653 case 'R': /* Esc [ O R == F3 on
654 * xterm. */
655 kbinput = KEY_F(3);
656 break;
657 case 'S': /* Esc [ O S == F4 on
658 * xterm. */
659 kbinput = KEY_F(4);
660 break;
661 default: /* Esc [ O == F3 on
662 * FreeBSD console. */
663 kbinput = KEY_F(3);
664 break;
665 }
666 }
667 break;
668 case 'P': /* Esc [ P == F4 on FreeBSD console. */
669 kbinput = KEY_F(4);
670 break;
671 case 'Q': /* Esc [ Q == F5 on FreeBSD console. */
672 kbinput = KEY_F(5);
673 break;
674 case 'R': /* Esc [ R == F6 on FreeBSD console. */
675 kbinput = KEY_F(6);
676 break;
677 case 'S': /* Esc [ S == F7 on FreeBSD console. */
678 kbinput = KEY_F(7);
679 break;
680 case 'T': /* Esc [ T == F8 on FreeBSD console. */
681 kbinput = KEY_F(8);
682 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000683 case 'U': /* Esc [ U == PageDown on Hurd console. */
684 kbinput = NANO_NEXTPAGE_KEY;
685 break;
686 case 'V': /* Esc [ V == PageUp on Hurd console. */
687 kbinput = NANO_PREVPAGE_KEY;
688 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000689 case 'W': /* Esc [ W == F11 on FreeBSD console. */
690 kbinput = KEY_F(11);
691 break;
692 case 'X': /* Esc [ X == F12 on FreeBSD console. */
693 kbinput = KEY_F(12);
694 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000695 case 'Y': /* Esc [ Y == End on Hurd console. */
696 kbinput = NANO_END_KEY;
697 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000698 case 'Z': /* Esc [ Z == F14 on FreeBSD console. */
699 kbinput = KEY_F(14);
700 break;
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +0000701 case 'a': /* Esc [ a == Shift-Up on rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +0000702 case 'b': /* Esc [ b == Shift-Down on rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +0000703 case 'c': /* Esc [ c == Shift-Right on
704 * rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +0000705 case 'd': /* Esc [ d == Shift-Left on rxvt/Eterm. */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000706 kbinput = get_escape_seq_abcd(escape_seq[1]);
707 break;
708 case '[':
709 if (escape_seq_len >= 3) {
710 switch (escape_seq[2]) {
711 case 'A': /* Esc [ [ A == F1 on Linux
712 * console. */
713 kbinput = KEY_F(1);
714 break;
715 case 'B': /* Esc [ [ B == F2 on Linux
716 * console. */
717 kbinput = KEY_F(2);
718 break;
719 case 'C': /* Esc [ [ C == F3 on Linux
720 * console. */
721 kbinput = KEY_F(3);
722 break;
723 case 'D': /* Esc [ [ D == F4 on Linux
724 * console. */
725 kbinput = KEY_F(4);
726 break;
727 case 'E': /* Esc [ [ E == F5 on Linux
728 * console. */
729 kbinput = KEY_F(5);
730 break;
731 }
732 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000733 break;
734 }
735 break;
736 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000737 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000738
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000739 if (kbinput == ERR) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000740 /* This escape sequence is unrecognized; send it back. */
741 for (; escape_seq_len > 1; escape_seq_len--)
742 ungetch(escape_seq[escape_seq_len - 1]);
743 kbinput = escape_seq[0];
744 }
745
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000746 return kbinput;
747}
748
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000749/* Return the equivalent arrow key value for the case-insensitive
David Lawrence Ramseyb7e5cf62004-02-07 03:39:48 +0000750 * letters A (up), B (down), C (right), and D (left). These are common
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000751 * to many escape sequences. */
752int get_escape_seq_abcd(int kbinput)
753{
754 switch (tolower(kbinput)) {
755 case 'a':
756 return NANO_PREVLINE_KEY;
757 case 'b':
758 return NANO_NEXTLINE_KEY;
759 case 'c':
760 return NANO_FORWARD_KEY;
761 case 'd':
762 return NANO_BACK_KEY;
763 default:
764 return ERR;
765 }
766}
767
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000768#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000769/* Check for a mouse event, and if one's taken place, save the
770 * coordinates where it took place in mouse_x and mouse_y. After that,
771 * if allow_shortcuts is zero, return 0. Otherwise, if the mouse event
772 * took place on the shortcut list on the bottom two lines of the screen
773 * (assuming that the shortcut list is visible), figure out which
774 * shortcut was clicked and ungetch() the equivalent keystroke(s).
775 * Return 0 if no keystrokes were ungetch()ed, or 1 if at least one was.
776 * Assume that KEY_MOUSE has already been read in. */
777int get_mouseinput(int *mouse_x, int *mouse_y, int allow_shortcuts)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000778{
779 MEVENT mevent;
780
781 *mouse_x = -1;
782 *mouse_y = -1;
783
784 /* First, get the actual mouse event. */
785 if (getmouse(&mevent) == ERR)
786 return 0;
787
788 /* Save the screen coordinates where the mouse event took place. */
789 *mouse_x = mevent.x;
790 *mouse_y = mevent.y;
791
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000792 /* If we're not allowing shortcuts' we're done now. */
793 if (!allow_shortcuts)
794 return 0;
795
796 /* Otherwise, if the current shortcut list is being displayed on the
797 * last two lines of the screen and the mouse event took place
798 * inside it, we need to figure out which shortcut was clicked and
799 * ungetch() the equivalent keystroke(s) for it. */
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000800 if (!ISSET(NO_HELP) && wenclose(bottomwin, *mouse_y, *mouse_x)) {
801 int i, j;
802 int currslen;
803 /* The number of shortcuts in the current shortcut list. */
804 const shortcut *s = currshortcut;
805 /* The actual shortcut we clicked on, starting at the first
806 * one in the current shortcut list. */
807
808 /* Get the shortcut lists' length. */
809 if (currshortcut == main_list)
810 currslen = MAIN_VISIBLE;
811 else
812 currslen = length_of_list(currshortcut);
813
814 /* Calculate the width of each shortcut in the list (it's the
815 * same for all of them). */
816 if (currslen < 2)
817 i = COLS / 6;
818 else
819 i = COLS / ((currslen / 2) + (currslen % 2));
820
821 /* Calculate the y-coordinates relative to the beginning of
822 * bottomwin, i.e, the bottom three lines of the screen. */
823 j = *mouse_y - (editwinrows + 3);
824
825 /* If we're on the statusbar, beyond the end of the shortcut
826 * list, or beyond the end of a shortcut on the right side of
827 * the screen, don't do anything. */
828 if (j < 0 || (*mouse_x / i) >= currslen)
829 return 0;
830 j = (*mouse_x / i) * 2 + j;
831 if (j >= currslen)
832 return 0;
833
834 /* Go through the shortcut list to determine which shortcut was
835 * clicked. */
836 for (; j > 0; j--)
837 s = s->next;
838
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000839 /* And ungetch() the equivalent control key. If it's a Meta key
840 * sequence, we need to ungetch() Escape too. Assume that the
841 * shortcut has an equivalent control key, meta key sequence, or
842 * both. */
843 if (s->ctrlval != NANO_NO_KEY)
844 ungetch(s->ctrlval);
845 else {
846 ungetch(s->metaval);
847 ungetch(NANO_CONTROL_3);
848 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000849
850 return 1;
851 }
852 return 0;
853}
854#endif
855
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000856int do_first_line(void)
857{
858 current = fileage;
859 placewewant = 0;
860 current_x = 0;
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +0000861 edit_update(current, TOP);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000862 return 1;
863}
864
865int do_last_line(void)
866{
867 current = filebot;
868 placewewant = 0;
869 current_x = 0;
Chris Allegretta234a34d2000-07-29 04:33:38 +0000870 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000871 return 1;
872}
873
Chris Allegretta6df90f52002-07-19 01:08:59 +0000874/* Return the placewewant associated with current_x. That is, xplustabs
875 * is the zero-based column position of the cursor. Value is no smaller
876 * than current_x. */
877size_t xplustabs(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000878{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000879 return strnlenpt(current->data, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000880}
881
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000882/* actual_x() gives the index in str of the character displayed at
883 * column xplus. That is, actual_x() is the largest value such that
884 * strnlenpt(str, actual_x(str, xplus)) <= xplus. */
885size_t actual_x(const char *str, size_t xplus)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000886{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000887 size_t i = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000888 /* the position in str, returned */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000889 size_t length = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000890 /* the screen display width to str[i] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000891
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000892 assert(str != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000893
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000894 for (; length < xplus && *str != '\0'; i++, str++) {
895 if (*str == '\t')
David Lawrence Ramsey0362c582003-09-30 03:31:56 +0000896 length += tabsize - (length % tabsize);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000897 else if (is_cntrl_char((int)*str))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000898 length += 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000899 else
900 length++;
901 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000902 assert(length == strnlenpt(str - i, i));
903 assert(i <= strlen(str - i));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000904
Chris Allegretta6df90f52002-07-19 01:08:59 +0000905 if (length > xplus)
906 i--;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000907
Chris Allegretta6df90f52002-07-19 01:08:59 +0000908 return i;
Robert Siemborskid8510b22000-06-06 23:04:06 +0000909}
910
David Lawrence Ramseya3370c42004-04-05 01:08:14 +0000911/* A strlen() with tabs factored in, similar to xplustabs(). How many
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000912 * columns wide are the first size characters of buf? */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000913size_t strnlenpt(const char *buf, size_t size)
Robert Siemborskid8510b22000-06-06 23:04:06 +0000914{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000915 size_t length = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000916
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000917 assert(buf != NULL);
918 for (; *buf != '\0' && size != 0; size--, buf++) {
919 if (*buf == '\t')
920 length += tabsize - (length % tabsize);
921 else if (is_cntrl_char((int)*buf))
922 length += 2;
923 else
924 length++;
925 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000926 return length;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000927}
928
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000929/* How many columns wide is buf? */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000930size_t strlenpt(const char *buf)
Chris Allegrettad4fa0d32002-03-05 19:55:55 +0000931{
David Lawrence Ramsey0b047c52004-03-29 23:09:08 +0000932 return strnlenpt(buf, (size_t)-1);
Chris Allegrettad4fa0d32002-03-05 19:55:55 +0000933}
934
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000935void blank_bottombars(void)
936{
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000937 if (!ISSET(NO_HELP)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +0000938 mvwaddstr(bottomwin, 1, 0, hblank);
939 mvwaddstr(bottomwin, 2, 0, hblank);
940 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000941}
942
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000943void blank_bottomwin(void)
944{
945 if (ISSET(NO_HELP))
946 return;
947
948 mvwaddstr(bottomwin, 1, 0, hblank);
949 mvwaddstr(bottomwin, 2, 0, hblank);
950}
951
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000952void blank_edit(void)
953{
954 int i;
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +0000955 for (i = 0; i < editwinrows; i++)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000956 mvwaddstr(edit, i, 0, hblank);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000957}
958
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000959void blank_statusbar(void)
960{
961 mvwaddstr(bottomwin, 0, 0, hblank);
962}
963
964void blank_statusbar_refresh(void)
965{
966 blank_statusbar();
967 wrefresh(bottomwin);
968}
969
970void check_statblank(void)
971{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000972 if (statblank > 1)
973 statblank--;
974 else if (statblank == 1 && !ISSET(CONSTUPDATE)) {
975 statblank--;
976 blank_statusbar_refresh();
977 }
978}
979
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000980/* Convert buf into a string that can be displayed on screen. The
981 * caller wants to display buf starting with column start_col, and
982 * extending for at most len columns. start_col is zero-based. len is
983 * one-based, so len == 0 means you get "" returned. The returned
984 * string is dynamically allocated, and should be freed. */
985char *display_string(const char *buf, size_t start_col, int len)
986{
987 size_t start_index;
988 /* Index in buf of first character shown in return value. */
989 size_t column;
990 /* Screen column start_index corresponds to. */
991 size_t end_index;
992 /* Index in buf of last character shown in return value. */
993 size_t alloc_len;
994 /* The length of memory allocated for converted. */
995 char *converted;
996 /* The string we return. */
997 size_t index;
998 /* Current position in converted. */
999
1000 if (len == 0)
1001 return mallocstrcpy(NULL, "");
1002
1003 start_index = actual_x(buf, start_col);
1004 column = strnlenpt(buf, start_index);
1005 assert(column <= start_col);
1006 end_index = actual_x(buf, start_col + len - 1);
1007 alloc_len = strnlenpt(buf, end_index + 1) - column;
1008 if (len > alloc_len + column - start_col)
1009 len = alloc_len + column - start_col;
1010 converted = charalloc(alloc_len + 1);
1011 buf += start_index;
1012 index = 0;
1013
1014 for (; index < alloc_len; buf++) {
1015 if (*buf == '\t')
1016 do {
1017 converted[index++] = ' ';
1018 } while ((column + index) % tabsize);
1019 else if (is_cntrl_char(*buf)) {
1020 converted[index++] = '^';
1021 if (*buf == '\n')
1022 /* Treat newlines embedded in a line as encoded nulls;
1023 * the line in question should be run through unsunder()
1024 * before reaching here. */
1025 converted[index++] = '@';
1026 else if (*buf == NANO_CONTROL_8)
1027 converted[index++] = '?';
1028 else
1029 converted[index++] = *buf + 64;
1030 } else
1031 converted[index++] = *buf;
1032 }
1033 assert(len <= alloc_len + column - start_col);
1034 charmove(converted, converted + start_col - column, len);
1035 null_at(&converted, len);
1036
1037 return charealloc(converted, len + 1);
1038}
1039
Chris Allegretta7662c862003-01-13 01:35:15 +00001040/* Repaint the statusbar when getting a character in nanogetstr(). buf
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001041 * should be no longer than max(0, COLS - 4).
Chris Allegretta6df90f52002-07-19 01:08:59 +00001042 *
Chris Allegretta7662c862003-01-13 01:35:15 +00001043 * Note that we must turn on A_REVERSE here, since do_help() turns it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001044 * off! */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001045void nanoget_repaint(const char *buf, const char *inputbuf, size_t x)
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001046{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001047 size_t x_real = strnlenpt(inputbuf, x);
1048 int wid = COLS - strlen(buf) - 2;
Chris Allegretta0d1e8d62000-11-02 15:30:24 +00001049
Chris Allegretta6df90f52002-07-19 01:08:59 +00001050 assert(0 <= x && x <= strlen(inputbuf));
1051
Chris Allegrettab3655b42001-10-22 03:15:31 +00001052 wattron(bottomwin, A_REVERSE);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001053 blank_statusbar();
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001054
Chris Allegretta6df90f52002-07-19 01:08:59 +00001055 mvwaddstr(bottomwin, 0, 0, buf);
1056 waddch(bottomwin, ':');
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001057
1058 if (COLS > 1)
1059 waddch(bottomwin, x_real < wid ? ' ' : '$');
1060 if (COLS > 2) {
1061 size_t page_start = x_real - x_real % wid;
1062 char *expanded = display_string(inputbuf, page_start, wid);
1063
1064 assert(wid > 0);
1065 assert(strlen(expanded) <= wid);
1066 waddstr(bottomwin, expanded);
1067 free(expanded);
1068 wmove(bottomwin, 0, COLS - wid + x_real - page_start);
1069 } else
1070 wmove(bottomwin, 0, COLS - 1);
Chris Allegrettab3655b42001-10-22 03:15:31 +00001071 wattroff(bottomwin, A_REVERSE);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001072}
1073
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001074/* Get the input from the keyboard; this should only be called from
Chris Allegretta6df90f52002-07-19 01:08:59 +00001075 * statusq(). */
Chris Allegrettaf717f982003-02-13 22:25:01 +00001076int nanogetstr(int allowtabs, const char *buf, const char *def,
Chris Allegretta5beed502003-01-05 20:41:21 +00001077#ifndef NANO_SMALL
1078 historyheadtype *history_list,
1079#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001080 const shortcut *s
Rocco Corsi06aca1c2001-01-11 05:30:31 +00001081#ifndef DISABLE_TABCOMP
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001082 , int *list
Chris Allegrettabe77c612000-11-24 14:00:16 +00001083#endif
Chris Allegretta65f075d2003-02-13 03:03:49 +00001084 )
Chris Allegretta6df90f52002-07-19 01:08:59 +00001085{
1086 int kbinput;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001087 int meta_key;
Chris Allegretta09fc4302003-01-16 22:16:38 +00001088 static int x = -1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001089 /* the cursor position in 'answer' */
1090 int xend;
1091 /* length of 'answer', the status bar text */
1092 int tabbed = 0;
1093 /* used by input_tab() */
1094 const shortcut *t;
Chris Allegretta598106e2002-01-19 01:59:37 +00001095
Chris Allegretta5beed502003-01-05 20:41:21 +00001096#ifndef NANO_SMALL
1097 /* for history */
1098 char *history = NULL;
Chris Allegretta8031f832003-01-09 05:29:58 +00001099 char *currentbuf = NULL;
Chris Allegretta5beed502003-01-05 20:41:21 +00001100 char *complete = NULL;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001101 int last_kbinput = 0;
1102
1103 /* This variable is used in the search history code. use_cb == 0
1104 means that we're using the existing history and ignoring
1105 currentbuf. use_cb == 1 means that the entry in answer should be
1106 moved to currentbuf or restored from currentbuf to answer.
1107 use_cb == 2 means that the entry in currentbuf should be moved to
1108 answer or restored from answer to currentbuf. */
1109 int use_cb = 0;
Chris Allegretta5beed502003-01-05 20:41:21 +00001110#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001111 xend = strlen(def);
Chris Allegretta09fc4302003-01-16 22:16:38 +00001112
1113 /* Only put x at the end of the string if it's uninitialized or if
1114 it would be past the end of the string as it is. Otherwise,
1115 leave it alone. This is so the cursor position stays at the same
1116 place if a prompt-changing toggle is pressed. */
Chris Allegretta65f075d2003-02-13 03:03:49 +00001117 if (x == -1 || x > xend || resetstatuspos)
Chris Allegretta09fc4302003-01-16 22:16:38 +00001118 x = xend;
1119
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00001120 answer = charealloc(answer, xend + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001121 if (xend > 0)
1122 strcpy(answer, def);
1123 else
1124 answer[0] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001125
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001126#if !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001127 currshortcut = s;
Chris Allegretta6fe61492001-05-21 12:56:25 +00001128#endif
1129
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001130 /* Get the input! */
Chris Allegretta31925e42000-11-02 04:40:39 +00001131
Chris Allegretta6df90f52002-07-19 01:08:59 +00001132 nanoget_repaint(buf, answer, x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001133
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001134 /* Make sure any editor screen updates are displayed before getting
1135 input */
Chris Allegretta022b96f2000-11-14 17:47:58 +00001136 wrefresh(edit);
1137
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001138 while ((kbinput = get_kbinput(bottomwin, &meta_key)) != NANO_ENTER_KEY) {
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001139 for (t = s; t != NULL; t = t->next) {
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001140#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001141 fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput, kbinput);
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001142#endif
1143
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001144 /* Temporary hack to interpret NANO_HELP_FKEY correctly. */
1145 if (kbinput == t->funcval)
1146 kbinput = t->ctrlval;
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00001147
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001148 if (kbinput == t->ctrlval && is_cntrl_char(kbinput)) {
Chris Allegretta5bf51d32000-11-16 06:01:10 +00001149
Chris Allegrettab3655b42001-10-22 03:15:31 +00001150#ifndef DISABLE_HELP
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001151 /* Have to do this here, it would be too late to do it
1152 in statusq() */
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00001153 if (kbinput == NANO_HELP_KEY) {
Chris Allegrettab3655b42001-10-22 03:15:31 +00001154 do_help();
1155 break;
1156 }
1157#endif
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001158#ifndef NANO_SMALL
1159 /* Have to handle these here too, for the time being */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001160 if (kbinput == NANO_PREVLINE_KEY || kbinput == NANO_NEXTLINE_KEY)
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001161 break;
1162#endif
Chris Allegretta5af58892003-01-17 21:07:38 +00001163
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001164 return t->ctrlval;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001165 }
1166 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001167 assert(0 <= x && x <= xend && xend == strlen(answer));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001168
Chris Allegretta04d848e2000-11-05 17:54:41 +00001169 if (kbinput != '\t')
1170 tabbed = 0;
1171
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001172 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001173#ifndef DISABLE_MOUSE
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001174 case KEY_MOUSE:
1175 do_mouse();
1176 break;
1177#endif
Chris Allegretta658399a2001-06-14 02:54:22 +00001178 case NANO_HOME_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001179 x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001180 break;
Chris Allegretta658399a2001-06-14 02:54:22 +00001181 case NANO_END_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001182 x = xend;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001183 break;
Chris Allegretta35dac582001-03-21 15:07:20 +00001184 case NANO_FORWARD_KEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001185 if (x < xend)
1186 x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001187 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001188 case NANO_DELETE_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001189 if (x < xend) {
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001190 charmove(answer + x, answer + x + 1, xend - x);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001191 xend--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001192 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001193 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001194 case NANO_CUT_KEY:
1195 case NANO_UNCUT_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001196 null_at(&answer, 0);
1197 xend = 0;
1198 x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001199 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001200 case NANO_BACKSPACE_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001201 if (x > 0) {
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001202 charmove(answer + x - 1, answer + x, xend - x + 1);
Chris Allegretta04d848e2000-11-05 17:54:41 +00001203 x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001204 xend--;
1205 }
Chris Allegretta04d848e2000-11-05 17:54:41 +00001206 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001207 case NANO_TAB_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001208#ifndef NANO_SMALL
1209 /* tab history completion */
Chris Allegretta7662c862003-01-13 01:35:15 +00001210 if (history_list != NULL) {
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001211 if (!complete || last_kbinput != NANO_TAB_KEY) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001212 history_list->current = (historytype *)history_list;
1213 history_list->len = strlen(answer);
1214 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001215
Chris Allegretta7662c862003-01-13 01:35:15 +00001216 if (history_list->len > 0) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001217 complete = get_history_completion(history_list, answer);
1218 xend = strlen(complete);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001219 x = xend;
Chris Allegretta5beed502003-01-05 20:41:21 +00001220 answer = mallocstrcpy(answer, complete);
1221 }
Chris Allegretta7da4e9f2000-11-06 02:57:22 +00001222 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001223#ifndef DISABLE_TABCOMP
Chris Allegretta327abda2003-01-17 05:04:17 +00001224 else
1225#endif
Chris Allegrettabe77c612000-11-24 14:00:16 +00001226#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001227#ifndef DISABLE_TABCOMP
Chris Allegretta327abda2003-01-17 05:04:17 +00001228 if (allowtabs) {
1229 int shift = 0;
Chris Allegretta5beed502003-01-05 20:41:21 +00001230
Chris Allegretta327abda2003-01-17 05:04:17 +00001231 answer = input_tab(answer, x, &tabbed, &shift, list);
1232 xend = strlen(answer);
1233 x += shift;
1234 if (x > xend)
1235 x = xend;
Chris Allegretta5beed502003-01-05 20:41:21 +00001236 }
1237#endif
1238 break;
Chris Allegretta35dac582001-03-21 15:07:20 +00001239 case NANO_BACK_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001240 if (x > 0)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001241 x--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001242 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001243 case NANO_PREVLINE_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001244#ifndef NANO_SMALL
Chris Allegretta09fc4302003-01-16 22:16:38 +00001245 if (history_list != NULL) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001246
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001247 /* if currentbuf is NULL, or if use_cb is 1, currentbuf
1248 isn't NULL, and currentbuf is different from answer,
1249 it means that we're scrolling up at the top of the
1250 search history, and we need to save the current
1251 answer in currentbuf; do this and reset use_cb to
1252 0 */
1253 if (currentbuf == NULL || (use_cb == 1 && strcmp(currentbuf, answer))) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001254 currentbuf = mallocstrcpy(currentbuf, answer);
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001255 use_cb = 0;
Chris Allegretta8031f832003-01-09 05:29:58 +00001256 }
1257
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001258 /* if currentbuf isn't NULL, use_cb is 2, and currentbuf
1259 is different from answer, it means that we're
1260 scrolling up at the bottom of the search history, and
1261 we need to make the string in currentbuf the current
1262 answer; do this, blow away currentbuf since we don't
1263 need it anymore, and reset use_cb to 0 */
1264 if (currentbuf != NULL && use_cb == 2 && strcmp(currentbuf, answer)) {
1265 answer = mallocstrcpy(answer, currentbuf);
1266 free(currentbuf);
1267 currentbuf = NULL;
1268 xend = strlen(answer);
1269 use_cb = 0;
1270
1271 /* else get older search from the history list and save
1272 it in answer; if there is no older search, blank out
1273 answer */
1274 } else if ((history = get_history_older(history_list)) != NULL) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001275 answer = mallocstrcpy(answer, history);
1276 xend = strlen(history);
1277 } else {
1278 answer = mallocstrcpy(answer, "");
1279 xend = 0;
1280 }
1281 x = xend;
1282 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001283#endif
Chris Allegretta54abd942003-01-09 23:43:12 +00001284 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001285 case NANO_NEXTLINE_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001286#ifndef NANO_SMALL
Chris Allegretta09fc4302003-01-16 22:16:38 +00001287 if (history_list != NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001288
1289 /* get newer search from the history list and save it
1290 in answer */
Chris Allegretta7662c862003-01-13 01:35:15 +00001291 if ((history = get_history_newer(history_list)) != NULL) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001292 answer = mallocstrcpy(answer, history);
1293 xend = strlen(history);
Chris Allegretta8031f832003-01-09 05:29:58 +00001294
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001295 /* if there is no newer search, we're here */
1296
1297 /* if currentbuf isn't NULL and use_cb isn't 2, it means
1298 that we're scrolling down at the bottom of the search
1299 history and we need to make the string in currentbuf
1300 the current answer; do this, blow away currentbuf
1301 since we don't need it anymore, and set use_cb to
1302 1 */
1303 } else if (currentbuf != NULL && use_cb != 2) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001304 answer = mallocstrcpy(answer, currentbuf);
Chris Allegretta09fc4302003-01-16 22:16:38 +00001305 free(currentbuf);
1306 currentbuf = NULL;
1307 xend = strlen(answer);
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001308 use_cb = 1;
1309
1310 /* otherwise, if currentbuf is NULL and use_cb isn't 2,
1311 it means that we're scrolling down at the bottom of
Chris Allegrettac30fc242003-08-11 00:32:45 +00001312 the search history and the current answer (if it's
1313 not blank) needs to be saved in currentbuf; do this,
1314 blank out answer (if necessary), and set use_cb to
1315 2 */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001316 } else if (use_cb != 2) {
Chris Allegrettac30fc242003-08-11 00:32:45 +00001317 if (answer[0] != '\0') {
1318 currentbuf = mallocstrcpy(currentbuf, answer);
1319 answer = mallocstrcpy(answer, "");
1320 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001321 xend = 0;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001322 use_cb = 2;
Chris Allegretta5beed502003-01-05 20:41:21 +00001323 }
1324 x = xend;
1325 }
1326#endif
1327 break;
Chris Allegretta658399a2001-06-14 02:54:22 +00001328 default:
1329
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001330 for (t = s; t != NULL; t = t->next) {
Chris Allegretta658399a2001-06-14 02:54:22 +00001331#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001332 fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput,
Chris Allegretta598106e2002-01-19 01:59:37 +00001333 kbinput);
Chris Allegretta658399a2001-06-14 02:54:22 +00001334#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001335 if (meta_key == TRUE && (kbinput == t->metaval || kbinput == t->miscval))
David Lawrence Ramsey82138502003-12-24 08:03:54 +00001336 /* We hit a Meta key. Do like above. We don't
1337 * just ungetch() the letter and let it get
1338 * caught above cause that screws the
1339 * keypad... */
1340 return kbinput;
Chris Allegretta658399a2001-06-14 02:54:22 +00001341 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001342
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001343 if (is_cntrl_char(kbinput))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001344 break;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001345 answer = charealloc(answer, xend + 2);
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001346 charmove(answer + x + 1, answer + x, xend - x + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001347 xend++;
1348 answer[x] = kbinput;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001349 x++;
1350
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001351#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001352 fprintf(stderr, "input \'%c\' (%d)\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001353#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001354 } /* switch (kbinput) */
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001355#ifndef NANO_SMALL
Chris Allegretta5beed502003-01-05 20:41:21 +00001356 last_kbinput = kbinput;
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001357#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001358 nanoget_repaint(buf, answer, x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001359 wrefresh(bottomwin);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001360 } /* while (kbinput ...) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001361
Chris Allegretta5af58892003-01-17 21:07:38 +00001362 /* We finished putting in an answer; reset x */
1363 x = -1;
1364
Chris Allegretta7662c862003-01-13 01:35:15 +00001365 /* Just check for a blank answer here */
Chris Allegretta15c28f82003-01-05 21:47:06 +00001366 if (answer[0] == '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001367 return -2;
1368 else
1369 return 0;
1370}
1371
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001372/* If modified is not already set, set it and update titlebar. */
1373void set_modified(void)
1374{
1375 if (!ISSET(MODIFIED)) {
1376 SET(MODIFIED);
1377 titlebar(NULL);
1378 wrefresh(topwin);
1379 }
1380}
1381
Chris Allegrettaf717f982003-02-13 22:25:01 +00001382void titlebar(const char *path)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001383{
1384 int namelen, space;
Chris Allegrettaf717f982003-02-13 22:25:01 +00001385 const char *what = path;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001386
1387 if (path == NULL)
1388 what = filename;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001389
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001390 wattron(topwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001391
Chris Allegretta6df90f52002-07-19 01:08:59 +00001392 mvwaddstr(topwin, 0, 0, hblank);
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00001393 mvwaddnstr(topwin, 0, 2, VERMSG, COLS - 3);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001394
David Lawrence Ramseyec290f22003-08-30 19:05:40 +00001395 space = COLS - sizeof(VERMSG) - 23;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001396
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001397 namelen = strlen(what);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001398
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00001399 if (space > 0) {
1400 if (what[0] == '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001401 mvwaddnstr(topwin, 0, COLS / 2 - 6, _("New Buffer"),
1402 COLS / 2 + COLS % 2 - 6);
1403 else if (namelen > space) {
1404 if (path == NULL)
1405 waddstr(topwin, _(" File: ..."));
1406 else
1407 waddstr(topwin, _(" DIR: ..."));
1408 waddstr(topwin, &what[namelen - space]);
1409 } else {
1410 if (path == NULL)
1411 mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
1412 _("File: "));
1413 else
1414 mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
1415 _(" DIR: "));
1416 waddstr(topwin, what);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001417 }
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00001418 } /* If we don't have space, we shouldn't bother */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001419 if (ISSET(MODIFIED))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001420 mvwaddnstr(topwin, 0, COLS - 11, _(" Modified "), 11);
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001421 else if (ISSET(VIEW_MODE))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001422 mvwaddnstr(topwin, 0, COLS - 11, _(" View "), 11);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001423
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001424 wattroff(topwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001425
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001426 wrefresh(topwin);
1427 reset_cursor();
1428}
1429
Chris Allegretta6232d662002-05-12 19:52:15 +00001430void bottombars(const shortcut *s)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001431{
Chris Allegrettabc72e362002-02-16 20:03:44 +00001432 int i, j, numcols;
Chris Allegretta3bbc4162003-01-23 00:46:12 +00001433 char keystr[9];
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001434 int slen;
1435
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001436 if (ISSET(NO_HELP))
1437 return;
1438
Chris Allegretta6232d662002-05-12 19:52:15 +00001439 if (s == main_list) {
1440 slen = MAIN_VISIBLE;
1441 assert(MAIN_VISIBLE <= length_of_list(s));
1442 } else
1443 slen = length_of_list(s);
1444
Chris Allegretta6232d662002-05-12 19:52:15 +00001445 /* There will be this many columns of shortcuts */
1446 numcols = (slen + (slen % 2)) / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001447
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001448 blank_bottomwin();
Chris Allegretta658399a2001-06-14 02:54:22 +00001449
Chris Allegrettabc72e362002-02-16 20:03:44 +00001450 for (i = 0; i < numcols; i++) {
1451 for (j = 0; j <= 1; j++) {
Chris Allegretta658399a2001-06-14 02:54:22 +00001452
Chris Allegretta6232d662002-05-12 19:52:15 +00001453 wmove(bottomwin, 1 + j, i * (COLS / numcols));
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001454
Chris Allegretta5beed502003-01-05 20:41:21 +00001455 /* Yucky sentinel values we can't handle a better way */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001456 if (s->ctrlval != NANO_NO_KEY) {
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001457#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001458 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001459 strncpy(keystr, _("Up"), 8);
Chris Allegretta6232d662002-05-12 19:52:15 +00001460 else
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001461#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001462 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001463 strcpy(keystr, "^ ");
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001464 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001465 strcpy(keystr, "^?");
1466 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001467 sprintf(keystr, "^%c", s->ctrlval + 64);
David Lawrence Ramsey82138502003-12-24 08:03:54 +00001468 } else if (s->metaval != NANO_NO_KEY)
1469 sprintf(keystr, "M-%c", toupper(s->metaval));
Chris Allegretta658399a2001-06-14 02:54:22 +00001470
Chris Allegretta6232d662002-05-12 19:52:15 +00001471 onekey(keystr, s->desc, COLS / numcols);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001472
Chris Allegretta6232d662002-05-12 19:52:15 +00001473 s = s->next;
1474 if (s == NULL)
1475 goto break_completely_out;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001476 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001477 }
1478
Chris Allegretta6df90f52002-07-19 01:08:59 +00001479 break_completely_out:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001480 wrefresh(bottomwin);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001481}
1482
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001483/* Write a shortcut key to the help area at the bottom of the window.
1484 * keystroke is e.g. "^G" and desc is e.g. "Get Help".
1485 * We are careful to write exactly len characters, even if len is
1486 * very small and keystroke and desc are long. */
Chris Allegrettaf717f982003-02-13 22:25:01 +00001487void onekey(const char *keystroke, const char *desc, int len)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001488{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001489 wattron(bottomwin, A_REVERSE);
1490 waddnstr(bottomwin, keystroke, len);
1491 wattroff(bottomwin, A_REVERSE);
1492 len -= strlen(keystroke);
1493 if (len > 0) {
1494 waddch(bottomwin, ' ');
1495 len--;
1496 waddnstr(bottomwin, desc, len);
1497 len -= strlen(desc);
1498 for (; len > 0; len--)
1499 waddch(bottomwin, ' ');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001500 }
1501}
1502
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001503/* And so start the display update routines. */
1504
1505#ifndef NDEBUG
1506int check_linenumbers(const filestruct *fileptr)
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001507{
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001508 int check_line = 0;
1509 const filestruct *filetmp;
Robert Siemborskid8510b22000-06-06 23:04:06 +00001510
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001511 for (filetmp = edittop; filetmp != fileptr; filetmp = filetmp->next)
1512 check_line++;
1513 return check_line;
Robert Siemborskid8510b22000-06-06 23:04:06 +00001514}
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001515#endif
Robert Siemborskid8510b22000-06-06 23:04:06 +00001516
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001517/* nano scrolls horizontally within a line in chunks. This function
1518 * returns the column number of the first character displayed in the
1519 * window when the cursor is at the given column. Note that
1520 * 0 <= column - get_page_start(column) < COLS. */
1521size_t get_page_start(size_t column)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001522{
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001523 assert(COLS > 0);
1524 if (column == 0 || column < COLS - 1)
1525 return 0;
1526 else if (COLS > 9)
David Lawrence Ramsey66081d42004-01-22 07:25:31 +00001527 return column - 7 - (column - 7) % (COLS - 8);
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001528 else if (COLS > 2)
1529 return column - (COLS - 2);
1530 else
1531 return column - (COLS - 1);
1532 /* The parentheses are necessary to avoid overflow. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001533}
1534
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001535/* Resets current_y, based on the position of current, and puts the
1536 * cursor at (current_y, current_x). */
1537void reset_cursor(void)
1538{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001539 /* Yuck. This condition can be true after open_file() when opening
1540 * the first file. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001541 if (edittop == NULL)
1542 return;
1543
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001544 current_y = current->lineno - edittop->lineno;
1545 if (current_y < editwinrows) {
1546 size_t x = xplustabs();
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001547
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001548 wmove(edit, current_y, x - get_page_start(x));
1549 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001550}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001551
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001552/* edit_add() takes care of the job of actually painting a line into the
1553 * edit window. fileptr is the line to be painted, at row yval of the
1554 * window. converted is the actual string to be written to the window,
1555 * with tabs and control characters replaced by strings of regular
1556 * characters. start is the column number of the first character
1557 * of this page. That is, the first character of converted corresponds to
1558 * character number actual_x(fileptr->data, start) of the line. */
David Lawrence Ramsey07d3feb2004-04-16 05:15:11 +00001559void edit_add(const filestruct *fileptr, const char *converted, int
1560 yval, size_t start)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001561{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001562#if defined(ENABLE_COLOR) || !defined(NANO_SMALL)
1563 size_t startpos = actual_x(fileptr->data, start);
1564 /* The position in fileptr->data of the leftmost character
1565 * that displays at least partially on the window. */
1566 size_t endpos = actual_x(fileptr->data, start + COLS - 1) + 1;
1567 /* The position in fileptr->data of the first character that is
1568 * completely off the window to the right.
1569 *
1570 * Note that endpos might be beyond the null terminator of the
1571 * string. */
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001572#endif
1573
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001574 assert(fileptr != NULL && converted != NULL);
1575 assert(strlen(converted) <= COLS);
1576
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001577 /* Just paint the string in any case (we'll add color or reverse on
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001578 * just the text that needs it). */
1579 mvwaddstr(edit, yval, 0, converted);
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001580
Chris Allegretta7dd77682001-12-08 19:52:28 +00001581#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00001582 if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001583 const colortype *tmpcolor = colorstrings;
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001584
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001585 for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
1586 int x_start;
1587 /* Starting column for mvwaddnstr. Zero-based. */
1588 int paintlen;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001589 /* Number of chars to paint on this line. There are COLS
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001590 * characters on a whole line. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001591 regmatch_t startmatch; /* match position for start_regexp */
1592 regmatch_t endmatch; /* match position for end_regexp */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001593
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001594 if (tmpcolor->bright)
1595 wattron(edit, A_BOLD);
1596 wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001597 /* Two notes about regexec(). Return value 0 means there is
1598 * a match. Also, rm_eo is the first non-matching character
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001599 * after the match. */
1600
1601 /* First case, tmpcolor is a single-line expression. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001602 if (tmpcolor->end == NULL) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001603 size_t k = 0;
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001604
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001605 /* We increment k by rm_eo, to move past the end of the
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001606 * last match. Even though two matches may overlap, we
1607 * want to ignore them, so that we can highlight
1608 * C-strings correctly. */
1609 while (k < endpos) {
1610 /* Note the fifth parameter to regexec(). It says
1611 * not to match the beginning-of-line character
1612 * unless k is 0. If regexec() returns REG_NOMATCH,
1613 * there are no more matches in the line. */
Chris Allegrettace452fb2003-02-03 02:56:44 +00001614 if (regexec(&tmpcolor->start, &fileptr->data[k], 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001615 &startmatch, k == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001616 break;
1617 /* Translate the match to the beginning of the line. */
1618 startmatch.rm_so += k;
1619 startmatch.rm_eo += k;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001620 if (startmatch.rm_so == startmatch.rm_eo) {
1621 startmatch.rm_eo++;
Chris Allegretta7c27be42002-05-05 23:03:54 +00001622 statusbar(_("Refusing 0 length regex match"));
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001623 } else if (startmatch.rm_so < endpos &&
1624 startmatch.rm_eo > startpos) {
1625 if (startmatch.rm_so <= startpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001626 x_start = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001627 else
1628 x_start = strnlenpt(fileptr->data, startmatch.rm_so)
1629 - start;
1630 paintlen = strnlenpt(fileptr->data, startmatch.rm_eo)
1631 - start - x_start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001632 if (paintlen > COLS - x_start)
1633 paintlen = COLS - x_start;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001634
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001635 assert(0 <= x_start && 0 < paintlen &&
1636 x_start + paintlen <= COLS);
1637 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001638 converted + x_start, paintlen);
1639 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001640 k = startmatch.rm_eo;
Chris Allegretta598106e2002-01-19 01:59:37 +00001641 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001642 } else {
1643 /* This is a multi-line regexp. There are two steps.
1644 * First, we have to see if the beginning of the line is
1645 * colored by a start on an earlier line, and an end on
1646 * this line or later.
1647 *
1648 * We find the first line before fileptr matching the
1649 * start. If every match on that line is followed by an
1650 * end, then go to step two. Otherwise, find the next line
1651 * after start_line matching the end. If that line is not
1652 * before fileptr, then paint the beginning of this line. */
Chris Allegretta3674c1d2002-05-12 20:43:49 +00001653
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001654 const filestruct *start_line = fileptr->prev;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001655 /* the first line before fileptr matching start */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001656 regoff_t start_col;
1657 /* where it starts in that line */
1658 const filestruct *end_line;
1659 int searched_later_lines = 0;
1660 /* Used in step 2. Have we looked for an end on
1661 * lines after fileptr? */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001662
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001663 while (start_line != NULL &&
Chris Allegrettace452fb2003-02-03 02:56:44 +00001664 regexec(&tmpcolor->start, start_line->data, 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001665 &startmatch, 0) == REG_NOMATCH) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001666 /* If there is an end on this line, there is no need
1667 * to look for starts on earlier lines. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001668 if (regexec(tmpcolor->end, start_line->data, 0, NULL, 0)
1669 == 0)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001670 goto step_two;
1671 start_line = start_line->prev;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001672 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001673 /* No start found, so skip to the next step. */
1674 if (start_line == NULL)
1675 goto step_two;
1676 /* Now start_line is the first line before fileptr
1677 * containing a start match. Is there a start on this
1678 * line not followed by an end on this line? */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001679
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001680 start_col = 0;
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001681 while (TRUE) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001682 start_col += startmatch.rm_so;
1683 startmatch.rm_eo -= startmatch.rm_so;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001684 if (regexec(tmpcolor->end,
1685 start_line->data + start_col + startmatch.rm_eo,
1686 0, NULL, start_col + startmatch.rm_eo == 0 ? 0 :
1687 REG_NOTBOL) == REG_NOMATCH)
1688 /* No end found after this start. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001689 break;
1690 start_col++;
Chris Allegrettace452fb2003-02-03 02:56:44 +00001691 if (regexec(&tmpcolor->start,
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001692 start_line->data + start_col, 1, &startmatch,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001693 REG_NOTBOL) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001694 /* No later start on this line. */
1695 goto step_two;
1696 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001697 /* Indeed, there is a start not followed on this line by
1698 * an end. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001699
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001700 /* We have already checked that there is no end before
1701 * fileptr and after the start. Is there an end after
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001702 * the start at all? We don't paint unterminated
1703 * starts. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001704 end_line = fileptr;
Chris Allegrettace452fb2003-02-03 02:56:44 +00001705 while (end_line != NULL &&
1706 regexec(tmpcolor->end, end_line->data, 1, &endmatch, 0))
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001707 end_line = end_line->next;
1708
1709 /* No end found, or it is too early. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001710 if (end_line == NULL ||
1711 (end_line == fileptr && endmatch.rm_eo <= startpos))
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001712 goto step_two;
1713
1714 /* Now paint the start of fileptr. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001715 paintlen = end_line != fileptr ? COLS :
1716 strnlenpt(fileptr->data, endmatch.rm_eo) - start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001717 if (paintlen > COLS)
1718 paintlen = COLS;
1719
1720 assert(0 < paintlen && paintlen <= COLS);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001721 mvwaddnstr(edit, yval, 0, converted, paintlen);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001722
1723 /* We have already painted the whole line. */
1724 if (paintlen == COLS)
1725 goto skip_step_two;
1726
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001727 step_two: /* Second step, we look for starts on this line. */
1728 start_col = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001729 while (start_col < endpos) {
Chris Allegrettace452fb2003-02-03 02:56:44 +00001730 if (regexec(&tmpcolor->start, fileptr->data + start_col, 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001731 &startmatch, start_col == 0 ? 0 : REG_NOTBOL)
1732 == REG_NOMATCH || start_col + startmatch.rm_so >=
1733 endpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001734 /* No more starts on this line. */
1735 break;
1736 /* Translate the match to be relative to the
1737 * beginning of the line. */
1738 startmatch.rm_so += start_col;
1739 startmatch.rm_eo += start_col;
1740
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001741 if (startmatch.rm_so <= startpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001742 x_start = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001743 else
1744 x_start = strnlenpt(fileptr->data, startmatch.rm_so)
1745 - start;
1746 if (regexec(tmpcolor->end, fileptr->data + startmatch.rm_eo,
1747 1, &endmatch, startmatch.rm_eo == 0 ? 0 :
1748 REG_NOTBOL) == 0) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001749 /* Translate the end match to be relative to the
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001750 * beginning of the line. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001751 endmatch.rm_so += startmatch.rm_eo;
1752 endmatch.rm_eo += startmatch.rm_eo;
1753 /* There is an end on this line. But does it
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001754 * appear on this page, and is the match more than
1755 * zero characters long? */
1756 if (endmatch.rm_eo > startpos &&
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001757 endmatch.rm_eo > startmatch.rm_so) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001758 paintlen = strnlenpt(fileptr->data, endmatch.rm_eo)
1759 - start - x_start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001760 if (x_start + paintlen > COLS)
1761 paintlen = COLS - x_start;
1762
1763 assert(0 <= x_start && 0 < paintlen &&
1764 x_start + paintlen <= COLS);
1765 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001766 converted + x_start, paintlen);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001767 }
1768 } else if (!searched_later_lines) {
1769 searched_later_lines = 1;
1770 /* There is no end on this line. But we haven't
1771 * yet looked for one on later lines. */
1772 end_line = fileptr->next;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001773 while (end_line != NULL &&
1774 regexec(tmpcolor->end, end_line->data, 0,
1775 NULL, 0) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001776 end_line = end_line->next;
1777 if (end_line != NULL) {
1778 assert(0 <= x_start && x_start < COLS);
1779 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001780 converted + x_start,
1781 COLS - x_start);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001782 /* We painted to the end of the line, so
1783 * don't bother checking any more starts. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001784 break;
Chris Allegretta3674c1d2002-05-12 20:43:49 +00001785 }
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001786 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001787 start_col = startmatch.rm_so + 1;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001788 } /* while start_col < endpos */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001789 } /* if (tmp_color->end != NULL) */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001790
Chris Allegrettace452fb2003-02-03 02:56:44 +00001791 skip_step_two:
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001792 wattroff(edit, A_BOLD);
1793 wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
1794 } /* for tmpcolor in colorstrings */
1795 }
Chris Allegretta598106e2002-01-19 01:59:37 +00001796#endif /* ENABLE_COLOR */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001797
Chris Allegretta7dd77682001-12-08 19:52:28 +00001798#ifndef NANO_SMALL
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001799 if (ISSET(MARK_ISSET)
1800 && (fileptr->lineno <= mark_beginbuf->lineno
1801 || fileptr->lineno <= current->lineno)
1802 && (fileptr->lineno >= mark_beginbuf->lineno
1803 || fileptr->lineno >= current->lineno)) {
1804 /* fileptr is at least partially selected. */
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001805
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001806 const filestruct *top;
1807 /* Either current or mark_beginbuf, whichever is first. */
1808 size_t top_x;
1809 /* current_x or mark_beginx, corresponding to top. */
1810 const filestruct *bot;
1811 size_t bot_x;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001812 int x_start;
1813 /* Starting column for mvwaddnstr. Zero-based. */
1814 int paintlen;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001815 /* Number of chars to paint on this line. There are COLS
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001816 * characters on a whole line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001817
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001818 mark_order(&top, &top_x, &bot, &bot_x);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001819
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001820 if (top->lineno < fileptr->lineno || top_x < startpos)
1821 top_x = startpos;
1822 if (bot->lineno > fileptr->lineno || bot_x > endpos)
1823 bot_x = endpos;
1824
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001825 /* The selected bit of fileptr is on this page. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001826 if (top_x < endpos && bot_x > startpos) {
1827 assert(startpos <= top_x);
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001828
1829 /* x_start is the expanded location of the beginning of the
1830 * mark minus the beginning of the page. */
1831 x_start = strnlenpt(fileptr->data, top_x) - start;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001832
1833 if (bot_x >= endpos)
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001834 /* If the end of the mark is off the page, paintlen is
1835 * -1, meaning that everything on the line gets
1836 * painted. */
1837 paintlen = -1;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001838 else
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001839 /* Otherwise, paintlen is the expanded location of the
1840 * end of the mark minus the expanded location of the
1841 * beginning of the mark. */
1842 paintlen = strnlenpt(fileptr->data, bot_x) - (x_start +
1843 start);
1844
1845 /* If x_start is before the beginning of the page, shift
1846 * paintlen x_start characters to compensate, and put
1847 * x_start at the beginning of the page. */
1848 if (x_start < 0) {
1849 paintlen += x_start;
1850 x_start = 0;
1851 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001852
1853 assert(x_start >= 0 && x_start <= strlen(converted));
1854
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001855 wattron(edit, A_REVERSE);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001856 mvwaddnstr(edit, yval, x_start, converted + x_start, paintlen);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001857 wattroff(edit, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001858 }
Chris Allegretta08893e02001-11-29 02:42:27 +00001859 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001860#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001861}
1862
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001863/* Just update one line in the edit buffer. Basically a wrapper for
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001864 * edit_add().
1865 *
David Lawrence Ramsey07d3feb2004-04-16 05:15:11 +00001866 * If fileptr != current, then index is considered 0. The line will be
1867 * displayed starting with fileptr->data[index]. Likely args are
1868 * current_x or 0. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001869void update_line(const filestruct *fileptr, size_t index)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001870{
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001871 int line;
1872 /* line in the edit window for CURSES calls */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001873 char *converted;
1874 /* fileptr->data converted to have tabs and control characters
1875 * expanded. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001876 size_t page_start;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001877
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001878 assert(fileptr != NULL);
Robert Siemborski53154a72000-06-18 00:11:03 +00001879
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001880 line = fileptr->lineno - edittop->lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001881
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001882 /* We assume the line numbers are valid. Is that really true? */
1883 assert(line < 0 || line == check_linenumbers(fileptr));
1884
1885 if (line < 0 || line >= editwinrows)
1886 return;
1887
1888 /* First, blank out the line (at a minimum) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001889 mvwaddstr(edit, line, 0, hblank);
1890
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001891 /* Next, convert variables that index the line to their equivalent
1892 * positions in the expanded line. */
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001893 index = (fileptr == current) ? strnlenpt(fileptr->data, index) : 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001894 page_start = get_page_start(index);
Chris Allegretta5beed502003-01-05 20:41:21 +00001895
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001896 /* Expand the line, replacing Tab by spaces, and control characters
1897 * by their display form. */
1898 converted = display_string(fileptr->data, page_start, COLS);
Robert Siemborski53875912000-06-16 04:25:30 +00001899
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001900 /* Now, paint the line */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001901 edit_add(fileptr, converted, line, page_start);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001902 free(converted);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001903
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001904 if (page_start > 0)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001905 mvwaddch(edit, line, 0, '$');
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001906 if (strlenpt(fileptr->data) > page_start + COLS)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001907 mvwaddch(edit, line, COLS - 1, '$');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001908}
1909
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001910/* This function updates current, based on where current_y is;
1911 * reset_cursor() does the opposite. */
1912void update_cursor(void)
1913{
1914 int i = 0;
1915
1916#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001917 fprintf(stderr, "Moved to (%d, %d) in edit buffer\n", current_y,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001918 current_x);
1919#endif
1920
1921 current = edittop;
1922 while (i < current_y && current->next != NULL) {
1923 current = current->next;
1924 i++;
1925 }
1926
1927#ifdef DEBUG
Chris Allegretta0e86e602003-01-23 04:27:23 +00001928 fprintf(stderr, "current->data = \"%s\"\n", current->data);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001929#endif
1930}
1931
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001932void center_cursor(void)
1933{
1934 current_y = editwinrows / 2;
1935 wmove(edit, current_y, current_x);
1936}
1937
Chris Allegretta6df90f52002-07-19 01:08:59 +00001938/* Refresh the screen without changing the position of lines. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001939void edit_refresh(void)
1940{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001941 /* Neither of these conditions should occur, but they do. edittop
1942 * is NULL when you open an existing file on the command line, and
Chris Allegretta6df90f52002-07-19 01:08:59 +00001943 * ENABLE_COLOR is defined. Yuck. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001944 if (current == NULL)
1945 return;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001946 if (edittop == NULL)
1947 edittop = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001948
Chris Allegretta63d0b482003-01-26 19:47:10 +00001949 if (current->lineno < edittop->lineno ||
1950 current->lineno >= edittop->lineno + editwinrows)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001951 /* Note that edit_update() changes edittop so that
1952 * current->lineno = edittop->lineno + editwinrows / 2. Thus
1953 * when it then calls edit_refresh(), there is no danger of
1954 * getting an infinite loop. */
Chris Allegrettada721be2000-07-31 01:26:42 +00001955 edit_update(current, CENTER);
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001956 else {
1957 int nlines = 0;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001958 const filestruct *foo = edittop;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001959
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001960#ifdef DEBUG
1961 fprintf(stderr, "edit_refresh(): edittop->lineno = %ld\n", edittop->lineno);
1962#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001963
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001964 while (nlines < editwinrows) {
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001965 update_line(foo, current_x);
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001966 nlines++;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001967 if (foo->next == NULL)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001968 break;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001969 foo = foo->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001970 }
1971 while (nlines < editwinrows) {
1972 mvwaddstr(edit, nlines, 0, hblank);
1973 nlines++;
1974 }
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001975 reset_cursor();
David Lawrence Ramsey07d3feb2004-04-16 05:15:11 +00001976
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001977 /* What the hell are we expecting to update the screen if this
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001978 * isn't here? Luck? */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001979 wrefresh(edit);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001980 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001981}
1982
Chris Allegretta7662c862003-01-13 01:35:15 +00001983/* Same as above, but touch the window first, so everything is
1984 * redrawn. */
Chris Allegrettaf1d33d32000-08-19 03:53:39 +00001985void edit_refresh_clearok(void)
1986{
1987 clearok(edit, TRUE);
1988 edit_refresh();
1989 clearok(edit, FALSE);
1990}
1991
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001992/* Nice generic routine to update the edit buffer, given a pointer to the
1993 * file struct =) */
David Lawrence Ramsey1356a0a2003-09-10 20:31:02 +00001994void edit_update(filestruct *fileptr, topmidnone location)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001995{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001996 if (fileptr == NULL)
1997 return;
1998
Chris Allegretta6df90f52002-07-19 01:08:59 +00001999 if (location != TOP) {
David Lawrence Ramsey07d3feb2004-04-16 05:15:11 +00002000 int goal = (location == NONE) ? current_y : editwinrows / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002001
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00002002 for (; goal > 0 && fileptr->prev != NULL; goal--)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002003 fileptr = fileptr->prev;
2004 }
2005 edittop = fileptr;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002006 edit_refresh();
2007}
2008
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002009/* Ask a question on the statusbar. Answer will be stored in answer
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002010 * global. Returns -1 on aborted enter, -2 on a blank string, and 0
Chris Allegretta88520c92001-05-05 17:45:54 +00002011 * otherwise, the valid shortcut key caught. Def is any editable text we
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002012 * want to put up by default.
Chris Allegretta7da4e9f2000-11-06 02:57:22 +00002013 *
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002014 * New arg tabs tells whether or not to allow tab completion. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002015int statusq(int allowtabs, const shortcut *s, const char *def,
Chris Allegretta5beed502003-01-05 20:41:21 +00002016#ifndef NANO_SMALL
2017 historyheadtype *which_history,
2018#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002019 const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002020{
2021 va_list ap;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002022 char *foo = charalloc(COLS - 3);
Chris Allegretta9caa1932002-02-15 20:08:05 +00002023 int ret;
Chris Allegretta2084acc2001-11-29 03:43:08 +00002024#ifndef DISABLE_TABCOMP
Chris Allegrettaa16e4e92002-01-05 18:59:54 +00002025 int list = 0;
Chris Allegretta2084acc2001-11-29 03:43:08 +00002026#endif
2027
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002028 bottombars(s);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002029
2030 va_start(ap, msg);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002031 vsnprintf(foo, COLS - 4, msg, ap);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002032 va_end(ap);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002033 foo[COLS - 4] = '\0';
Chris Allegretta8ce24132001-04-30 11:28:46 +00002034
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002035 ret = nanogetstr(allowtabs, foo, def,
Chris Allegretta5beed502003-01-05 20:41:21 +00002036#ifndef NANO_SMALL
2037 which_history,
Chris Allegretta2084acc2001-11-29 03:43:08 +00002038#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00002039 s
2040#ifndef DISABLE_TABCOMP
2041 , &list
2042#endif
Chris Allegretta65f075d2003-02-13 03:03:49 +00002043 );
Chris Allegretta6df90f52002-07-19 01:08:59 +00002044 free(foo);
Chris Allegretta65f075d2003-02-13 03:03:49 +00002045 resetstatuspos = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002046
2047 switch (ret) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002048 case NANO_FIRSTLINE_KEY:
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00002049 case NANO_FIRSTLINE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002050 do_first_line();
Chris Allegretta65f075d2003-02-13 03:03:49 +00002051 resetstatuspos = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002052 break;
2053 case NANO_LASTLINE_KEY:
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00002054 case NANO_LASTLINE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002055 do_last_line();
Chris Allegretta65f075d2003-02-13 03:03:49 +00002056 resetstatuspos = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002057 break;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002058#ifndef DISABLE_JUSTIFY
2059 case NANO_PARABEGIN_KEY:
2060 do_para_begin();
2061 resetstatuspos = 1;
2062 break;
2063 case NANO_PARAEND_KEY:
2064 do_para_end();
2065 resetstatuspos = 1;
2066 break;
2067#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002068 case NANO_CANCEL_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002069 ret = -1;
Chris Allegretta65f075d2003-02-13 03:03:49 +00002070 resetstatuspos = 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002071 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002072 }
Chris Allegrettaa90d0cf2003-02-10 02:55:03 +00002073 blank_statusbar();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002074
2075#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00002076 fprintf(stderr, "I got \"%s\"\n", answer);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002077#endif
2078
Chris Allegretta6df90f52002-07-19 01:08:59 +00002079#ifndef DISABLE_TABCOMP
2080 /* if we've done tab completion, there might be a list of
2081 filename matches on the edit window at this point; make sure
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002082 they're cleared off. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002083 if (list)
2084 edit_refresh();
2085#endif
2086
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002087 return ret;
2088}
2089
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002090/* Ask a simple yes/no question on the statusbar. Returns 1 for Y, 0
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002091 * for N, 2 for All (if all is nonzero when passed in) and -1 for abort
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002092 * (^C). */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002093int do_yesno(int all, const char *msg)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002094{
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002095 int ok = -2, width = 16;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002096 const char *yesstr; /* String of yes characters accepted */
2097 const char *nostr; /* Same for no */
2098 const char *allstr; /* And all, surprise! */
Chris Allegretta235ab192001-04-12 13:24:40 +00002099
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002100 /* Yes, no and all are strings of any length. Each string consists
2101 * of all characters accepted as a valid character for that value.
2102 * The first value will be the one displayed in the shortcuts. */
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002103 yesstr = _("Yy");
2104 nostr = _("Nn");
2105 allstr = _("Aa");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002106
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002107 /* Remove gettext call for keybindings until we clear the thing
2108 * up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002109 if (!ISSET(NO_HELP)) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002110 char shortstr[3]; /* Temp string for Y, N, A. */
Chris Allegretta6232d662002-05-12 19:52:15 +00002111
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002112 if (COLS < 32)
2113 width = COLS / 2;
2114
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002115 /* Write the bottom of the screen. */
Chris Allegrettadb28e962003-01-28 01:23:40 +00002116 blank_bottombars();
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002117
Chris Allegretta6232d662002-05-12 19:52:15 +00002118 sprintf(shortstr, " %c", yesstr[0]);
Chris Allegrettadb28e962003-01-28 01:23:40 +00002119 wmove(bottomwin, 1, 0);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002120 onekey(shortstr, _("Yes"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002121
2122 if (all) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002123 wmove(bottomwin, 1, width);
Chris Allegretta6232d662002-05-12 19:52:15 +00002124 shortstr[1] = allstr[0];
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002125 onekey(shortstr, _("All"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002126 }
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002127
Chris Allegrettadb28e962003-01-28 01:23:40 +00002128 wmove(bottomwin, 2, 0);
Chris Allegretta6232d662002-05-12 19:52:15 +00002129 shortstr[1] = nostr[0];
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002130 onekey(shortstr, _("No"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002131
Chris Allegrettadb28e962003-01-28 01:23:40 +00002132 wmove(bottomwin, 2, 16);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002133 onekey("^C", _("Cancel"), width);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002134 }
Chris Allegrettadb28e962003-01-28 01:23:40 +00002135
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002136 wattron(bottomwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002137
2138 blank_statusbar();
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002139 mvwaddnstr(bottomwin, 0, 0, msg, COLS - 1);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002140
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002141 wattroff(bottomwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002142
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002143 wrefresh(bottomwin);
2144
Chris Allegrettadb28e962003-01-28 01:23:40 +00002145 do {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002146 int kbinput;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002147 int meta_key;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002148#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002149 int mouse_x, mouse_y;
Chris Allegretta235ab192001-04-12 13:24:40 +00002150#endif
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002151
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002152 kbinput = get_kbinput(edit, &meta_key);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002153
2154 if (kbinput == NANO_CANCEL_KEY)
Chris Allegrettadb28e962003-01-28 01:23:40 +00002155 ok = -1;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002156#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002157 /* Look ma! We get to duplicate lots of code from
2158 * do_mouse()!! */
2159 else if (kbinput == KEY_MOUSE) {
2160 kbinput = get_mouseinput(&mouse_x, &mouse_y, 0);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002161
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002162 if (mouse_x != -1 && mouse_y != -1 && !ISSET(NO_HELP) &&
2163 wenclose(bottomwin, mouse_y, mouse_x) && mouse_x <
2164 (width * 2) && mouse_y >= editwinrows + 3) {
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002165
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002166 int x = mouse_x / width;
2167 /* Did we click in the first column of shortcuts, or
2168 * the second? */
2169 int y = mouse_y - editwinrows - 3;
2170 /* Did we click in the first row of shortcuts? */
2171
2172 assert(0 <= x && x <= 1 && 0 <= y && y <= 1);
2173
2174 /* x = 0 means they clicked Yes or No.
2175 * y = 0 means Yes or All. */
2176 ok = -2 * x * y + x - y + 1;
2177
2178 if (ok == 2 && !all)
2179 ok = -2;
2180 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002181 }
Chris Allegrettadb28e962003-01-28 01:23:40 +00002182#endif
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002183 /* Look for the kbinput in the yes, no and (optionally) all
2184 * str. */
Chris Allegrettadb28e962003-01-28 01:23:40 +00002185 else if (strchr(yesstr, kbinput) != NULL)
2186 ok = 1;
2187 else if (strchr(nostr, kbinput) != NULL)
2188 ok = 0;
2189 else if (all && strchr(allstr, kbinput) != NULL)
2190 ok = 2;
2191 } while (ok == -2);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002192
Chris Allegrettadb28e962003-01-28 01:23:40 +00002193 return ok;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002194}
2195
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002196int total_refresh(void)
2197{
2198 clearok(edit, TRUE);
2199 clearok(topwin, TRUE);
2200 clearok(bottomwin, TRUE);
2201 wnoutrefresh(edit);
2202 wnoutrefresh(topwin);
2203 wnoutrefresh(bottomwin);
2204 doupdate();
2205 clearok(edit, FALSE);
2206 clearok(topwin, FALSE);
2207 clearok(bottomwin, FALSE);
2208 edit_refresh();
2209 titlebar(NULL);
2210 return 1;
2211}
2212
2213void display_main_list(void)
2214{
2215 bottombars(main_list);
2216}
2217
Chris Allegretta6df90f52002-07-19 01:08:59 +00002218void statusbar(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002219{
2220 va_list ap;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002221
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002222 va_start(ap, msg);
2223
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002224 /* Curses mode is turned off. If we use wmove() now, it will muck
2225 * up the terminal settings. So we just use vfprintf(). */
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002226 if (curses_ended) {
2227 vfprintf(stderr, msg, ap);
2228 va_end(ap);
2229 return;
2230 }
2231
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002232 /* Blank out the line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002233 blank_statusbar();
2234
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002235 if (COLS >= 4) {
2236 char *bar;
2237 char *foo;
2238 int start_x = 0;
2239 size_t foo_len;
2240 bar = charalloc(COLS - 3);
2241 vsnprintf(bar, COLS - 3, msg, ap);
2242 va_end(ap);
2243 foo = display_string(bar, 0, COLS - 4);
2244 free(bar);
2245 foo_len = strlen(foo);
2246 start_x = (COLS - foo_len - 4) / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002247
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002248 wmove(bottomwin, 0, start_x);
2249 wattron(bottomwin, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002250
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002251 waddstr(bottomwin, "[ ");
2252 waddstr(bottomwin, foo);
2253 free(foo);
2254 waddstr(bottomwin, " ]");
2255 wattroff(bottomwin, A_REVERSE);
2256 wnoutrefresh(bottomwin);
2257 wrefresh(edit);
2258 /* Leave the cursor at its position in the edit window, not
2259 * in the statusbar. */
2260 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002261
Chris Allegrettad26ab912003-01-28 01:16:47 +00002262 SET(DISABLE_CURPOS);
2263 statblank = 26;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002264}
2265
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002266/* If constant is false, the user typed ^C so we unconditionally display
Chris Allegrettad26ab912003-01-28 01:16:47 +00002267 * the cursor position. Otherwise, we display it only if the character
2268 * position changed, and DISABLE_CURPOS is not set.
2269 *
2270 * If constant and DISABLE_CURPOS is set, we unset it and update old_i and
2271 * old_totsize. That way, we leave the current statusbar alone, but next
2272 * time we will display. */
Chris Allegretta2084acc2001-11-29 03:43:08 +00002273int do_cursorpos(int constant)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002274{
Chris Allegrettad26ab912003-01-28 01:16:47 +00002275 const filestruct *fileptr;
2276 unsigned long i = 0;
2277 static unsigned long old_i = 0;
2278 static long old_totsize = -1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002279
Chris Allegrettad26ab912003-01-28 01:16:47 +00002280 assert(current != NULL && fileage != NULL && totlines != 0);
Chris Allegretta2084acc2001-11-29 03:43:08 +00002281
2282 if (old_totsize == -1)
2283 old_totsize = totsize;
2284
Chris Allegrettad26ab912003-01-28 01:16:47 +00002285 for (fileptr = fileage; fileptr != current; fileptr = fileptr->next) {
2286 assert(fileptr != NULL);
Chris Allegrettaf27c6972002-02-12 01:57:24 +00002287 i += strlen(fileptr->data) + 1;
Chris Allegrettad26ab912003-01-28 01:16:47 +00002288 }
Chris Allegrettaf27c6972002-02-12 01:57:24 +00002289 i += current_x;
Chris Allegretta14b3ca92002-01-25 21:59:02 +00002290
Chris Allegrettad26ab912003-01-28 01:16:47 +00002291 if (constant && ISSET(DISABLE_CURPOS)) {
2292 UNSET(DISABLE_CURPOS);
2293 old_i = i;
2294 old_totsize = totsize;
2295 return 0;
2296 }
Chris Allegretta14b3ca92002-01-25 21:59:02 +00002297
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002298 /* If constant is false, display the position on the statusbar
2299 * unconditionally; otherwise, only display the position when the
2300 * character values have changed. */
Chris Allegrettad26ab912003-01-28 01:16:47 +00002301 if (!constant || old_i != i || old_totsize != totsize) {
2302 unsigned long xpt = xplustabs() + 1;
2303 unsigned long cur_len = strlenpt(current->data) + 1;
2304 int linepct = 100 * current->lineno / totlines;
2305 int colpct = 100 * xpt / cur_len;
2306 int bytepct = totsize == 0 ? 0 : 100 * i / totsize;
2307
2308 statusbar(
2309 _("line %ld/%ld (%d%%), col %lu/%lu (%d%%), char %lu/%ld (%d%%)"),
2310 current->lineno, totlines, linepct,
2311 xpt, cur_len, colpct,
2312 i, totsize, bytepct);
2313 UNSET(DISABLE_CURPOS);
Chris Allegretta2084acc2001-11-29 03:43:08 +00002314 }
2315
2316 old_i = i;
2317 old_totsize = totsize;
2318
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002319 reset_cursor();
Chris Allegrettad26ab912003-01-28 01:16:47 +00002320 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002321}
2322
Chris Allegretta2084acc2001-11-29 03:43:08 +00002323int do_cursorpos_void(void)
2324{
2325 return do_cursorpos(0);
2326}
2327
Chris Allegretta4640fe32003-02-10 03:10:03 +00002328/* Calculate the next line of help_text, starting at ptr. */
2329int line_len(const char *ptr)
2330{
2331 int j = 0;
2332
2333 while (*ptr != '\n' && *ptr != '\0' && j < COLS - 5) {
2334 ptr++;
2335 j++;
2336 }
2337 if (j == COLS - 5) {
2338 /* Don't wrap at the first of two spaces following a period. */
2339 if (*ptr == ' ' && *(ptr + 1) == ' ')
2340 j++;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002341 /* Don't print half a word if we've run out of space. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00002342 while (*ptr != ' ' && j > 0) {
2343 ptr--;
2344 j--;
2345 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002346 /* Word longer than COLS - 5 chars just gets broken. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00002347 if (j == 0)
2348 j = COLS - 5;
2349 }
2350 assert(j >= 0 && j <= COLS - 4 && (j > 0 || *ptr == '\n'));
2351 return j;
2352}
2353
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002354/* Our shortcut-list-compliant help function, which is better than
2355 * nothing, and dynamic! */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002356int do_help(void)
2357{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002358#ifndef DISABLE_HELP
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002359 int i, page = 0, kbinput = ERR, meta_key, no_more = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002360 int no_help_flag = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002361 const shortcut *oldshortcut;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002362
2363 blank_edit();
2364 curs_set(0);
Chris Allegrettab3655b42001-10-22 03:15:31 +00002365 wattroff(bottomwin, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002366 blank_statusbar();
2367
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002368 /* Set help_text as the string to display. */
Chris Allegrettab3655b42001-10-22 03:15:31 +00002369 help_init();
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002370 assert(help_text != NULL);
Chris Allegrettab3655b42001-10-22 03:15:31 +00002371
2372 oldshortcut = currshortcut;
Chris Allegrettab3655b42001-10-22 03:15:31 +00002373
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002374 currshortcut = help_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00002375
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002376 if (ISSET(NO_HELP)) {
2377
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002378 /* Well, if we're going to do this, we should at least do it the
2379 * right way. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002380 no_help_flag = 1;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002381 UNSET(NO_HELP);
Chris Allegretta70444892001-01-07 23:02:02 +00002382 window_init();
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002383 bottombars(help_list);
Chris Allegretta70444892001-01-07 23:02:02 +00002384
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002385 } else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002386 bottombars(help_list);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002387
2388 do {
Chris Allegrettaf717f982003-02-13 22:25:01 +00002389 const char *ptr = help_text;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002390
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002391 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002392#ifndef DISABLE_MOUSE
Chris Allegretta598106e2002-01-19 01:59:37 +00002393 case KEY_MOUSE:
2394 do_mouse();
2395 break;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002396#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002397 case NANO_NEXTPAGE_KEY:
2398 case NANO_NEXTPAGE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002399 if (!no_more) {
2400 blank_edit();
2401 page++;
2402 }
2403 break;
2404 case NANO_PREVPAGE_KEY:
2405 case NANO_PREVPAGE_FKEY:
Chris Allegretta4640fe32003-02-10 03:10:03 +00002406 if (page > 0) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002407 no_more = 0;
2408 blank_edit();
2409 page--;
2410 }
2411 break;
2412 }
2413
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002414 /* Calculate where in the text we should be, based on the
2415 * page. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00002416 for (i = 1; i < page * (editwinrows - 1); i++) {
2417 ptr += line_len(ptr);
2418 if (*ptr == '\n')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002419 ptr++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002420 }
2421
Chris Allegretta4640fe32003-02-10 03:10:03 +00002422 for (i = 0; i < editwinrows && *ptr != '\0'; i++) {
2423 int j = line_len(ptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002424
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002425 mvwaddnstr(edit, i, 0, ptr, j);
Chris Allegretta4640fe32003-02-10 03:10:03 +00002426 ptr += j;
2427 if (*ptr == '\n')
2428 ptr++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002429 }
Chris Allegretta4640fe32003-02-10 03:10:03 +00002430
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002431 if (*ptr == '\0') {
2432 no_more = 1;
2433 continue;
2434 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002435 } while ((kbinput = get_kbinput(edit, &meta_key)) != NANO_EXIT_KEY && kbinput != NANO_EXIT_FKEY);
Chris Allegrettad1627cf2000-12-18 05:03:16 +00002436
Chris Allegrettab3655b42001-10-22 03:15:31 +00002437 currshortcut = oldshortcut;
Chris Allegrettab3655b42001-10-22 03:15:31 +00002438
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002439 if (no_help_flag) {
Chris Allegretta70444892001-01-07 23:02:02 +00002440 blank_bottombars();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002441 wrefresh(bottomwin);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002442 SET(NO_HELP);
Chris Allegretta70444892001-01-07 23:02:02 +00002443 window_init();
Chris Allegretta598106e2002-01-19 01:59:37 +00002444 } else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002445 bottombars(currshortcut);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002446
2447 curs_set(1);
2448 edit_refresh();
Chris Allegrettac08f50d2001-01-06 18:12:43 +00002449
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002450 /* The help_init() at the beginning allocated help_text, which has
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002451 * now been written to the screen. */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002452 free(help_text);
2453 help_text = NULL;
2454
Chris Allegretta6df90f52002-07-19 01:08:59 +00002455#elif defined(DISABLE_HELP)
2456 nano_disabled_msg();
2457#endif
2458
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002459 return 1;
2460}
2461
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002462/* Highlight the current word being replaced or spell checked. We
2463 * expect word to have tabs and control characters expanded. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002464void do_replace_highlight(int highlight_flag, const char *word)
Chris Allegrettafb62f732000-12-05 11:36:41 +00002465{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002466 int y = xplustabs();
2467 size_t word_len = strlen(word);
Chris Allegrettafb62f732000-12-05 11:36:41 +00002468
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002469 y = get_page_start(y) + COLS - y;
2470 /* Now y is the number of characters we can display on this
2471 * line. */
Chris Allegrettafb62f732000-12-05 11:36:41 +00002472
2473 reset_cursor();
Chris Allegretta598106e2002-01-19 01:59:37 +00002474
Chris Allegrettafb62f732000-12-05 11:36:41 +00002475 if (highlight_flag)
2476 wattron(edit, A_REVERSE);
2477
David Lawrence Ramsey2a4ab6d2003-12-24 08:29:49 +00002478#ifdef HAVE_REGEX_H
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00002479 /* This is so we can show zero-length regexes. */
2480 if (word_len == 0)
2481 waddstr(edit, " ");
2482 else
David Lawrence Ramsey2a4ab6d2003-12-24 08:29:49 +00002483#endif
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00002484 waddnstr(edit, word, y - 1);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002485
2486 if (word_len > y)
2487 waddch(edit, '$');
2488 else if (word_len == y)
2489 waddch(edit, word[word_len - 1]);
Chris Allegrettafb62f732000-12-05 11:36:41 +00002490
2491 if (highlight_flag)
2492 wattroff(edit, A_REVERSE);
Chris Allegrettafb62f732000-12-05 11:36:41 +00002493}
2494
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002495#ifdef DEBUG
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002496/* Dump the passed-in file structure to stderr. */
2497void dump_buffer(const filestruct *inptr)
2498{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002499 if (inptr == fileage)
Jordi Mallachf9390af2003-08-05 19:31:12 +00002500 fprintf(stderr, "Dumping file buffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002501 else if (inptr == cutbuffer)
Jordi Mallachf9390af2003-08-05 19:31:12 +00002502 fprintf(stderr, "Dumping cutbuffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002503 else
Jordi Mallachf9390af2003-08-05 19:31:12 +00002504 fprintf(stderr, "Dumping a buffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002505
2506 while (inptr != NULL) {
2507 fprintf(stderr, "(%d) %s\n", inptr->lineno, inptr->data);
2508 inptr = inptr->next;
2509 }
2510}
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002511
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002512/* Dump the file structure to stderr in reverse. */
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00002513void dump_buffer_reverse(void)
2514{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002515 const filestruct *fileptr = filebot;
2516
2517 while (fileptr != NULL) {
2518 fprintf(stderr, "(%d) %s\n", fileptr->lineno, fileptr->data);
2519 fileptr = fileptr->prev;
2520 }
2521}
2522#endif /* DEBUG */
2523
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002524#ifdef NANO_EXTRA
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002525#define CREDIT_LEN 53
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002526#define XLCREDIT_LEN 8
2527
David Lawrence Ramseyfdece462004-01-19 18:15:03 +00002528/* Easter egg: Display credits. Assume nodelay(edit) is FALSE. */
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002529void do_credits(void)
2530{
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002531 int i, j = 0, k, place = 0, start_x;
David Lawrence Ramseye97c8d52004-01-14 19:26:29 +00002532 struct timespec scrolldelay;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002533
Chris Allegrettaf717f982003-02-13 22:25:01 +00002534 const char *what;
2535 const char *xlcredits[XLCREDIT_LEN];
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002536
Chris Allegrettaf717f982003-02-13 22:25:01 +00002537 const char *credits[CREDIT_LEN] = {
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002538 "0", /* "The nano text editor" */
2539 "1", /* "version" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002540 VERSION,
2541 "",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002542 "2", /* "Brought to you by:" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002543 "Chris Allegretta",
2544 "Jordi Mallach",
2545 "Adam Rogoyski",
2546 "Rob Siemborski",
2547 "Rocco Corsi",
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002548 "David Lawrence Ramsey",
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002549 "David Benbennick",
Chris Allegretta598106e2002-01-19 01:59:37 +00002550 "Ken Tyler",
2551 "Sven Guckes",
2552 "Florian König",
2553 "Pauli Virtanen",
2554 "Daniele Medri",
2555 "Clement Laforet",
2556 "Tedi Heriyanto",
2557 "Bill Soudan",
2558 "Christian Weisgerber",
2559 "Erik Andersen",
2560 "Big Gaute",
2561 "Joshua Jensen",
2562 "Ryan Krebs",
2563 "Albert Chin",
Chris Allegretta598106e2002-01-19 01:59:37 +00002564 "",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002565 "3", /* "Special thanks to:" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002566 "Plattsburgh State University",
2567 "Benet Laboratories",
2568 "Amy Allegretta",
2569 "Linda Young",
2570 "Jeremy Robichaud",
2571 "Richard Kolb II",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002572 "4", /* "The Free Software Foundation" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002573 "Linus Torvalds",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002574 "5", /* "For ncurses:" */
Chris Allegrettadce44ab2002-03-16 01:03:41 +00002575 "Thomas Dickey",
2576 "Pavel Curtis",
2577 "Zeyd Ben-Halim",
2578 "Eric S. Raymond",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002579 "6", /* "and anyone else we forgot..." */
2580 "7", /* "Thank you for using nano!\n" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002581 "", "", "", "",
David Lawrence Ramsey6481c3f2004-01-09 23:06:54 +00002582 "(c) 1999-2004 Chris Allegretta",
Chris Allegretta598106e2002-01-19 01:59:37 +00002583 "", "", "", "",
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002584 "http://www.nano-editor.org/"
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002585 };
2586
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002587 xlcredits[0] = _("The nano text editor");
2588 xlcredits[1] = _("version ");
2589 xlcredits[2] = _("Brought to you by:");
2590 xlcredits[3] = _("Special thanks to:");
2591 xlcredits[4] = _("The Free Software Foundation");
2592 xlcredits[5] = _("For ncurses:");
2593 xlcredits[6] = _("and anyone else we forgot...");
2594 xlcredits[7] = _("Thank you for using nano!\n");
2595
David Lawrence Ramsey9da08312004-01-14 22:40:38 +00002596 scrolldelay.tv_sec = 0;
David Lawrence Ramsey62187d92004-01-14 22:45:05 +00002597 scrolldelay.tv_nsec = 700000000;
David Lawrence Ramseye97c8d52004-01-14 19:26:29 +00002598
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002599 curs_set(0);
2600 nodelay(edit, TRUE);
2601 blank_bottombars();
2602 mvwaddstr(topwin, 0, 0, hblank);
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002603 blank_edit();
2604 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002605 wrefresh(bottomwin);
2606 wrefresh(topwin);
2607
2608 while (wgetch(edit) == ERR) {
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002609 for (k = 0; k <= 1; k++) {
2610 blank_edit();
Chris Allegretta598106e2002-01-19 01:59:37 +00002611 for (i = editwinrows / 2 - 1; i >= (editwinrows / 2 - 1 - j);
2612 i--) {
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002613 mvwaddstr(edit, i * 2 - k, 0, hblank);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002614
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002615 if (place - (editwinrows / 2 - 1 - i) < CREDIT_LEN) {
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002616 what = credits[place - (editwinrows / 2 - 1 - i)];
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002617
2618 /* God I've missed hacking. If what is exactly
2619 1 char long, it's a sentinel for a translated
2620 string, so use that instead. This means no
2621 thanking people with 1 character long names ;-) */
2622 if (strlen(what) == 1)
2623 what = xlcredits[atoi(what)];
2624 } else
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002625 what = "";
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002626
Chris Allegretta17dcb722001-01-20 21:40:07 +00002627 start_x = COLS / 2 - strlen(what) / 2 - 1;
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002628 mvwaddstr(edit, i * 2 - k, start_x, what);
2629 }
David Lawrence Ramseye97c8d52004-01-14 19:26:29 +00002630 nanosleep(&scrolldelay, NULL);
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002631 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002632 }
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002633 if (j < editwinrows / 2 - 1)
2634 j++;
2635
2636 place++;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002637
2638 if (place >= CREDIT_LEN + editwinrows / 2)
2639 break;
2640 }
2641
2642 nodelay(edit, FALSE);
2643 curs_set(1);
2644 display_main_list();
2645 total_refresh();
Chris Allegretta598106e2002-01-19 01:59:37 +00002646}
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002647#endif