blob: fff100ee7f5a98b91572d33fbe5290ffb5b84f1d [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 Ramseyf4276942003-12-24 03:33:09 +000047int get_kbinput(WINDOW *win, int *meta)
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 Ramseyf4276942003-12-24 03:33:09 +000056 retval = get_accepted_kbinput(win, kbinput, meta);
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
130 while (1) {
131 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
154 * sequences. Set meta to 1 if we get a Meta sequence. Assume
155 * nodelay(win) is FALSE. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000156int get_accepted_kbinput(WINDOW *win, int kbinput, int *meta)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000157{
158 *meta = 0;
159
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 Ramsey4d7c2602003-08-17 02:48:43 +0000202 *meta = 1;
203 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 Ramsey4d7c2602003-08-17 02:48:43 +0000217 *meta = 1;
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
275 fprintf(stderr, "get_accepted_kbinput(): kbinput = %d, meta = %d\n", kbinput, *meta);
276#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
836 /* And ungetch() the equivalent keystroke. */
837 ungetch(s->val);
838
839 /* If it's not a control character, assume it's a Meta key
840 * sequence, in which case we need to ungetch() Escape too. */
841 if (!is_cntrl_char(s->val))
842 ungetch(NANO_CONTROL_3);
843
844 return 1;
845 }
846 return 0;
847}
848#endif
849
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000850int do_first_line(void)
851{
852 current = fileage;
853 placewewant = 0;
854 current_x = 0;
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +0000855 edit_update(current, TOP);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000856 return 1;
857}
858
859int do_last_line(void)
860{
861 current = filebot;
862 placewewant = 0;
863 current_x = 0;
Chris Allegretta234a34d2000-07-29 04:33:38 +0000864 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000865 return 1;
866}
867
Chris Allegretta6df90f52002-07-19 01:08:59 +0000868/* Return the placewewant associated with current_x. That is, xplustabs
869 * is the zero-based column position of the cursor. Value is no smaller
870 * than current_x. */
871size_t xplustabs(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000872{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000873 return strnlenpt(current->data, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000874}
875
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000876/* actual_x() gives the index in str of the character displayed at
877 * column xplus. That is, actual_x() is the largest value such that
878 * strnlenpt(str, actual_x(str, xplus)) <= xplus. */
879size_t actual_x(const char *str, size_t xplus)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000880{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000881 size_t i = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000882 /* the position in str, returned */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000883 size_t length = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000884 /* the screen display width to str[i] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000885
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000886 assert(str != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000887
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000888 for (; length < xplus && *str != '\0'; i++, str++) {
889 if (*str == '\t')
David Lawrence Ramsey0362c582003-09-30 03:31:56 +0000890 length += tabsize - (length % tabsize);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000891 else if (is_cntrl_char((int)*str))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000892 length += 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000893 else
894 length++;
895 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000896 assert(length == strnlenpt(str - i, i));
897 assert(i <= strlen(str - i));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000898
Chris Allegretta6df90f52002-07-19 01:08:59 +0000899 if (length > xplus)
900 i--;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000901
Chris Allegretta6df90f52002-07-19 01:08:59 +0000902 return i;
Robert Siemborskid8510b22000-06-06 23:04:06 +0000903}
904
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000905/* A strlen with tabs factored in, similar to xplustabs(). How many
906 * columns wide are the first size characters of buf? */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000907size_t strnlenpt(const char *buf, size_t size)
Robert Siemborskid8510b22000-06-06 23:04:06 +0000908{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000909 size_t length = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000910
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000911 assert(buf != NULL);
912 for (; *buf != '\0' && size != 0; size--, buf++) {
913 if (*buf == '\t')
914 length += tabsize - (length % tabsize);
915 else if (is_cntrl_char((int)*buf))
916 length += 2;
917 else
918 length++;
919 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000920 return length;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000921}
922
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000923/* How many columns wide is buf? */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000924size_t strlenpt(const char *buf)
Chris Allegrettad4fa0d32002-03-05 19:55:55 +0000925{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000926 return strnlenpt(buf, -1);
Chris Allegrettad4fa0d32002-03-05 19:55:55 +0000927}
928
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000929void blank_bottombars(void)
930{
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000931 if (!ISSET(NO_HELP)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +0000932 mvwaddstr(bottomwin, 1, 0, hblank);
933 mvwaddstr(bottomwin, 2, 0, hblank);
934 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000935}
936
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000937void blank_bottomwin(void)
938{
939 if (ISSET(NO_HELP))
940 return;
941
942 mvwaddstr(bottomwin, 1, 0, hblank);
943 mvwaddstr(bottomwin, 2, 0, hblank);
944}
945
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000946void blank_edit(void)
947{
948 int i;
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +0000949 for (i = 0; i < editwinrows; i++)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000950 mvwaddstr(edit, i, 0, hblank);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000951}
952
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000953void blank_statusbar(void)
954{
955 mvwaddstr(bottomwin, 0, 0, hblank);
956}
957
958void blank_statusbar_refresh(void)
959{
960 blank_statusbar();
961 wrefresh(bottomwin);
962}
963
964void check_statblank(void)
965{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000966 if (statblank > 1)
967 statblank--;
968 else if (statblank == 1 && !ISSET(CONSTUPDATE)) {
969 statblank--;
970 blank_statusbar_refresh();
971 }
972}
973
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000974/* Convert buf into a string that can be displayed on screen. The
975 * caller wants to display buf starting with column start_col, and
976 * extending for at most len columns. start_col is zero-based. len is
977 * one-based, so len == 0 means you get "" returned. The returned
978 * string is dynamically allocated, and should be freed. */
979char *display_string(const char *buf, size_t start_col, int len)
980{
981 size_t start_index;
982 /* Index in buf of first character shown in return value. */
983 size_t column;
984 /* Screen column start_index corresponds to. */
985 size_t end_index;
986 /* Index in buf of last character shown in return value. */
987 size_t alloc_len;
988 /* The length of memory allocated for converted. */
989 char *converted;
990 /* The string we return. */
991 size_t index;
992 /* Current position in converted. */
993
994 if (len == 0)
995 return mallocstrcpy(NULL, "");
996
997 start_index = actual_x(buf, start_col);
998 column = strnlenpt(buf, start_index);
999 assert(column <= start_col);
1000 end_index = actual_x(buf, start_col + len - 1);
1001 alloc_len = strnlenpt(buf, end_index + 1) - column;
1002 if (len > alloc_len + column - start_col)
1003 len = alloc_len + column - start_col;
1004 converted = charalloc(alloc_len + 1);
1005 buf += start_index;
1006 index = 0;
1007
1008 for (; index < alloc_len; buf++) {
1009 if (*buf == '\t')
1010 do {
1011 converted[index++] = ' ';
1012 } while ((column + index) % tabsize);
1013 else if (is_cntrl_char(*buf)) {
1014 converted[index++] = '^';
1015 if (*buf == '\n')
1016 /* Treat newlines embedded in a line as encoded nulls;
1017 * the line in question should be run through unsunder()
1018 * before reaching here. */
1019 converted[index++] = '@';
1020 else if (*buf == NANO_CONTROL_8)
1021 converted[index++] = '?';
1022 else
1023 converted[index++] = *buf + 64;
1024 } else
1025 converted[index++] = *buf;
1026 }
1027 assert(len <= alloc_len + column - start_col);
1028 charmove(converted, converted + start_col - column, len);
1029 null_at(&converted, len);
1030
1031 return charealloc(converted, len + 1);
1032}
1033
Chris Allegretta7662c862003-01-13 01:35:15 +00001034/* Repaint the statusbar when getting a character in nanogetstr(). buf
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001035 * should be no longer than max(0, COLS - 4).
Chris Allegretta6df90f52002-07-19 01:08:59 +00001036 *
Chris Allegretta7662c862003-01-13 01:35:15 +00001037 * Note that we must turn on A_REVERSE here, since do_help() turns it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001038 * off! */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001039void nanoget_repaint(const char *buf, const char *inputbuf, size_t x)
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001040{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001041 size_t x_real = strnlenpt(inputbuf, x);
1042 int wid = COLS - strlen(buf) - 2;
Chris Allegretta0d1e8d62000-11-02 15:30:24 +00001043
Chris Allegretta6df90f52002-07-19 01:08:59 +00001044 assert(0 <= x && x <= strlen(inputbuf));
1045
Chris Allegrettab3655b42001-10-22 03:15:31 +00001046 wattron(bottomwin, A_REVERSE);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001047 blank_statusbar();
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001048
Chris Allegretta6df90f52002-07-19 01:08:59 +00001049 mvwaddstr(bottomwin, 0, 0, buf);
1050 waddch(bottomwin, ':');
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001051
1052 if (COLS > 1)
1053 waddch(bottomwin, x_real < wid ? ' ' : '$');
1054 if (COLS > 2) {
1055 size_t page_start = x_real - x_real % wid;
1056 char *expanded = display_string(inputbuf, page_start, wid);
1057
1058 assert(wid > 0);
1059 assert(strlen(expanded) <= wid);
1060 waddstr(bottomwin, expanded);
1061 free(expanded);
1062 wmove(bottomwin, 0, COLS - wid + x_real - page_start);
1063 } else
1064 wmove(bottomwin, 0, COLS - 1);
Chris Allegrettab3655b42001-10-22 03:15:31 +00001065 wattroff(bottomwin, A_REVERSE);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +00001066}
1067
Chris Allegretta6df90f52002-07-19 01:08:59 +00001068/* Get the input from the kb; this should only be called from
1069 * statusq(). */
Chris Allegrettaf717f982003-02-13 22:25:01 +00001070int nanogetstr(int allowtabs, const char *buf, const char *def,
Chris Allegretta5beed502003-01-05 20:41:21 +00001071#ifndef NANO_SMALL
1072 historyheadtype *history_list,
1073#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001074 const shortcut *s
Rocco Corsi06aca1c2001-01-11 05:30:31 +00001075#ifndef DISABLE_TABCOMP
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001076 , int *list
Chris Allegrettabe77c612000-11-24 14:00:16 +00001077#endif
Chris Allegretta65f075d2003-02-13 03:03:49 +00001078 )
Chris Allegretta6df90f52002-07-19 01:08:59 +00001079{
1080 int kbinput;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001081 int meta;
Chris Allegretta09fc4302003-01-16 22:16:38 +00001082 static int x = -1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001083 /* the cursor position in 'answer' */
1084 int xend;
1085 /* length of 'answer', the status bar text */
1086 int tabbed = 0;
1087 /* used by input_tab() */
1088 const shortcut *t;
Chris Allegretta598106e2002-01-19 01:59:37 +00001089
Chris Allegretta5beed502003-01-05 20:41:21 +00001090#ifndef NANO_SMALL
1091 /* for history */
1092 char *history = NULL;
Chris Allegretta8031f832003-01-09 05:29:58 +00001093 char *currentbuf = NULL;
Chris Allegretta5beed502003-01-05 20:41:21 +00001094 char *complete = NULL;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001095 int last_kbinput = 0;
1096
1097 /* This variable is used in the search history code. use_cb == 0
1098 means that we're using the existing history and ignoring
1099 currentbuf. use_cb == 1 means that the entry in answer should be
1100 moved to currentbuf or restored from currentbuf to answer.
1101 use_cb == 2 means that the entry in currentbuf should be moved to
1102 answer or restored from answer to currentbuf. */
1103 int use_cb = 0;
Chris Allegretta5beed502003-01-05 20:41:21 +00001104#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001105 xend = strlen(def);
Chris Allegretta09fc4302003-01-16 22:16:38 +00001106
1107 /* Only put x at the end of the string if it's uninitialized or if
1108 it would be past the end of the string as it is. Otherwise,
1109 leave it alone. This is so the cursor position stays at the same
1110 place if a prompt-changing toggle is pressed. */
Chris Allegretta65f075d2003-02-13 03:03:49 +00001111 if (x == -1 || x > xend || resetstatuspos)
Chris Allegretta09fc4302003-01-16 22:16:38 +00001112 x = xend;
1113
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00001114 answer = charealloc(answer, xend + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001115 if (xend > 0)
1116 strcpy(answer, def);
1117 else
1118 answer[0] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001119
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001120#if !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001121 currshortcut = s;
Chris Allegretta6fe61492001-05-21 12:56:25 +00001122#endif
1123
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001124 /* Get the input! */
Chris Allegretta31925e42000-11-02 04:40:39 +00001125
Chris Allegretta6df90f52002-07-19 01:08:59 +00001126 nanoget_repaint(buf, answer, x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001127
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001128 /* Make sure any editor screen updates are displayed before getting
1129 input */
Chris Allegretta022b96f2000-11-14 17:47:58 +00001130 wrefresh(edit);
1131
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001132 while ((kbinput = get_kbinput(bottomwin, &meta)) != NANO_ENTER_KEY) {
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001133 for (t = s; t != NULL; t = t->next) {
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001134#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001135 fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput, kbinput);
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001136#endif
1137
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00001138 if (kbinput == t->func_key)
1139 kbinput = t->val;
1140
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001141 if (kbinput == t->val && is_cntrl_char(kbinput)) {
Chris Allegretta5bf51d32000-11-16 06:01:10 +00001142
Chris Allegrettab3655b42001-10-22 03:15:31 +00001143#ifndef DISABLE_HELP
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001144 /* Have to do this here, it would be too late to do it
1145 in statusq() */
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00001146 if (kbinput == NANO_HELP_KEY) {
1147 kbinput = NANO_HELP_KEY;
Chris Allegrettab3655b42001-10-22 03:15:31 +00001148 do_help();
1149 break;
1150 }
1151#endif
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001152#ifndef NANO_SMALL
1153 /* Have to handle these here too, for the time being */
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001154 if (kbinput == NANO_PREVLINE_KEY || kbinput == NANO_NEXTLINE_KEY)
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001155 break;
1156#endif
Chris Allegretta5af58892003-01-17 21:07:38 +00001157
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001158 return t->val;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001159 }
1160 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001161 assert(0 <= x && x <= xend && xend == strlen(answer));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001162
Chris Allegretta04d848e2000-11-05 17:54:41 +00001163 if (kbinput != '\t')
1164 tabbed = 0;
1165
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001166 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001167#ifndef DISABLE_MOUSE
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001168 case KEY_MOUSE:
1169 do_mouse();
1170 break;
1171#endif
Chris Allegretta658399a2001-06-14 02:54:22 +00001172 case NANO_HOME_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001173 x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001174 break;
Chris Allegretta658399a2001-06-14 02:54:22 +00001175 case NANO_END_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001176 x = xend;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001177 break;
Chris Allegretta35dac582001-03-21 15:07:20 +00001178 case NANO_FORWARD_KEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001179 if (x < xend)
1180 x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001181 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001182 case NANO_DELETE_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001183 if (x < xend) {
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001184 charmove(answer + x, answer + x + 1, xend - x);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001185 xend--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001186 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001187 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001188 case NANO_CUT_KEY:
1189 case NANO_UNCUT_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001190 null_at(&answer, 0);
1191 xend = 0;
1192 x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001193 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001194 case NANO_BACKSPACE_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001195 if (x > 0) {
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001196 charmove(answer + x - 1, answer + x, xend - x + 1);
Chris Allegretta04d848e2000-11-05 17:54:41 +00001197 x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001198 xend--;
1199 }
Chris Allegretta04d848e2000-11-05 17:54:41 +00001200 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001201 case NANO_TAB_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001202#ifndef NANO_SMALL
1203 /* tab history completion */
Chris Allegretta7662c862003-01-13 01:35:15 +00001204 if (history_list != NULL) {
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00001205 if (!complete || last_kbinput != NANO_TAB_KEY) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001206 history_list->current = (historytype *)history_list;
1207 history_list->len = strlen(answer);
1208 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001209
Chris Allegretta7662c862003-01-13 01:35:15 +00001210 if (history_list->len > 0) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001211 complete = get_history_completion(history_list, answer);
1212 xend = strlen(complete);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001213 x = xend;
Chris Allegretta5beed502003-01-05 20:41:21 +00001214 answer = mallocstrcpy(answer, complete);
1215 }
Chris Allegretta7da4e9f2000-11-06 02:57:22 +00001216 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001217#ifndef DISABLE_TABCOMP
Chris Allegretta327abda2003-01-17 05:04:17 +00001218 else
1219#endif
Chris Allegrettabe77c612000-11-24 14:00:16 +00001220#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001221#ifndef DISABLE_TABCOMP
Chris Allegretta327abda2003-01-17 05:04:17 +00001222 if (allowtabs) {
1223 int shift = 0;
Chris Allegretta5beed502003-01-05 20:41:21 +00001224
Chris Allegretta327abda2003-01-17 05:04:17 +00001225 answer = input_tab(answer, x, &tabbed, &shift, list);
1226 xend = strlen(answer);
1227 x += shift;
1228 if (x > xend)
1229 x = xend;
Chris Allegretta5beed502003-01-05 20:41:21 +00001230 }
1231#endif
1232 break;
Chris Allegretta35dac582001-03-21 15:07:20 +00001233 case NANO_BACK_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001234 if (x > 0)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001235 x--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001236 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001237 case NANO_PREVLINE_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001238#ifndef NANO_SMALL
Chris Allegretta09fc4302003-01-16 22:16:38 +00001239 if (history_list != NULL) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001240
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001241 /* if currentbuf is NULL, or if use_cb is 1, currentbuf
1242 isn't NULL, and currentbuf is different from answer,
1243 it means that we're scrolling up at the top of the
1244 search history, and we need to save the current
1245 answer in currentbuf; do this and reset use_cb to
1246 0 */
1247 if (currentbuf == NULL || (use_cb == 1 && strcmp(currentbuf, answer))) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001248 currentbuf = mallocstrcpy(currentbuf, answer);
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001249 use_cb = 0;
Chris Allegretta8031f832003-01-09 05:29:58 +00001250 }
1251
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001252 /* if currentbuf isn't NULL, use_cb is 2, and currentbuf
1253 is different from answer, it means that we're
1254 scrolling up at the bottom of the search history, and
1255 we need to make the string in currentbuf the current
1256 answer; do this, blow away currentbuf since we don't
1257 need it anymore, and reset use_cb to 0 */
1258 if (currentbuf != NULL && use_cb == 2 && strcmp(currentbuf, answer)) {
1259 answer = mallocstrcpy(answer, currentbuf);
1260 free(currentbuf);
1261 currentbuf = NULL;
1262 xend = strlen(answer);
1263 use_cb = 0;
1264
1265 /* else get older search from the history list and save
1266 it in answer; if there is no older search, blank out
1267 answer */
1268 } else if ((history = get_history_older(history_list)) != NULL) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001269 answer = mallocstrcpy(answer, history);
1270 xend = strlen(history);
1271 } else {
1272 answer = mallocstrcpy(answer, "");
1273 xend = 0;
1274 }
1275 x = xend;
1276 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001277#endif
Chris Allegretta54abd942003-01-09 23:43:12 +00001278 break;
David Lawrence Ramseyc2c5a512004-01-23 19:26:17 +00001279 case NANO_NEXTLINE_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001280#ifndef NANO_SMALL
Chris Allegretta09fc4302003-01-16 22:16:38 +00001281 if (history_list != NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001282
1283 /* get newer search from the history list and save it
1284 in answer */
Chris Allegretta7662c862003-01-13 01:35:15 +00001285 if ((history = get_history_newer(history_list)) != NULL) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001286 answer = mallocstrcpy(answer, history);
1287 xend = strlen(history);
Chris Allegretta8031f832003-01-09 05:29:58 +00001288
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001289 /* if there is no newer search, we're here */
1290
1291 /* if currentbuf isn't NULL and use_cb isn't 2, it means
1292 that we're scrolling down at the bottom of the search
1293 history and we need to make the string in currentbuf
1294 the current answer; do this, blow away currentbuf
1295 since we don't need it anymore, and set use_cb to
1296 1 */
1297 } else if (currentbuf != NULL && use_cb != 2) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001298 answer = mallocstrcpy(answer, currentbuf);
Chris Allegretta09fc4302003-01-16 22:16:38 +00001299 free(currentbuf);
1300 currentbuf = NULL;
1301 xend = strlen(answer);
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001302 use_cb = 1;
1303
1304 /* otherwise, if currentbuf is NULL and use_cb isn't 2,
1305 it means that we're scrolling down at the bottom of
Chris Allegrettac30fc242003-08-11 00:32:45 +00001306 the search history and the current answer (if it's
1307 not blank) needs to be saved in currentbuf; do this,
1308 blank out answer (if necessary), and set use_cb to
1309 2 */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001310 } else if (use_cb != 2) {
Chris Allegrettac30fc242003-08-11 00:32:45 +00001311 if (answer[0] != '\0') {
1312 currentbuf = mallocstrcpy(currentbuf, answer);
1313 answer = mallocstrcpy(answer, "");
1314 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001315 xend = 0;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001316 use_cb = 2;
Chris Allegretta5beed502003-01-05 20:41:21 +00001317 }
1318 x = xend;
1319 }
1320#endif
1321 break;
Chris Allegretta658399a2001-06-14 02:54:22 +00001322 default:
1323
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001324 for (t = s; t != NULL; t = t->next) {
Chris Allegretta658399a2001-06-14 02:54:22 +00001325#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001326 fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput,
Chris Allegretta598106e2002-01-19 01:59:37 +00001327 kbinput);
Chris Allegretta658399a2001-06-14 02:54:22 +00001328#endif
David Lawrence Ramsey82138502003-12-24 08:03:54 +00001329 if (meta == 1 && (kbinput == t->metaval || kbinput == t->misc))
1330 /* We hit a Meta key. Do like above. We don't
1331 * just ungetch() the letter and let it get
1332 * caught above cause that screws the
1333 * keypad... */
1334 return kbinput;
Chris Allegretta658399a2001-06-14 02:54:22 +00001335 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001336
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001337 if (is_cntrl_char(kbinput))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001338 break;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001339 answer = charealloc(answer, xend + 2);
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001340 charmove(answer + x + 1, answer + x, xend - x + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001341 xend++;
1342 answer[x] = kbinput;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001343 x++;
1344
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001345#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001346 fprintf(stderr, "input \'%c\' (%d)\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001347#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001348 } /* switch (kbinput) */
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001349#ifndef NANO_SMALL
Chris Allegretta5beed502003-01-05 20:41:21 +00001350 last_kbinput = kbinput;
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001351#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001352 nanoget_repaint(buf, answer, x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001353 wrefresh(bottomwin);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001354 } /* while (kbinput ...) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001355
Chris Allegretta5af58892003-01-17 21:07:38 +00001356 /* We finished putting in an answer; reset x */
1357 x = -1;
1358
Chris Allegretta7662c862003-01-13 01:35:15 +00001359 /* Just check for a blank answer here */
Chris Allegretta15c28f82003-01-05 21:47:06 +00001360 if (answer[0] == '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001361 return -2;
1362 else
1363 return 0;
1364}
1365
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001366/* If modified is not already set, set it and update titlebar. */
1367void set_modified(void)
1368{
1369 if (!ISSET(MODIFIED)) {
1370 SET(MODIFIED);
1371 titlebar(NULL);
1372 wrefresh(topwin);
1373 }
1374}
1375
Chris Allegrettaf717f982003-02-13 22:25:01 +00001376void titlebar(const char *path)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001377{
1378 int namelen, space;
Chris Allegrettaf717f982003-02-13 22:25:01 +00001379 const char *what = path;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001380
1381 if (path == NULL)
1382 what = filename;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001383
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001384 wattron(topwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001385
Chris Allegretta6df90f52002-07-19 01:08:59 +00001386 mvwaddstr(topwin, 0, 0, hblank);
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00001387 mvwaddnstr(topwin, 0, 2, VERMSG, COLS - 3);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001388
David Lawrence Ramseyec290f22003-08-30 19:05:40 +00001389 space = COLS - sizeof(VERMSG) - 23;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001390
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001391 namelen = strlen(what);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001392
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00001393 if (space > 0) {
1394 if (what[0] == '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001395 mvwaddnstr(topwin, 0, COLS / 2 - 6, _("New Buffer"),
1396 COLS / 2 + COLS % 2 - 6);
1397 else if (namelen > space) {
1398 if (path == NULL)
1399 waddstr(topwin, _(" File: ..."));
1400 else
1401 waddstr(topwin, _(" DIR: ..."));
1402 waddstr(topwin, &what[namelen - space]);
1403 } else {
1404 if (path == NULL)
1405 mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
1406 _("File: "));
1407 else
1408 mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
1409 _(" DIR: "));
1410 waddstr(topwin, what);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001411 }
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00001412 } /* If we don't have space, we shouldn't bother */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001413 if (ISSET(MODIFIED))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001414 mvwaddnstr(topwin, 0, COLS - 11, _(" Modified "), 11);
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001415 else if (ISSET(VIEW_MODE))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001416 mvwaddnstr(topwin, 0, COLS - 11, _(" View "), 11);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001417
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001418 wattroff(topwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001419
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001420 wrefresh(topwin);
1421 reset_cursor();
1422}
1423
Chris Allegretta6232d662002-05-12 19:52:15 +00001424void bottombars(const shortcut *s)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001425{
Chris Allegrettabc72e362002-02-16 20:03:44 +00001426 int i, j, numcols;
Chris Allegretta3bbc4162003-01-23 00:46:12 +00001427 char keystr[9];
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001428 int slen;
1429
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001430 if (ISSET(NO_HELP))
1431 return;
1432
Chris Allegretta6232d662002-05-12 19:52:15 +00001433 if (s == main_list) {
1434 slen = MAIN_VISIBLE;
1435 assert(MAIN_VISIBLE <= length_of_list(s));
1436 } else
1437 slen = length_of_list(s);
1438
Chris Allegretta6232d662002-05-12 19:52:15 +00001439 /* There will be this many columns of shortcuts */
1440 numcols = (slen + (slen % 2)) / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001441
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001442 blank_bottomwin();
Chris Allegretta658399a2001-06-14 02:54:22 +00001443
Chris Allegrettabc72e362002-02-16 20:03:44 +00001444 for (i = 0; i < numcols; i++) {
1445 for (j = 0; j <= 1; j++) {
Chris Allegretta658399a2001-06-14 02:54:22 +00001446
Chris Allegretta6232d662002-05-12 19:52:15 +00001447 wmove(bottomwin, 1 + j, i * (COLS / numcols));
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001448
Chris Allegretta5beed502003-01-05 20:41:21 +00001449 /* Yucky sentinel values we can't handle a better way */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001450 if (s->val != NANO_NO_KEY) {
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001451#ifndef NANO_SMALL
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001452 if (s->val == NANO_HISTORY_KEY)
1453 strncpy(keystr, _("Up"), 8);
Chris Allegretta6232d662002-05-12 19:52:15 +00001454 else
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001455#endif
1456 if (s->val == NANO_CONTROL_SPACE)
1457 strcpy(keystr, "^ ");
1458 else if (s->val == NANO_CONTROL_8)
1459 strcpy(keystr, "^?");
1460 else
1461 sprintf(keystr, "^%c", s->val + 64);
David Lawrence Ramsey82138502003-12-24 08:03:54 +00001462 } else if (s->metaval != NANO_NO_KEY)
1463 sprintf(keystr, "M-%c", toupper(s->metaval));
Chris Allegretta658399a2001-06-14 02:54:22 +00001464
Chris Allegretta6232d662002-05-12 19:52:15 +00001465 onekey(keystr, s->desc, COLS / numcols);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001466
Chris Allegretta6232d662002-05-12 19:52:15 +00001467 s = s->next;
1468 if (s == NULL)
1469 goto break_completely_out;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001470 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001471 }
1472
Chris Allegretta6df90f52002-07-19 01:08:59 +00001473 break_completely_out:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001474 wrefresh(bottomwin);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001475}
1476
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001477/* Write a shortcut key to the help area at the bottom of the window.
1478 * keystroke is e.g. "^G" and desc is e.g. "Get Help".
1479 * We are careful to write exactly len characters, even if len is
1480 * very small and keystroke and desc are long. */
Chris Allegrettaf717f982003-02-13 22:25:01 +00001481void onekey(const char *keystroke, const char *desc, int len)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001482{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001483 wattron(bottomwin, A_REVERSE);
1484 waddnstr(bottomwin, keystroke, len);
1485 wattroff(bottomwin, A_REVERSE);
1486 len -= strlen(keystroke);
1487 if (len > 0) {
1488 waddch(bottomwin, ' ');
1489 len--;
1490 waddnstr(bottomwin, desc, len);
1491 len -= strlen(desc);
1492 for (; len > 0; len--)
1493 waddch(bottomwin, ' ');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001494 }
1495}
1496
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001497/* And so start the display update routines. */
1498
1499#ifndef NDEBUG
1500int check_linenumbers(const filestruct *fileptr)
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001501{
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001502 int check_line = 0;
1503 const filestruct *filetmp;
Robert Siemborskid8510b22000-06-06 23:04:06 +00001504
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001505 for (filetmp = edittop; filetmp != fileptr; filetmp = filetmp->next)
1506 check_line++;
1507 return check_line;
Robert Siemborskid8510b22000-06-06 23:04:06 +00001508}
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001509#endif
Robert Siemborskid8510b22000-06-06 23:04:06 +00001510
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001511/* nano scrolls horizontally within a line in chunks. This function
1512 * returns the column number of the first character displayed in the
1513 * window when the cursor is at the given column. Note that
1514 * 0 <= column - get_page_start(column) < COLS. */
1515size_t get_page_start(size_t column)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001516{
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001517 assert(COLS > 0);
1518 if (column == 0 || column < COLS - 1)
1519 return 0;
1520 else if (COLS > 9)
David Lawrence Ramsey66081d42004-01-22 07:25:31 +00001521 return column - 7 - (column - 7) % (COLS - 8);
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001522 else if (COLS > 2)
1523 return column - (COLS - 2);
1524 else
1525 return column - (COLS - 1);
1526 /* The parentheses are necessary to avoid overflow. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001527}
1528
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001529/* Resets current_y, based on the position of current, and puts the
1530 * cursor at (current_y, current_x). */
1531void reset_cursor(void)
1532{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001533 /* Yuck. This condition can be true after open_file() when opening
1534 * the first file. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001535 if (edittop == NULL)
1536 return;
1537
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001538 current_y = current->lineno - edittop->lineno;
1539 if (current_y < editwinrows) {
1540 size_t x = xplustabs();
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001541
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001542 wmove(edit, current_y, x - get_page_start(x));
1543 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001544}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001545
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001546/* edit_add() takes care of the job of actually painting a line into the
1547 * edit window. fileptr is the line to be painted, at row yval of the
1548 * window. converted is the actual string to be written to the window,
1549 * with tabs and control characters replaced by strings of regular
1550 * characters. start is the column number of the first character
1551 * of this page. That is, the first character of converted corresponds to
1552 * character number actual_x(fileptr->data, start) of the line. */
1553void edit_add(const filestruct *fileptr, const char *converted,
1554 int yval, size_t start)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001555{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001556#if defined(ENABLE_COLOR) || !defined(NANO_SMALL)
1557 size_t startpos = actual_x(fileptr->data, start);
1558 /* The position in fileptr->data of the leftmost character
1559 * that displays at least partially on the window. */
1560 size_t endpos = actual_x(fileptr->data, start + COLS - 1) + 1;
1561 /* The position in fileptr->data of the first character that is
1562 * completely off the window to the right.
1563 *
1564 * Note that endpos might be beyond the null terminator of the
1565 * string. */
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001566#endif
1567
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001568 assert(fileptr != NULL && converted != NULL);
1569 assert(strlen(converted) <= COLS);
1570
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001571 /* Just paint the string in any case (we'll add color or reverse on
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001572 * just the text that needs it). */
1573 mvwaddstr(edit, yval, 0, converted);
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001574
Chris Allegretta7dd77682001-12-08 19:52:28 +00001575#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00001576 if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001577 const colortype *tmpcolor = colorstrings;
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001578
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001579 for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
1580 int x_start;
1581 /* Starting column for mvwaddnstr. Zero-based. */
1582 int paintlen;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001583 /* Number of chars to paint on this line. There are COLS
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001584 * characters on a whole line. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001585 regmatch_t startmatch; /* match position for start_regexp */
1586 regmatch_t endmatch; /* match position for end_regexp */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001587
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001588 if (tmpcolor->bright)
1589 wattron(edit, A_BOLD);
1590 wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001591 /* Two notes about regexec(). Return value 0 means there is
1592 * a match. Also, rm_eo is the first non-matching character
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001593 * after the match. */
1594
1595 /* First case, tmpcolor is a single-line expression. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001596 if (tmpcolor->end == NULL) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001597 size_t k = 0;
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001598
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001599 /* We increment k by rm_eo, to move past the end of the
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001600 * last match. Even though two matches may overlap, we
1601 * want to ignore them, so that we can highlight
1602 * C-strings correctly. */
1603 while (k < endpos) {
1604 /* Note the fifth parameter to regexec(). It says
1605 * not to match the beginning-of-line character
1606 * unless k is 0. If regexec() returns REG_NOMATCH,
1607 * there are no more matches in the line. */
Chris Allegrettace452fb2003-02-03 02:56:44 +00001608 if (regexec(&tmpcolor->start, &fileptr->data[k], 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001609 &startmatch, k == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001610 break;
1611 /* Translate the match to the beginning of the line. */
1612 startmatch.rm_so += k;
1613 startmatch.rm_eo += k;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001614 if (startmatch.rm_so == startmatch.rm_eo) {
1615 startmatch.rm_eo++;
Chris Allegretta7c27be42002-05-05 23:03:54 +00001616 statusbar(_("Refusing 0 length regex match"));
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001617 } else if (startmatch.rm_so < endpos &&
1618 startmatch.rm_eo > startpos) {
1619 if (startmatch.rm_so <= startpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001620 x_start = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001621 else
1622 x_start = strnlenpt(fileptr->data, startmatch.rm_so)
1623 - start;
1624 paintlen = strnlenpt(fileptr->data, startmatch.rm_eo)
1625 - start - x_start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001626 if (paintlen > COLS - x_start)
1627 paintlen = COLS - x_start;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001628
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001629 assert(0 <= x_start && 0 < paintlen &&
1630 x_start + paintlen <= COLS);
1631 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001632 converted + x_start, paintlen);
1633 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001634 k = startmatch.rm_eo;
Chris Allegretta598106e2002-01-19 01:59:37 +00001635 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001636 } else {
1637 /* This is a multi-line regexp. There are two steps.
1638 * First, we have to see if the beginning of the line is
1639 * colored by a start on an earlier line, and an end on
1640 * this line or later.
1641 *
1642 * We find the first line before fileptr matching the
1643 * start. If every match on that line is followed by an
1644 * end, then go to step two. Otherwise, find the next line
1645 * after start_line matching the end. If that line is not
1646 * before fileptr, then paint the beginning of this line. */
Chris Allegretta3674c1d2002-05-12 20:43:49 +00001647
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001648 const filestruct *start_line = fileptr->prev;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001649 /* the first line before fileptr matching start */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001650 regoff_t start_col;
1651 /* where it starts in that line */
1652 const filestruct *end_line;
1653 int searched_later_lines = 0;
1654 /* Used in step 2. Have we looked for an end on
1655 * lines after fileptr? */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001656
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001657 while (start_line != NULL &&
Chris Allegrettace452fb2003-02-03 02:56:44 +00001658 regexec(&tmpcolor->start, start_line->data, 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001659 &startmatch, 0) == REG_NOMATCH) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001660 /* If there is an end on this line, there is no need
1661 * to look for starts on earlier lines. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001662 if (regexec(tmpcolor->end, start_line->data, 0, NULL, 0)
1663 == 0)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001664 goto step_two;
1665 start_line = start_line->prev;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001666 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001667 /* No start found, so skip to the next step. */
1668 if (start_line == NULL)
1669 goto step_two;
1670 /* Now start_line is the first line before fileptr
1671 * containing a start match. Is there a start on this
1672 * line not followed by an end on this line? */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001673
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001674 start_col = 0;
1675 while (1) {
1676 start_col += startmatch.rm_so;
1677 startmatch.rm_eo -= startmatch.rm_so;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001678 if (regexec(tmpcolor->end,
1679 start_line->data + start_col + startmatch.rm_eo,
1680 0, NULL, start_col + startmatch.rm_eo == 0 ? 0 :
1681 REG_NOTBOL) == REG_NOMATCH)
1682 /* No end found after this start. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001683 break;
1684 start_col++;
Chris Allegrettace452fb2003-02-03 02:56:44 +00001685 if (regexec(&tmpcolor->start,
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001686 start_line->data + start_col, 1, &startmatch,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001687 REG_NOTBOL) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001688 /* No later start on this line. */
1689 goto step_two;
1690 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001691 /* Indeed, there is a start not followed on this line by
1692 * an end. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001693
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001694 /* We have already checked that there is no end before
1695 * fileptr and after the start. Is there an end after
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001696 * the start at all? We don't paint unterminated
1697 * starts. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001698 end_line = fileptr;
Chris Allegrettace452fb2003-02-03 02:56:44 +00001699 while (end_line != NULL &&
1700 regexec(tmpcolor->end, end_line->data, 1, &endmatch, 0))
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001701 end_line = end_line->next;
1702
1703 /* No end found, or it is too early. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001704 if (end_line == NULL ||
1705 (end_line == fileptr && endmatch.rm_eo <= startpos))
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001706 goto step_two;
1707
1708 /* Now paint the start of fileptr. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001709 paintlen = end_line != fileptr ? COLS :
1710 strnlenpt(fileptr->data, endmatch.rm_eo) - start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001711 if (paintlen > COLS)
1712 paintlen = COLS;
1713
1714 assert(0 < paintlen && paintlen <= COLS);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001715 mvwaddnstr(edit, yval, 0, converted, paintlen);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001716
1717 /* We have already painted the whole line. */
1718 if (paintlen == COLS)
1719 goto skip_step_two;
1720
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001721 step_two: /* Second step, we look for starts on this line. */
1722 start_col = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001723 while (start_col < endpos) {
Chris Allegrettace452fb2003-02-03 02:56:44 +00001724 if (regexec(&tmpcolor->start, fileptr->data + start_col, 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001725 &startmatch, start_col == 0 ? 0 : REG_NOTBOL)
1726 == REG_NOMATCH || start_col + startmatch.rm_so >=
1727 endpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001728 /* No more starts on this line. */
1729 break;
1730 /* Translate the match to be relative to the
1731 * beginning of the line. */
1732 startmatch.rm_so += start_col;
1733 startmatch.rm_eo += start_col;
1734
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001735 if (startmatch.rm_so <= startpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001736 x_start = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001737 else
1738 x_start = strnlenpt(fileptr->data, startmatch.rm_so)
1739 - start;
1740 if (regexec(tmpcolor->end, fileptr->data + startmatch.rm_eo,
1741 1, &endmatch, startmatch.rm_eo == 0 ? 0 :
1742 REG_NOTBOL) == 0) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001743 /* Translate the end match to be relative to the
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001744 * beginning of the line. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001745 endmatch.rm_so += startmatch.rm_eo;
1746 endmatch.rm_eo += startmatch.rm_eo;
1747 /* There is an end on this line. But does it
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001748 * appear on this page, and is the match more than
1749 * zero characters long? */
1750 if (endmatch.rm_eo > startpos &&
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001751 endmatch.rm_eo > startmatch.rm_so) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001752 paintlen = strnlenpt(fileptr->data, endmatch.rm_eo)
1753 - start - x_start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001754 if (x_start + paintlen > COLS)
1755 paintlen = COLS - x_start;
1756
1757 assert(0 <= x_start && 0 < paintlen &&
1758 x_start + paintlen <= COLS);
1759 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001760 converted + x_start, paintlen);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001761 }
1762 } else if (!searched_later_lines) {
1763 searched_later_lines = 1;
1764 /* There is no end on this line. But we haven't
1765 * yet looked for one on later lines. */
1766 end_line = fileptr->next;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001767 while (end_line != NULL &&
1768 regexec(tmpcolor->end, end_line->data, 0,
1769 NULL, 0) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001770 end_line = end_line->next;
1771 if (end_line != NULL) {
1772 assert(0 <= x_start && x_start < COLS);
1773 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001774 converted + x_start,
1775 COLS - x_start);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001776 /* We painted to the end of the line, so
1777 * don't bother checking any more starts. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001778 break;
Chris Allegretta3674c1d2002-05-12 20:43:49 +00001779 }
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001780 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001781 start_col = startmatch.rm_so + 1;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001782 } /* while start_col < endpos */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001783 } /* if (tmp_color->end != NULL) */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001784
Chris Allegrettace452fb2003-02-03 02:56:44 +00001785 skip_step_two:
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001786 wattroff(edit, A_BOLD);
1787 wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
1788 } /* for tmpcolor in colorstrings */
1789 }
Chris Allegretta598106e2002-01-19 01:59:37 +00001790#endif /* ENABLE_COLOR */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001791
Chris Allegretta7dd77682001-12-08 19:52:28 +00001792#ifndef NANO_SMALL
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001793 if (ISSET(MARK_ISSET)
1794 && (fileptr->lineno <= mark_beginbuf->lineno
1795 || fileptr->lineno <= current->lineno)
1796 && (fileptr->lineno >= mark_beginbuf->lineno
1797 || fileptr->lineno >= current->lineno)) {
1798 /* fileptr is at least partially selected. */
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001799
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001800 const filestruct *top;
1801 /* Either current or mark_beginbuf, whichever is first. */
1802 size_t top_x;
1803 /* current_x or mark_beginx, corresponding to top. */
1804 const filestruct *bot;
1805 size_t bot_x;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001806 int x_start;
1807 /* Starting column for mvwaddnstr. Zero-based. */
1808 int paintlen;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001809 /* Number of chars to paint on this line. There are COLS
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001810 * characters on a whole line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001811
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001812 mark_order(&top, &top_x, &bot, &bot_x);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001813
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001814 if (top->lineno < fileptr->lineno || top_x < startpos)
1815 top_x = startpos;
1816 if (bot->lineno > fileptr->lineno || bot_x > endpos)
1817 bot_x = endpos;
1818
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001819 /* The selected bit of fileptr is on this page. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001820 if (top_x < endpos && bot_x > startpos) {
1821 assert(startpos <= top_x);
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001822
1823 /* x_start is the expanded location of the beginning of the
1824 * mark minus the beginning of the page. */
1825 x_start = strnlenpt(fileptr->data, top_x) - start;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001826
1827 if (bot_x >= endpos)
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001828 /* If the end of the mark is off the page, paintlen is
1829 * -1, meaning that everything on the line gets
1830 * painted. */
1831 paintlen = -1;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001832 else
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001833 /* Otherwise, paintlen is the expanded location of the
1834 * end of the mark minus the expanded location of the
1835 * beginning of the mark. */
1836 paintlen = strnlenpt(fileptr->data, bot_x) - (x_start +
1837 start);
1838
1839 /* If x_start is before the beginning of the page, shift
1840 * paintlen x_start characters to compensate, and put
1841 * x_start at the beginning of the page. */
1842 if (x_start < 0) {
1843 paintlen += x_start;
1844 x_start = 0;
1845 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001846
1847 assert(x_start >= 0 && x_start <= strlen(converted));
1848
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001849 wattron(edit, A_REVERSE);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001850 mvwaddnstr(edit, yval, x_start, converted + x_start, paintlen);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001851 wattroff(edit, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001852 }
Chris Allegretta08893e02001-11-29 02:42:27 +00001853 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001854#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001855}
1856
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001857/* Just update one line in the edit buffer. Basically a wrapper for
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001858 * edit_add().
1859 *
1860 * If fileptr != current, then index is considered 0.
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001861 * The line will be displayed starting with fileptr->data[index].
1862 * Likely args are current_x or 0. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001863void update_line(const filestruct *fileptr, size_t index)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001864{
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001865 int line;
1866 /* line in the edit window for CURSES calls */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001867 char *converted;
1868 /* fileptr->data converted to have tabs and control characters
1869 * expanded. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001870 size_t page_start;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001871
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001872 assert(fileptr != NULL);
Robert Siemborski53154a72000-06-18 00:11:03 +00001873
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001874 line = fileptr->lineno - edittop->lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001875
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001876 /* We assume the line numbers are valid. Is that really true? */
1877 assert(line < 0 || line == check_linenumbers(fileptr));
1878
1879 if (line < 0 || line >= editwinrows)
1880 return;
1881
1882 /* First, blank out the line (at a minimum) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001883 mvwaddstr(edit, line, 0, hblank);
1884
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001885 /* Next, convert variables that index the line to their equivalent
1886 * positions in the expanded line. */
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001887 index = (fileptr == current) ? strnlenpt(fileptr->data, index) : 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001888 page_start = get_page_start(index);
Chris Allegretta5beed502003-01-05 20:41:21 +00001889
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001890 /* Expand the line, replacing Tab by spaces, and control characters
1891 * by their display form. */
1892 converted = display_string(fileptr->data, page_start, COLS);
Robert Siemborski53875912000-06-16 04:25:30 +00001893
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001894 /* Now, paint the line */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001895 edit_add(fileptr, converted, line, page_start);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001896 free(converted);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001897
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001898 if (page_start > 0)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001899 mvwaddch(edit, line, 0, '$');
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001900 if (strlenpt(fileptr->data) > page_start + COLS)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001901 mvwaddch(edit, line, COLS - 1, '$');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001902}
1903
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001904/* This function updates current, based on where current_y is;
1905 * reset_cursor() does the opposite. */
1906void update_cursor(void)
1907{
1908 int i = 0;
1909
1910#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001911 fprintf(stderr, "Moved to (%d, %d) in edit buffer\n", current_y,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001912 current_x);
1913#endif
1914
1915 current = edittop;
1916 while (i < current_y && current->next != NULL) {
1917 current = current->next;
1918 i++;
1919 }
1920
1921#ifdef DEBUG
Chris Allegretta0e86e602003-01-23 04:27:23 +00001922 fprintf(stderr, "current->data = \"%s\"\n", current->data);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001923#endif
1924}
1925
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001926void center_cursor(void)
1927{
1928 current_y = editwinrows / 2;
1929 wmove(edit, current_y, current_x);
1930}
1931
Chris Allegretta6df90f52002-07-19 01:08:59 +00001932/* Refresh the screen without changing the position of lines. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001933void edit_refresh(void)
1934{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001935 /* Neither of these conditions should occur, but they do. edittop
1936 * is NULL when you open an existing file on the command line, and
Chris Allegretta6df90f52002-07-19 01:08:59 +00001937 * ENABLE_COLOR is defined. Yuck. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001938 if (current == NULL)
1939 return;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001940 if (edittop == NULL)
1941 edittop = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001942
Chris Allegretta63d0b482003-01-26 19:47:10 +00001943 if (current->lineno < edittop->lineno ||
1944 current->lineno >= edittop->lineno + editwinrows)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001945 /* Note that edit_update() changes edittop so that
1946 * current->lineno = edittop->lineno + editwinrows / 2. Thus
1947 * when it then calls edit_refresh(), there is no danger of
1948 * getting an infinite loop. */
Chris Allegrettada721be2000-07-31 01:26:42 +00001949 edit_update(current, CENTER);
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001950 else {
1951 int nlines = 0;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001952 const filestruct *foo = edittop;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001953
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001954#ifdef DEBUG
1955 fprintf(stderr, "edit_refresh(): edittop->lineno = %ld\n", edittop->lineno);
1956#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001957
David Lawrence Ramseyb55e3822004-02-25 06:25:12 +00001958 /* Don't let the cursor jump around the screen while
1959 * updating. */
1960 leaveok(edit, TRUE);
1961
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001962 while (nlines < editwinrows) {
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001963 update_line(foo, current_x);
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001964 nlines++;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001965 if (foo->next == NULL)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001966 break;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001967 foo = foo->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001968 }
1969 while (nlines < editwinrows) {
1970 mvwaddstr(edit, nlines, 0, hblank);
1971 nlines++;
1972 }
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001973 reset_cursor();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001974 /* What the hell are we expecting to update the screen if this
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001975 * isn't here? Luck? */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001976 wrefresh(edit);
David Lawrence Ramseyb55e3822004-02-25 06:25:12 +00001977
1978 /* Let the cursor jump around the screen again. */
1979 leaveok(edit, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001980 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001981}
1982
Chris Allegretta7662c862003-01-13 01:35:15 +00001983/* Same as above, but touch the window first, so everything is
1984 * redrawn. */
Chris Allegrettaf1d33d32000-08-19 03:53:39 +00001985void edit_refresh_clearok(void)
1986{
1987 clearok(edit, TRUE);
1988 edit_refresh();
1989 clearok(edit, FALSE);
1990}
1991
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001992/* Nice generic routine to update the edit buffer, given a pointer to the
1993 * file struct =) */
David Lawrence Ramsey1356a0a2003-09-10 20:31:02 +00001994void edit_update(filestruct *fileptr, topmidnone location)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001995{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001996 if (fileptr == NULL)
1997 return;
1998
Chris Allegretta6df90f52002-07-19 01:08:59 +00001999 if (location != TOP) {
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00002000 int goal = location == NONE ? current_y : editwinrows / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002001
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00002002 for (; goal > 0 && fileptr->prev != NULL; goal--)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002003 fileptr = fileptr->prev;
2004 }
2005 edittop = fileptr;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002006 edit_refresh();
2007}
2008
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002009/* Ask a question on the statusbar. Answer will be stored in answer
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002010 * global. Returns -1 on aborted enter, -2 on a blank string, and 0
Chris Allegretta88520c92001-05-05 17:45:54 +00002011 * otherwise, the valid shortcut key caught. Def is any editable text we
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002012 * want to put up by default.
Chris Allegretta7da4e9f2000-11-06 02:57:22 +00002013 *
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002014 * New arg tabs tells whether or not to allow tab completion. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002015int statusq(int tabs, const shortcut *s, const char *def,
Chris Allegretta5beed502003-01-05 20:41:21 +00002016#ifndef NANO_SMALL
2017 historyheadtype *which_history,
2018#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002019 const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002020{
2021 va_list ap;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002022 char *foo = charalloc(COLS - 3);
Chris Allegretta9caa1932002-02-15 20:08:05 +00002023 int ret;
Chris Allegretta2084acc2001-11-29 03:43:08 +00002024#ifndef DISABLE_TABCOMP
Chris Allegrettaa16e4e92002-01-05 18:59:54 +00002025 int list = 0;
Chris Allegretta2084acc2001-11-29 03:43:08 +00002026#endif
2027
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002028 bottombars(s);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002029
2030 va_start(ap, msg);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002031 vsnprintf(foo, COLS - 4, msg, ap);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002032 va_end(ap);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002033 foo[COLS - 4] = '\0';
Chris Allegretta8ce24132001-04-30 11:28:46 +00002034
Chris Allegretta5beed502003-01-05 20:41:21 +00002035 ret = nanogetstr(tabs, foo, def,
2036#ifndef NANO_SMALL
2037 which_history,
Chris Allegretta2084acc2001-11-29 03:43:08 +00002038#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00002039 s
2040#ifndef DISABLE_TABCOMP
2041 , &list
2042#endif
Chris Allegretta65f075d2003-02-13 03:03:49 +00002043 );
Chris Allegretta6df90f52002-07-19 01:08:59 +00002044 free(foo);
Chris Allegretta65f075d2003-02-13 03:03:49 +00002045 resetstatuspos = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002046
2047 switch (ret) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002048 case NANO_FIRSTLINE_KEY:
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00002049 case NANO_FIRSTLINE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002050 do_first_line();
Chris Allegretta65f075d2003-02-13 03:03:49 +00002051 resetstatuspos = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002052 break;
2053 case NANO_LASTLINE_KEY:
David Lawrence Ramseyd7f5ad92004-03-04 19:30:53 +00002054 case NANO_LASTLINE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002055 do_last_line();
Chris Allegretta65f075d2003-02-13 03:03:49 +00002056 resetstatuspos = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002057 break;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002058#ifndef DISABLE_JUSTIFY
2059 case NANO_PARABEGIN_KEY:
David Lawrence Ramsey795a16b2004-02-07 05:03:25 +00002060 case NANO_PARABEGIN_ALTKEY:
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002061 do_para_begin();
2062 resetstatuspos = 1;
2063 break;
2064 case NANO_PARAEND_KEY:
David Lawrence Ramsey795a16b2004-02-07 05:03:25 +00002065 case NANO_PARAEND_ALTKEY:
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002066 do_para_end();
2067 resetstatuspos = 1;
2068 break;
2069#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002070 case NANO_CANCEL_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002071 ret = -1;
Chris Allegretta65f075d2003-02-13 03:03:49 +00002072 resetstatuspos = 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002073 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002074 }
Chris Allegrettaa90d0cf2003-02-10 02:55:03 +00002075 blank_statusbar();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002076
2077#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00002078 fprintf(stderr, "I got \"%s\"\n", answer);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002079#endif
2080
Chris Allegretta6df90f52002-07-19 01:08:59 +00002081#ifndef DISABLE_TABCOMP
2082 /* if we've done tab completion, there might be a list of
2083 filename matches on the edit window at this point; make sure
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002084 they're cleared off. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002085 if (list)
2086 edit_refresh();
2087#endif
2088
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002089 return ret;
2090}
2091
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002092/* Ask a simple yes/no question on the statusbar. Returns 1 for Y, 0
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002093 * for N, 2 for All (if all is nonzero when passed in) and -1 for abort
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002094 * (^C). */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002095int do_yesno(int all, const char *msg)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002096{
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002097 int ok = -2, width = 16;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002098 const char *yesstr; /* String of yes characters accepted */
2099 const char *nostr; /* Same for no */
2100 const char *allstr; /* And all, surprise! */
Chris Allegretta235ab192001-04-12 13:24:40 +00002101
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002102 /* Yes, no and all are strings of any length. Each string consists
2103 * of all characters accepted as a valid character for that value.
2104 * The first value will be the one displayed in the shortcuts. */
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002105 yesstr = _("Yy");
2106 nostr = _("Nn");
2107 allstr = _("Aa");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002108
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002109 /* Remove gettext call for keybindings until we clear the thing
2110 * up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002111 if (!ISSET(NO_HELP)) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002112 char shortstr[3]; /* Temp string for Y, N, A. */
Chris Allegretta6232d662002-05-12 19:52:15 +00002113
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002114 if (COLS < 32)
2115 width = COLS / 2;
2116
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002117 /* Write the bottom of the screen. */
Chris Allegrettadb28e962003-01-28 01:23:40 +00002118 blank_bottombars();
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002119
Chris Allegretta6232d662002-05-12 19:52:15 +00002120 sprintf(shortstr, " %c", yesstr[0]);
Chris Allegrettadb28e962003-01-28 01:23:40 +00002121 wmove(bottomwin, 1, 0);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002122 onekey(shortstr, _("Yes"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002123
2124 if (all) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002125 wmove(bottomwin, 1, width);
Chris Allegretta6232d662002-05-12 19:52:15 +00002126 shortstr[1] = allstr[0];
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002127 onekey(shortstr, _("All"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002128 }
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002129
Chris Allegrettadb28e962003-01-28 01:23:40 +00002130 wmove(bottomwin, 2, 0);
Chris Allegretta6232d662002-05-12 19:52:15 +00002131 shortstr[1] = nostr[0];
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002132 onekey(shortstr, _("No"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002133
Chris Allegrettadb28e962003-01-28 01:23:40 +00002134 wmove(bottomwin, 2, 16);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002135 onekey("^C", _("Cancel"), width);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002136 }
Chris Allegrettadb28e962003-01-28 01:23:40 +00002137
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002138 wattron(bottomwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002139
2140 blank_statusbar();
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002141 mvwaddnstr(bottomwin, 0, 0, msg, COLS - 1);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002142
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002143 wattroff(bottomwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002144
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002145 wrefresh(bottomwin);
2146
Chris Allegrettadb28e962003-01-28 01:23:40 +00002147 do {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002148 int kbinput;
2149 int meta;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002150#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002151 int mouse_x, mouse_y;
Chris Allegretta235ab192001-04-12 13:24:40 +00002152#endif
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002153
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002154 kbinput = get_kbinput(edit, &meta);
2155
2156 if (kbinput == NANO_CANCEL_KEY)
Chris Allegrettadb28e962003-01-28 01:23:40 +00002157 ok = -1;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002158#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002159 /* Look ma! We get to duplicate lots of code from
2160 * do_mouse()!! */
2161 else if (kbinput == KEY_MOUSE) {
2162 kbinput = get_mouseinput(&mouse_x, &mouse_y, 0);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002163
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002164 if (mouse_x != -1 && mouse_y != -1 && !ISSET(NO_HELP) &&
2165 wenclose(bottomwin, mouse_y, mouse_x) && mouse_x <
2166 (width * 2) && mouse_y >= editwinrows + 3) {
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00002167
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002168 int x = mouse_x / width;
2169 /* Did we click in the first column of shortcuts, or
2170 * the second? */
2171 int y = mouse_y - editwinrows - 3;
2172 /* Did we click in the first row of shortcuts? */
2173
2174 assert(0 <= x && x <= 1 && 0 <= y && y <= 1);
2175
2176 /* x = 0 means they clicked Yes or No.
2177 * y = 0 means Yes or All. */
2178 ok = -2 * x * y + x - y + 1;
2179
2180 if (ok == 2 && !all)
2181 ok = -2;
2182 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002183 }
Chris Allegrettadb28e962003-01-28 01:23:40 +00002184#endif
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002185 /* Look for the kbinput in the yes, no and (optionally) all
2186 * str. */
Chris Allegrettadb28e962003-01-28 01:23:40 +00002187 else if (strchr(yesstr, kbinput) != NULL)
2188 ok = 1;
2189 else if (strchr(nostr, kbinput) != NULL)
2190 ok = 0;
2191 else if (all && strchr(allstr, kbinput) != NULL)
2192 ok = 2;
2193 } while (ok == -2);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002194
Chris Allegrettadb28e962003-01-28 01:23:40 +00002195 return ok;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002196}
2197
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002198int total_refresh(void)
2199{
2200 clearok(edit, TRUE);
2201 clearok(topwin, TRUE);
2202 clearok(bottomwin, TRUE);
2203 wnoutrefresh(edit);
2204 wnoutrefresh(topwin);
2205 wnoutrefresh(bottomwin);
2206 doupdate();
2207 clearok(edit, FALSE);
2208 clearok(topwin, FALSE);
2209 clearok(bottomwin, FALSE);
2210 edit_refresh();
2211 titlebar(NULL);
2212 return 1;
2213}
2214
2215void display_main_list(void)
2216{
2217 bottombars(main_list);
2218}
2219
Chris Allegretta6df90f52002-07-19 01:08:59 +00002220void statusbar(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002221{
2222 va_list ap;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002223
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002224 va_start(ap, msg);
2225
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002226 /* Curses mode is turned off. If we use wmove() now, it will muck
2227 * up the terminal settings. So we just use vfprintf(). */
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002228 if (curses_ended) {
2229 vfprintf(stderr, msg, ap);
2230 va_end(ap);
2231 return;
2232 }
2233
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002234 /* Blank out the line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002235 blank_statusbar();
2236
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002237 if (COLS >= 4) {
2238 char *bar;
2239 char *foo;
2240 int start_x = 0;
2241 size_t foo_len;
2242 bar = charalloc(COLS - 3);
2243 vsnprintf(bar, COLS - 3, msg, ap);
2244 va_end(ap);
2245 foo = display_string(bar, 0, COLS - 4);
2246 free(bar);
2247 foo_len = strlen(foo);
2248 start_x = (COLS - foo_len - 4) / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002249
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002250 wmove(bottomwin, 0, start_x);
2251 wattron(bottomwin, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002252
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002253 waddstr(bottomwin, "[ ");
2254 waddstr(bottomwin, foo);
2255 free(foo);
2256 waddstr(bottomwin, " ]");
2257 wattroff(bottomwin, A_REVERSE);
2258 wnoutrefresh(bottomwin);
2259 wrefresh(edit);
2260 /* Leave the cursor at its position in the edit window, not
2261 * in the statusbar. */
2262 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002263
Chris Allegrettad26ab912003-01-28 01:16:47 +00002264 SET(DISABLE_CURPOS);
2265 statblank = 26;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002266}
2267
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002268/* If constant is false, the user typed ^C so we unconditionally display
Chris Allegrettad26ab912003-01-28 01:16:47 +00002269 * the cursor position. Otherwise, we display it only if the character
2270 * position changed, and DISABLE_CURPOS is not set.
2271 *
2272 * If constant and DISABLE_CURPOS is set, we unset it and update old_i and
2273 * old_totsize. That way, we leave the current statusbar alone, but next
2274 * time we will display. */
Chris Allegretta2084acc2001-11-29 03:43:08 +00002275int do_cursorpos(int constant)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002276{
Chris Allegrettad26ab912003-01-28 01:16:47 +00002277 const filestruct *fileptr;
2278 unsigned long i = 0;
2279 static unsigned long old_i = 0;
2280 static long old_totsize = -1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002281
Chris Allegrettad26ab912003-01-28 01:16:47 +00002282 assert(current != NULL && fileage != NULL && totlines != 0);
Chris Allegretta2084acc2001-11-29 03:43:08 +00002283
2284 if (old_totsize == -1)
2285 old_totsize = totsize;
2286
Chris Allegrettad26ab912003-01-28 01:16:47 +00002287 for (fileptr = fileage; fileptr != current; fileptr = fileptr->next) {
2288 assert(fileptr != NULL);
Chris Allegrettaf27c6972002-02-12 01:57:24 +00002289 i += strlen(fileptr->data) + 1;
Chris Allegrettad26ab912003-01-28 01:16:47 +00002290 }
Chris Allegrettaf27c6972002-02-12 01:57:24 +00002291 i += current_x;
Chris Allegretta14b3ca92002-01-25 21:59:02 +00002292
Chris Allegrettad26ab912003-01-28 01:16:47 +00002293 if (constant && ISSET(DISABLE_CURPOS)) {
2294 UNSET(DISABLE_CURPOS);
2295 old_i = i;
2296 old_totsize = totsize;
2297 return 0;
2298 }
Chris Allegretta14b3ca92002-01-25 21:59:02 +00002299
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002300 /* If constant is false, display the position on the statusbar
2301 * unconditionally; otherwise, only display the position when the
2302 * character values have changed. */
Chris Allegrettad26ab912003-01-28 01:16:47 +00002303 if (!constant || old_i != i || old_totsize != totsize) {
2304 unsigned long xpt = xplustabs() + 1;
2305 unsigned long cur_len = strlenpt(current->data) + 1;
2306 int linepct = 100 * current->lineno / totlines;
2307 int colpct = 100 * xpt / cur_len;
2308 int bytepct = totsize == 0 ? 0 : 100 * i / totsize;
2309
2310 statusbar(
2311 _("line %ld/%ld (%d%%), col %lu/%lu (%d%%), char %lu/%ld (%d%%)"),
2312 current->lineno, totlines, linepct,
2313 xpt, cur_len, colpct,
2314 i, totsize, bytepct);
2315 UNSET(DISABLE_CURPOS);
Chris Allegretta2084acc2001-11-29 03:43:08 +00002316 }
2317
2318 old_i = i;
2319 old_totsize = totsize;
2320
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002321 reset_cursor();
Chris Allegrettad26ab912003-01-28 01:16:47 +00002322 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002323}
2324
Chris Allegretta2084acc2001-11-29 03:43:08 +00002325int do_cursorpos_void(void)
2326{
2327 return do_cursorpos(0);
2328}
2329
Chris Allegretta4640fe32003-02-10 03:10:03 +00002330/* Calculate the next line of help_text, starting at ptr. */
2331int line_len(const char *ptr)
2332{
2333 int j = 0;
2334
2335 while (*ptr != '\n' && *ptr != '\0' && j < COLS - 5) {
2336 ptr++;
2337 j++;
2338 }
2339 if (j == COLS - 5) {
2340 /* Don't wrap at the first of two spaces following a period. */
2341 if (*ptr == ' ' && *(ptr + 1) == ' ')
2342 j++;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002343 /* Don't print half a word if we've run out of space. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00002344 while (*ptr != ' ' && j > 0) {
2345 ptr--;
2346 j--;
2347 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002348 /* Word longer than COLS - 5 chars just gets broken. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00002349 if (j == 0)
2350 j = COLS - 5;
2351 }
2352 assert(j >= 0 && j <= COLS - 4 && (j > 0 || *ptr == '\n'));
2353 return j;
2354}
2355
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002356/* Our shortcut-list-compliant help function, which is better than
2357 * nothing, and dynamic! */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002358int do_help(void)
2359{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002360#ifndef DISABLE_HELP
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00002361 int i, page = 0, kbinput = -1, meta, no_more = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002362 int no_help_flag = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002363 const shortcut *oldshortcut;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002364
2365 blank_edit();
2366 curs_set(0);
Chris Allegrettab3655b42001-10-22 03:15:31 +00002367 wattroff(bottomwin, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002368 blank_statusbar();
2369
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002370 /* Set help_text as the string to display. */
Chris Allegrettab3655b42001-10-22 03:15:31 +00002371 help_init();
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002372 assert(help_text != NULL);
Chris Allegrettab3655b42001-10-22 03:15:31 +00002373
2374 oldshortcut = currshortcut;
Chris Allegrettab3655b42001-10-22 03:15:31 +00002375
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002376 currshortcut = help_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00002377
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002378 if (ISSET(NO_HELP)) {
2379
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002380 /* Well, if we're going to do this, we should at least do it the
2381 * right way. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002382 no_help_flag = 1;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002383 UNSET(NO_HELP);
Chris Allegretta70444892001-01-07 23:02:02 +00002384 window_init();
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002385 bottombars(help_list);
Chris Allegretta70444892001-01-07 23:02:02 +00002386
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002387 } else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002388 bottombars(help_list);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002389
2390 do {
Chris Allegrettaf717f982003-02-13 22:25:01 +00002391 const char *ptr = help_text;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002392
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002393 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002394#ifndef DISABLE_MOUSE
Chris Allegretta598106e2002-01-19 01:59:37 +00002395 case KEY_MOUSE:
2396 do_mouse();
2397 break;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002398#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002399 case NANO_NEXTPAGE_KEY:
2400 case NANO_NEXTPAGE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002401 if (!no_more) {
2402 blank_edit();
2403 page++;
2404 }
2405 break;
2406 case NANO_PREVPAGE_KEY:
2407 case NANO_PREVPAGE_FKEY:
Chris Allegretta4640fe32003-02-10 03:10:03 +00002408 if (page > 0) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002409 no_more = 0;
2410 blank_edit();
2411 page--;
2412 }
2413 break;
2414 }
2415
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002416 /* Calculate where in the text we should be, based on the
2417 * page. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00002418 for (i = 1; i < page * (editwinrows - 1); i++) {
2419 ptr += line_len(ptr);
2420 if (*ptr == '\n')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002421 ptr++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002422 }
2423
Chris Allegretta4640fe32003-02-10 03:10:03 +00002424 for (i = 0; i < editwinrows && *ptr != '\0'; i++) {
2425 int j = line_len(ptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002426
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002427 mvwaddnstr(edit, i, 0, ptr, j);
Chris Allegretta4640fe32003-02-10 03:10:03 +00002428 ptr += j;
2429 if (*ptr == '\n')
2430 ptr++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002431 }
Chris Allegretta4640fe32003-02-10 03:10:03 +00002432
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002433 if (*ptr == '\0') {
2434 no_more = 1;
2435 continue;
2436 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002437 } while ((kbinput = get_kbinput(edit, &meta)) != NANO_EXIT_KEY && kbinput != NANO_EXIT_FKEY);
Chris Allegrettad1627cf2000-12-18 05:03:16 +00002438
Chris Allegrettab3655b42001-10-22 03:15:31 +00002439 currshortcut = oldshortcut;
Chris Allegrettab3655b42001-10-22 03:15:31 +00002440
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002441 if (no_help_flag) {
Chris Allegretta70444892001-01-07 23:02:02 +00002442 blank_bottombars();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002443 wrefresh(bottomwin);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002444 SET(NO_HELP);
Chris Allegretta70444892001-01-07 23:02:02 +00002445 window_init();
Chris Allegretta598106e2002-01-19 01:59:37 +00002446 } else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002447 bottombars(currshortcut);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002448
2449 curs_set(1);
2450 edit_refresh();
Chris Allegrettac08f50d2001-01-06 18:12:43 +00002451
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002452 /* The help_init() at the beginning allocated help_text, which has
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002453 * now been written to the screen. */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002454 free(help_text);
2455 help_text = NULL;
2456
Chris Allegretta6df90f52002-07-19 01:08:59 +00002457#elif defined(DISABLE_HELP)
2458 nano_disabled_msg();
2459#endif
2460
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002461 return 1;
2462}
2463
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002464/* Highlight the current word being replaced or spell checked. We
2465 * expect word to have tabs and control characters expanded. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002466void do_replace_highlight(int highlight_flag, const char *word)
Chris Allegrettafb62f732000-12-05 11:36:41 +00002467{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002468 int y = xplustabs();
2469 size_t word_len = strlen(word);
Chris Allegrettafb62f732000-12-05 11:36:41 +00002470
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002471 y = get_page_start(y) + COLS - y;
2472 /* Now y is the number of characters we can display on this
2473 * line. */
Chris Allegrettafb62f732000-12-05 11:36:41 +00002474
2475 reset_cursor();
Chris Allegretta598106e2002-01-19 01:59:37 +00002476
Chris Allegrettafb62f732000-12-05 11:36:41 +00002477 if (highlight_flag)
2478 wattron(edit, A_REVERSE);
2479
David Lawrence Ramsey2a4ab6d2003-12-24 08:29:49 +00002480#ifdef HAVE_REGEX_H
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00002481 /* This is so we can show zero-length regexes. */
2482 if (word_len == 0)
2483 waddstr(edit, " ");
2484 else
David Lawrence Ramsey2a4ab6d2003-12-24 08:29:49 +00002485#endif
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00002486 waddnstr(edit, word, y - 1);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002487
2488 if (word_len > y)
2489 waddch(edit, '$');
2490 else if (word_len == y)
2491 waddch(edit, word[word_len - 1]);
Chris Allegrettafb62f732000-12-05 11:36:41 +00002492
2493 if (highlight_flag)
2494 wattroff(edit, A_REVERSE);
Chris Allegrettafb62f732000-12-05 11:36:41 +00002495}
2496
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002497/* Fix editbot, based on the assumption that edittop is correct. */
2498void fix_editbot(void)
2499{
2500 int i;
2501
2502 editbot = edittop;
2503 for (i = 0; i < editwinrows && editbot->next != NULL; i++)
2504 editbot = editbot->next;
2505}
2506
2507#ifdef DEBUG
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002508/* Dump the passed-in file structure to stderr. */
2509void dump_buffer(const filestruct *inptr)
2510{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002511 if (inptr == fileage)
Jordi Mallachf9390af2003-08-05 19:31:12 +00002512 fprintf(stderr, "Dumping file buffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002513 else if (inptr == cutbuffer)
Jordi Mallachf9390af2003-08-05 19:31:12 +00002514 fprintf(stderr, "Dumping cutbuffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002515 else
Jordi Mallachf9390af2003-08-05 19:31:12 +00002516 fprintf(stderr, "Dumping a buffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002517
2518 while (inptr != NULL) {
2519 fprintf(stderr, "(%d) %s\n", inptr->lineno, inptr->data);
2520 inptr = inptr->next;
2521 }
2522}
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002523
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002524/* Dump the file structure to stderr in reverse. */
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00002525void dump_buffer_reverse(void)
2526{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002527 const filestruct *fileptr = filebot;
2528
2529 while (fileptr != NULL) {
2530 fprintf(stderr, "(%d) %s\n", fileptr->lineno, fileptr->data);
2531 fileptr = fileptr->prev;
2532 }
2533}
2534#endif /* DEBUG */
2535
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002536#ifdef NANO_EXTRA
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002537#define CREDIT_LEN 53
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002538#define XLCREDIT_LEN 8
2539
David Lawrence Ramseyfdece462004-01-19 18:15:03 +00002540/* Easter egg: Display credits. Assume nodelay(edit) is FALSE. */
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002541void do_credits(void)
2542{
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002543 int i, j = 0, k, place = 0, start_x;
David Lawrence Ramseye97c8d52004-01-14 19:26:29 +00002544 struct timespec scrolldelay;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002545
Chris Allegrettaf717f982003-02-13 22:25:01 +00002546 const char *what;
2547 const char *xlcredits[XLCREDIT_LEN];
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002548
Chris Allegrettaf717f982003-02-13 22:25:01 +00002549 const char *credits[CREDIT_LEN] = {
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002550 "0", /* "The nano text editor" */
2551 "1", /* "version" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002552 VERSION,
2553 "",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002554 "2", /* "Brought to you by:" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002555 "Chris Allegretta",
2556 "Jordi Mallach",
2557 "Adam Rogoyski",
2558 "Rob Siemborski",
2559 "Rocco Corsi",
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002560 "David Lawrence Ramsey",
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002561 "David Benbennick",
Chris Allegretta598106e2002-01-19 01:59:37 +00002562 "Ken Tyler",
2563 "Sven Guckes",
2564 "Florian König",
2565 "Pauli Virtanen",
2566 "Daniele Medri",
2567 "Clement Laforet",
2568 "Tedi Heriyanto",
2569 "Bill Soudan",
2570 "Christian Weisgerber",
2571 "Erik Andersen",
2572 "Big Gaute",
2573 "Joshua Jensen",
2574 "Ryan Krebs",
2575 "Albert Chin",
Chris Allegretta598106e2002-01-19 01:59:37 +00002576 "",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002577 "3", /* "Special thanks to:" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002578 "Plattsburgh State University",
2579 "Benet Laboratories",
2580 "Amy Allegretta",
2581 "Linda Young",
2582 "Jeremy Robichaud",
2583 "Richard Kolb II",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002584 "4", /* "The Free Software Foundation" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002585 "Linus Torvalds",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002586 "5", /* "For ncurses:" */
Chris Allegrettadce44ab2002-03-16 01:03:41 +00002587 "Thomas Dickey",
2588 "Pavel Curtis",
2589 "Zeyd Ben-Halim",
2590 "Eric S. Raymond",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002591 "6", /* "and anyone else we forgot..." */
2592 "7", /* "Thank you for using nano!\n" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002593 "", "", "", "",
David Lawrence Ramsey6481c3f2004-01-09 23:06:54 +00002594 "(c) 1999-2004 Chris Allegretta",
Chris Allegretta598106e2002-01-19 01:59:37 +00002595 "", "", "", "",
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002596 "http://www.nano-editor.org/"
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002597 };
2598
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002599 xlcredits[0] = _("The nano text editor");
2600 xlcredits[1] = _("version ");
2601 xlcredits[2] = _("Brought to you by:");
2602 xlcredits[3] = _("Special thanks to:");
2603 xlcredits[4] = _("The Free Software Foundation");
2604 xlcredits[5] = _("For ncurses:");
2605 xlcredits[6] = _("and anyone else we forgot...");
2606 xlcredits[7] = _("Thank you for using nano!\n");
2607
David Lawrence Ramsey9da08312004-01-14 22:40:38 +00002608 scrolldelay.tv_sec = 0;
David Lawrence Ramsey62187d92004-01-14 22:45:05 +00002609 scrolldelay.tv_nsec = 700000000;
David Lawrence Ramseye97c8d52004-01-14 19:26:29 +00002610
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002611 curs_set(0);
2612 nodelay(edit, TRUE);
2613 blank_bottombars();
2614 mvwaddstr(topwin, 0, 0, hblank);
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002615 blank_edit();
2616 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002617 wrefresh(bottomwin);
2618 wrefresh(topwin);
2619
2620 while (wgetch(edit) == ERR) {
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002621 for (k = 0; k <= 1; k++) {
2622 blank_edit();
Chris Allegretta598106e2002-01-19 01:59:37 +00002623 for (i = editwinrows / 2 - 1; i >= (editwinrows / 2 - 1 - j);
2624 i--) {
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002625 mvwaddstr(edit, i * 2 - k, 0, hblank);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002626
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002627 if (place - (editwinrows / 2 - 1 - i) < CREDIT_LEN) {
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002628 what = credits[place - (editwinrows / 2 - 1 - i)];
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002629
2630 /* God I've missed hacking. If what is exactly
2631 1 char long, it's a sentinel for a translated
2632 string, so use that instead. This means no
2633 thanking people with 1 character long names ;-) */
2634 if (strlen(what) == 1)
2635 what = xlcredits[atoi(what)];
2636 } else
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002637 what = "";
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002638
Chris Allegretta17dcb722001-01-20 21:40:07 +00002639 start_x = COLS / 2 - strlen(what) / 2 - 1;
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002640 mvwaddstr(edit, i * 2 - k, start_x, what);
2641 }
David Lawrence Ramseye97c8d52004-01-14 19:26:29 +00002642 nanosleep(&scrolldelay, NULL);
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002643 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002644 }
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002645 if (j < editwinrows / 2 - 1)
2646 j++;
2647
2648 place++;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002649
2650 if (place >= CREDIT_LEN + editwinrows / 2)
2651 break;
2652 }
2653
2654 nodelay(edit, FALSE);
2655 curs_set(1);
2656 display_main_list();
2657 total_refresh();
Chris Allegretta598106e2002-01-19 01:59:37 +00002658}
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002659#endif