blob: 718afafaace30bee915ba338bbdf35b069ff68ad [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 Ramsey58f6d832004-01-27 07:12:47 +000077 /* Turn the keypad off so that we don't get extended keypad values,
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +000078 * all of which are outside the ASCII range, and switch to raw mode
David Lawrence Ramsey1bc92192004-02-03 17:36:55 +000079 * so that we can type ^C, ^Q, ^S, ^Z, and ^\ (and ^Y on the Hurd)
80 * without getting interrupts. */
David Lawrence Ramsey58f6d832004-01-27 07:12:47 +000081 keypad(win, FALSE);
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 Ramsey58f6d832004-01-27 07:12:47 +000085
86 kbinput = wgetch(win);
David Lawrence Ramseyee383db2004-02-06 03:07:10 +000087 verbatim_kbinput = (int *)nmalloc(sizeof(int));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000088 verbatim_kbinput[0] = kbinput;
89 *kbinput_len = 1;
90
David Lawrence Ramseyf4276942003-12-24 03:33:09 +000091 if (allow_ascii && kbinput >= '0' && kbinput <= '2')
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000092 /* Entering a three-digit decimal ASCII code from 000-255 in
93 * verbatim mode will produce the corresponding ASCII
94 * character. */
David Lawrence Ramseyee383db2004-02-06 03:07:10 +000095 verbatim_kbinput[0] = get_ascii_kbinput(win, kbinput);
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000096 else {
97 nodelay(win, TRUE);
98 while ((kbinput = wgetch(win)) != ERR) {
David Lawrence Ramseyda8fd8f2003-09-16 01:22:31 +000099 (*kbinput_len)++;
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000100 verbatim_kbinput = realloc(verbatim_kbinput, *kbinput_len * sizeof(int));
101 verbatim_kbinput[*kbinput_len - 1] = kbinput;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000102 }
103 nodelay(win, FALSE);
104 }
105
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +0000106 /* Turn the keypad back on and switch back to cbreak mode now that
107 * we're done. */
David Lawrence Ramsey58f6d832004-01-27 07:12:47 +0000108 keypad(win, TRUE);
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +0000109#ifdef _POSIX_VDISABLE
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +0000110 cbreak();
111#endif
David Lawrence Ramsey58f6d832004-01-27 07:12:47 +0000112
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000113#ifdef DEBUG
114 fprintf(stderr, "get_verbatim_kbinput(): verbatim_kbinput = %s\n", verbatim_kbinput);
115#endif
David Lawrence Ramsey369732f2004-02-16 20:32:40 +0000116
117#ifndef NANO_SMALL
118 allow_pending_sigwinch(FALSE);
119#endif
120
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000121 return verbatim_kbinput;
122}
123
124/* Swallow input characters that should be quietly ignored, and return
125 * the first input character that shouldn't be. */
126int get_ignored_kbinput(WINDOW *win)
127{
128 int kbinput;
129
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +0000130 while (TRUE) {
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000131 kbinput = wgetch(win);
132 switch (kbinput) {
133 case ERR:
134 case KEY_RESIZE:
135#ifdef PDCURSES
136 case KEY_SHIFT_L:
137 case KEY_SHIFT_R:
138 case KEY_CONTROL_L:
139 case KEY_CONTROL_R:
140 case KEY_ALT_L:
141 case KEY_ALT_R:
142#endif
143#ifdef DEBUG
144 fprintf(stderr, "get_ignored_kbinput(): kbinput = %d\n", kbinput);
145#endif
146 break;
147 default:
148 return kbinput;
149 }
150 }
151}
152
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000153/* Translate acceptable ASCII, extended keypad values, and/or escape
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000154 * sequences. Set meta_key to 1 if we get a Meta sequence. Assume
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000155 * nodelay(win) is FALSE. */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000156int get_accepted_kbinput(WINDOW *win, int kbinput, int *meta_key)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000157{
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000158 *meta_key = FALSE;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000159
160 switch (kbinput) {
161 case NANO_CONTROL_3: /* Escape */
David Lawrence Ramsey25061362004-01-16 19:12:46 +0000162 kbinput = wgetch(win);
163 switch (kbinput) {
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000164 case NANO_CONTROL_3: /* Escape */
165 kbinput = wgetch(win);
166 /* Esc Esc [three-digit decimal ASCII code from
167 * 000-255] == [corresponding ASCII character];
David Lawrence Ramseyd390dd82004-02-07 03:38:02 +0000168 * Esc Esc 2 obviously can't be Ctrl-2 here */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000169 if (kbinput >= '0' && kbinput <= '2')
170 kbinput = get_ascii_kbinput(win, kbinput);
171 /* Esc Esc [character] == Ctrl-[character];
172 * Ctrl-Space (Ctrl-2) == Ctrl-@ == Ctrl-` */
173 else if (kbinput == ' ' || kbinput == '@' || kbinput == '`')
174 kbinput = NANO_CONTROL_SPACE;
175 /* Ctrl-3 (Ctrl-[, Esc) to Ctrl-7 (Ctrl-_) */
176 else if (kbinput >= '3' && kbinput <= '7')
177 kbinput -= 24;
178 /* Ctrl-8 (Ctrl-?) */
179 else if (kbinput == '8' || kbinput == '?')
180 kbinput = NANO_CONTROL_8;
181 /* Ctrl-A to Ctrl-_ */
182 else if (kbinput >= 'A' && kbinput <= '_')
183 kbinput -= 64;
David Lawrence Ramseyda8fd8f2003-09-16 01:22:31 +0000184 /* Ctrl-A to Ctrl-~ */
185 else if (kbinput >= 'a' && kbinput <= '~')
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000186 kbinput -= 96;
187 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000188 case 'O':
189 case 'o':
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000190 /* Terminal breakage, part 1: We shouldn't get an escape
191 * sequence here for terminals that support Delete, but
192 * we do sometimes on FreeBSD. Thank you, Wouter van
193 * Hemel. */
194 case '[':
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000195 {
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000196 int old_kbinput = kbinput, *escape_seq, escape_seq_len;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000197 nodelay(win, TRUE);
198 kbinput = wgetch(win);
199 switch (kbinput) {
200 case ERR:
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000201 kbinput = tolower(old_kbinput);
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000202 *meta_key = TRUE;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000203 break;
204 default:
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000205 ungetch(kbinput);
206 ungetch(old_kbinput);
207 escape_seq = get_verbatim_kbinput(win, &escape_seq_len, 0);
208 kbinput = get_escape_seq_kbinput(win, escape_seq, escape_seq_len);
209 free(escape_seq);
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000210 }
211 nodelay(win, FALSE);
212 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000213 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000214 default:
215 /* Esc [character] == Meta-[character] */
David Lawrence Ramseyda8fd8f2003-09-16 01:22:31 +0000216 kbinput = tolower(kbinput);
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000217 *meta_key = TRUE;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000218 }
219 break;
David Lawrence Ramsey7776ef92003-11-04 18:32:35 +0000220 case NANO_CONTROL_8:
221 /* Terminal breakage, part 2: We shouldn't get Ctrl-8
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000222 * (Ctrl-?) for Backspace or Delete, but we do sometimes. */
223 kbinput = ISSET(REBIND_DELETE) ? NANO_DELETE_KEY : NANO_BACKSPACE_KEY;
David Lawrence Ramsey7776ef92003-11-04 18:32:35 +0000224 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000225 case KEY_DOWN:
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000226 kbinput = NANO_NEXTLINE_KEY;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000227 break;
228 case KEY_UP:
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000229 kbinput = NANO_PREVLINE_KEY;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000230 break;
231 case KEY_LEFT:
232 kbinput = NANO_BACK_KEY;
233 break;
234 case KEY_RIGHT:
235 kbinput = NANO_FORWARD_KEY;
236 break;
237 case KEY_HOME:
238 kbinput = NANO_HOME_KEY;
239 break;
240 case KEY_BACKSPACE:
241 kbinput = NANO_BACKSPACE_KEY;
242 break;
243 case KEY_DC:
David Lawrence Ramsey7776ef92003-11-04 18:32:35 +0000244 /* Terminal breakage, part 3: We should only get KEY_DC when
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000245 * hitting Delete, but we get it when hitting Backspace
246 * sometimes on FreeBSD. Thank you, Lee Nelson. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000247 kbinput = ISSET(REBIND_DELETE) ? NANO_BACKSPACE_KEY : NANO_DELETE_KEY;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000248 break;
249 case KEY_IC:
250 kbinput = NANO_INSERTFILE_KEY;
251 break;
252 case KEY_NPAGE:
253 kbinput = NANO_NEXTPAGE_KEY;
254 break;
255 case KEY_PPAGE:
256 kbinput = NANO_PREVPAGE_KEY;
257 break;
258 case KEY_ENTER:
259 kbinput = NANO_ENTER_KEY;
260 break;
261 case KEY_END:
262 kbinput = NANO_END_KEY;
263 break;
264 case KEY_SUSPEND:
265 kbinput = NANO_SUSPEND_KEY;
266 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000267 case KEY_SLEFT:
268 kbinput = NANO_BACK_KEY;
269 break;
270 case KEY_SRIGHT:
271 kbinput = NANO_FORWARD_KEY;
272 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000273 }
274#ifdef DEBUG
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000275 fprintf(stderr, "get_accepted_kbinput(): kbinput = %d, meta_key = %d\n", kbinput, *meta_key);
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000276#endif
277 return kbinput;
278}
279
280/* Translate a three-digit decimal ASCII code from 000-255 into the
281 * corresponding ASCII character. */
282int get_ascii_kbinput(WINDOW *win, int kbinput)
283{
284 int retval;
285
286 switch (kbinput) {
287 case '0':
288 case '1':
289 case '2':
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000290 retval = (kbinput - '0') * 100;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000291 break;
292 default:
293 return kbinput;
294 }
295
296 kbinput = wgetch(win);
297 switch (kbinput) {
298 case '0':
299 case '1':
300 case '2':
301 case '3':
302 case '4':
303 case '5':
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000304 retval += (kbinput - '0') * 10;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000305 break;
306 case '6':
307 case '7':
308 case '8':
309 case '9':
310 if (retval < 200) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000311 retval += (kbinput - '0') * 10;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000312 break;
313 }
314 default:
315 return kbinput;
316 }
317
318 kbinput = wgetch(win);
319 switch (kbinput) {
320 case '0':
321 case '1':
322 case '2':
323 case '3':
324 case '4':
325 case '5':
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000326 retval += kbinput - '0';
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000327 break;
328 case '6':
329 case '7':
330 case '8':
331 case '9':
332 if (retval < 250) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000333 retval += kbinput - '0';
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000334 break;
335 }
336 default:
337 return kbinput;
338 }
339
340#ifdef DEBUG
341 fprintf(stderr, "get_ascii_kbinput(): kbinput = %d\n", kbinput);
342#endif
343 return retval;
344}
345
David Lawrence Ramsey58f6d832004-01-27 07:12:47 +0000346/* Translate escape sequences, most of which correspond to extended
347 * keypad values. These sequences are generated when the terminal
348 * doesn't support the needed keys. Assume that Escape has already been
349 * read in, and that nodelay(win) is TRUE.
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000350 *
351 * The supported terminals are the Linux console, the FreeBSD console,
352 * the Hurd console (a.k.a. the Mach console), xterm, rxvt, and Eterm.
353 * There are several escape sequence conflicts and omissions, outlined
354 * as follows:
355 *
356 * - F1 on FreeBSD console == kmous on xterm/rxvt/Eterm; the latter is
357 * omitted. (Mouse input will only work properly if the extended
358 * keypad value KEY_MOUSE is generated on mouse events instead of the
359 * kmous escape sequence.)
360 * - F9 on FreeBSD console == PageDown on Hurd console; the former is
David Lawrence Ramsey0ee54d92004-01-26 20:18:52 +0000361 * omitted. (The editing keypad, consisting of Insert, Delete, Home,
362 * End, PageUp, and PageDown, is more important to have working than
363 * the function keys, because the functions of the former are not
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000364 * arbitrary and the functions of the latter are.)
365 * - F10 on FreeBSD console == PageUp on Hurd console; the former is
366 * omitted. (Same as above.)
367 * - F13 on FreeBSD console == End on Hurd console; the former is
368 * omitted. (Same as above.)
369 * - The Hurd console has no escape sequences for F11, F12, F13, or
370 * F14. */
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000371int get_escape_seq_kbinput(WINDOW *win, int *escape_seq, int
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000372 escape_seq_len)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000373{
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000374 int kbinput = ERR;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000375
376 if (escape_seq_len > 1) {
377 switch (escape_seq[0]) {
378 case 'O':
379 switch (escape_seq[1]) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000380 case '2':
381 if (escape_seq_len >= 3) {
382 switch (escape_seq[2]) {
383 case 'P': /* Esc O 2 P == F13 on
384 * xterm. */
385 kbinput = KEY_F(13);
386 break;
387 case 'Q': /* Esc O 2 Q == F14 on
388 * xterm. */
389 kbinput = KEY_F(14);
390 break;
391 }
392 }
393 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000394 case 'A': /* Esc O A == Up on xterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000395 case 'B': /* Esc O B == Down on xterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000396 case 'C': /* Esc O C == Right on xterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000397 case 'D': /* Esc O D == Left on xterm. */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000398 kbinput = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000399 break;
400 case 'F': /* Esc O F == End on xterm. */
401 kbinput = NANO_END_KEY;
402 break;
403 case 'H': /* Esc O H == Home on xterm. */
404 kbinput = NANO_HOME_KEY;
405 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000406 case 'P': /* Esc O P == F1 on Hurd console. */
407 kbinput = KEY_F(1);
408 break;
409 case 'Q': /* Esc O Q == F2 on Hurd console. */
410 kbinput = KEY_F(2);
411 break;
412 case 'R': /* Esc O R == F3 on Hurd console. */
413 kbinput = KEY_F(3);
414 break;
415 case 'S': /* Esc O S == F4 on Hurd console. */
416 kbinput = KEY_F(4);
417 break;
418 case 'T': /* Esc O T == F5 on Hurd console. */
419 kbinput = KEY_F(5);
420 break;
421 case 'U': /* Esc O U == F6 on Hurd console. */
422 kbinput = KEY_F(6);
423 break;
424 case 'V': /* Esc O V == F7 on Hurd console. */
425 kbinput = KEY_F(7);
426 break;
427 case 'W': /* Esc O W == F8 on Hurd console. */
428 kbinput = KEY_F(8);
429 break;
430 case 'X': /* Esc O X == F9 on Hurd console. */
431 kbinput = KEY_F(9);
432 break;
433 case 'Y': /* Esc O Y == F10 on Hurd console. */
434 kbinput = KEY_F(10);
435 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000436 case 'a': /* Esc O a == Ctrl-Up on rxvt. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000437 case 'b': /* Esc O b == Ctrl-Down on rxvt. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000438 case 'c': /* Esc O c == Ctrl-Right on rxvt. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000439 case 'd': /* Esc O d == Ctrl-Left on rxvt. */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000440 kbinput = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000441 break;
442 }
443 break;
444 case 'o':
445 switch (escape_seq[1]) {
446 case 'a': /* Esc o a == Ctrl-Up on Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000447 case 'b': /* Esc o b == Ctrl-Down on Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000448 case 'c': /* Esc o c == Ctrl-Right on Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000449 case 'd': /* Esc o d == Ctrl-Left on Eterm. */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000450 kbinput = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000451 break;
452 }
453 break;
454 case '[':
455 switch (escape_seq[1]) {
456 case '1':
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000457 if (escape_seq_len >= 3) {
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000458 switch (escape_seq[2]) {
459 case '1': /* Esc [ 1 1 ~ == F1 on
460 * rxvt/Eterm. */
461 kbinput = KEY_F(1);
462 break;
463 case '2': /* Esc [ 1 2 ~ == F2 on
464 * rxvt/Eterm. */
465 kbinput = KEY_F(2);
466 break;
467 case '3': /* Esc [ 1 3 ~ == F3 on
468 * rxvt/Eterm. */
469 kbinput = KEY_F(3);
470 break;
471 case '4': /* Esc [ 1 4 ~ == F4 on
472 * rxvt/Eterm. */
473 kbinput = KEY_F(4);
474 break;
475 case '5': /* Esc [ 1 5 ~ == F5 on
476 * xterm/rxvt/Eterm. */
477 kbinput = KEY_F(5);
478 break;
479 case '7': /* Esc [ 1 7 ~ == F6 on Linux
480 * console/xterm/rxvt/Eterm. */
481 kbinput = KEY_F(6);
482 break;
483 case '8': /* Esc [ 1 8 ~ == F7 on Linux
484 * console/xterm/rxvt/Eterm. */
485 kbinput = KEY_F(7);
486 break;
487 case '9': /* Esc [ 1 9 ~ == F8 on Linux
488 * console/xterm/rxvt/Eterm. */
489 kbinput = KEY_F(8);
490 break;
David Lawrence Ramseyee383db2004-02-06 03:07:10 +0000491 case ';':
492 if (escape_seq_len >= 4) {
493 switch (escape_seq[3]) {
494 case '2':
495 if (escape_seq_len >= 5) {
496 switch (escape_seq[4]) {
497 case 'A': /* Esc [ 1 ; 2 A == Shift-Up on
498 * xterm. */
499 case 'B': /* Esc [ 1 ; 2 B == Shift-Down on
500 * xterm. */
501 case 'C': /* Esc [ 1 ; 2 C == Shift-Right on
502 * xterm. */
503 case 'D': /* Esc [ 1 ; 2 D == Shift-Left on
504 * xterm. */
505 kbinput = get_escape_seq_abcd(escape_seq[4]);
506 break;
507 }
508 }
509 break;
510 case '5':
511 if (escape_seq_len >= 5) {
512 switch (escape_seq[4]) {
513 case 'A': /* Esc [ 1 ; 5 A == Ctrl-Up on
514 * xterm. */
515 case 'B': /* Esc [ 1 ; 5 B == Ctrl-Down on
516 * xterm. */
517 case 'C': /* Esc [ 1 ; 5 C == Ctrl-Right on
518 * xterm. */
519 case 'D': /* Esc [ 1 ; 5 D == Ctrl-Left on
520 * xterm. */
521 kbinput = get_escape_seq_abcd(escape_seq[4]);
522 break;
523 }
524 }
525 break;
526 }
527 }
528 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000529 default: /* Esc [ 1 ~ == Home on Linux
530 * console. */
531 kbinput = NANO_HOME_KEY;
532 break;
533 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000534 }
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000535 break;
536 case '2':
537 if (escape_seq_len >= 3) {
538 switch (escape_seq[2]) {
539 case '0': /* Esc [ 2 0 ~ == F9 on Linux
540 * console/xterm/rxvt/Eterm. */
541 kbinput = KEY_F(9);
542 break;
543 case '1': /* Esc [ 2 1 ~ == F10 on Linux
544 * console/xterm/rxvt/Eterm. */
545 kbinput = KEY_F(10);
546 break;
547 case '3': /* Esc [ 2 3 ~ == F11 on Linux
548 * console/xterm/rxvt/Eterm. */
549 kbinput = KEY_F(11);
550 break;
551 case '4': /* Esc [ 2 4 ~ == F12 on Linux
552 * console/xterm/rxvt/Eterm. */
553 kbinput = KEY_F(12);
554 break;
555 case '5': /* Esc [ 2 5 ~ == F13 on Linux
556 * console/rxvt/Eterm. */
557 kbinput = KEY_F(13);
558 break;
559 case '6': /* Esc [ 2 6 ~ == F14 on Linux
560 * console/rxvt/Eterm. */
561 kbinput = KEY_F(14);
562 break;
563 default: /* Esc [ 2 ~ == Insert on Linux
564 * console/xterm. */
565 kbinput = NANO_INSERTFILE_KEY;
566 break;
567 }
568 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000569 break;
570 case '3': /* Esc [ 3 ~ == Delete on Linux
571 * console/xterm. */
572 kbinput = NANO_DELETE_KEY;
573 break;
574 case '4': /* Esc [ 4 ~ == End on Linux
575 * console/xterm. */
576 kbinput = NANO_END_KEY;
577 break;
578 case '5': /* Esc [ 5 ~ == PageUp on Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000579 * console/xterm; Esc [ 5 ^ == PageUp on
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000580 * Eterm. */
581 kbinput = NANO_PREVPAGE_KEY;
582 break;
583 case '6': /* Esc [ 6 ~ == PageDown on Linux
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000584 * console/xterm; Esc [ 6 ^ == PageDown on
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000585 * Eterm. */
586 kbinput = NANO_NEXTPAGE_KEY;
587 break;
588 case '7': /* Esc [ 7 ~ == Home on rxvt. */
589 kbinput = NANO_HOME_KEY;
590 break;
591 case '8': /* Esc [ 8 ~ == End on rxvt. */
592 kbinput = NANO_END_KEY;
593 break;
594 case '9': /* Esc [ 9 == Delete on Hurd console. */
595 kbinput = NANO_DELETE_KEY;
596 break;
597 case '@': /* Esc [ @ == Insert on Hurd console. */
598 kbinput = NANO_INSERTFILE_KEY;
599 break;
600 case 'A': /* Esc [ A == Up on Linux console/FreeBSD
601 * console/Hurd console/rxvt/Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000602 case 'B': /* Esc [ B == Down on Linux
603 * console/FreeBSD console/Hurd
604 * console/rxvt/Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000605 case 'C': /* Esc [ C == Right on Linux
606 * console/FreeBSD console/Hurd
607 * console/rxvt/Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000608 case 'D': /* Esc [ D == Left on Linux
609 * console/FreeBSD console/Hurd
610 * console/rxvt/Eterm. */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000611 kbinput = get_escape_seq_abcd(escape_seq[1]);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000612 break;
613 case 'F': /* Esc [ F == End on FreeBSD
614 * console/Eterm. */
615 kbinput = NANO_END_KEY;
616 break;
617 case 'G': /* Esc [ G == PageDown on FreeBSD
618 * console. */
619 kbinput = NANO_NEXTPAGE_KEY;
620 break;
621 case 'H': /* Esc [ H == Home on FreeBSD
622 * console/Hurd console/Eterm. */
623 kbinput = NANO_HOME_KEY;
624 break;
625 case 'I': /* Esc [ I == PageUp on FreeBSD
626 * console. */
627 kbinput = NANO_PREVPAGE_KEY;
628 break;
629 case 'L': /* Esc [ L == Insert on FreeBSD
630 * console. */
631 kbinput = NANO_INSERTFILE_KEY;
632 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000633 case 'M': /* Esc [ M == F1 on FreeBSD console. */
634 kbinput = KEY_F(1);
635 break;
636 case 'N': /* Esc [ N == F2 on FreeBSD console. */
637 kbinput = KEY_F(2);
638 break;
639 case 'O':
640 if (escape_seq_len >= 3) {
641 switch (escape_seq[2]) {
642 case 'P': /* Esc [ O P == F1 on
643 * xterm. */
644 kbinput = KEY_F(1);
645 break;
646 case 'Q': /* Esc [ O Q == F2 on
647 * xterm. */
648 kbinput = KEY_F(2);
649 break;
650 case 'R': /* Esc [ O R == F3 on
651 * xterm. */
652 kbinput = KEY_F(3);
653 break;
654 case 'S': /* Esc [ O S == F4 on
655 * xterm. */
656 kbinput = KEY_F(4);
657 break;
658 default: /* Esc [ O == F3 on
659 * FreeBSD console. */
660 kbinput = KEY_F(3);
661 break;
662 }
663 }
664 break;
665 case 'P': /* Esc [ P == F4 on FreeBSD console. */
666 kbinput = KEY_F(4);
667 break;
668 case 'Q': /* Esc [ Q == F5 on FreeBSD console. */
669 kbinput = KEY_F(5);
670 break;
671 case 'R': /* Esc [ R == F6 on FreeBSD console. */
672 kbinput = KEY_F(6);
673 break;
674 case 'S': /* Esc [ S == F7 on FreeBSD console. */
675 kbinput = KEY_F(7);
676 break;
677 case 'T': /* Esc [ T == F8 on FreeBSD console. */
678 kbinput = KEY_F(8);
679 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000680 case 'U': /* Esc [ U == PageDown on Hurd console. */
681 kbinput = NANO_NEXTPAGE_KEY;
682 break;
683 case 'V': /* Esc [ V == PageUp on Hurd console. */
684 kbinput = NANO_PREVPAGE_KEY;
685 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000686 case 'W': /* Esc [ W == F11 on FreeBSD console. */
687 kbinput = KEY_F(11);
688 break;
689 case 'X': /* Esc [ X == F12 on FreeBSD console. */
690 kbinput = KEY_F(12);
691 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000692 case 'Y': /* Esc [ Y == End on Hurd console. */
693 kbinput = NANO_END_KEY;
694 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000695 case 'Z': /* Esc [ Z == F14 on FreeBSD console. */
696 kbinput = KEY_F(14);
697 break;
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +0000698 case 'a': /* Esc [ a == Shift-Up on rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +0000699 case 'b': /* Esc [ b == Shift-Down on rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +0000700 case 'c': /* Esc [ c == Shift-Right on
701 * rxvt/Eterm. */
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +0000702 case 'd': /* Esc [ d == Shift-Left on rxvt/Eterm. */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000703 kbinput = get_escape_seq_abcd(escape_seq[1]);
704 break;
705 case '[':
706 if (escape_seq_len >= 3) {
707 switch (escape_seq[2]) {
708 case 'A': /* Esc [ [ A == F1 on Linux
709 * console. */
710 kbinput = KEY_F(1);
711 break;
712 case 'B': /* Esc [ [ B == F2 on Linux
713 * console. */
714 kbinput = KEY_F(2);
715 break;
716 case 'C': /* Esc [ [ C == F3 on Linux
717 * console. */
718 kbinput = KEY_F(3);
719 break;
720 case 'D': /* Esc [ [ D == F4 on Linux
721 * console. */
722 kbinput = KEY_F(4);
723 break;
724 case 'E': /* Esc [ [ E == F5 on Linux
725 * console. */
726 kbinput = KEY_F(5);
727 break;
728 }
729 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000730 break;
731 }
732 break;
733 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000734 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000735
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000736 if (kbinput == ERR) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000737 /* This escape sequence is unrecognized; send it back. */
738 for (; escape_seq_len > 1; escape_seq_len--)
739 ungetch(escape_seq[escape_seq_len - 1]);
740 kbinput = escape_seq[0];
741 }
742
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000743 return kbinput;
744}
745
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000746/* Return the equivalent arrow key value for the case-insensitive
David Lawrence Ramseyb7e5cf62004-02-07 03:39:48 +0000747 * letters A (up), B (down), C (right), and D (left). These are common
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +0000748 * to many escape sequences. */
749int get_escape_seq_abcd(int kbinput)
750{
751 switch (tolower(kbinput)) {
752 case 'a':
753 return NANO_PREVLINE_KEY;
754 case 'b':
755 return NANO_NEXTLINE_KEY;
756 case 'c':
757 return NANO_FORWARD_KEY;
758 case 'd':
759 return NANO_BACK_KEY;
760 default:
761 return ERR;
762 }
763}
764
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000765#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000766/* Check for a mouse event, and if one's taken place, save the
767 * coordinates where it took place in mouse_x and mouse_y. After that,
768 * if allow_shortcuts is zero, return 0. Otherwise, if the mouse event
769 * took place on the shortcut list on the bottom two lines of the screen
770 * (assuming that the shortcut list is visible), figure out which
771 * shortcut was clicked and ungetch() the equivalent keystroke(s).
772 * Return 0 if no keystrokes were ungetch()ed, or 1 if at least one was.
773 * Assume that KEY_MOUSE has already been read in. */
774int get_mouseinput(int *mouse_x, int *mouse_y, int allow_shortcuts)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000775{
776 MEVENT mevent;
777
778 *mouse_x = -1;
779 *mouse_y = -1;
780
781 /* First, get the actual mouse event. */
782 if (getmouse(&mevent) == ERR)
783 return 0;
784
785 /* Save the screen coordinates where the mouse event took place. */
786 *mouse_x = mevent.x;
787 *mouse_y = mevent.y;
788
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000789 /* If we're not allowing shortcuts' we're done now. */
790 if (!allow_shortcuts)
791 return 0;
792
793 /* Otherwise, if the current shortcut list is being displayed on the
794 * last two lines of the screen and the mouse event took place
795 * inside it, we need to figure out which shortcut was clicked and
796 * ungetch() the equivalent keystroke(s) for it. */
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000797 if (!ISSET(NO_HELP) && wenclose(bottomwin, *mouse_y, *mouse_x)) {
798 int i, j;
799 int currslen;
800 /* The number of shortcuts in the current shortcut list. */
801 const shortcut *s = currshortcut;
802 /* The actual shortcut we clicked on, starting at the first
803 * one in the current shortcut list. */
804
805 /* Get the shortcut lists' length. */
806 if (currshortcut == main_list)
807 currslen = MAIN_VISIBLE;
808 else
809 currslen = length_of_list(currshortcut);
810
811 /* Calculate the width of each shortcut in the list (it's the
812 * same for all of them). */
813 if (currslen < 2)
814 i = COLS / 6;
815 else
816 i = COLS / ((currslen / 2) + (currslen % 2));
817
818 /* Calculate the y-coordinates relative to the beginning of
819 * bottomwin, i.e, the bottom three lines of the screen. */
820 j = *mouse_y - (editwinrows + 3);
821
822 /* If we're on the statusbar, beyond the end of the shortcut
823 * list, or beyond the end of a shortcut on the right side of
824 * the screen, don't do anything. */
825 if (j < 0 || (*mouse_x / i) >= currslen)
826 return 0;
827 j = (*mouse_x / i) * 2 + j;
828 if (j >= currslen)
829 return 0;
830
831 /* Go through the shortcut list to determine which shortcut was
832 * clicked. */
833 for (; j > 0; j--)
834 s = s->next;
835
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000836 /* And ungetch() the equivalent control key. If it's a Meta key
837 * sequence, we need to ungetch() Escape too. Assume that the
838 * shortcut has an equivalent control key, meta key sequence, or
839 * both. */
840 if (s->ctrlval != NANO_NO_KEY)
841 ungetch(s->ctrlval);
842 else {
843 ungetch(s->metaval);
844 ungetch(NANO_CONTROL_3);
845 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000846
847 return 1;
848 }
849 return 0;
850}
851#endif
852
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000853int do_first_line(void)
854{
855 current = fileage;
856 placewewant = 0;
857 current_x = 0;
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +0000858 edit_update(current, TOP);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000859 return 1;
860}
861
862int do_last_line(void)
863{
864 current = filebot;
865 placewewant = 0;
866 current_x = 0;
Chris Allegretta234a34d2000-07-29 04:33:38 +0000867 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000868 return 1;
869}
870
Chris Allegretta6df90f52002-07-19 01:08:59 +0000871/* Return the placewewant associated with current_x. That is, xplustabs
872 * is the zero-based column position of the cursor. Value is no smaller
873 * than current_x. */
874size_t xplustabs(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000875{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000876 return strnlenpt(current->data, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000877}
878
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000879/* actual_x() gives the index in str of the character displayed at
880 * column xplus. That is, actual_x() is the largest value such that
881 * strnlenpt(str, actual_x(str, xplus)) <= xplus. */
882size_t actual_x(const char *str, size_t xplus)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000883{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000884 size_t i = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000885 /* the position in str, returned */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000886 size_t length = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000887 /* the screen display width to str[i] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000888
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000889 assert(str != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000890
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000891 for (; length < xplus && *str != '\0'; i++, str++) {
892 if (*str == '\t')
David Lawrence Ramsey0362c582003-09-30 03:31:56 +0000893 length += tabsize - (length % tabsize);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000894 else if (is_cntrl_char((int)*str))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000895 length += 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000896 else
897 length++;
898 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000899 assert(length == strnlenpt(str - i, i));
900 assert(i <= strlen(str - i));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000901
Chris Allegretta6df90f52002-07-19 01:08:59 +0000902 if (length > xplus)
903 i--;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000904
Chris Allegretta6df90f52002-07-19 01:08:59 +0000905 return i;
Robert Siemborskid8510b22000-06-06 23:04:06 +0000906}
907
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000908/* A strlen with tabs factored in, similar to xplustabs(). How many
909 * columns wide are the first size characters of buf? */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000910size_t strnlenpt(const char *buf, size_t size)
Robert Siemborskid8510b22000-06-06 23:04:06 +0000911{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000912 size_t length = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000913
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000914 assert(buf != NULL);
915 for (; *buf != '\0' && size != 0; size--, buf++) {
916 if (*buf == '\t')
917 length += tabsize - (length % tabsize);
918 else if (is_cntrl_char((int)*buf))
919 length += 2;
920 else
921 length++;
922 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000923 return length;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000924}
925
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000926/* How many columns wide is buf? */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000927size_t strlenpt(const char *buf)
Chris Allegrettad4fa0d32002-03-05 19:55:55 +0000928{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000929 return strnlenpt(buf, -1);
Chris Allegrettad4fa0d32002-03-05 19:55:55 +0000930}
931
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000932void blank_bottombars(void)
933{
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000934 if (!ISSET(NO_HELP)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +0000935 mvwaddstr(bottomwin, 1, 0, hblank);
936 mvwaddstr(bottomwin, 2, 0, hblank);
937 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000938}
939
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000940void blank_bottomwin(void)
941{
942 if (ISSET(NO_HELP))
943 return;
944
945 mvwaddstr(bottomwin, 1, 0, hblank);
946 mvwaddstr(bottomwin, 2, 0, hblank);
947}
948
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000949void blank_edit(void)
950{
951 int i;
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +0000952 for (i = 0; i < editwinrows; i++)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000953 mvwaddstr(edit, i, 0, hblank);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000954}
955
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000956void blank_statusbar(void)
957{
958 mvwaddstr(bottomwin, 0, 0, hblank);
959}
960
961void blank_statusbar_refresh(void)
962{
963 blank_statusbar();
964 wrefresh(bottomwin);
965}
966
967void check_statblank(void)
968{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000969 if (statblank > 1)
970 statblank--;
971 else if (statblank == 1 && !ISSET(CONSTUPDATE)) {
972 statblank--;
973 blank_statusbar_refresh();
974 }
975}
976
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000977/* Convert buf into a string that can be displayed on screen. The
978 * caller wants to display buf starting with column start_col, and
979 * extending for at most len columns. start_col is zero-based. len is
980 * one-based, so len == 0 means you get "" returned. The returned
981 * string is dynamically allocated, and should be freed. */
982char *display_string(const char *buf, size_t start_col, int len)
983{
984 size_t start_index;
985 /* Index in buf of first character shown in return value. */
986 size_t column;
987 /* Screen column start_index corresponds to. */
988 size_t end_index;
989 /* Index in buf of last character shown in return value. */
990 size_t alloc_len;
991 /* The length of memory allocated for converted. */
992 char *converted;
993 /* The string we return. */
994 size_t index;
995 /* Current position in converted. */
996
997 if (len == 0)
998 return mallocstrcpy(NULL, "");
999
1000 start_index = actual_x(buf, start_col);
1001 column = strnlenpt(buf, start_index);
1002 assert(column <= start_col);
1003 end_index = actual_x(buf, start_col + len - 1);
1004 alloc_len = strnlenpt(buf, end_index + 1) - column;
1005 if (len > alloc_len + column - start_col)
1006 len = alloc_len + column - start_col;
1007 converted = charalloc(alloc_len + 1);
1008 buf += start_index;
1009 index = 0;
1010
1011 for (; index < alloc_len; buf++) {
1012 if (*buf == '\t')
1013 do {
1014 converted[index++] = ' ';
1015 } while ((column + index) % tabsize);
1016 else if (is_cntrl_char(*buf)) {
1017 converted[index++] = '^';
1018 if (*buf == '\n')
1019 /* Treat newlines embedded in a line as encoded nulls;
1020 * the line in question should be run through unsunder()
1021 * before reaching here. */
1022 converted[index++] = '@';
1023 else if (*buf == NANO_CONTROL_8)
1024 converted[index++] = '?';
1025 else
1026 converted[index++] = *buf + 64;
1027 } else
1028 converted[index++] = *buf;
1029 }
1030 assert(len <= alloc_len + column - start_col);
1031 charmove(converted, converted + start_col - column, len);
1032 null_at(&converted, len);
1033
1034 return charealloc(converted, len + 1);
1035}
1036
Chris Allegretta7662c862003-01-13 01:35:15 +00001037/* Repaint the statusbar when getting a character in nanogetstr(). buf
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001038 * should be no longer than max(0, COLS - 4).
Chris Allegretta6df90f52002-07-19 01:08:59 +00001039 *
Chris Allegretta7662c862003-01-13 01:35:15 +00001040 * Note that we must turn on A_REVERSE here, since do_help() turns it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001041 * off! */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001042void nanoget_repaint(const char *buf, const char *inputbuf, size_t x)
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001043{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001044 size_t x_real = strnlenpt(inputbuf, x);
1045 int wid = COLS - strlen(buf) - 2;
Chris Allegretta0d1e8d62000-11-02 15:30:24 +00001046
Chris Allegretta6df90f52002-07-19 01:08:59 +00001047 assert(0 <= x && x <= strlen(inputbuf));
1048
Chris Allegrettab3655b42001-10-22 03:15:31 +00001049 wattron(bottomwin, A_REVERSE);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001050 blank_statusbar();
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001051
Chris Allegretta6df90f52002-07-19 01:08:59 +00001052 mvwaddstr(bottomwin, 0, 0, buf);
1053 waddch(bottomwin, ':');
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001054
1055 if (COLS > 1)
1056 waddch(bottomwin, x_real < wid ? ' ' : '$');
1057 if (COLS > 2) {
1058 size_t page_start = x_real - x_real % wid;
1059 char *expanded = display_string(inputbuf, page_start, wid);
1060
1061 assert(wid > 0);
1062 assert(strlen(expanded) <= wid);
1063 waddstr(bottomwin, expanded);
1064 free(expanded);
1065 wmove(bottomwin, 0, COLS - wid + x_real - page_start);
1066 } else
1067 wmove(bottomwin, 0, COLS - 1);
Chris Allegrettab3655b42001-10-22 03:15:31 +00001068 wattroff(bottomwin, A_REVERSE);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001069}
1070
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001071/* Get the input from the keyboard; this should only be called from
Chris Allegretta6df90f52002-07-19 01:08:59 +00001072 * statusq(). */
Chris Allegrettaf717f982003-02-13 22:25:01 +00001073int nanogetstr(int allowtabs, const char *buf, const char *def,
Chris Allegretta5beed502003-01-05 20:41:21 +00001074#ifndef NANO_SMALL
1075 historyheadtype *history_list,
1076#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001077 const shortcut *s
Rocco Corsi06aca1c2001-01-11 05:30:31 +00001078#ifndef DISABLE_TABCOMP
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001079 , int *list
Chris Allegrettabe77c612000-11-24 14:00:16 +00001080#endif
Chris Allegretta65f075d2003-02-13 03:03:49 +00001081 )
Chris Allegretta6df90f52002-07-19 01:08:59 +00001082{
1083 int kbinput;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001084 int meta_key;
Chris Allegretta09fc4302003-01-16 22:16:38 +00001085 static int x = -1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001086 /* the cursor position in 'answer' */
1087 int xend;
1088 /* length of 'answer', the status bar text */
1089 int tabbed = 0;
1090 /* used by input_tab() */
1091 const shortcut *t;
Chris Allegretta598106e2002-01-19 01:59:37 +00001092
Chris Allegretta5beed502003-01-05 20:41:21 +00001093#ifndef NANO_SMALL
1094 /* for history */
1095 char *history = NULL;
Chris Allegretta8031f832003-01-09 05:29:58 +00001096 char *currentbuf = NULL;
Chris Allegretta5beed502003-01-05 20:41:21 +00001097 char *complete = NULL;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001098 int last_kbinput = 0;
1099
1100 /* This variable is used in the search history code. use_cb == 0
1101 means that we're using the existing history and ignoring
1102 currentbuf. use_cb == 1 means that the entry in answer should be
1103 moved to currentbuf or restored from currentbuf to answer.
1104 use_cb == 2 means that the entry in currentbuf should be moved to
1105 answer or restored from answer to currentbuf. */
1106 int use_cb = 0;
Chris Allegretta5beed502003-01-05 20:41:21 +00001107#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001108 xend = strlen(def);
Chris Allegretta09fc4302003-01-16 22:16:38 +00001109
1110 /* Only put x at the end of the string if it's uninitialized or if
1111 it would be past the end of the string as it is. Otherwise,
1112 leave it alone. This is so the cursor position stays at the same
1113 place if a prompt-changing toggle is pressed. */
Chris Allegretta65f075d2003-02-13 03:03:49 +00001114 if (x == -1 || x > xend || resetstatuspos)
Chris Allegretta09fc4302003-01-16 22:16:38 +00001115 x = xend;
1116
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00001117 answer = charealloc(answer, xend + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001118 if (xend > 0)
1119 strcpy(answer, def);
1120 else
1121 answer[0] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001122
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001123#if !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001124 currshortcut = s;
Chris Allegretta6fe61492001-05-21 12:56:25 +00001125#endif
1126
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001127 /* Get the input! */
Chris Allegretta31925e42000-11-02 04:40:39 +00001128
Chris Allegretta6df90f52002-07-19 01:08:59 +00001129 nanoget_repaint(buf, answer, x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001130
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001131 /* Make sure any editor screen updates are displayed before getting
1132 input */
Chris Allegretta022b96f2000-11-14 17:47:58 +00001133 wrefresh(edit);
1134
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001135 while ((kbinput = get_kbinput(bottomwin, &meta_key)) != NANO_ENTER_KEY) {
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001136 for (t = s; t != NULL; t = t->next) {
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001137#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001138 fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput, kbinput);
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001139#endif
1140
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001141 /* Temporary hack to interpret NANO_HELP_FKEY correctly. */
1142 if (kbinput == t->funcval)
1143 kbinput = t->ctrlval;
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00001144
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001145 if (kbinput == t->ctrlval && is_cntrl_char(kbinput)) {
Chris Allegretta5bf51d32000-11-16 06:01:10 +00001146
Chris Allegrettab3655b42001-10-22 03:15:31 +00001147#ifndef DISABLE_HELP
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001148 /* Have to do this here, it would be too late to do it
1149 in statusq() */
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00001150 if (kbinput == NANO_HELP_KEY) {
Chris Allegrettab3655b42001-10-22 03:15:31 +00001151 do_help();
1152 break;
1153 }
1154#endif
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001155#ifndef NANO_SMALL
1156 /* Have to handle these here too, for the time being */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001157 if (kbinput == NANO_PREVLINE_KEY || kbinput == NANO_NEXTLINE_KEY)
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001158 break;
1159#endif
Chris Allegretta5af58892003-01-17 21:07:38 +00001160
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001161 return t->ctrlval;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001162 }
1163 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001164 assert(0 <= x && x <= xend && xend == strlen(answer));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001165
Chris Allegretta04d848e2000-11-05 17:54:41 +00001166 if (kbinput != '\t')
1167 tabbed = 0;
1168
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001169 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001170#ifndef DISABLE_MOUSE
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001171 case KEY_MOUSE:
1172 do_mouse();
1173 break;
1174#endif
Chris Allegretta658399a2001-06-14 02:54:22 +00001175 case NANO_HOME_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001176 x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001177 break;
Chris Allegretta658399a2001-06-14 02:54:22 +00001178 case NANO_END_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001179 x = xend;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001180 break;
Chris Allegretta35dac582001-03-21 15:07:20 +00001181 case NANO_FORWARD_KEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001182 if (x < xend)
1183 x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001184 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001185 case NANO_DELETE_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001186 if (x < xend) {
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001187 charmove(answer + x, answer + x + 1, xend - x);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001188 xend--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001189 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001190 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001191 case NANO_CUT_KEY:
1192 case NANO_UNCUT_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001193 null_at(&answer, 0);
1194 xend = 0;
1195 x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001196 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001197 case NANO_BACKSPACE_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001198 if (x > 0) {
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001199 charmove(answer + x - 1, answer + x, xend - x + 1);
Chris Allegretta04d848e2000-11-05 17:54:41 +00001200 x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001201 xend--;
1202 }
Chris Allegretta04d848e2000-11-05 17:54:41 +00001203 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001204 case NANO_TAB_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001205#ifndef NANO_SMALL
1206 /* tab history completion */
Chris Allegretta7662c862003-01-13 01:35:15 +00001207 if (history_list != NULL) {
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001208 if (!complete || last_kbinput != NANO_TAB_KEY) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001209 history_list->current = (historytype *)history_list;
1210 history_list->len = strlen(answer);
1211 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001212
Chris Allegretta7662c862003-01-13 01:35:15 +00001213 if (history_list->len > 0) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001214 complete = get_history_completion(history_list, answer);
1215 xend = strlen(complete);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001216 x = xend;
Chris Allegretta5beed502003-01-05 20:41:21 +00001217 answer = mallocstrcpy(answer, complete);
1218 }
Chris Allegretta7da4e9f2000-11-06 02:57:22 +00001219 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001220#ifndef DISABLE_TABCOMP
Chris Allegretta327abda2003-01-17 05:04:17 +00001221 else
1222#endif
Chris Allegrettabe77c612000-11-24 14:00:16 +00001223#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001224#ifndef DISABLE_TABCOMP
Chris Allegretta327abda2003-01-17 05:04:17 +00001225 if (allowtabs) {
1226 int shift = 0;
Chris Allegretta5beed502003-01-05 20:41:21 +00001227
Chris Allegretta327abda2003-01-17 05:04:17 +00001228 answer = input_tab(answer, x, &tabbed, &shift, list);
1229 xend = strlen(answer);
1230 x += shift;
1231 if (x > xend)
1232 x = xend;
Chris Allegretta5beed502003-01-05 20:41:21 +00001233 }
1234#endif
1235 break;
Chris Allegretta35dac582001-03-21 15:07:20 +00001236 case NANO_BACK_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001237 if (x > 0)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001238 x--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001239 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001240 case NANO_PREVLINE_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001241#ifndef NANO_SMALL
Chris Allegretta09fc4302003-01-16 22:16:38 +00001242 if (history_list != NULL) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001243
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001244 /* if currentbuf is NULL, or if use_cb is 1, currentbuf
1245 isn't NULL, and currentbuf is different from answer,
1246 it means that we're scrolling up at the top of the
1247 search history, and we need to save the current
1248 answer in currentbuf; do this and reset use_cb to
1249 0 */
1250 if (currentbuf == NULL || (use_cb == 1 && strcmp(currentbuf, answer))) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001251 currentbuf = mallocstrcpy(currentbuf, answer);
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001252 use_cb = 0;
Chris Allegretta8031f832003-01-09 05:29:58 +00001253 }
1254
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001255 /* if currentbuf isn't NULL, use_cb is 2, and currentbuf
1256 is different from answer, it means that we're
1257 scrolling up at the bottom of the search history, and
1258 we need to make the string in currentbuf the current
1259 answer; do this, blow away currentbuf since we don't
1260 need it anymore, and reset use_cb to 0 */
1261 if (currentbuf != NULL && use_cb == 2 && strcmp(currentbuf, answer)) {
1262 answer = mallocstrcpy(answer, currentbuf);
1263 free(currentbuf);
1264 currentbuf = NULL;
1265 xend = strlen(answer);
1266 use_cb = 0;
1267
1268 /* else get older search from the history list and save
1269 it in answer; if there is no older search, blank out
1270 answer */
1271 } else if ((history = get_history_older(history_list)) != NULL) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001272 answer = mallocstrcpy(answer, history);
1273 xend = strlen(history);
1274 } else {
1275 answer = mallocstrcpy(answer, "");
1276 xend = 0;
1277 }
1278 x = xend;
1279 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001280#endif
Chris Allegretta54abd942003-01-09 23:43:12 +00001281 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001282 case NANO_NEXTLINE_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001283#ifndef NANO_SMALL
Chris Allegretta09fc4302003-01-16 22:16:38 +00001284 if (history_list != NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001285
1286 /* get newer search from the history list and save it
1287 in answer */
Chris Allegretta7662c862003-01-13 01:35:15 +00001288 if ((history = get_history_newer(history_list)) != NULL) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001289 answer = mallocstrcpy(answer, history);
1290 xend = strlen(history);
Chris Allegretta8031f832003-01-09 05:29:58 +00001291
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001292 /* if there is no newer search, we're here */
1293
1294 /* if currentbuf isn't NULL and use_cb isn't 2, it means
1295 that we're scrolling down at the bottom of the search
1296 history and we need to make the string in currentbuf
1297 the current answer; do this, blow away currentbuf
1298 since we don't need it anymore, and set use_cb to
1299 1 */
1300 } else if (currentbuf != NULL && use_cb != 2) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001301 answer = mallocstrcpy(answer, currentbuf);
Chris Allegretta09fc4302003-01-16 22:16:38 +00001302 free(currentbuf);
1303 currentbuf = NULL;
1304 xend = strlen(answer);
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001305 use_cb = 1;
1306
1307 /* otherwise, if currentbuf is NULL and use_cb isn't 2,
1308 it means that we're scrolling down at the bottom of
Chris Allegrettac30fc242003-08-11 00:32:45 +00001309 the search history and the current answer (if it's
1310 not blank) needs to be saved in currentbuf; do this,
1311 blank out answer (if necessary), and set use_cb to
1312 2 */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001313 } else if (use_cb != 2) {
Chris Allegrettac30fc242003-08-11 00:32:45 +00001314 if (answer[0] != '\0') {
1315 currentbuf = mallocstrcpy(currentbuf, answer);
1316 answer = mallocstrcpy(answer, "");
1317 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001318 xend = 0;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001319 use_cb = 2;
Chris Allegretta5beed502003-01-05 20:41:21 +00001320 }
1321 x = xend;
1322 }
1323#endif
1324 break;
Chris Allegretta658399a2001-06-14 02:54:22 +00001325 default:
1326
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001327 for (t = s; t != NULL; t = t->next) {
Chris Allegretta658399a2001-06-14 02:54:22 +00001328#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001329 fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput,
Chris Allegretta598106e2002-01-19 01:59:37 +00001330 kbinput);
Chris Allegretta658399a2001-06-14 02:54:22 +00001331#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001332 if (meta_key == TRUE && (kbinput == t->metaval || kbinput == t->miscval))
David Lawrence Ramsey82138502003-12-24 08:03:54 +00001333 /* We hit a Meta key. Do like above. We don't
1334 * just ungetch() the letter and let it get
1335 * caught above cause that screws the
1336 * keypad... */
1337 return kbinput;
Chris Allegretta658399a2001-06-14 02:54:22 +00001338 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001339
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001340 if (is_cntrl_char(kbinput))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001341 break;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001342 answer = charealloc(answer, xend + 2);
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001343 charmove(answer + x + 1, answer + x, xend - x + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001344 xend++;
1345 answer[x] = kbinput;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001346 x++;
1347
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001348#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001349 fprintf(stderr, "input \'%c\' (%d)\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001350#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001351 } /* switch (kbinput) */
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001352#ifndef NANO_SMALL
Chris Allegretta5beed502003-01-05 20:41:21 +00001353 last_kbinput = kbinput;
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001354#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001355 nanoget_repaint(buf, answer, x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001356 wrefresh(bottomwin);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001357 } /* while (kbinput ...) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001358
Chris Allegretta5af58892003-01-17 21:07:38 +00001359 /* We finished putting in an answer; reset x */
1360 x = -1;
1361
Chris Allegretta7662c862003-01-13 01:35:15 +00001362 /* Just check for a blank answer here */
Chris Allegretta15c28f82003-01-05 21:47:06 +00001363 if (answer[0] == '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001364 return -2;
1365 else
1366 return 0;
1367}
1368
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001369/* If modified is not already set, set it and update titlebar. */
1370void set_modified(void)
1371{
1372 if (!ISSET(MODIFIED)) {
1373 SET(MODIFIED);
1374 titlebar(NULL);
1375 wrefresh(topwin);
1376 }
1377}
1378
Chris Allegrettaf717f982003-02-13 22:25:01 +00001379void titlebar(const char *path)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001380{
1381 int namelen, space;
Chris Allegrettaf717f982003-02-13 22:25:01 +00001382 const char *what = path;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001383
1384 if (path == NULL)
1385 what = filename;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001386
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001387 wattron(topwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001388
Chris Allegretta6df90f52002-07-19 01:08:59 +00001389 mvwaddstr(topwin, 0, 0, hblank);
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00001390 mvwaddnstr(topwin, 0, 2, VERMSG, COLS - 3);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001391
David Lawrence Ramseyec290f22003-08-30 19:05:40 +00001392 space = COLS - sizeof(VERMSG) - 23;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001393
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001394 namelen = strlen(what);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001395
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00001396 if (space > 0) {
1397 if (what[0] == '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001398 mvwaddnstr(topwin, 0, COLS / 2 - 6, _("New Buffer"),
1399 COLS / 2 + COLS % 2 - 6);
1400 else if (namelen > space) {
1401 if (path == NULL)
1402 waddstr(topwin, _(" File: ..."));
1403 else
1404 waddstr(topwin, _(" DIR: ..."));
1405 waddstr(topwin, &what[namelen - space]);
1406 } else {
1407 if (path == NULL)
1408 mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
1409 _("File: "));
1410 else
1411 mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
1412 _(" DIR: "));
1413 waddstr(topwin, what);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001414 }
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00001415 } /* If we don't have space, we shouldn't bother */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001416 if (ISSET(MODIFIED))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001417 mvwaddnstr(topwin, 0, COLS - 11, _(" Modified "), 11);
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001418 else if (ISSET(VIEW_MODE))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001419 mvwaddnstr(topwin, 0, COLS - 11, _(" View "), 11);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001420
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001421 wattroff(topwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001422
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001423 wrefresh(topwin);
1424 reset_cursor();
1425}
1426
Chris Allegretta6232d662002-05-12 19:52:15 +00001427void bottombars(const shortcut *s)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001428{
Chris Allegrettabc72e362002-02-16 20:03:44 +00001429 int i, j, numcols;
Chris Allegretta3bbc4162003-01-23 00:46:12 +00001430 char keystr[9];
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001431 int slen;
1432
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001433 if (ISSET(NO_HELP))
1434 return;
1435
Chris Allegretta6232d662002-05-12 19:52:15 +00001436 if (s == main_list) {
1437 slen = MAIN_VISIBLE;
1438 assert(MAIN_VISIBLE <= length_of_list(s));
1439 } else
1440 slen = length_of_list(s);
1441
Chris Allegretta6232d662002-05-12 19:52:15 +00001442 /* There will be this many columns of shortcuts */
1443 numcols = (slen + (slen % 2)) / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001444
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001445 blank_bottomwin();
Chris Allegretta658399a2001-06-14 02:54:22 +00001446
Chris Allegrettabc72e362002-02-16 20:03:44 +00001447 for (i = 0; i < numcols; i++) {
1448 for (j = 0; j <= 1; j++) {
Chris Allegretta658399a2001-06-14 02:54:22 +00001449
Chris Allegretta6232d662002-05-12 19:52:15 +00001450 wmove(bottomwin, 1 + j, i * (COLS / numcols));
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001451
Chris Allegretta5beed502003-01-05 20:41:21 +00001452 /* Yucky sentinel values we can't handle a better way */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001453 if (s->ctrlval != NANO_NO_KEY) {
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001454#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001455 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001456 strncpy(keystr, _("Up"), 8);
Chris Allegretta6232d662002-05-12 19:52:15 +00001457 else
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001458#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001459 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001460 strcpy(keystr, "^ ");
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001461 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001462 strcpy(keystr, "^?");
1463 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00001464 sprintf(keystr, "^%c", s->ctrlval + 64);
David Lawrence Ramsey82138502003-12-24 08:03:54 +00001465 } else if (s->metaval != NANO_NO_KEY)
1466 sprintf(keystr, "M-%c", toupper(s->metaval));
Chris Allegretta658399a2001-06-14 02:54:22 +00001467
Chris Allegretta6232d662002-05-12 19:52:15 +00001468 onekey(keystr, s->desc, COLS / numcols);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001469
Chris Allegretta6232d662002-05-12 19:52:15 +00001470 s = s->next;
1471 if (s == NULL)
1472 goto break_completely_out;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001473 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001474 }
1475
Chris Allegretta6df90f52002-07-19 01:08:59 +00001476 break_completely_out:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001477 wrefresh(bottomwin);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001478}
1479
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001480/* Write a shortcut key to the help area at the bottom of the window.
1481 * keystroke is e.g. "^G" and desc is e.g. "Get Help".
1482 * We are careful to write exactly len characters, even if len is
1483 * very small and keystroke and desc are long. */
Chris Allegrettaf717f982003-02-13 22:25:01 +00001484void onekey(const char *keystroke, const char *desc, int len)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001485{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001486 wattron(bottomwin, A_REVERSE);
1487 waddnstr(bottomwin, keystroke, len);
1488 wattroff(bottomwin, A_REVERSE);
1489 len -= strlen(keystroke);
1490 if (len > 0) {
1491 waddch(bottomwin, ' ');
1492 len--;
1493 waddnstr(bottomwin, desc, len);
1494 len -= strlen(desc);
1495 for (; len > 0; len--)
1496 waddch(bottomwin, ' ');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001497 }
1498}
1499
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001500/* And so start the display update routines. */
1501
1502#ifndef NDEBUG
1503int check_linenumbers(const filestruct *fileptr)
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001504{
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001505 int check_line = 0;
1506 const filestruct *filetmp;
Robert Siemborskid8510b22000-06-06 23:04:06 +00001507
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001508 for (filetmp = edittop; filetmp != fileptr; filetmp = filetmp->next)
1509 check_line++;
1510 return check_line;
Robert Siemborskid8510b22000-06-06 23:04:06 +00001511}
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001512#endif
Robert Siemborskid8510b22000-06-06 23:04:06 +00001513
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001514/* nano scrolls horizontally within a line in chunks. This function
1515 * returns the column number of the first character displayed in the
1516 * window when the cursor is at the given column. Note that
1517 * 0 <= column - get_page_start(column) < COLS. */
1518size_t get_page_start(size_t column)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001519{
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001520 assert(COLS > 0);
1521 if (column == 0 || column < COLS - 1)
1522 return 0;
1523 else if (COLS > 9)
David Lawrence Ramsey66081d42004-01-22 07:25:31 +00001524 return column - 7 - (column - 7) % (COLS - 8);
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001525 else if (COLS > 2)
1526 return column - (COLS - 2);
1527 else
1528 return column - (COLS - 1);
1529 /* The parentheses are necessary to avoid overflow. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001530}
1531
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001532/* Resets current_y, based on the position of current, and puts the
1533 * cursor at (current_y, current_x). */
1534void reset_cursor(void)
1535{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001536 /* Yuck. This condition can be true after open_file() when opening
1537 * the first file. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001538 if (edittop == NULL)
1539 return;
1540
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001541 current_y = current->lineno - edittop->lineno;
1542 if (current_y < editwinrows) {
1543 size_t x = xplustabs();
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001544
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001545 wmove(edit, current_y, x - get_page_start(x));
1546 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001547}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001548
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001549/* edit_add() takes care of the job of actually painting a line into the
1550 * edit window. fileptr is the line to be painted, at row yval of the
1551 * window. converted is the actual string to be written to the window,
1552 * with tabs and control characters replaced by strings of regular
1553 * characters. start is the column number of the first character
1554 * of this page. That is, the first character of converted corresponds to
1555 * character number actual_x(fileptr->data, start) of the line. */
1556void edit_add(const filestruct *fileptr, const char *converted,
1557 int yval, size_t start)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001558{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001559#if defined(ENABLE_COLOR) || !defined(NANO_SMALL)
1560 size_t startpos = actual_x(fileptr->data, start);
1561 /* The position in fileptr->data of the leftmost character
1562 * that displays at least partially on the window. */
1563 size_t endpos = actual_x(fileptr->data, start + COLS - 1) + 1;
1564 /* The position in fileptr->data of the first character that is
1565 * completely off the window to the right.
1566 *
1567 * Note that endpos might be beyond the null terminator of the
1568 * string. */
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001569#endif
1570
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001571 assert(fileptr != NULL && converted != NULL);
1572 assert(strlen(converted) <= COLS);
1573
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001574 /* Just paint the string in any case (we'll add color or reverse on
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001575 * just the text that needs it). */
1576 mvwaddstr(edit, yval, 0, converted);
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001577
Chris Allegretta7dd77682001-12-08 19:52:28 +00001578#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00001579 if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001580 const colortype *tmpcolor = colorstrings;
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001581
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001582 for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
1583 int x_start;
1584 /* Starting column for mvwaddnstr. Zero-based. */
1585 int paintlen;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001586 /* Number of chars to paint on this line. There are COLS
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001587 * characters on a whole line. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001588 regmatch_t startmatch; /* match position for start_regexp */
1589 regmatch_t endmatch; /* match position for end_regexp */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001590
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001591 if (tmpcolor->bright)
1592 wattron(edit, A_BOLD);
1593 wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001594 /* Two notes about regexec(). Return value 0 means there is
1595 * a match. Also, rm_eo is the first non-matching character
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001596 * after the match. */
1597
1598 /* First case, tmpcolor is a single-line expression. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001599 if (tmpcolor->end == NULL) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001600 size_t k = 0;
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001601
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001602 /* We increment k by rm_eo, to move past the end of the
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001603 * last match. Even though two matches may overlap, we
1604 * want to ignore them, so that we can highlight
1605 * C-strings correctly. */
1606 while (k < endpos) {
1607 /* Note the fifth parameter to regexec(). It says
1608 * not to match the beginning-of-line character
1609 * unless k is 0. If regexec() returns REG_NOMATCH,
1610 * there are no more matches in the line. */
Chris Allegrettace452fb2003-02-03 02:56:44 +00001611 if (regexec(&tmpcolor->start, &fileptr->data[k], 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001612 &startmatch, k == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001613 break;
1614 /* Translate the match to the beginning of the line. */
1615 startmatch.rm_so += k;
1616 startmatch.rm_eo += k;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001617 if (startmatch.rm_so == startmatch.rm_eo) {
1618 startmatch.rm_eo++;
Chris Allegretta7c27be42002-05-05 23:03:54 +00001619 statusbar(_("Refusing 0 length regex match"));
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001620 } else if (startmatch.rm_so < endpos &&
1621 startmatch.rm_eo > startpos) {
1622 if (startmatch.rm_so <= startpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001623 x_start = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001624 else
1625 x_start = strnlenpt(fileptr->data, startmatch.rm_so)
1626 - start;
1627 paintlen = strnlenpt(fileptr->data, startmatch.rm_eo)
1628 - start - x_start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001629 if (paintlen > COLS - x_start)
1630 paintlen = COLS - x_start;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001631
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001632 assert(0 <= x_start && 0 < paintlen &&
1633 x_start + paintlen <= COLS);
1634 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001635 converted + x_start, paintlen);
1636 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001637 k = startmatch.rm_eo;
Chris Allegretta598106e2002-01-19 01:59:37 +00001638 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001639 } else {
1640 /* This is a multi-line regexp. There are two steps.
1641 * First, we have to see if the beginning of the line is
1642 * colored by a start on an earlier line, and an end on
1643 * this line or later.
1644 *
1645 * We find the first line before fileptr matching the
1646 * start. If every match on that line is followed by an
1647 * end, then go to step two. Otherwise, find the next line
1648 * after start_line matching the end. If that line is not
1649 * before fileptr, then paint the beginning of this line. */
Chris Allegretta3674c1d2002-05-12 20:43:49 +00001650
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001651 const filestruct *start_line = fileptr->prev;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001652 /* the first line before fileptr matching start */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001653 regoff_t start_col;
1654 /* where it starts in that line */
1655 const filestruct *end_line;
1656 int searched_later_lines = 0;
1657 /* Used in step 2. Have we looked for an end on
1658 * lines after fileptr? */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001659
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001660 while (start_line != NULL &&
Chris Allegrettace452fb2003-02-03 02:56:44 +00001661 regexec(&tmpcolor->start, start_line->data, 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001662 &startmatch, 0) == REG_NOMATCH) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001663 /* If there is an end on this line, there is no need
1664 * to look for starts on earlier lines. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001665 if (regexec(tmpcolor->end, start_line->data, 0, NULL, 0)
1666 == 0)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001667 goto step_two;
1668 start_line = start_line->prev;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001669 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001670 /* No start found, so skip to the next step. */
1671 if (start_line == NULL)
1672 goto step_two;
1673 /* Now start_line is the first line before fileptr
1674 * containing a start match. Is there a start on this
1675 * line not followed by an end on this line? */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001676
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001677 start_col = 0;
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001678 while (TRUE) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001679 start_col += startmatch.rm_so;
1680 startmatch.rm_eo -= startmatch.rm_so;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001681 if (regexec(tmpcolor->end,
1682 start_line->data + start_col + startmatch.rm_eo,
1683 0, NULL, start_col + startmatch.rm_eo == 0 ? 0 :
1684 REG_NOTBOL) == REG_NOMATCH)
1685 /* No end found after this start. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001686 break;
1687 start_col++;
Chris Allegrettace452fb2003-02-03 02:56:44 +00001688 if (regexec(&tmpcolor->start,
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001689 start_line->data + start_col, 1, &startmatch,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001690 REG_NOTBOL) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001691 /* No later start on this line. */
1692 goto step_two;
1693 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001694 /* Indeed, there is a start not followed on this line by
1695 * an end. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001696
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001697 /* We have already checked that there is no end before
1698 * fileptr and after the start. Is there an end after
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001699 * the start at all? We don't paint unterminated
1700 * starts. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001701 end_line = fileptr;
Chris Allegrettace452fb2003-02-03 02:56:44 +00001702 while (end_line != NULL &&
1703 regexec(tmpcolor->end, end_line->data, 1, &endmatch, 0))
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001704 end_line = end_line->next;
1705
1706 /* No end found, or it is too early. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001707 if (end_line == NULL ||
1708 (end_line == fileptr && endmatch.rm_eo <= startpos))
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001709 goto step_two;
1710
1711 /* Now paint the start of fileptr. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001712 paintlen = end_line != fileptr ? COLS :
1713 strnlenpt(fileptr->data, endmatch.rm_eo) - start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001714 if (paintlen > COLS)
1715 paintlen = COLS;
1716
1717 assert(0 < paintlen && paintlen <= COLS);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001718 mvwaddnstr(edit, yval, 0, converted, paintlen);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001719
1720 /* We have already painted the whole line. */
1721 if (paintlen == COLS)
1722 goto skip_step_two;
1723
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001724 step_two: /* Second step, we look for starts on this line. */
1725 start_col = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001726 while (start_col < endpos) {
Chris Allegrettace452fb2003-02-03 02:56:44 +00001727 if (regexec(&tmpcolor->start, fileptr->data + start_col, 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001728 &startmatch, start_col == 0 ? 0 : REG_NOTBOL)
1729 == REG_NOMATCH || start_col + startmatch.rm_so >=
1730 endpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001731 /* No more starts on this line. */
1732 break;
1733 /* Translate the match to be relative to the
1734 * beginning of the line. */
1735 startmatch.rm_so += start_col;
1736 startmatch.rm_eo += start_col;
1737
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001738 if (startmatch.rm_so <= startpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001739 x_start = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001740 else
1741 x_start = strnlenpt(fileptr->data, startmatch.rm_so)
1742 - start;
1743 if (regexec(tmpcolor->end, fileptr->data + startmatch.rm_eo,
1744 1, &endmatch, startmatch.rm_eo == 0 ? 0 :
1745 REG_NOTBOL) == 0) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001746 /* Translate the end match to be relative to the
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001747 * beginning of the line. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001748 endmatch.rm_so += startmatch.rm_eo;
1749 endmatch.rm_eo += startmatch.rm_eo;
1750 /* There is an end on this line. But does it
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001751 * appear on this page, and is the match more than
1752 * zero characters long? */
1753 if (endmatch.rm_eo > startpos &&
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001754 endmatch.rm_eo > startmatch.rm_so) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001755 paintlen = strnlenpt(fileptr->data, endmatch.rm_eo)
1756 - start - x_start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001757 if (x_start + paintlen > COLS)
1758 paintlen = COLS - x_start;
1759
1760 assert(0 <= x_start && 0 < paintlen &&
1761 x_start + paintlen <= COLS);
1762 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001763 converted + x_start, paintlen);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001764 }
1765 } else if (!searched_later_lines) {
1766 searched_later_lines = 1;
1767 /* There is no end on this line. But we haven't
1768 * yet looked for one on later lines. */
1769 end_line = fileptr->next;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001770 while (end_line != NULL &&
1771 regexec(tmpcolor->end, end_line->data, 0,
1772 NULL, 0) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001773 end_line = end_line->next;
1774 if (end_line != NULL) {
1775 assert(0 <= x_start && x_start < COLS);
1776 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001777 converted + x_start,
1778 COLS - x_start);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001779 /* We painted to the end of the line, so
1780 * don't bother checking any more starts. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001781 break;
Chris Allegretta3674c1d2002-05-12 20:43:49 +00001782 }
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001783 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001784 start_col = startmatch.rm_so + 1;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001785 } /* while start_col < endpos */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001786 } /* if (tmp_color->end != NULL) */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001787
Chris Allegrettace452fb2003-02-03 02:56:44 +00001788 skip_step_two:
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001789 wattroff(edit, A_BOLD);
1790 wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
1791 } /* for tmpcolor in colorstrings */
1792 }
Chris Allegretta598106e2002-01-19 01:59:37 +00001793#endif /* ENABLE_COLOR */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001794
Chris Allegretta7dd77682001-12-08 19:52:28 +00001795#ifndef NANO_SMALL
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001796 if (ISSET(MARK_ISSET)
1797 && (fileptr->lineno <= mark_beginbuf->lineno
1798 || fileptr->lineno <= current->lineno)
1799 && (fileptr->lineno >= mark_beginbuf->lineno
1800 || fileptr->lineno >= current->lineno)) {
1801 /* fileptr is at least partially selected. */
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001802
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001803 const filestruct *top;
1804 /* Either current or mark_beginbuf, whichever is first. */
1805 size_t top_x;
1806 /* current_x or mark_beginx, corresponding to top. */
1807 const filestruct *bot;
1808 size_t bot_x;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001809 int x_start;
1810 /* Starting column for mvwaddnstr. Zero-based. */
1811 int paintlen;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001812 /* Number of chars to paint on this line. There are COLS
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001813 * characters on a whole line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001814
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001815 mark_order(&top, &top_x, &bot, &bot_x);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001816
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001817 if (top->lineno < fileptr->lineno || top_x < startpos)
1818 top_x = startpos;
1819 if (bot->lineno > fileptr->lineno || bot_x > endpos)
1820 bot_x = endpos;
1821
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001822 /* The selected bit of fileptr is on this page. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001823 if (top_x < endpos && bot_x > startpos) {
1824 assert(startpos <= top_x);
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001825
1826 /* x_start is the expanded location of the beginning of the
1827 * mark minus the beginning of the page. */
1828 x_start = strnlenpt(fileptr->data, top_x) - start;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001829
1830 if (bot_x >= endpos)
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001831 /* If the end of the mark is off the page, paintlen is
1832 * -1, meaning that everything on the line gets
1833 * painted. */
1834 paintlen = -1;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001835 else
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001836 /* Otherwise, paintlen is the expanded location of the
1837 * end of the mark minus the expanded location of the
1838 * beginning of the mark. */
1839 paintlen = strnlenpt(fileptr->data, bot_x) - (x_start +
1840 start);
1841
1842 /* If x_start is before the beginning of the page, shift
1843 * paintlen x_start characters to compensate, and put
1844 * x_start at the beginning of the page. */
1845 if (x_start < 0) {
1846 paintlen += x_start;
1847 x_start = 0;
1848 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001849
1850 assert(x_start >= 0 && x_start <= strlen(converted));
1851
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001852 wattron(edit, A_REVERSE);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001853 mvwaddnstr(edit, yval, x_start, converted + x_start, paintlen);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001854 wattroff(edit, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001855 }
Chris Allegretta08893e02001-11-29 02:42:27 +00001856 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001857#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001858}
1859
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001860/* Just update one line in the edit buffer. Basically a wrapper for
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001861 * edit_add().
1862 *
1863 * If fileptr != current, then index is considered 0.
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001864 * The line will be displayed starting with fileptr->data[index].
1865 * Likely args are current_x or 0. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001866void update_line(const filestruct *fileptr, size_t index)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001867{
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001868 int line;
1869 /* line in the edit window for CURSES calls */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001870 char *converted;
1871 /* fileptr->data converted to have tabs and control characters
1872 * expanded. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001873 size_t page_start;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001874
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001875 assert(fileptr != NULL);
Robert Siemborski53154a72000-06-18 00:11:03 +00001876
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001877 line = fileptr->lineno - edittop->lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001878
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001879 /* We assume the line numbers are valid. Is that really true? */
1880 assert(line < 0 || line == check_linenumbers(fileptr));
1881
1882 if (line < 0 || line >= editwinrows)
1883 return;
1884
1885 /* First, blank out the line (at a minimum) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001886 mvwaddstr(edit, line, 0, hblank);
1887
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001888 /* Next, convert variables that index the line to their equivalent
1889 * positions in the expanded line. */
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001890 index = (fileptr == current) ? strnlenpt(fileptr->data, index) : 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001891 page_start = get_page_start(index);
Chris Allegretta5beed502003-01-05 20:41:21 +00001892
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001893 /* Expand the line, replacing Tab by spaces, and control characters
1894 * by their display form. */
1895 converted = display_string(fileptr->data, page_start, COLS);
Robert Siemborski53875912000-06-16 04:25:30 +00001896
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001897 /* Now, paint the line */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001898 edit_add(fileptr, converted, line, page_start);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001899 free(converted);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001900
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001901 if (page_start > 0)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001902 mvwaddch(edit, line, 0, '$');
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001903 if (strlenpt(fileptr->data) > page_start + COLS)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001904 mvwaddch(edit, line, COLS - 1, '$');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001905}
1906
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001907/* This function updates current, based on where current_y is;
1908 * reset_cursor() does the opposite. */
1909void update_cursor(void)
1910{
1911 int i = 0;
1912
1913#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001914 fprintf(stderr, "Moved to (%d, %d) in edit buffer\n", current_y,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001915 current_x);
1916#endif
1917
1918 current = edittop;
1919 while (i < current_y && current->next != NULL) {
1920 current = current->next;
1921 i++;
1922 }
1923
1924#ifdef DEBUG
Chris Allegretta0e86e602003-01-23 04:27:23 +00001925 fprintf(stderr, "current->data = \"%s\"\n", current->data);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001926#endif
1927}
1928
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001929void center_cursor(void)
1930{
1931 current_y = editwinrows / 2;
1932 wmove(edit, current_y, current_x);
1933}
1934
Chris Allegretta6df90f52002-07-19 01:08:59 +00001935/* Refresh the screen without changing the position of lines. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001936void edit_refresh(void)
1937{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001938 /* Neither of these conditions should occur, but they do. edittop
1939 * is NULL when you open an existing file on the command line, and
Chris Allegretta6df90f52002-07-19 01:08:59 +00001940 * ENABLE_COLOR is defined. Yuck. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001941 if (current == NULL)
1942 return;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001943 if (edittop == NULL)
1944 edittop = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001945
Chris Allegretta63d0b482003-01-26 19:47:10 +00001946 if (current->lineno < edittop->lineno ||
1947 current->lineno >= edittop->lineno + editwinrows)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001948 /* Note that edit_update() changes edittop so that
1949 * current->lineno = edittop->lineno + editwinrows / 2. Thus
1950 * when it then calls edit_refresh(), there is no danger of
1951 * getting an infinite loop. */
Chris Allegrettada721be2000-07-31 01:26:42 +00001952 edit_update(current, CENTER);
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001953 else {
1954 int nlines = 0;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001955 const filestruct *foo = edittop;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001956
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001957#ifdef DEBUG
1958 fprintf(stderr, "edit_refresh(): edittop->lineno = %ld\n", edittop->lineno);
1959#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001960
David Lawrence Ramseyb55e3822004-02-25 06:25:12 +00001961 /* Don't let the cursor jump around the screen while
1962 * updating. */
1963 leaveok(edit, TRUE);
1964
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001965 while (nlines < editwinrows) {
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001966 update_line(foo, current_x);
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001967 nlines++;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001968 if (foo->next == NULL)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001969 break;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001970 foo = foo->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001971 }
1972 while (nlines < editwinrows) {
1973 mvwaddstr(edit, nlines, 0, hblank);
1974 nlines++;
1975 }
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001976 reset_cursor();
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);
David Lawrence Ramseyb55e3822004-02-25 06:25:12 +00001980
1981 /* Let the cursor jump around the screen again. */
1982 leaveok(edit, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001983 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001984}
1985
Chris Allegretta7662c862003-01-13 01:35:15 +00001986/* Same as above, but touch the window first, so everything is
1987 * redrawn. */
Chris Allegrettaf1d33d32000-08-19 03:53:39 +00001988void edit_refresh_clearok(void)
1989{
1990 clearok(edit, TRUE);
1991 edit_refresh();
1992 clearok(edit, FALSE);
1993}
1994
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001995/* Nice generic routine to update the edit buffer, given a pointer to the
1996 * file struct =) */
David Lawrence Ramsey1356a0a2003-09-10 20:31:02 +00001997void edit_update(filestruct *fileptr, topmidnone location)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001998{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001999 if (fileptr == NULL)
2000 return;
2001
Chris Allegretta6df90f52002-07-19 01:08:59 +00002002 if (location != TOP) {
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00002003 int goal = location == NONE ? current_y : editwinrows / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002004
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00002005 for (; goal > 0 && fileptr->prev != NULL; goal--)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002006 fileptr = fileptr->prev;
2007 }
2008 edittop = fileptr;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002009 edit_refresh();
2010}
2011
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002012/* Ask a question on the statusbar. Answer will be stored in answer
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002013 * global. Returns -1 on aborted enter, -2 on a blank string, and 0
Chris Allegretta88520c92001-05-05 17:45:54 +00002014 * otherwise, the valid shortcut key caught. Def is any editable text we
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002015 * want to put up by default.
Chris Allegretta7da4e9f2000-11-06 02:57:22 +00002016 *
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002017 * New arg tabs tells whether or not to allow tab completion. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002018int statusq(int allowtabs, const shortcut *s, const char *def,
Chris Allegretta5beed502003-01-05 20:41:21 +00002019#ifndef NANO_SMALL
2020 historyheadtype *which_history,
2021#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002022 const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002023{
2024 va_list ap;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002025 char *foo = charalloc(COLS - 3);
Chris Allegretta9caa1932002-02-15 20:08:05 +00002026 int ret;
Chris Allegretta2084acc2001-11-29 03:43:08 +00002027#ifndef DISABLE_TABCOMP
Chris Allegrettaa16e4e92002-01-05 18:59:54 +00002028 int list = 0;
Chris Allegretta2084acc2001-11-29 03:43:08 +00002029#endif
2030
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002031 bottombars(s);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002032
2033 va_start(ap, msg);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002034 vsnprintf(foo, COLS - 4, msg, ap);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002035 va_end(ap);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002036 foo[COLS - 4] = '\0';
Chris Allegretta8ce24132001-04-30 11:28:46 +00002037
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002038 ret = nanogetstr(allowtabs, foo, def,
Chris Allegretta5beed502003-01-05 20:41:21 +00002039#ifndef NANO_SMALL
2040 which_history,
Chris Allegretta2084acc2001-11-29 03:43:08 +00002041#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00002042 s
2043#ifndef DISABLE_TABCOMP
2044 , &list
2045#endif
Chris Allegretta65f075d2003-02-13 03:03:49 +00002046 );
Chris Allegretta6df90f52002-07-19 01:08:59 +00002047 free(foo);
Chris Allegretta65f075d2003-02-13 03:03:49 +00002048 resetstatuspos = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002049
2050 switch (ret) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002051 case NANO_FIRSTLINE_KEY:
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00002052 case NANO_FIRSTLINE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002053 do_first_line();
Chris Allegretta65f075d2003-02-13 03:03:49 +00002054 resetstatuspos = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002055 break;
2056 case NANO_LASTLINE_KEY:
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00002057 case NANO_LASTLINE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002058 do_last_line();
Chris Allegretta65f075d2003-02-13 03:03:49 +00002059 resetstatuspos = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002060 break;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002061#ifndef DISABLE_JUSTIFY
2062 case NANO_PARABEGIN_KEY:
2063 do_para_begin();
2064 resetstatuspos = 1;
2065 break;
2066 case NANO_PARAEND_KEY:
2067 do_para_end();
2068 resetstatuspos = 1;
2069 break;
2070#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002071 case NANO_CANCEL_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002072 ret = -1;
Chris Allegretta65f075d2003-02-13 03:03:49 +00002073 resetstatuspos = 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002074 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002075 }
Chris Allegrettaa90d0cf2003-02-10 02:55:03 +00002076 blank_statusbar();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002077
2078#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00002079 fprintf(stderr, "I got \"%s\"\n", answer);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002080#endif
2081
Chris Allegretta6df90f52002-07-19 01:08:59 +00002082#ifndef DISABLE_TABCOMP
2083 /* if we've done tab completion, there might be a list of
2084 filename matches on the edit window at this point; make sure
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002085 they're cleared off. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002086 if (list)
2087 edit_refresh();
2088#endif
2089
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002090 return ret;
2091}
2092
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002093/* Ask a simple yes/no question on the statusbar. Returns 1 for Y, 0
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002094 * for N, 2 for All (if all is nonzero when passed in) and -1 for abort
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002095 * (^C). */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002096int do_yesno(int all, const char *msg)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002097{
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002098 int ok = -2, width = 16;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002099 const char *yesstr; /* String of yes characters accepted */
2100 const char *nostr; /* Same for no */
2101 const char *allstr; /* And all, surprise! */
Chris Allegretta235ab192001-04-12 13:24:40 +00002102
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002103 /* Yes, no and all are strings of any length. Each string consists
2104 * of all characters accepted as a valid character for that value.
2105 * The first value will be the one displayed in the shortcuts. */
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002106 yesstr = _("Yy");
2107 nostr = _("Nn");
2108 allstr = _("Aa");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002109
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002110 /* Remove gettext call for keybindings until we clear the thing
2111 * up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002112 if (!ISSET(NO_HELP)) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002113 char shortstr[3]; /* Temp string for Y, N, A. */
Chris Allegretta6232d662002-05-12 19:52:15 +00002114
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002115 if (COLS < 32)
2116 width = COLS / 2;
2117
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002118 /* Write the bottom of the screen. */
Chris Allegrettadb28e962003-01-28 01:23:40 +00002119 blank_bottombars();
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002120
Chris Allegretta6232d662002-05-12 19:52:15 +00002121 sprintf(shortstr, " %c", yesstr[0]);
Chris Allegrettadb28e962003-01-28 01:23:40 +00002122 wmove(bottomwin, 1, 0);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002123 onekey(shortstr, _("Yes"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002124
2125 if (all) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002126 wmove(bottomwin, 1, width);
Chris Allegretta6232d662002-05-12 19:52:15 +00002127 shortstr[1] = allstr[0];
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002128 onekey(shortstr, _("All"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002129 }
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002130
Chris Allegrettadb28e962003-01-28 01:23:40 +00002131 wmove(bottomwin, 2, 0);
Chris Allegretta6232d662002-05-12 19:52:15 +00002132 shortstr[1] = nostr[0];
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002133 onekey(shortstr, _("No"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002134
Chris Allegrettadb28e962003-01-28 01:23:40 +00002135 wmove(bottomwin, 2, 16);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002136 onekey("^C", _("Cancel"), width);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002137 }
Chris Allegrettadb28e962003-01-28 01:23:40 +00002138
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002139 wattron(bottomwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002140
2141 blank_statusbar();
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002142 mvwaddnstr(bottomwin, 0, 0, msg, COLS - 1);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002143
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002144 wattroff(bottomwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002145
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002146 wrefresh(bottomwin);
2147
Chris Allegrettadb28e962003-01-28 01:23:40 +00002148 do {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002149 int kbinput;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002150 int meta_key;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002151#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002152 int mouse_x, mouse_y;
Chris Allegretta235ab192001-04-12 13:24:40 +00002153#endif
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002154
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002155 kbinput = get_kbinput(edit, &meta_key);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002156
2157 if (kbinput == NANO_CANCEL_KEY)
Chris Allegrettadb28e962003-01-28 01:23:40 +00002158 ok = -1;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002159#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002160 /* Look ma! We get to duplicate lots of code from
2161 * do_mouse()!! */
2162 else if (kbinput == KEY_MOUSE) {
2163 kbinput = get_mouseinput(&mouse_x, &mouse_y, 0);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002164
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002165 if (mouse_x != -1 && mouse_y != -1 && !ISSET(NO_HELP) &&
2166 wenclose(bottomwin, mouse_y, mouse_x) && mouse_x <
2167 (width * 2) && mouse_y >= editwinrows + 3) {
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002168
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002169 int x = mouse_x / width;
2170 /* Did we click in the first column of shortcuts, or
2171 * the second? */
2172 int y = mouse_y - editwinrows - 3;
2173 /* Did we click in the first row of shortcuts? */
2174
2175 assert(0 <= x && x <= 1 && 0 <= y && y <= 1);
2176
2177 /* x = 0 means they clicked Yes or No.
2178 * y = 0 means Yes or All. */
2179 ok = -2 * x * y + x - y + 1;
2180
2181 if (ok == 2 && !all)
2182 ok = -2;
2183 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002184 }
Chris Allegrettadb28e962003-01-28 01:23:40 +00002185#endif
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002186 /* Look for the kbinput in the yes, no and (optionally) all
2187 * str. */
Chris Allegrettadb28e962003-01-28 01:23:40 +00002188 else if (strchr(yesstr, kbinput) != NULL)
2189 ok = 1;
2190 else if (strchr(nostr, kbinput) != NULL)
2191 ok = 0;
2192 else if (all && strchr(allstr, kbinput) != NULL)
2193 ok = 2;
2194 } while (ok == -2);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002195
Chris Allegrettadb28e962003-01-28 01:23:40 +00002196 return ok;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002197}
2198
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002199int total_refresh(void)
2200{
2201 clearok(edit, TRUE);
2202 clearok(topwin, TRUE);
2203 clearok(bottomwin, TRUE);
2204 wnoutrefresh(edit);
2205 wnoutrefresh(topwin);
2206 wnoutrefresh(bottomwin);
2207 doupdate();
2208 clearok(edit, FALSE);
2209 clearok(topwin, FALSE);
2210 clearok(bottomwin, FALSE);
2211 edit_refresh();
2212 titlebar(NULL);
2213 return 1;
2214}
2215
2216void display_main_list(void)
2217{
2218 bottombars(main_list);
2219}
2220
Chris Allegretta6df90f52002-07-19 01:08:59 +00002221void statusbar(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002222{
2223 va_list ap;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002224
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002225 va_start(ap, msg);
2226
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002227 /* Curses mode is turned off. If we use wmove() now, it will muck
2228 * up the terminal settings. So we just use vfprintf(). */
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002229 if (curses_ended) {
2230 vfprintf(stderr, msg, ap);
2231 va_end(ap);
2232 return;
2233 }
2234
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002235 /* Blank out the line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002236 blank_statusbar();
2237
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002238 if (COLS >= 4) {
2239 char *bar;
2240 char *foo;
2241 int start_x = 0;
2242 size_t foo_len;
2243 bar = charalloc(COLS - 3);
2244 vsnprintf(bar, COLS - 3, msg, ap);
2245 va_end(ap);
2246 foo = display_string(bar, 0, COLS - 4);
2247 free(bar);
2248 foo_len = strlen(foo);
2249 start_x = (COLS - foo_len - 4) / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002250
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002251 wmove(bottomwin, 0, start_x);
2252 wattron(bottomwin, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002253
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002254 waddstr(bottomwin, "[ ");
2255 waddstr(bottomwin, foo);
2256 free(foo);
2257 waddstr(bottomwin, " ]");
2258 wattroff(bottomwin, A_REVERSE);
2259 wnoutrefresh(bottomwin);
2260 wrefresh(edit);
2261 /* Leave the cursor at its position in the edit window, not
2262 * in the statusbar. */
2263 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002264
Chris Allegrettad26ab912003-01-28 01:16:47 +00002265 SET(DISABLE_CURPOS);
2266 statblank = 26;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002267}
2268
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002269/* If constant is false, the user typed ^C so we unconditionally display
Chris Allegrettad26ab912003-01-28 01:16:47 +00002270 * the cursor position. Otherwise, we display it only if the character
2271 * position changed, and DISABLE_CURPOS is not set.
2272 *
2273 * If constant and DISABLE_CURPOS is set, we unset it and update old_i and
2274 * old_totsize. That way, we leave the current statusbar alone, but next
2275 * time we will display. */
Chris Allegretta2084acc2001-11-29 03:43:08 +00002276int do_cursorpos(int constant)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002277{
Chris Allegrettad26ab912003-01-28 01:16:47 +00002278 const filestruct *fileptr;
2279 unsigned long i = 0;
2280 static unsigned long old_i = 0;
2281 static long old_totsize = -1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002282
Chris Allegrettad26ab912003-01-28 01:16:47 +00002283 assert(current != NULL && fileage != NULL && totlines != 0);
Chris Allegretta2084acc2001-11-29 03:43:08 +00002284
2285 if (old_totsize == -1)
2286 old_totsize = totsize;
2287
Chris Allegrettad26ab912003-01-28 01:16:47 +00002288 for (fileptr = fileage; fileptr != current; fileptr = fileptr->next) {
2289 assert(fileptr != NULL);
Chris Allegrettaf27c6972002-02-12 01:57:24 +00002290 i += strlen(fileptr->data) + 1;
Chris Allegrettad26ab912003-01-28 01:16:47 +00002291 }
Chris Allegrettaf27c6972002-02-12 01:57:24 +00002292 i += current_x;
Chris Allegretta14b3ca92002-01-25 21:59:02 +00002293
Chris Allegrettad26ab912003-01-28 01:16:47 +00002294 if (constant && ISSET(DISABLE_CURPOS)) {
2295 UNSET(DISABLE_CURPOS);
2296 old_i = i;
2297 old_totsize = totsize;
2298 return 0;
2299 }
Chris Allegretta14b3ca92002-01-25 21:59:02 +00002300
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002301 /* If constant is false, display the position on the statusbar
2302 * unconditionally; otherwise, only display the position when the
2303 * character values have changed. */
Chris Allegrettad26ab912003-01-28 01:16:47 +00002304 if (!constant || old_i != i || old_totsize != totsize) {
2305 unsigned long xpt = xplustabs() + 1;
2306 unsigned long cur_len = strlenpt(current->data) + 1;
2307 int linepct = 100 * current->lineno / totlines;
2308 int colpct = 100 * xpt / cur_len;
2309 int bytepct = totsize == 0 ? 0 : 100 * i / totsize;
2310
2311 statusbar(
2312 _("line %ld/%ld (%d%%), col %lu/%lu (%d%%), char %lu/%ld (%d%%)"),
2313 current->lineno, totlines, linepct,
2314 xpt, cur_len, colpct,
2315 i, totsize, bytepct);
2316 UNSET(DISABLE_CURPOS);
Chris Allegretta2084acc2001-11-29 03:43:08 +00002317 }
2318
2319 old_i = i;
2320 old_totsize = totsize;
2321
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002322 reset_cursor();
Chris Allegrettad26ab912003-01-28 01:16:47 +00002323 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002324}
2325
Chris Allegretta2084acc2001-11-29 03:43:08 +00002326int do_cursorpos_void(void)
2327{
2328 return do_cursorpos(0);
2329}
2330
Chris Allegretta4640fe32003-02-10 03:10:03 +00002331/* Calculate the next line of help_text, starting at ptr. */
2332int line_len(const char *ptr)
2333{
2334 int j = 0;
2335
2336 while (*ptr != '\n' && *ptr != '\0' && j < COLS - 5) {
2337 ptr++;
2338 j++;
2339 }
2340 if (j == COLS - 5) {
2341 /* Don't wrap at the first of two spaces following a period. */
2342 if (*ptr == ' ' && *(ptr + 1) == ' ')
2343 j++;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002344 /* Don't print half a word if we've run out of space. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00002345 while (*ptr != ' ' && j > 0) {
2346 ptr--;
2347 j--;
2348 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002349 /* Word longer than COLS - 5 chars just gets broken. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00002350 if (j == 0)
2351 j = COLS - 5;
2352 }
2353 assert(j >= 0 && j <= COLS - 4 && (j > 0 || *ptr == '\n'));
2354 return j;
2355}
2356
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002357/* Our shortcut-list-compliant help function, which is better than
2358 * nothing, and dynamic! */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002359int do_help(void)
2360{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002361#ifndef DISABLE_HELP
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002362 int i, page = 0, kbinput = ERR, meta_key, no_more = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002363 int no_help_flag = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002364 const shortcut *oldshortcut;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002365
2366 blank_edit();
2367 curs_set(0);
Chris Allegrettab3655b42001-10-22 03:15:31 +00002368 wattroff(bottomwin, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002369 blank_statusbar();
2370
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002371 /* Set help_text as the string to display. */
Chris Allegrettab3655b42001-10-22 03:15:31 +00002372 help_init();
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002373 assert(help_text != NULL);
Chris Allegrettab3655b42001-10-22 03:15:31 +00002374
2375 oldshortcut = currshortcut;
Chris Allegrettab3655b42001-10-22 03:15:31 +00002376
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002377 currshortcut = help_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00002378
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002379 if (ISSET(NO_HELP)) {
2380
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002381 /* Well, if we're going to do this, we should at least do it the
2382 * right way. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002383 no_help_flag = 1;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002384 UNSET(NO_HELP);
Chris Allegretta70444892001-01-07 23:02:02 +00002385 window_init();
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002386 bottombars(help_list);
Chris Allegretta70444892001-01-07 23:02:02 +00002387
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002388 } else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002389 bottombars(help_list);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002390
2391 do {
Chris Allegrettaf717f982003-02-13 22:25:01 +00002392 const char *ptr = help_text;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002393
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002394 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002395#ifndef DISABLE_MOUSE
Chris Allegretta598106e2002-01-19 01:59:37 +00002396 case KEY_MOUSE:
2397 do_mouse();
2398 break;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002399#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002400 case NANO_NEXTPAGE_KEY:
2401 case NANO_NEXTPAGE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002402 if (!no_more) {
2403 blank_edit();
2404 page++;
2405 }
2406 break;
2407 case NANO_PREVPAGE_KEY:
2408 case NANO_PREVPAGE_FKEY:
Chris Allegretta4640fe32003-02-10 03:10:03 +00002409 if (page > 0) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002410 no_more = 0;
2411 blank_edit();
2412 page--;
2413 }
2414 break;
2415 }
2416
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002417 /* Calculate where in the text we should be, based on the
2418 * page. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00002419 for (i = 1; i < page * (editwinrows - 1); i++) {
2420 ptr += line_len(ptr);
2421 if (*ptr == '\n')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002422 ptr++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002423 }
2424
Chris Allegretta4640fe32003-02-10 03:10:03 +00002425 for (i = 0; i < editwinrows && *ptr != '\0'; i++) {
2426 int j = line_len(ptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002427
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002428 mvwaddnstr(edit, i, 0, ptr, j);
Chris Allegretta4640fe32003-02-10 03:10:03 +00002429 ptr += j;
2430 if (*ptr == '\n')
2431 ptr++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002432 }
Chris Allegretta4640fe32003-02-10 03:10:03 +00002433
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002434 if (*ptr == '\0') {
2435 no_more = 1;
2436 continue;
2437 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002438 } while ((kbinput = get_kbinput(edit, &meta_key)) != NANO_EXIT_KEY && kbinput != NANO_EXIT_FKEY);
Chris Allegrettad1627cf2000-12-18 05:03:16 +00002439
Chris Allegrettab3655b42001-10-22 03:15:31 +00002440 currshortcut = oldshortcut;
Chris Allegrettab3655b42001-10-22 03:15:31 +00002441
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002442 if (no_help_flag) {
Chris Allegretta70444892001-01-07 23:02:02 +00002443 blank_bottombars();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002444 wrefresh(bottomwin);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002445 SET(NO_HELP);
Chris Allegretta70444892001-01-07 23:02:02 +00002446 window_init();
Chris Allegretta598106e2002-01-19 01:59:37 +00002447 } else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002448 bottombars(currshortcut);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002449
2450 curs_set(1);
2451 edit_refresh();
Chris Allegrettac08f50d2001-01-06 18:12:43 +00002452
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002453 /* The help_init() at the beginning allocated help_text, which has
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002454 * now been written to the screen. */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002455 free(help_text);
2456 help_text = NULL;
2457
Chris Allegretta6df90f52002-07-19 01:08:59 +00002458#elif defined(DISABLE_HELP)
2459 nano_disabled_msg();
2460#endif
2461
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002462 return 1;
2463}
2464
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002465/* Highlight the current word being replaced or spell checked. We
2466 * expect word to have tabs and control characters expanded. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002467void do_replace_highlight(int highlight_flag, const char *word)
Chris Allegrettafb62f732000-12-05 11:36:41 +00002468{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002469 int y = xplustabs();
2470 size_t word_len = strlen(word);
Chris Allegrettafb62f732000-12-05 11:36:41 +00002471
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002472 y = get_page_start(y) + COLS - y;
2473 /* Now y is the number of characters we can display on this
2474 * line. */
Chris Allegrettafb62f732000-12-05 11:36:41 +00002475
2476 reset_cursor();
Chris Allegretta598106e2002-01-19 01:59:37 +00002477
Chris Allegrettafb62f732000-12-05 11:36:41 +00002478 if (highlight_flag)
2479 wattron(edit, A_REVERSE);
2480
David Lawrence Ramsey2a4ab6d2003-12-24 08:29:49 +00002481#ifdef HAVE_REGEX_H
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00002482 /* This is so we can show zero-length regexes. */
2483 if (word_len == 0)
2484 waddstr(edit, " ");
2485 else
David Lawrence Ramsey2a4ab6d2003-12-24 08:29:49 +00002486#endif
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00002487 waddnstr(edit, word, y - 1);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002488
2489 if (word_len > y)
2490 waddch(edit, '$');
2491 else if (word_len == y)
2492 waddch(edit, word[word_len - 1]);
Chris Allegrettafb62f732000-12-05 11:36:41 +00002493
2494 if (highlight_flag)
2495 wattroff(edit, A_REVERSE);
Chris Allegrettafb62f732000-12-05 11:36:41 +00002496}
2497
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002498#ifdef DEBUG
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002499/* Dump the passed-in file structure to stderr. */
2500void dump_buffer(const filestruct *inptr)
2501{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002502 if (inptr == fileage)
Jordi Mallachf9390af2003-08-05 19:31:12 +00002503 fprintf(stderr, "Dumping file buffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002504 else if (inptr == cutbuffer)
Jordi Mallachf9390af2003-08-05 19:31:12 +00002505 fprintf(stderr, "Dumping cutbuffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002506 else
Jordi Mallachf9390af2003-08-05 19:31:12 +00002507 fprintf(stderr, "Dumping a buffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002508
2509 while (inptr != NULL) {
2510 fprintf(stderr, "(%d) %s\n", inptr->lineno, inptr->data);
2511 inptr = inptr->next;
2512 }
2513}
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002514
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002515/* Dump the file structure to stderr in reverse. */
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00002516void dump_buffer_reverse(void)
2517{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002518 const filestruct *fileptr = filebot;
2519
2520 while (fileptr != NULL) {
2521 fprintf(stderr, "(%d) %s\n", fileptr->lineno, fileptr->data);
2522 fileptr = fileptr->prev;
2523 }
2524}
2525#endif /* DEBUG */
2526
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002527#ifdef NANO_EXTRA
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002528#define CREDIT_LEN 53
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002529#define XLCREDIT_LEN 8
2530
David Lawrence Ramseyfdece462004-01-19 18:15:03 +00002531/* Easter egg: Display credits. Assume nodelay(edit) is FALSE. */
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002532void do_credits(void)
2533{
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002534 int i, j = 0, k, place = 0, start_x;
David Lawrence Ramseye97c8d52004-01-14 19:26:29 +00002535 struct timespec scrolldelay;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002536
Chris Allegrettaf717f982003-02-13 22:25:01 +00002537 const char *what;
2538 const char *xlcredits[XLCREDIT_LEN];
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002539
Chris Allegrettaf717f982003-02-13 22:25:01 +00002540 const char *credits[CREDIT_LEN] = {
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002541 "0", /* "The nano text editor" */
2542 "1", /* "version" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002543 VERSION,
2544 "",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002545 "2", /* "Brought to you by:" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002546 "Chris Allegretta",
2547 "Jordi Mallach",
2548 "Adam Rogoyski",
2549 "Rob Siemborski",
2550 "Rocco Corsi",
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002551 "David Lawrence Ramsey",
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002552 "David Benbennick",
Chris Allegretta598106e2002-01-19 01:59:37 +00002553 "Ken Tyler",
2554 "Sven Guckes",
2555 "Florian König",
2556 "Pauli Virtanen",
2557 "Daniele Medri",
2558 "Clement Laforet",
2559 "Tedi Heriyanto",
2560 "Bill Soudan",
2561 "Christian Weisgerber",
2562 "Erik Andersen",
2563 "Big Gaute",
2564 "Joshua Jensen",
2565 "Ryan Krebs",
2566 "Albert Chin",
Chris Allegretta598106e2002-01-19 01:59:37 +00002567 "",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002568 "3", /* "Special thanks to:" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002569 "Plattsburgh State University",
2570 "Benet Laboratories",
2571 "Amy Allegretta",
2572 "Linda Young",
2573 "Jeremy Robichaud",
2574 "Richard Kolb II",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002575 "4", /* "The Free Software Foundation" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002576 "Linus Torvalds",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002577 "5", /* "For ncurses:" */
Chris Allegrettadce44ab2002-03-16 01:03:41 +00002578 "Thomas Dickey",
2579 "Pavel Curtis",
2580 "Zeyd Ben-Halim",
2581 "Eric S. Raymond",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002582 "6", /* "and anyone else we forgot..." */
2583 "7", /* "Thank you for using nano!\n" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002584 "", "", "", "",
David Lawrence Ramsey6481c3f2004-01-09 23:06:54 +00002585 "(c) 1999-2004 Chris Allegretta",
Chris Allegretta598106e2002-01-19 01:59:37 +00002586 "", "", "", "",
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002587 "http://www.nano-editor.org/"
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002588 };
2589
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002590 xlcredits[0] = _("The nano text editor");
2591 xlcredits[1] = _("version ");
2592 xlcredits[2] = _("Brought to you by:");
2593 xlcredits[3] = _("Special thanks to:");
2594 xlcredits[4] = _("The Free Software Foundation");
2595 xlcredits[5] = _("For ncurses:");
2596 xlcredits[6] = _("and anyone else we forgot...");
2597 xlcredits[7] = _("Thank you for using nano!\n");
2598
David Lawrence Ramsey9da08312004-01-14 22:40:38 +00002599 scrolldelay.tv_sec = 0;
David Lawrence Ramsey62187d92004-01-14 22:45:05 +00002600 scrolldelay.tv_nsec = 700000000;
David Lawrence Ramseye97c8d52004-01-14 19:26:29 +00002601
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002602 curs_set(0);
2603 nodelay(edit, TRUE);
2604 blank_bottombars();
2605 mvwaddstr(topwin, 0, 0, hblank);
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002606 blank_edit();
2607 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002608 wrefresh(bottomwin);
2609 wrefresh(topwin);
2610
2611 while (wgetch(edit) == ERR) {
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002612 for (k = 0; k <= 1; k++) {
2613 blank_edit();
Chris Allegretta598106e2002-01-19 01:59:37 +00002614 for (i = editwinrows / 2 - 1; i >= (editwinrows / 2 - 1 - j);
2615 i--) {
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002616 mvwaddstr(edit, i * 2 - k, 0, hblank);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002617
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002618 if (place - (editwinrows / 2 - 1 - i) < CREDIT_LEN) {
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002619 what = credits[place - (editwinrows / 2 - 1 - i)];
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002620
2621 /* God I've missed hacking. If what is exactly
2622 1 char long, it's a sentinel for a translated
2623 string, so use that instead. This means no
2624 thanking people with 1 character long names ;-) */
2625 if (strlen(what) == 1)
2626 what = xlcredits[atoi(what)];
2627 } else
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002628 what = "";
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002629
Chris Allegretta17dcb722001-01-20 21:40:07 +00002630 start_x = COLS / 2 - strlen(what) / 2 - 1;
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002631 mvwaddstr(edit, i * 2 - k, start_x, what);
2632 }
David Lawrence Ramseye97c8d52004-01-14 19:26:29 +00002633 nanosleep(&scrolldelay, NULL);
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002634 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002635 }
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002636 if (j < editwinrows / 2 - 1)
2637 j++;
2638
2639 place++;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002640
2641 if (place >= CREDIT_LEN + editwinrows / 2)
2642 break;
2643 }
2644
2645 nodelay(edit, FALSE);
2646 curs_set(1);
2647 display_main_list();
2648 total_refresh();
Chris Allegretta598106e2002-01-19 01:59:37 +00002649}
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002650#endif