blob: 07940585fccff76c0b997a31cc9ed9739f67c3f9 [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>
David Lawrence Ramseye97c8d52004-01-14 19:26:29 +000027#include <time.h>
Chris Allegretta8a0de3b2000-11-24 20:45:14 +000028#include <unistd.h>
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +000029#include <ctype.h>
Chris Allegretta6232d662002-05-12 19:52:15 +000030#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000031#include "proto.h"
32#include "nano.h"
33
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000034static int statblank = 0; /* Number of keystrokes left after
Chris Allegretta88520c92001-05-05 17:45:54 +000035 we call statusbar(), before we
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000036 actually blank the statusbar */
Robert Siemborskid8510b22000-06-06 23:04:06 +000037
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000038/* Read in a single input character. If it's ignored, swallow it and go
39 * on. Otherwise, try to translate it from ASCII and extended (keypad)
40 * input. Assume nodelay(win) is FALSE. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +000041int get_kbinput(WINDOW *win, int *meta)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000042{
43 int kbinput, retval;
44
45 kbinput = get_ignored_kbinput(win);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +000046 retval = get_accepted_kbinput(win, kbinput, meta);
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000047
48 return retval;
49}
50
51/* Read in a string of input characters (e. g. an escape sequence)
52 * verbatim, and return the length of the string in kbinput_len. Assume
53 * nodelay(win) is FALSE. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +000054char *get_verbatim_kbinput(WINDOW *win, int *kbinput_len,
55 int allow_ascii)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000056{
57 char *verbatim_kbinput;
58 int kbinput = wgetch(win);
59
60 verbatim_kbinput = charalloc(1);
61 verbatim_kbinput[0] = kbinput;
62 *kbinput_len = 1;
63
David Lawrence Ramseyf4276942003-12-24 03:33:09 +000064 if (allow_ascii && kbinput >= '0' && kbinput <= '2')
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000065 /* Entering a three-digit decimal ASCII code from 000-255 in
66 * verbatim mode will produce the corresponding ASCII
67 * character. */
68 verbatim_kbinput[0] = (char)get_ascii_kbinput(win, kbinput);
69 else {
70 nodelay(win, TRUE);
71 while ((kbinput = wgetch(win)) != ERR) {
David Lawrence Ramseyda8fd8f2003-09-16 01:22:31 +000072 (*kbinput_len)++;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +000073 verbatim_kbinput = charealloc(verbatim_kbinput, *kbinput_len);
74 verbatim_kbinput[*kbinput_len - 1] = (char)kbinput;
75 }
76 nodelay(win, FALSE);
77 }
78
79#ifdef DEBUG
80 fprintf(stderr, "get_verbatim_kbinput(): verbatim_kbinput = %s\n", verbatim_kbinput);
81#endif
82 return verbatim_kbinput;
83}
84
85/* Swallow input characters that should be quietly ignored, and return
86 * the first input character that shouldn't be. */
87int get_ignored_kbinput(WINDOW *win)
88{
89 int kbinput;
90
91 while (1) {
92 kbinput = wgetch(win);
93 switch (kbinput) {
94 case ERR:
95 case KEY_RESIZE:
96#ifdef PDCURSES
97 case KEY_SHIFT_L:
98 case KEY_SHIFT_R:
99 case KEY_CONTROL_L:
100 case KEY_CONTROL_R:
101 case KEY_ALT_L:
102 case KEY_ALT_R:
103#endif
104#ifdef DEBUG
105 fprintf(stderr, "get_ignored_kbinput(): kbinput = %d\n", kbinput);
106#endif
107 break;
108 default:
109 return kbinput;
110 }
111 }
112}
113
114/* Translate acceptable ASCII and extended (keypad) input. Set meta to
115 * 1 if we get a Meta sequence. Assume nodelay(win) is FALSE. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000116int get_accepted_kbinput(WINDOW *win, int kbinput, int *meta)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000117{
118 *meta = 0;
119
120 switch (kbinput) {
121 case NANO_CONTROL_3: /* Escape */
David Lawrence Ramsey25061362004-01-16 19:12:46 +0000122 kbinput = wgetch(win);
123 switch (kbinput) {
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000124 case NANO_CONTROL_3: /* Escape */
125 kbinput = wgetch(win);
126 /* Esc Esc [three-digit decimal ASCII code from
127 * 000-255] == [corresponding ASCII character];
128 Esc Esc 2 obviously can't be Ctrl-2 here */
129 if (kbinput >= '0' && kbinput <= '2')
130 kbinput = get_ascii_kbinput(win, kbinput);
131 /* Esc Esc [character] == Ctrl-[character];
132 * Ctrl-Space (Ctrl-2) == Ctrl-@ == Ctrl-` */
133 else if (kbinput == ' ' || kbinput == '@' || kbinput == '`')
134 kbinput = NANO_CONTROL_SPACE;
135 /* Ctrl-3 (Ctrl-[, Esc) to Ctrl-7 (Ctrl-_) */
136 else if (kbinput >= '3' && kbinput <= '7')
137 kbinput -= 24;
138 /* Ctrl-8 (Ctrl-?) */
139 else if (kbinput == '8' || kbinput == '?')
140 kbinput = NANO_CONTROL_8;
141 /* Ctrl-A to Ctrl-_ */
142 else if (kbinput >= 'A' && kbinput <= '_')
143 kbinput -= 64;
David Lawrence Ramseyda8fd8f2003-09-16 01:22:31 +0000144 /* Ctrl-A to Ctrl-~ */
145 else if (kbinput >= 'a' && kbinput <= '~')
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000146 kbinput -= 96;
147 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000148 case 'O':
149 case 'o':
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000150 /* Terminal breakage, part 1: We shouldn't get an escape
151 * sequence here for terminals that support Delete, but
152 * we do sometimes on FreeBSD. Thank you, Wouter van
153 * Hemel. */
154 case '[':
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000155 {
156 int old_kbinput = kbinput, escape_seq_len;
157 char *escape_seq;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000158 nodelay(win, TRUE);
159 kbinput = wgetch(win);
160 switch (kbinput) {
161 case ERR:
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000162 kbinput = tolower(old_kbinput);
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000163 *meta = 1;
164 break;
165 default:
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000166 ungetch(kbinput);
167 ungetch(old_kbinput);
168 escape_seq = get_verbatim_kbinput(win, &escape_seq_len, 0);
169 kbinput = get_escape_seq_kbinput(win, escape_seq, escape_seq_len);
170 free(escape_seq);
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000171 }
172 nodelay(win, FALSE);
173 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000174 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000175 default:
176 /* Esc [character] == Meta-[character] */
David Lawrence Ramseyda8fd8f2003-09-16 01:22:31 +0000177 kbinput = tolower(kbinput);
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000178 *meta = 1;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000179 }
180 break;
David Lawrence Ramsey7776ef92003-11-04 18:32:35 +0000181 case NANO_CONTROL_8:
182 /* Terminal breakage, part 2: We shouldn't get Ctrl-8
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000183 * (Ctrl-?) for Backspace or Delete, but we do sometimes. */
184 kbinput = ISSET(REBIND_DELETE) ? NANO_DELETE_KEY : NANO_BACKSPACE_KEY;
David Lawrence Ramsey7776ef92003-11-04 18:32:35 +0000185 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000186 case KEY_DOWN:
187 kbinput = NANO_DOWN_KEY;
188 break;
189 case KEY_UP:
190 kbinput = NANO_UP_KEY;
191 break;
192 case KEY_LEFT:
193 kbinput = NANO_BACK_KEY;
194 break;
195 case KEY_RIGHT:
196 kbinput = NANO_FORWARD_KEY;
197 break;
198 case KEY_HOME:
199 kbinput = NANO_HOME_KEY;
200 break;
201 case KEY_BACKSPACE:
202 kbinput = NANO_BACKSPACE_KEY;
203 break;
204 case KEY_DC:
David Lawrence Ramsey7776ef92003-11-04 18:32:35 +0000205 /* Terminal breakage, part 3: We should only get KEY_DC when
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000206 * hitting Delete, but we get it when hitting Backspace
207 * sometimes on FreeBSD. Thank you, Lee Nelson. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000208 kbinput = ISSET(REBIND_DELETE) ? NANO_BACKSPACE_KEY : NANO_DELETE_KEY;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000209 break;
210 case KEY_IC:
211 kbinput = NANO_INSERTFILE_KEY;
212 break;
213 case KEY_NPAGE:
214 kbinput = NANO_NEXTPAGE_KEY;
215 break;
216 case KEY_PPAGE:
217 kbinput = NANO_PREVPAGE_KEY;
218 break;
219 case KEY_ENTER:
220 kbinput = NANO_ENTER_KEY;
221 break;
222 case KEY_END:
223 kbinput = NANO_END_KEY;
224 break;
225 case KEY_SUSPEND:
226 kbinput = NANO_SUSPEND_KEY;
227 break;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000228 case KEY_SLEFT:
229 kbinput = NANO_BACK_KEY;
230 break;
231 case KEY_SRIGHT:
232 kbinput = NANO_FORWARD_KEY;
233 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000234 }
235#ifdef DEBUG
236 fprintf(stderr, "get_accepted_kbinput(): kbinput = %d, meta = %d\n", kbinput, *meta);
237#endif
238 return kbinput;
239}
240
241/* Translate a three-digit decimal ASCII code from 000-255 into the
242 * corresponding ASCII character. */
243int get_ascii_kbinput(WINDOW *win, int kbinput)
244{
245 int retval;
246
247 switch (kbinput) {
248 case '0':
249 case '1':
250 case '2':
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000251 retval = (kbinput - '0') * 100;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000252 break;
253 default:
254 return kbinput;
255 }
256
257 kbinput = wgetch(win);
258 switch (kbinput) {
259 case '0':
260 case '1':
261 case '2':
262 case '3':
263 case '4':
264 case '5':
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000265 retval += (kbinput - '0') * 10;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000266 break;
267 case '6':
268 case '7':
269 case '8':
270 case '9':
271 if (retval < 200) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000272 retval += (kbinput - '0') * 10;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000273 break;
274 }
275 default:
276 return kbinput;
277 }
278
279 kbinput = wgetch(win);
280 switch (kbinput) {
281 case '0':
282 case '1':
283 case '2':
284 case '3':
285 case '4':
286 case '5':
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000287 retval += kbinput - '0';
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000288 break;
289 case '6':
290 case '7':
291 case '8':
292 case '9':
293 if (retval < 250) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000294 retval += kbinput - '0';
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000295 break;
296 }
297 default:
298 return kbinput;
299 }
300
301#ifdef DEBUG
302 fprintf(stderr, "get_ascii_kbinput(): kbinput = %d\n", kbinput);
303#endif
304 return retval;
305}
306
307/* Translate common escape sequences for some keys. These are generated
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000308 * when the terminal doesn't support those keys. Assume that Escape has
309 * already been read in, and that nodelay(win) is TRUE. */
310int get_escape_seq_kbinput(WINDOW *win, char *escape_seq, int
311 escape_seq_len)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000312{
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000313 int kbinput = -1;
314
315 if (escape_seq_len > 1) {
316 switch (escape_seq[0]) {
317 case 'O':
318 switch (escape_seq[1]) {
319 case 'A': /* Esc O A == Up on xterm. */
320 kbinput = NANO_UP_KEY;
321 break;
322 case 'B': /* Esc O B == Down on xterm. */
323 kbinput = NANO_DOWN_KEY;
324 break;
325 case 'C': /* Esc O C == Right on xterm. */
326 kbinput = NANO_FORWARD_KEY;
327 break;
328 case 'D': /* Esc O D == Left on xterm. */
329 kbinput = NANO_BACK_KEY;
330 break;
331 case 'F': /* Esc O F == End on xterm. */
332 kbinput = NANO_END_KEY;
333 break;
334 case 'H': /* Esc O H == Home on xterm. */
335 kbinput = NANO_HOME_KEY;
336 break;
337 case 'a': /* Esc O a == Ctrl-Up on rxvt. */
338 kbinput = NANO_UP_KEY;
339 break;
340 case 'b': /* Esc O b == Ctrl-Down on rxvt. */
341 kbinput = NANO_DOWN_KEY;
342 break;
343 case 'c': /* Esc O c == Ctrl-Right on rxvt. */
344 kbinput = NANO_FORWARD_KEY;
345 break;
346 case 'd': /* Esc O d == Ctrl-Left on rxvt. */
347 kbinput = NANO_BACK_KEY;
348 break;
349 }
350 break;
351 case 'o':
352 switch (escape_seq[1]) {
353 case 'a': /* Esc o a == Ctrl-Up on Eterm. */
354 kbinput = NANO_UP_KEY;
355 break;
356 case 'b': /* Esc o b == Ctrl-Down on Eterm. */
357 kbinput = NANO_DOWN_KEY;
358 break;
359 case 'c': /* Esc o c == Ctrl-Right on Eterm. */
360 kbinput = NANO_FORWARD_KEY;
361 break;
362 case 'd': /* Esc o d == Ctrl-Left on Eterm. */
363 kbinput = NANO_BACK_KEY;
364 break;
365 }
366 break;
367 case '[':
368 switch (escape_seq[1]) {
369 case '1':
370 if (escape_seq_len >= 5) {
371 if (!strncmp(escape_seq, "[1;2", 4)) {
372 switch (escape_seq[4]) {
373 case 'A':
374 /* Esc [ 1 ; 2 A == Shift-Up on
375 * xterm. */
376 kbinput = NANO_UP_KEY;
377 break;
378 case 'B':
379 /* Esc [ 1 ; 2 B == Shift-Down
380 * on xterm. */
381 kbinput = NANO_DOWN_KEY;
382 break;
383 case 'C':
384 /* Esc [ 1 ; 2 C == Shift-Right
385 * on xterm. */
386 kbinput = NANO_FORWARD_KEY;
387 break;
388 case 'D':
389 /* Esc [ 1 ; 2 D == Shift-Left
390 * on xterm. */
391 kbinput = NANO_BACK_KEY;
392 break;
393 }
394 } else if (!strncmp(escape_seq, "[1;5", 4)) {
395 switch (escape_seq[4]) {
396 case 'A':
397 /* Esc [ 1 ; 5 A == Ctrl-Up on
398 * xterm. */
399 kbinput = NANO_UP_KEY;
400 break;
401 case 'B':
402 /* Esc [ 1 ; 5 B == Ctrl-Down on
403 * xterm. */
404 kbinput = NANO_DOWN_KEY;
405 break;
406 case 'C':
407 /* Esc [ 1 ; 5 C == Ctrl-Right
408 * on xterm. */
409 kbinput = NANO_FORWARD_KEY;
410 break;
411 case 'D':
412 /* Esc [ 1 ; 5 D == Ctrl-Left on
413 * xterm. */
414 kbinput = NANO_BACK_KEY;
415 break;
416 }
417 }
418 break;
419 } else {
420 /* Esc [ 1 ~ == Home on Linux console. */
421 kbinput = NANO_HOME_KEY;
422 break;
423 }
424 case '2': /* Esc [ 2 ~ == Insert on Linux
425 * console/xterm. */
426 kbinput = NANO_INSERTFILE_KEY;
427 break;
428 case '3': /* Esc [ 3 ~ == Delete on Linux
429 * console/xterm. */
430 kbinput = NANO_DELETE_KEY;
431 break;
432 case '4': /* Esc [ 4 ~ == End on Linux
433 * console/xterm. */
434 kbinput = NANO_END_KEY;
435 break;
436 case '5': /* Esc [ 5 ~ == PageUp on Linux
437 * console/xterm, Esc [ 5 ^ == PageUp on
438 * Eterm. */
439 kbinput = NANO_PREVPAGE_KEY;
440 break;
441 case '6': /* Esc [ 6 ~ == PageDown on Linux
442 * console/xterm, Esc [ 6 ^ == PageDown on
443 * Eterm. */
444 kbinput = NANO_NEXTPAGE_KEY;
445 break;
446 case '7': /* Esc [ 7 ~ == Home on rxvt. */
447 kbinput = NANO_HOME_KEY;
448 break;
449 case '8': /* Esc [ 8 ~ == End on rxvt. */
450 kbinput = NANO_END_KEY;
451 break;
452 case '9': /* Esc [ 9 == Delete on Hurd console. */
453 kbinput = NANO_DELETE_KEY;
454 break;
455 case '@': /* Esc [ @ == Insert on Hurd console. */
456 kbinput = NANO_INSERTFILE_KEY;
457 break;
458 case 'A': /* Esc [ A == Up on Linux console/FreeBSD
459 * console/Hurd console/rxvt/Eterm. */
460 kbinput = NANO_UP_KEY;
461 break;
462 case 'B': /* Esc [ B == Down on Linux
463 * console/FreeBSD console/Hurd
464 * console/rxvt/Eterm. */
465 kbinput = NANO_DOWN_KEY;
466 break;
467 case 'C': /* Esc [ C == Right on Linux
468 * console/FreeBSD console/Hurd
469 * console/rxvt/Eterm. */
470 kbinput = NANO_FORWARD_KEY;
471 break;
472 case 'D': /* Esc [ D == Left on Linux
473 * console/FreeBSD console/Hurd
474 * console/rxvt/Eterm. */
475 kbinput = NANO_BACK_KEY;
476 break;
477 case 'F': /* Esc [ F == End on FreeBSD
478 * console/Eterm. */
479 kbinput = NANO_END_KEY;
480 break;
481 case 'G': /* Esc [ G == PageDown on FreeBSD
482 * console. */
483 kbinput = NANO_NEXTPAGE_KEY;
484 break;
485 case 'H': /* Esc [ H == Home on FreeBSD
486 * console/Hurd console/Eterm. */
487 kbinput = NANO_HOME_KEY;
488 break;
489 case 'I': /* Esc [ I == PageUp on FreeBSD
490 * console. */
491 kbinput = NANO_PREVPAGE_KEY;
492 break;
493 case 'L': /* Esc [ L == Insert on FreeBSD
494 * console. */
495 kbinput = NANO_INSERTFILE_KEY;
496 break;
497 case 'U': /* Esc [ U == PageDown on Hurd console. */
498 kbinput = NANO_NEXTPAGE_KEY;
499 break;
500 case 'V': /* Esc [ V == PageUp on Hurd console. */
501 kbinput = NANO_PREVPAGE_KEY;
502 break;
503 case 'Y': /* Esc [ Y == End on Hurd console. */
504 kbinput = NANO_END_KEY;
505 break;
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +0000506 case 'a': /* Esc [ a == Shift-Up on rxvt/Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000507 kbinput = NANO_UP_KEY;
508 break;
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +0000509 case 'b': /* Esc [ b == Shift-Down on rxvt/Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000510 kbinput = NANO_DOWN_KEY;
511 break;
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +0000512 case 'c': /* Esc [ c == Shift-Right on
513 * rxvt/Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000514 kbinput = NANO_FORWARD_KEY;
515 break;
David Lawrence Ramsey9b5bd422004-01-06 01:45:04 +0000516 case 'd': /* Esc [ d == Shift-Left on rxvt/Eterm. */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000517 kbinput = NANO_BACK_KEY;
518 break;
519 }
520 break;
521 }
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000522 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000523
524 if (kbinput == -1) {
525 /* This escape sequence is unrecognized; send it back. */
526 for (; escape_seq_len > 1; escape_seq_len--)
527 ungetch(escape_seq[escape_seq_len - 1]);
528 kbinput = escape_seq[0];
529 }
530
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000531 return kbinput;
532}
533
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000534#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000535/* Check for a mouse event, and if one's taken place, save the
536 * coordinates where it took place in mouse_x and mouse_y. After that,
537 * if allow_shortcuts is zero, return 0. Otherwise, if the mouse event
538 * took place on the shortcut list on the bottom two lines of the screen
539 * (assuming that the shortcut list is visible), figure out which
540 * shortcut was clicked and ungetch() the equivalent keystroke(s).
541 * Return 0 if no keystrokes were ungetch()ed, or 1 if at least one was.
542 * Assume that KEY_MOUSE has already been read in. */
543int get_mouseinput(int *mouse_x, int *mouse_y, int allow_shortcuts)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000544{
545 MEVENT mevent;
546
547 *mouse_x = -1;
548 *mouse_y = -1;
549
550 /* First, get the actual mouse event. */
551 if (getmouse(&mevent) == ERR)
552 return 0;
553
554 /* Save the screen coordinates where the mouse event took place. */
555 *mouse_x = mevent.x;
556 *mouse_y = mevent.y;
557
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000558 /* If we're not allowing shortcuts' we're done now. */
559 if (!allow_shortcuts)
560 return 0;
561
562 /* Otherwise, if the current shortcut list is being displayed on the
563 * last two lines of the screen and the mouse event took place
564 * inside it, we need to figure out which shortcut was clicked and
565 * ungetch() the equivalent keystroke(s) for it. */
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000566 if (!ISSET(NO_HELP) && wenclose(bottomwin, *mouse_y, *mouse_x)) {
567 int i, j;
568 int currslen;
569 /* The number of shortcuts in the current shortcut list. */
570 const shortcut *s = currshortcut;
571 /* The actual shortcut we clicked on, starting at the first
572 * one in the current shortcut list. */
573
574 /* Get the shortcut lists' length. */
575 if (currshortcut == main_list)
576 currslen = MAIN_VISIBLE;
577 else
578 currslen = length_of_list(currshortcut);
579
580 /* Calculate the width of each shortcut in the list (it's the
581 * same for all of them). */
582 if (currslen < 2)
583 i = COLS / 6;
584 else
585 i = COLS / ((currslen / 2) + (currslen % 2));
586
587 /* Calculate the y-coordinates relative to the beginning of
588 * bottomwin, i.e, the bottom three lines of the screen. */
589 j = *mouse_y - (editwinrows + 3);
590
591 /* If we're on the statusbar, beyond the end of the shortcut
592 * list, or beyond the end of a shortcut on the right side of
593 * the screen, don't do anything. */
594 if (j < 0 || (*mouse_x / i) >= currslen)
595 return 0;
596 j = (*mouse_x / i) * 2 + j;
597 if (j >= currslen)
598 return 0;
599
600 /* Go through the shortcut list to determine which shortcut was
601 * clicked. */
602 for (; j > 0; j--)
603 s = s->next;
604
605 /* And ungetch() the equivalent keystroke. */
606 ungetch(s->val);
607
608 /* If it's not a control character, assume it's a Meta key
609 * sequence, in which case we need to ungetch() Escape too. */
610 if (!is_cntrl_char(s->val))
611 ungetch(NANO_CONTROL_3);
612
613 return 1;
614 }
615 return 0;
616}
617#endif
618
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000619int do_first_line(void)
620{
621 current = fileage;
622 placewewant = 0;
623 current_x = 0;
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +0000624 edit_update(current, TOP);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000625 return 1;
626}
627
628int do_last_line(void)
629{
630 current = filebot;
631 placewewant = 0;
632 current_x = 0;
Chris Allegretta234a34d2000-07-29 04:33:38 +0000633 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000634 return 1;
635}
636
Chris Allegretta6df90f52002-07-19 01:08:59 +0000637/* Return the placewewant associated with current_x. That is, xplustabs
638 * is the zero-based column position of the cursor. Value is no smaller
639 * than current_x. */
640size_t xplustabs(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000641{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000642 return strnlenpt(current->data, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000643}
644
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000645/* actual_x() gives the index in str of the character displayed at
646 * column xplus. That is, actual_x() is the largest value such that
647 * strnlenpt(str, actual_x(str, xplus)) <= xplus. */
648size_t actual_x(const char *str, size_t xplus)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000649{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000650 size_t i = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000651 /* the position in str, returned */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000652 size_t length = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000653 /* the screen display width to str[i] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000654
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000655 assert(str != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000656
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000657 for (; length < xplus && *str != '\0'; i++, str++) {
658 if (*str == '\t')
David Lawrence Ramsey0362c582003-09-30 03:31:56 +0000659 length += tabsize - (length % tabsize);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000660 else if (is_cntrl_char((int)*str))
Chris Allegretta6df90f52002-07-19 01:08:59 +0000661 length += 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000662 else
663 length++;
664 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000665 assert(length == strnlenpt(str - i, i));
666 assert(i <= strlen(str - i));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000667
Chris Allegretta6df90f52002-07-19 01:08:59 +0000668 if (length > xplus)
669 i--;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000670
Chris Allegretta6df90f52002-07-19 01:08:59 +0000671 return i;
Robert Siemborskid8510b22000-06-06 23:04:06 +0000672}
673
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000674/* A strlen with tabs factored in, similar to xplustabs(). How many
675 * columns wide are the first size characters of buf? */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000676size_t strnlenpt(const char *buf, size_t size)
Robert Siemborskid8510b22000-06-06 23:04:06 +0000677{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000678 size_t length = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000679
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000680 assert(buf != NULL);
681 for (; *buf != '\0' && size != 0; size--, buf++) {
682 if (*buf == '\t')
683 length += tabsize - (length % tabsize);
684 else if (is_cntrl_char((int)*buf))
685 length += 2;
686 else
687 length++;
688 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000689 return length;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000690}
691
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000692/* How many columns wide is buf? */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000693size_t strlenpt(const char *buf)
Chris Allegrettad4fa0d32002-03-05 19:55:55 +0000694{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000695 return strnlenpt(buf, -1);
Chris Allegrettad4fa0d32002-03-05 19:55:55 +0000696}
697
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000698void blank_bottombars(void)
699{
David Lawrence Ramsey5dcba302003-09-28 19:15:18 +0000700 if (!ISSET(NO_HELP)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +0000701 mvwaddstr(bottomwin, 1, 0, hblank);
702 mvwaddstr(bottomwin, 2, 0, hblank);
703 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000704}
705
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000706void blank_bottomwin(void)
707{
708 if (ISSET(NO_HELP))
709 return;
710
711 mvwaddstr(bottomwin, 1, 0, hblank);
712 mvwaddstr(bottomwin, 2, 0, hblank);
713}
714
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000715void blank_edit(void)
716{
717 int i;
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +0000718 for (i = 0; i < editwinrows; i++)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000719 mvwaddstr(edit, i, 0, hblank);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000720}
721
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000722void blank_statusbar(void)
723{
724 mvwaddstr(bottomwin, 0, 0, hblank);
725}
726
727void blank_statusbar_refresh(void)
728{
729 blank_statusbar();
730 wrefresh(bottomwin);
731}
732
733void check_statblank(void)
734{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000735 if (statblank > 1)
736 statblank--;
737 else if (statblank == 1 && !ISSET(CONSTUPDATE)) {
738 statblank--;
739 blank_statusbar_refresh();
740 }
741}
742
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000743/* Convert buf into a string that can be displayed on screen. The
744 * caller wants to display buf starting with column start_col, and
745 * extending for at most len columns. start_col is zero-based. len is
746 * one-based, so len == 0 means you get "" returned. The returned
747 * string is dynamically allocated, and should be freed. */
748char *display_string(const char *buf, size_t start_col, int len)
749{
750 size_t start_index;
751 /* Index in buf of first character shown in return value. */
752 size_t column;
753 /* Screen column start_index corresponds to. */
754 size_t end_index;
755 /* Index in buf of last character shown in return value. */
756 size_t alloc_len;
757 /* The length of memory allocated for converted. */
758 char *converted;
759 /* The string we return. */
760 size_t index;
761 /* Current position in converted. */
762
763 if (len == 0)
764 return mallocstrcpy(NULL, "");
765
766 start_index = actual_x(buf, start_col);
767 column = strnlenpt(buf, start_index);
768 assert(column <= start_col);
769 end_index = actual_x(buf, start_col + len - 1);
770 alloc_len = strnlenpt(buf, end_index + 1) - column;
771 if (len > alloc_len + column - start_col)
772 len = alloc_len + column - start_col;
773 converted = charalloc(alloc_len + 1);
774 buf += start_index;
775 index = 0;
776
777 for (; index < alloc_len; buf++) {
778 if (*buf == '\t')
779 do {
780 converted[index++] = ' ';
781 } while ((column + index) % tabsize);
782 else if (is_cntrl_char(*buf)) {
783 converted[index++] = '^';
784 if (*buf == '\n')
785 /* Treat newlines embedded in a line as encoded nulls;
786 * the line in question should be run through unsunder()
787 * before reaching here. */
788 converted[index++] = '@';
789 else if (*buf == NANO_CONTROL_8)
790 converted[index++] = '?';
791 else
792 converted[index++] = *buf + 64;
793 } else
794 converted[index++] = *buf;
795 }
796 assert(len <= alloc_len + column - start_col);
797 charmove(converted, converted + start_col - column, len);
798 null_at(&converted, len);
799
800 return charealloc(converted, len + 1);
801}
802
Chris Allegretta7662c862003-01-13 01:35:15 +0000803/* Repaint the statusbar when getting a character in nanogetstr(). buf
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000804 * should be no longer than max(0, COLS - 4).
Chris Allegretta6df90f52002-07-19 01:08:59 +0000805 *
Chris Allegretta7662c862003-01-13 01:35:15 +0000806 * Note that we must turn on A_REVERSE here, since do_help() turns it
Chris Allegretta6df90f52002-07-19 01:08:59 +0000807 * off! */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000808void nanoget_repaint(const char *buf, const char *inputbuf, size_t x)
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000809{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000810 size_t x_real = strnlenpt(inputbuf, x);
811 int wid = COLS - strlen(buf) - 2;
Chris Allegretta0d1e8d62000-11-02 15:30:24 +0000812
Chris Allegretta6df90f52002-07-19 01:08:59 +0000813 assert(0 <= x && x <= strlen(inputbuf));
814
Chris Allegrettab3655b42001-10-22 03:15:31 +0000815 wattron(bottomwin, A_REVERSE);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000816 blank_statusbar();
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000817
Chris Allegretta6df90f52002-07-19 01:08:59 +0000818 mvwaddstr(bottomwin, 0, 0, buf);
819 waddch(bottomwin, ':');
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000820
821 if (COLS > 1)
822 waddch(bottomwin, x_real < wid ? ' ' : '$');
823 if (COLS > 2) {
824 size_t page_start = x_real - x_real % wid;
825 char *expanded = display_string(inputbuf, page_start, wid);
826
827 assert(wid > 0);
828 assert(strlen(expanded) <= wid);
829 waddstr(bottomwin, expanded);
830 free(expanded);
831 wmove(bottomwin, 0, COLS - wid + x_real - page_start);
832 } else
833 wmove(bottomwin, 0, COLS - 1);
Chris Allegrettab3655b42001-10-22 03:15:31 +0000834 wattroff(bottomwin, A_REVERSE);
Chris Allegrettaa0e957b2000-10-24 22:25:36 +0000835}
836
Chris Allegretta6df90f52002-07-19 01:08:59 +0000837/* Get the input from the kb; this should only be called from
838 * statusq(). */
Chris Allegrettaf717f982003-02-13 22:25:01 +0000839int nanogetstr(int allowtabs, const char *buf, const char *def,
Chris Allegretta5beed502003-01-05 20:41:21 +0000840#ifndef NANO_SMALL
841 historyheadtype *history_list,
842#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000843 const shortcut *s
Rocco Corsi06aca1c2001-01-11 05:30:31 +0000844#ifndef DISABLE_TABCOMP
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000845 , int *list
Chris Allegrettabe77c612000-11-24 14:00:16 +0000846#endif
Chris Allegretta65f075d2003-02-13 03:03:49 +0000847 )
Chris Allegretta6df90f52002-07-19 01:08:59 +0000848{
849 int kbinput;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000850 int meta;
Chris Allegretta09fc4302003-01-16 22:16:38 +0000851 static int x = -1;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000852 /* the cursor position in 'answer' */
853 int xend;
854 /* length of 'answer', the status bar text */
855 int tabbed = 0;
856 /* used by input_tab() */
857 const shortcut *t;
Chris Allegretta598106e2002-01-19 01:59:37 +0000858
Chris Allegretta5beed502003-01-05 20:41:21 +0000859#ifndef NANO_SMALL
860 /* for history */
861 char *history = NULL;
Chris Allegretta8031f832003-01-09 05:29:58 +0000862 char *currentbuf = NULL;
Chris Allegretta5beed502003-01-05 20:41:21 +0000863 char *complete = NULL;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000864 int last_kbinput = 0;
865
866 /* This variable is used in the search history code. use_cb == 0
867 means that we're using the existing history and ignoring
868 currentbuf. use_cb == 1 means that the entry in answer should be
869 moved to currentbuf or restored from currentbuf to answer.
870 use_cb == 2 means that the entry in currentbuf should be moved to
871 answer or restored from answer to currentbuf. */
872 int use_cb = 0;
Chris Allegretta5beed502003-01-05 20:41:21 +0000873#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000874 xend = strlen(def);
Chris Allegretta09fc4302003-01-16 22:16:38 +0000875
876 /* Only put x at the end of the string if it's uninitialized or if
877 it would be past the end of the string as it is. Otherwise,
878 leave it alone. This is so the cursor position stays at the same
879 place if a prompt-changing toggle is pressed. */
Chris Allegretta65f075d2003-02-13 03:03:49 +0000880 if (x == -1 || x > xend || resetstatuspos)
Chris Allegretta09fc4302003-01-16 22:16:38 +0000881 x = xend;
882
Chris Allegrettae1e0fd62003-04-15 01:15:09 +0000883 answer = charealloc(answer, xend + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000884 if (xend > 0)
885 strcpy(answer, def);
886 else
887 answer[0] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000888
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000889#if !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000890 currshortcut = s;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000891#endif
892
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000893 /* Get the input! */
Chris Allegretta31925e42000-11-02 04:40:39 +0000894
Chris Allegretta6df90f52002-07-19 01:08:59 +0000895 nanoget_repaint(buf, answer, x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000896
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000897 /* Make sure any editor screen updates are displayed before getting
898 input */
Chris Allegretta022b96f2000-11-14 17:47:58 +0000899 wrefresh(edit);
900
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000901 while ((kbinput = get_kbinput(bottomwin, &meta)) != NANO_ENTER_KEY) {
Chris Allegrettaa8c22572002-02-15 19:17:02 +0000902 for (t = s; t != NULL; t = t->next) {
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000903#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000904 fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput, kbinput);
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000905#endif
906
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000907 if (kbinput == t->val && is_cntrl_char(kbinput)) {
Chris Allegretta5bf51d32000-11-16 06:01:10 +0000908
Chris Allegrettab3655b42001-10-22 03:15:31 +0000909#ifndef DISABLE_HELP
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000910 /* Have to do this here, it would be too late to do it
911 in statusq() */
Chris Allegretta598106e2002-01-19 01:59:37 +0000912 if (kbinput == NANO_HELP_KEY || kbinput == NANO_HELP_FKEY) {
Chris Allegrettab3655b42001-10-22 03:15:31 +0000913 do_help();
914 break;
915 }
916#endif
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000917#ifndef NANO_SMALL
918 /* Have to handle these here too, for the time being */
919 if (kbinput == NANO_UP_KEY || kbinput == NANO_DOWN_KEY)
920 break;
921#endif
Chris Allegretta5af58892003-01-17 21:07:38 +0000922
Chris Allegrettaa8c22572002-02-15 19:17:02 +0000923 return t->val;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000924 }
925 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000926 assert(0 <= x && x <= xend && xend == strlen(answer));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000927
Chris Allegretta04d848e2000-11-05 17:54:41 +0000928 if (kbinput != '\t')
929 tabbed = 0;
930
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000931 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000932#ifndef DISABLE_MOUSE
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000933 case KEY_MOUSE:
934 do_mouse();
935 break;
936#endif
Chris Allegretta658399a2001-06-14 02:54:22 +0000937 case NANO_HOME_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +0000938 x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000939 break;
Chris Allegretta658399a2001-06-14 02:54:22 +0000940 case NANO_END_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +0000941 x = xend;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000942 break;
Chris Allegretta35dac582001-03-21 15:07:20 +0000943 case NANO_FORWARD_KEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000944 if (x < xend)
945 x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000946 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000947 case NANO_DELETE_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +0000948 if (x < xend) {
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +0000949 charmove(answer + x, answer + x + 1, xend - x);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000950 xend--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000951 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000952 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000953 case NANO_CUT_KEY:
954 case NANO_UNCUT_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +0000955 null_at(&answer, 0);
956 xend = 0;
957 x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000958 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000959 case NANO_BACKSPACE_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +0000960 if (x > 0) {
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +0000961 charmove(answer + x - 1, answer + x, xend - x + 1);
Chris Allegretta04d848e2000-11-05 17:54:41 +0000962 x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000963 xend--;
964 }
Chris Allegretta04d848e2000-11-05 17:54:41 +0000965 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000966 case NANO_TAB_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +0000967#ifndef NANO_SMALL
968 /* tab history completion */
Chris Allegretta7662c862003-01-13 01:35:15 +0000969 if (history_list != NULL) {
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000970 if (!complete || last_kbinput != NANO_TAB_KEY) {
Chris Allegretta5beed502003-01-05 20:41:21 +0000971 history_list->current = (historytype *)history_list;
972 history_list->len = strlen(answer);
973 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000974
Chris Allegretta7662c862003-01-13 01:35:15 +0000975 if (history_list->len > 0) {
Chris Allegretta5beed502003-01-05 20:41:21 +0000976 complete = get_history_completion(history_list, answer);
977 xend = strlen(complete);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000978 x = xend;
Chris Allegretta5beed502003-01-05 20:41:21 +0000979 answer = mallocstrcpy(answer, complete);
980 }
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000981 }
Chris Allegretta5beed502003-01-05 20:41:21 +0000982#ifndef DISABLE_TABCOMP
Chris Allegretta327abda2003-01-17 05:04:17 +0000983 else
984#endif
Chris Allegrettabe77c612000-11-24 14:00:16 +0000985#endif
Chris Allegretta5beed502003-01-05 20:41:21 +0000986#ifndef DISABLE_TABCOMP
Chris Allegretta327abda2003-01-17 05:04:17 +0000987 if (allowtabs) {
988 int shift = 0;
Chris Allegretta5beed502003-01-05 20:41:21 +0000989
Chris Allegretta327abda2003-01-17 05:04:17 +0000990 answer = input_tab(answer, x, &tabbed, &shift, list);
991 xend = strlen(answer);
992 x += shift;
993 if (x > xend)
994 x = xend;
Chris Allegretta5beed502003-01-05 20:41:21 +0000995 }
996#endif
997 break;
Chris Allegretta35dac582001-03-21 15:07:20 +0000998 case NANO_BACK_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +0000999 if (x > 0)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001000 x--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001001 break;
Chris Allegretta7662c862003-01-13 01:35:15 +00001002 case NANO_UP_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001003#ifndef NANO_SMALL
Chris Allegretta09fc4302003-01-16 22:16:38 +00001004 if (history_list != NULL) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001005
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001006 /* if currentbuf is NULL, or if use_cb is 1, currentbuf
1007 isn't NULL, and currentbuf is different from answer,
1008 it means that we're scrolling up at the top of the
1009 search history, and we need to save the current
1010 answer in currentbuf; do this and reset use_cb to
1011 0 */
1012 if (currentbuf == NULL || (use_cb == 1 && strcmp(currentbuf, answer))) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001013 currentbuf = mallocstrcpy(currentbuf, answer);
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001014 use_cb = 0;
Chris Allegretta8031f832003-01-09 05:29:58 +00001015 }
1016
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001017 /* if currentbuf isn't NULL, use_cb is 2, and currentbuf
1018 is different from answer, it means that we're
1019 scrolling up at the bottom of the search history, and
1020 we need to make the string in currentbuf the current
1021 answer; do this, blow away currentbuf since we don't
1022 need it anymore, and reset use_cb to 0 */
1023 if (currentbuf != NULL && use_cb == 2 && strcmp(currentbuf, answer)) {
1024 answer = mallocstrcpy(answer, currentbuf);
1025 free(currentbuf);
1026 currentbuf = NULL;
1027 xend = strlen(answer);
1028 use_cb = 0;
1029
1030 /* else get older search from the history list and save
1031 it in answer; if there is no older search, blank out
1032 answer */
1033 } else if ((history = get_history_older(history_list)) != NULL) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001034 answer = mallocstrcpy(answer, history);
1035 xend = strlen(history);
1036 } else {
1037 answer = mallocstrcpy(answer, "");
1038 xend = 0;
1039 }
1040 x = xend;
1041 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001042#endif
Chris Allegretta54abd942003-01-09 23:43:12 +00001043 break;
Chris Allegretta7662c862003-01-13 01:35:15 +00001044 case NANO_DOWN_KEY:
Chris Allegretta5beed502003-01-05 20:41:21 +00001045#ifndef NANO_SMALL
Chris Allegretta09fc4302003-01-16 22:16:38 +00001046 if (history_list != NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001047
1048 /* get newer search from the history list and save it
1049 in answer */
Chris Allegretta7662c862003-01-13 01:35:15 +00001050 if ((history = get_history_newer(history_list)) != NULL) {
Chris Allegretta5beed502003-01-05 20:41:21 +00001051 answer = mallocstrcpy(answer, history);
1052 xend = strlen(history);
Chris Allegretta8031f832003-01-09 05:29:58 +00001053
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001054 /* if there is no newer search, we're here */
1055
1056 /* if currentbuf isn't NULL and use_cb isn't 2, it means
1057 that we're scrolling down at the bottom of the search
1058 history and we need to make the string in currentbuf
1059 the current answer; do this, blow away currentbuf
1060 since we don't need it anymore, and set use_cb to
1061 1 */
1062 } else if (currentbuf != NULL && use_cb != 2) {
Chris Allegretta8031f832003-01-09 05:29:58 +00001063 answer = mallocstrcpy(answer, currentbuf);
Chris Allegretta09fc4302003-01-16 22:16:38 +00001064 free(currentbuf);
1065 currentbuf = NULL;
1066 xend = strlen(answer);
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001067 use_cb = 1;
1068
1069 /* otherwise, if currentbuf is NULL and use_cb isn't 2,
1070 it means that we're scrolling down at the bottom of
Chris Allegrettac30fc242003-08-11 00:32:45 +00001071 the search history and the current answer (if it's
1072 not blank) needs to be saved in currentbuf; do this,
1073 blank out answer (if necessary), and set use_cb to
1074 2 */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001075 } else if (use_cb != 2) {
Chris Allegrettac30fc242003-08-11 00:32:45 +00001076 if (answer[0] != '\0') {
1077 currentbuf = mallocstrcpy(currentbuf, answer);
1078 answer = mallocstrcpy(answer, "");
1079 }
Chris Allegretta5beed502003-01-05 20:41:21 +00001080 xend = 0;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001081 use_cb = 2;
Chris Allegretta5beed502003-01-05 20:41:21 +00001082 }
1083 x = xend;
1084 }
1085#endif
1086 break;
Chris Allegretta658399a2001-06-14 02:54:22 +00001087 default:
1088
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001089 for (t = s; t != NULL; t = t->next) {
Chris Allegretta658399a2001-06-14 02:54:22 +00001090#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001091 fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput,
Chris Allegretta598106e2002-01-19 01:59:37 +00001092 kbinput);
Chris Allegretta658399a2001-06-14 02:54:22 +00001093#endif
David Lawrence Ramsey82138502003-12-24 08:03:54 +00001094 if (meta == 1 && (kbinput == t->metaval || kbinput == t->misc))
1095 /* We hit a Meta key. Do like above. We don't
1096 * just ungetch() the letter and let it get
1097 * caught above cause that screws the
1098 * keypad... */
1099 return kbinput;
Chris Allegretta658399a2001-06-14 02:54:22 +00001100 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001101
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001102 if (is_cntrl_char(kbinput))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001103 break;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001104 answer = charealloc(answer, xend + 2);
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001105 charmove(answer + x + 1, answer + x, xend - x + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001106 xend++;
1107 answer[x] = kbinput;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001108 x++;
1109
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001110#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001111 fprintf(stderr, "input \'%c\' (%d)\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001112#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001113 } /* switch (kbinput) */
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001114#ifndef NANO_SMALL
Chris Allegretta5beed502003-01-05 20:41:21 +00001115 last_kbinput = kbinput;
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001116#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001117 nanoget_repaint(buf, answer, x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001118 wrefresh(bottomwin);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001119 } /* while (kbinput ...) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001120
Chris Allegretta5af58892003-01-17 21:07:38 +00001121 /* We finished putting in an answer; reset x */
1122 x = -1;
1123
Chris Allegretta7662c862003-01-13 01:35:15 +00001124 /* Just check for a blank answer here */
Chris Allegretta15c28f82003-01-05 21:47:06 +00001125 if (answer[0] == '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001126 return -2;
1127 else
1128 return 0;
1129}
1130
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001131/* If modified is not already set, set it and update titlebar. */
1132void set_modified(void)
1133{
1134 if (!ISSET(MODIFIED)) {
1135 SET(MODIFIED);
1136 titlebar(NULL);
1137 wrefresh(topwin);
1138 }
1139}
1140
Chris Allegrettaf717f982003-02-13 22:25:01 +00001141void titlebar(const char *path)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001142{
1143 int namelen, space;
Chris Allegrettaf717f982003-02-13 22:25:01 +00001144 const char *what = path;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001145
1146 if (path == NULL)
1147 what = filename;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001148
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001149 wattron(topwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001150
Chris Allegretta6df90f52002-07-19 01:08:59 +00001151 mvwaddstr(topwin, 0, 0, hblank);
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00001152 mvwaddnstr(topwin, 0, 2, VERMSG, COLS - 3);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001153
David Lawrence Ramseyec290f22003-08-30 19:05:40 +00001154 space = COLS - sizeof(VERMSG) - 23;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001155
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001156 namelen = strlen(what);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001157
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00001158 if (space > 0) {
1159 if (what[0] == '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001160 mvwaddnstr(topwin, 0, COLS / 2 - 6, _("New Buffer"),
1161 COLS / 2 + COLS % 2 - 6);
1162 else if (namelen > space) {
1163 if (path == NULL)
1164 waddstr(topwin, _(" File: ..."));
1165 else
1166 waddstr(topwin, _(" DIR: ..."));
1167 waddstr(topwin, &what[namelen - space]);
1168 } else {
1169 if (path == NULL)
1170 mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
1171 _("File: "));
1172 else
1173 mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
1174 _(" DIR: "));
1175 waddstr(topwin, what);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001176 }
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00001177 } /* If we don't have space, we shouldn't bother */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001178 if (ISSET(MODIFIED))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001179 mvwaddnstr(topwin, 0, COLS - 11, _(" Modified "), 11);
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001180 else if (ISSET(VIEW_MODE))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001181 mvwaddnstr(topwin, 0, COLS - 11, _(" View "), 11);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001182
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001183 wattroff(topwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001184
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001185 wrefresh(topwin);
1186 reset_cursor();
1187}
1188
Chris Allegretta6232d662002-05-12 19:52:15 +00001189void bottombars(const shortcut *s)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001190{
Chris Allegrettabc72e362002-02-16 20:03:44 +00001191 int i, j, numcols;
Chris Allegretta3bbc4162003-01-23 00:46:12 +00001192 char keystr[9];
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001193 int slen;
1194
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001195 if (ISSET(NO_HELP))
1196 return;
1197
Chris Allegretta6232d662002-05-12 19:52:15 +00001198 if (s == main_list) {
1199 slen = MAIN_VISIBLE;
1200 assert(MAIN_VISIBLE <= length_of_list(s));
1201 } else
1202 slen = length_of_list(s);
1203
Chris Allegretta6232d662002-05-12 19:52:15 +00001204 /* There will be this many columns of shortcuts */
1205 numcols = (slen + (slen % 2)) / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001206
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001207 blank_bottomwin();
Chris Allegretta658399a2001-06-14 02:54:22 +00001208
Chris Allegrettabc72e362002-02-16 20:03:44 +00001209 for (i = 0; i < numcols; i++) {
1210 for (j = 0; j <= 1; j++) {
Chris Allegretta658399a2001-06-14 02:54:22 +00001211
Chris Allegretta6232d662002-05-12 19:52:15 +00001212 wmove(bottomwin, 1 + j, i * (COLS / numcols));
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001213
Chris Allegretta5beed502003-01-05 20:41:21 +00001214 /* Yucky sentinel values we can't handle a better way */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001215 if (s->val != NANO_NO_KEY) {
Chris Allegrettaa65ba512003-01-05 20:57:07 +00001216#ifndef NANO_SMALL
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001217 if (s->val == NANO_HISTORY_KEY)
1218 strncpy(keystr, _("Up"), 8);
Chris Allegretta6232d662002-05-12 19:52:15 +00001219 else
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001220#endif
1221 if (s->val == NANO_CONTROL_SPACE)
1222 strcpy(keystr, "^ ");
1223 else if (s->val == NANO_CONTROL_8)
1224 strcpy(keystr, "^?");
1225 else
1226 sprintf(keystr, "^%c", s->val + 64);
David Lawrence Ramsey82138502003-12-24 08:03:54 +00001227 } else if (s->metaval != NANO_NO_KEY)
1228 sprintf(keystr, "M-%c", toupper(s->metaval));
Chris Allegretta658399a2001-06-14 02:54:22 +00001229
Chris Allegretta6232d662002-05-12 19:52:15 +00001230 onekey(keystr, s->desc, COLS / numcols);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001231
Chris Allegretta6232d662002-05-12 19:52:15 +00001232 s = s->next;
1233 if (s == NULL)
1234 goto break_completely_out;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001235 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001236 }
1237
Chris Allegretta6df90f52002-07-19 01:08:59 +00001238 break_completely_out:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001239 wrefresh(bottomwin);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001240}
1241
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001242/* Write a shortcut key to the help area at the bottom of the window.
1243 * keystroke is e.g. "^G" and desc is e.g. "Get Help".
1244 * We are careful to write exactly len characters, even if len is
1245 * very small and keystroke and desc are long. */
Chris Allegrettaf717f982003-02-13 22:25:01 +00001246void onekey(const char *keystroke, const char *desc, int len)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001247{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001248 wattron(bottomwin, A_REVERSE);
1249 waddnstr(bottomwin, keystroke, len);
1250 wattroff(bottomwin, A_REVERSE);
1251 len -= strlen(keystroke);
1252 if (len > 0) {
1253 waddch(bottomwin, ' ');
1254 len--;
1255 waddnstr(bottomwin, desc, len);
1256 len -= strlen(desc);
1257 for (; len > 0; len--)
1258 waddch(bottomwin, ' ');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001259 }
1260}
1261
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001262/* And so start the display update routines. */
1263
1264#ifndef NDEBUG
1265int check_linenumbers(const filestruct *fileptr)
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001266{
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001267 int check_line = 0;
1268 const filestruct *filetmp;
Robert Siemborskid8510b22000-06-06 23:04:06 +00001269
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001270 for (filetmp = edittop; filetmp != fileptr; filetmp = filetmp->next)
1271 check_line++;
1272 return check_line;
Robert Siemborskid8510b22000-06-06 23:04:06 +00001273}
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001274#endif
Robert Siemborskid8510b22000-06-06 23:04:06 +00001275
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001276/* nano scrolls horizontally within a line in chunks. This function
1277 * returns the column number of the first character displayed in the
1278 * window when the cursor is at the given column. Note that
1279 * 0 <= column - get_page_start(column) < COLS. */
1280size_t get_page_start(size_t column)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001281{
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001282 assert(COLS > 0);
1283 if (column == 0 || column < COLS - 1)
1284 return 0;
1285 else if (COLS > 9)
1286 return column - 7 - (column - 8) % (COLS - 9);
1287 else if (COLS > 2)
1288 return column - (COLS - 2);
1289 else
1290 return column - (COLS - 1);
1291 /* The parentheses are necessary to avoid overflow. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001292}
1293
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001294/* Resets current_y, based on the position of current, and puts the
1295 * cursor at (current_y, current_x). */
1296void reset_cursor(void)
1297{
1298 const filestruct *ptr = edittop;
1299 size_t x;
1300
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001301 /* Yuck. This condition can be true after open_file() when opening
1302 * the first file. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001303 if (edittop == NULL)
1304 return;
1305
1306 current_y = 0;
1307
1308 while (ptr != current && ptr != editbot && ptr->next != NULL) {
1309 ptr = ptr->next;
1310 current_y++;
1311 }
1312
1313 x = xplustabs();
1314 wmove(edit, current_y, x - get_page_start(x));
1315}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001316
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001317/* edit_add() takes care of the job of actually painting a line into the
1318 * edit window. fileptr is the line to be painted, at row yval of the
1319 * window. converted is the actual string to be written to the window,
1320 * with tabs and control characters replaced by strings of regular
1321 * characters. start is the column number of the first character
1322 * of this page. That is, the first character of converted corresponds to
1323 * character number actual_x(fileptr->data, start) of the line. */
1324void edit_add(const filestruct *fileptr, const char *converted,
1325 int yval, size_t start)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001326{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001327#if defined(ENABLE_COLOR) || !defined(NANO_SMALL)
1328 size_t startpos = actual_x(fileptr->data, start);
1329 /* The position in fileptr->data of the leftmost character
1330 * that displays at least partially on the window. */
1331 size_t endpos = actual_x(fileptr->data, start + COLS - 1) + 1;
1332 /* The position in fileptr->data of the first character that is
1333 * completely off the window to the right.
1334 *
1335 * Note that endpos might be beyond the null terminator of the
1336 * string. */
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001337#endif
1338
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001339 assert(fileptr != NULL && converted != NULL);
1340 assert(strlen(converted) <= COLS);
1341
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001342 /* Just paint the string in any case (we'll add color or reverse on
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001343 * just the text that needs it). */
1344 mvwaddstr(edit, yval, 0, converted);
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001345
Chris Allegretta7dd77682001-12-08 19:52:28 +00001346#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00001347 if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001348 const colortype *tmpcolor = colorstrings;
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001349
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001350 for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
1351 int x_start;
1352 /* Starting column for mvwaddnstr. Zero-based. */
1353 int paintlen;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001354 /* Number of chars to paint on this line. There are COLS
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001355 * characters on a whole line. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001356 regmatch_t startmatch; /* match position for start_regexp */
1357 regmatch_t endmatch; /* match position for end_regexp */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001358
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001359 if (tmpcolor->bright)
1360 wattron(edit, A_BOLD);
1361 wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001362 /* Two notes about regexec(). Return value 0 means there is
1363 * a match. Also, rm_eo is the first non-matching character
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001364 * after the match. */
1365
1366 /* First case, tmpcolor is a single-line expression. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001367 if (tmpcolor->end == NULL) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001368 size_t k = 0;
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001369
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001370 /* We increment k by rm_eo, to move past the end of the
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001371 * last match. Even though two matches may overlap, we
1372 * want to ignore them, so that we can highlight
1373 * C-strings correctly. */
1374 while (k < endpos) {
1375 /* Note the fifth parameter to regexec(). It says
1376 * not to match the beginning-of-line character
1377 * unless k is 0. If regexec() returns REG_NOMATCH,
1378 * there are no more matches in the line. */
Chris Allegrettace452fb2003-02-03 02:56:44 +00001379 if (regexec(&tmpcolor->start, &fileptr->data[k], 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001380 &startmatch, k == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001381 break;
1382 /* Translate the match to the beginning of the line. */
1383 startmatch.rm_so += k;
1384 startmatch.rm_eo += k;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001385 if (startmatch.rm_so == startmatch.rm_eo) {
1386 startmatch.rm_eo++;
Chris Allegretta7c27be42002-05-05 23:03:54 +00001387 statusbar(_("Refusing 0 length regex match"));
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001388 } else if (startmatch.rm_so < endpos &&
1389 startmatch.rm_eo > startpos) {
1390 if (startmatch.rm_so <= startpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001391 x_start = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001392 else
1393 x_start = strnlenpt(fileptr->data, startmatch.rm_so)
1394 - start;
1395 paintlen = strnlenpt(fileptr->data, startmatch.rm_eo)
1396 - start - x_start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001397 if (paintlen > COLS - x_start)
1398 paintlen = COLS - x_start;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001399
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001400 assert(0 <= x_start && 0 < paintlen &&
1401 x_start + paintlen <= COLS);
1402 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001403 converted + x_start, paintlen);
1404 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001405 k = startmatch.rm_eo;
Chris Allegretta598106e2002-01-19 01:59:37 +00001406 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001407 } else {
1408 /* This is a multi-line regexp. There are two steps.
1409 * First, we have to see if the beginning of the line is
1410 * colored by a start on an earlier line, and an end on
1411 * this line or later.
1412 *
1413 * We find the first line before fileptr matching the
1414 * start. If every match on that line is followed by an
1415 * end, then go to step two. Otherwise, find the next line
1416 * after start_line matching the end. If that line is not
1417 * before fileptr, then paint the beginning of this line. */
Chris Allegretta3674c1d2002-05-12 20:43:49 +00001418
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001419 const filestruct *start_line = fileptr->prev;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001420 /* the first line before fileptr matching start */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001421 regoff_t start_col;
1422 /* where it starts in that line */
1423 const filestruct *end_line;
1424 int searched_later_lines = 0;
1425 /* Used in step 2. Have we looked for an end on
1426 * lines after fileptr? */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001427
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001428 while (start_line != NULL &&
Chris Allegrettace452fb2003-02-03 02:56:44 +00001429 regexec(&tmpcolor->start, start_line->data, 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001430 &startmatch, 0) == REG_NOMATCH) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001431 /* If there is an end on this line, there is no need
1432 * to look for starts on earlier lines. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001433 if (regexec(tmpcolor->end, start_line->data, 0, NULL, 0)
1434 == 0)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001435 goto step_two;
1436 start_line = start_line->prev;
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001437 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001438 /* No start found, so skip to the next step. */
1439 if (start_line == NULL)
1440 goto step_two;
1441 /* Now start_line is the first line before fileptr
1442 * containing a start match. Is there a start on this
1443 * line not followed by an end on this line? */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001444
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001445 start_col = 0;
1446 while (1) {
1447 start_col += startmatch.rm_so;
1448 startmatch.rm_eo -= startmatch.rm_so;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001449 if (regexec(tmpcolor->end,
1450 start_line->data + start_col + startmatch.rm_eo,
1451 0, NULL, start_col + startmatch.rm_eo == 0 ? 0 :
1452 REG_NOTBOL) == REG_NOMATCH)
1453 /* No end found after this start. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001454 break;
1455 start_col++;
Chris Allegrettace452fb2003-02-03 02:56:44 +00001456 if (regexec(&tmpcolor->start,
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001457 start_line->data + start_col, 1, &startmatch,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001458 REG_NOTBOL) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001459 /* No later start on this line. */
1460 goto step_two;
1461 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001462 /* Indeed, there is a start not followed on this line by
1463 * an end. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001464
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001465 /* We have already checked that there is no end before
1466 * fileptr and after the start. Is there an end after
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001467 * the start at all? We don't paint unterminated
1468 * starts. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001469 end_line = fileptr;
Chris Allegrettace452fb2003-02-03 02:56:44 +00001470 while (end_line != NULL &&
1471 regexec(tmpcolor->end, end_line->data, 1, &endmatch, 0))
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001472 end_line = end_line->next;
1473
1474 /* No end found, or it is too early. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001475 if (end_line == NULL ||
1476 (end_line == fileptr && endmatch.rm_eo <= startpos))
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001477 goto step_two;
1478
1479 /* Now paint the start of fileptr. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001480 paintlen = end_line != fileptr ? COLS :
1481 strnlenpt(fileptr->data, endmatch.rm_eo) - start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001482 if (paintlen > COLS)
1483 paintlen = COLS;
1484
1485 assert(0 < paintlen && paintlen <= COLS);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001486 mvwaddnstr(edit, yval, 0, converted, paintlen);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001487
1488 /* We have already painted the whole line. */
1489 if (paintlen == COLS)
1490 goto skip_step_two;
1491
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001492 step_two: /* Second step, we look for starts on this line. */
1493 start_col = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001494 while (start_col < endpos) {
Chris Allegrettace452fb2003-02-03 02:56:44 +00001495 if (regexec(&tmpcolor->start, fileptr->data + start_col, 1,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001496 &startmatch, start_col == 0 ? 0 : REG_NOTBOL)
1497 == REG_NOMATCH || start_col + startmatch.rm_so >=
1498 endpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001499 /* No more starts on this line. */
1500 break;
1501 /* Translate the match to be relative to the
1502 * beginning of the line. */
1503 startmatch.rm_so += start_col;
1504 startmatch.rm_eo += start_col;
1505
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001506 if (startmatch.rm_so <= startpos)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001507 x_start = 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001508 else
1509 x_start = strnlenpt(fileptr->data, startmatch.rm_so)
1510 - start;
1511 if (regexec(tmpcolor->end, fileptr->data + startmatch.rm_eo,
1512 1, &endmatch, startmatch.rm_eo == 0 ? 0 :
1513 REG_NOTBOL) == 0) {
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001514 /* Translate the end match to be relative to the
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001515 * beginning of the line. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001516 endmatch.rm_so += startmatch.rm_eo;
1517 endmatch.rm_eo += startmatch.rm_eo;
1518 /* There is an end on this line. But does it
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001519 * appear on this page, and is the match more than
1520 * zero characters long? */
1521 if (endmatch.rm_eo > startpos &&
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001522 endmatch.rm_eo > startmatch.rm_so) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001523 paintlen = strnlenpt(fileptr->data, endmatch.rm_eo)
1524 - start - x_start;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001525 if (x_start + paintlen > COLS)
1526 paintlen = COLS - x_start;
1527
1528 assert(0 <= x_start && 0 < paintlen &&
1529 x_start + paintlen <= COLS);
1530 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001531 converted + x_start, paintlen);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001532 }
1533 } else if (!searched_later_lines) {
1534 searched_later_lines = 1;
1535 /* There is no end on this line. But we haven't
1536 * yet looked for one on later lines. */
1537 end_line = fileptr->next;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001538 while (end_line != NULL &&
1539 regexec(tmpcolor->end, end_line->data, 0,
1540 NULL, 0) == REG_NOMATCH)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001541 end_line = end_line->next;
1542 if (end_line != NULL) {
1543 assert(0 <= x_start && x_start < COLS);
1544 mvwaddnstr(edit, yval, x_start,
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001545 converted + x_start,
1546 COLS - x_start);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001547 /* We painted to the end of the line, so
1548 * don't bother checking any more starts. */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001549 break;
Chris Allegretta3674c1d2002-05-12 20:43:49 +00001550 }
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001551 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001552 start_col = startmatch.rm_so + 1;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001553 } /* while start_col < endpos */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001554 } /* if (tmp_color->end != NULL) */
Chris Allegretta6c1e6612002-01-19 16:52:34 +00001555
Chris Allegrettace452fb2003-02-03 02:56:44 +00001556 skip_step_two:
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001557 wattroff(edit, A_BOLD);
1558 wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
1559 } /* for tmpcolor in colorstrings */
1560 }
Chris Allegretta598106e2002-01-19 01:59:37 +00001561#endif /* ENABLE_COLOR */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001562
Chris Allegretta7dd77682001-12-08 19:52:28 +00001563#ifndef NANO_SMALL
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001564 if (ISSET(MARK_ISSET)
1565 && (fileptr->lineno <= mark_beginbuf->lineno
1566 || fileptr->lineno <= current->lineno)
1567 && (fileptr->lineno >= mark_beginbuf->lineno
1568 || fileptr->lineno >= current->lineno)) {
1569 /* fileptr is at least partially selected. */
Chris Allegretta2fa11b82001-12-02 04:55:44 +00001570
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001571 const filestruct *top;
1572 /* Either current or mark_beginbuf, whichever is first. */
1573 size_t top_x;
1574 /* current_x or mark_beginx, corresponding to top. */
1575 const filestruct *bot;
1576 size_t bot_x;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001577 int x_start;
1578 /* Starting column for mvwaddnstr. Zero-based. */
1579 int paintlen;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001580 /* Number of chars to paint on this line. There are COLS
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001581 * characters on a whole line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001582
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001583 mark_order(&top, &top_x, &bot, &bot_x);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001584
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001585 if (top->lineno < fileptr->lineno || top_x < startpos)
1586 top_x = startpos;
1587 if (bot->lineno > fileptr->lineno || bot_x > endpos)
1588 bot_x = endpos;
1589
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001590 /* The selected bit of fileptr is on this page. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001591 if (top_x < endpos && bot_x > startpos) {
1592 assert(startpos <= top_x);
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001593
1594 /* x_start is the expanded location of the beginning of the
1595 * mark minus the beginning of the page. */
1596 x_start = strnlenpt(fileptr->data, top_x) - start;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001597
1598 if (bot_x >= endpos)
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001599 /* If the end of the mark is off the page, paintlen is
1600 * -1, meaning that everything on the line gets
1601 * painted. */
1602 paintlen = -1;
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001603 else
David Lawrence Ramsey4dcd0702003-10-03 04:20:28 +00001604 /* Otherwise, paintlen is the expanded location of the
1605 * end of the mark minus the expanded location of the
1606 * beginning of the mark. */
1607 paintlen = strnlenpt(fileptr->data, bot_x) - (x_start +
1608 start);
1609
1610 /* If x_start is before the beginning of the page, shift
1611 * paintlen x_start characters to compensate, and put
1612 * x_start at the beginning of the page. */
1613 if (x_start < 0) {
1614 paintlen += x_start;
1615 x_start = 0;
1616 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001617
1618 assert(x_start >= 0 && x_start <= strlen(converted));
1619
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001620 wattron(edit, A_REVERSE);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001621 mvwaddnstr(edit, yval, x_start, converted + x_start, paintlen);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001622 wattroff(edit, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001623 }
Chris Allegretta08893e02001-11-29 02:42:27 +00001624 }
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001625#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001626}
1627
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001628/* Just update one line in the edit buffer. Basically a wrapper for
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001629 * edit_add().
1630 *
1631 * If fileptr != current, then index is considered 0.
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001632 * The line will be displayed starting with fileptr->data[index].
1633 * Likely args are current_x or 0. */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001634void update_line(const filestruct *fileptr, size_t index)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001635{
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001636 int line;
1637 /* line in the edit window for CURSES calls */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001638 char *converted;
1639 /* fileptr->data converted to have tabs and control characters
1640 * expanded. */
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001641 size_t page_start;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001642
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001643 assert(fileptr != NULL);
Robert Siemborski53154a72000-06-18 00:11:03 +00001644
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001645 line = fileptr->lineno - edittop->lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001646
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001647 /* We assume the line numbers are valid. Is that really true? */
1648 assert(line < 0 || line == check_linenumbers(fileptr));
1649
1650 if (line < 0 || line >= editwinrows)
1651 return;
1652
1653 /* First, blank out the line (at a minimum) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001654 mvwaddstr(edit, line, 0, hblank);
1655
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001656 /* Next, convert variables that index the line to their equivalent
1657 * positions in the expanded line. */
David Lawrence Ramsey2dd7ed12003-09-29 05:15:24 +00001658 index = (fileptr == current) ? strnlenpt(fileptr->data, index) : 0;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001659 page_start = get_page_start(index);
Chris Allegretta5beed502003-01-05 20:41:21 +00001660
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001661 /* Expand the line, replacing Tab by spaces, and control characters
1662 * by their display form. */
1663 converted = display_string(fileptr->data, page_start, COLS);
Robert Siemborski53875912000-06-16 04:25:30 +00001664
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001665 /* Now, paint the line */
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001666 edit_add(fileptr, converted, line, page_start);
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001667 free(converted);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001668
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001669 if (page_start > 0)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001670 mvwaddch(edit, line, 0, '$');
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001671 if (strlenpt(fileptr->data) > page_start + COLS)
David Lawrence Ramsey1f28b8f2002-09-27 14:21:59 +00001672 mvwaddch(edit, line, COLS - 1, '$');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001673}
1674
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001675/* This function updates current, based on where current_y is;
1676 * reset_cursor() does the opposite. */
1677void update_cursor(void)
1678{
1679 int i = 0;
1680
1681#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001682 fprintf(stderr, "Moved to (%d, %d) in edit buffer\n", current_y,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001683 current_x);
1684#endif
1685
1686 current = edittop;
1687 while (i < current_y && current->next != NULL) {
1688 current = current->next;
1689 i++;
1690 }
1691
1692#ifdef DEBUG
Chris Allegretta0e86e602003-01-23 04:27:23 +00001693 fprintf(stderr, "current->data = \"%s\"\n", current->data);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001694#endif
1695}
1696
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001697void center_cursor(void)
1698{
1699 current_y = editwinrows / 2;
1700 wmove(edit, current_y, current_x);
1701}
1702
Chris Allegretta6df90f52002-07-19 01:08:59 +00001703/* Refresh the screen without changing the position of lines. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001704void edit_refresh(void)
1705{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001706 /* Neither of these conditions should occur, but they do. edittop
1707 * is NULL when you open an existing file on the command line, and
Chris Allegretta6df90f52002-07-19 01:08:59 +00001708 * ENABLE_COLOR is defined. Yuck. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001709 if (current == NULL)
1710 return;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001711 if (edittop == NULL)
1712 edittop = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001713
Chris Allegretta63d0b482003-01-26 19:47:10 +00001714 if (current->lineno < edittop->lineno ||
1715 current->lineno >= edittop->lineno + editwinrows)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001716 /* Note that edit_update() changes edittop so that
1717 * current->lineno = edittop->lineno + editwinrows / 2. Thus
1718 * when it then calls edit_refresh(), there is no danger of
1719 * getting an infinite loop. */
Chris Allegrettada721be2000-07-31 01:26:42 +00001720 edit_update(current, CENTER);
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001721 else {
1722 int nlines = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001723
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001724 /* Don't make the cursor jump around the screen whilst
1725 * updating. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001726 leaveok(edit, TRUE);
1727
1728 editbot = edittop;
1729 while (nlines < editwinrows) {
1730 update_line(editbot, current_x);
1731 nlines++;
1732 if (editbot->next == NULL)
1733 break;
1734 editbot = editbot->next;
1735 }
1736 while (nlines < editwinrows) {
1737 mvwaddstr(edit, nlines, 0, hblank);
1738 nlines++;
1739 }
1740 /* What the hell are we expecting to update the screen if this
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001741 * isn't here? Luck? */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001742 wrefresh(edit);
1743 leaveok(edit, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001744 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001745}
1746
Chris Allegretta7662c862003-01-13 01:35:15 +00001747/* Same as above, but touch the window first, so everything is
1748 * redrawn. */
Chris Allegrettaf1d33d32000-08-19 03:53:39 +00001749void edit_refresh_clearok(void)
1750{
1751 clearok(edit, TRUE);
1752 edit_refresh();
1753 clearok(edit, FALSE);
1754}
1755
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001756/* Nice generic routine to update the edit buffer, given a pointer to the
1757 * file struct =) */
David Lawrence Ramsey1356a0a2003-09-10 20:31:02 +00001758void edit_update(filestruct *fileptr, topmidnone location)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001759{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001760 if (fileptr == NULL)
1761 return;
1762
Chris Allegretta6df90f52002-07-19 01:08:59 +00001763 if (location != TOP) {
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001764 int goal = location == NONE ? current_y : editwinrows / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001765
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001766 for (; goal > 0 && fileptr->prev != NULL; goal--)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001767 fileptr = fileptr->prev;
1768 }
1769 edittop = fileptr;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001770 edit_refresh();
1771}
1772
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001773/* Ask a question on the statusbar. Answer will be stored in answer
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001774 * global. Returns -1 on aborted enter, -2 on a blank string, and 0
Chris Allegretta88520c92001-05-05 17:45:54 +00001775 * otherwise, the valid shortcut key caught. Def is any editable text we
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001776 * want to put up by default.
Chris Allegretta7da4e9f2000-11-06 02:57:22 +00001777 *
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001778 * New arg tabs tells whether or not to allow tab completion. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001779int statusq(int tabs, const shortcut *s, const char *def,
Chris Allegretta5beed502003-01-05 20:41:21 +00001780#ifndef NANO_SMALL
1781 historyheadtype *which_history,
1782#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001783 const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001784{
1785 va_list ap;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001786 char *foo = charalloc(COLS - 3);
Chris Allegretta9caa1932002-02-15 20:08:05 +00001787 int ret;
Chris Allegretta2084acc2001-11-29 03:43:08 +00001788#ifndef DISABLE_TABCOMP
Chris Allegrettaa16e4e92002-01-05 18:59:54 +00001789 int list = 0;
Chris Allegretta2084acc2001-11-29 03:43:08 +00001790#endif
1791
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001792 bottombars(s);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001793
1794 va_start(ap, msg);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001795 vsnprintf(foo, COLS - 4, msg, ap);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001796 va_end(ap);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001797 foo[COLS - 4] = '\0';
Chris Allegretta8ce24132001-04-30 11:28:46 +00001798
Chris Allegretta5beed502003-01-05 20:41:21 +00001799 ret = nanogetstr(tabs, foo, def,
1800#ifndef NANO_SMALL
1801 which_history,
Chris Allegretta2084acc2001-11-29 03:43:08 +00001802#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00001803 s
1804#ifndef DISABLE_TABCOMP
1805 , &list
1806#endif
Chris Allegretta65f075d2003-02-13 03:03:49 +00001807 );
Chris Allegretta6df90f52002-07-19 01:08:59 +00001808 free(foo);
Chris Allegretta65f075d2003-02-13 03:03:49 +00001809 resetstatuspos = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001810
1811 switch (ret) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001812 case NANO_FIRSTLINE_KEY:
1813 do_first_line();
Chris Allegretta65f075d2003-02-13 03:03:49 +00001814 resetstatuspos = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001815 break;
1816 case NANO_LASTLINE_KEY:
1817 do_last_line();
Chris Allegretta65f075d2003-02-13 03:03:49 +00001818 resetstatuspos = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001819 break;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00001820#ifndef DISABLE_JUSTIFY
1821 case NANO_PARABEGIN_KEY:
1822 do_para_begin();
1823 resetstatuspos = 1;
1824 break;
1825 case NANO_PARAEND_KEY:
1826 do_para_end();
1827 resetstatuspos = 1;
1828 break;
1829#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001830 case NANO_CANCEL_KEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00001831 ret = -1;
Chris Allegretta65f075d2003-02-13 03:03:49 +00001832 resetstatuspos = 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001833 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001834 }
Chris Allegrettaa90d0cf2003-02-10 02:55:03 +00001835 blank_statusbar();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001836
1837#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001838 fprintf(stderr, "I got \"%s\"\n", answer);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001839#endif
1840
Chris Allegretta6df90f52002-07-19 01:08:59 +00001841#ifndef DISABLE_TABCOMP
1842 /* if we've done tab completion, there might be a list of
1843 filename matches on the edit window at this point; make sure
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001844 they're cleared off. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001845 if (list)
1846 edit_refresh();
1847#endif
1848
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001849 return ret;
1850}
1851
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001852/* Ask a simple yes/no question on the statusbar. Returns 1 for Y, 0
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001853 * for N, 2 for All (if all is nonzero when passed in) and -1 for abort
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001854 * (^C). */
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001855int do_yesno(int all, const char *msg)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001856{
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001857 int ok = -2, width = 16;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001858 const char *yesstr; /* String of yes characters accepted */
1859 const char *nostr; /* Same for no */
1860 const char *allstr; /* And all, surprise! */
Chris Allegretta235ab192001-04-12 13:24:40 +00001861
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001862 /* Yes, no and all are strings of any length. Each string consists
1863 * of all characters accepted as a valid character for that value.
1864 * The first value will be the one displayed in the shortcuts. */
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00001865 yesstr = _("Yy");
1866 nostr = _("Nn");
1867 allstr = _("Aa");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001868
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001869 /* Remove gettext call for keybindings until we clear the thing
1870 * up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001871 if (!ISSET(NO_HELP)) {
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001872 char shortstr[3]; /* Temp string for Y, N, A. */
Chris Allegretta6232d662002-05-12 19:52:15 +00001873
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001874 if (COLS < 32)
1875 width = COLS / 2;
1876
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001877 /* Write the bottom of the screen. */
Chris Allegrettadb28e962003-01-28 01:23:40 +00001878 blank_bottombars();
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00001879
Chris Allegretta6232d662002-05-12 19:52:15 +00001880 sprintf(shortstr, " %c", yesstr[0]);
Chris Allegrettadb28e962003-01-28 01:23:40 +00001881 wmove(bottomwin, 1, 0);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001882 onekey(shortstr, _("Yes"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00001883
1884 if (all) {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001885 wmove(bottomwin, 1, width);
Chris Allegretta6232d662002-05-12 19:52:15 +00001886 shortstr[1] = allstr[0];
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001887 onekey(shortstr, _("All"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00001888 }
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00001889
Chris Allegrettadb28e962003-01-28 01:23:40 +00001890 wmove(bottomwin, 2, 0);
Chris Allegretta6232d662002-05-12 19:52:15 +00001891 shortstr[1] = nostr[0];
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001892 onekey(shortstr, _("No"), width);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00001893
Chris Allegrettadb28e962003-01-28 01:23:40 +00001894 wmove(bottomwin, 2, 16);
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001895 onekey("^C", _("Cancel"), width);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001896 }
Chris Allegrettadb28e962003-01-28 01:23:40 +00001897
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001898 wattron(bottomwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001899
1900 blank_statusbar();
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001901 mvwaddnstr(bottomwin, 0, 0, msg, COLS - 1);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001902
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001903 wattroff(bottomwin, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001904
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001905 wrefresh(bottomwin);
1906
Chris Allegrettadb28e962003-01-28 01:23:40 +00001907 do {
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001908 int kbinput;
1909 int meta;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001910#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001911 int mouse_x, mouse_y;
Chris Allegretta235ab192001-04-12 13:24:40 +00001912#endif
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00001913
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001914 kbinput = get_kbinput(edit, &meta);
1915
1916 if (kbinput == NANO_CANCEL_KEY)
Chris Allegrettadb28e962003-01-28 01:23:40 +00001917 ok = -1;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001918#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001919 /* Look ma! We get to duplicate lots of code from
1920 * do_mouse()!! */
1921 else if (kbinput == KEY_MOUSE) {
1922 kbinput = get_mouseinput(&mouse_x, &mouse_y, 0);
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00001923
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001924 if (mouse_x != -1 && mouse_y != -1 && !ISSET(NO_HELP) &&
1925 wenclose(bottomwin, mouse_y, mouse_x) && mouse_x <
1926 (width * 2) && mouse_y >= editwinrows + 3) {
Chris Allegretta4ce8e3b2001-02-16 01:49:31 +00001927
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001928 int x = mouse_x / width;
1929 /* Did we click in the first column of shortcuts, or
1930 * the second? */
1931 int y = mouse_y - editwinrows - 3;
1932 /* Did we click in the first row of shortcuts? */
1933
1934 assert(0 <= x && x <= 1 && 0 <= y && y <= 1);
1935
1936 /* x = 0 means they clicked Yes or No.
1937 * y = 0 means Yes or All. */
1938 ok = -2 * x * y + x - y + 1;
1939
1940 if (ok == 2 && !all)
1941 ok = -2;
1942 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001943 }
Chris Allegrettadb28e962003-01-28 01:23:40 +00001944#endif
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001945 /* Look for the kbinput in the yes, no and (optionally) all
1946 * str. */
Chris Allegrettadb28e962003-01-28 01:23:40 +00001947 else if (strchr(yesstr, kbinput) != NULL)
1948 ok = 1;
1949 else if (strchr(nostr, kbinput) != NULL)
1950 ok = 0;
1951 else if (all && strchr(allstr, kbinput) != NULL)
1952 ok = 2;
1953 } while (ok == -2);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001954
Chris Allegrettadb28e962003-01-28 01:23:40 +00001955 return ok;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001956}
1957
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001958int total_refresh(void)
1959{
1960 clearok(edit, TRUE);
1961 clearok(topwin, TRUE);
1962 clearok(bottomwin, TRUE);
1963 wnoutrefresh(edit);
1964 wnoutrefresh(topwin);
1965 wnoutrefresh(bottomwin);
1966 doupdate();
1967 clearok(edit, FALSE);
1968 clearok(topwin, FALSE);
1969 clearok(bottomwin, FALSE);
1970 edit_refresh();
1971 titlebar(NULL);
1972 return 1;
1973}
1974
1975void display_main_list(void)
1976{
1977 bottombars(main_list);
1978}
1979
Chris Allegretta6df90f52002-07-19 01:08:59 +00001980void statusbar(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001981{
1982 va_list ap;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001983
Chris Allegrettaa0d89972003-02-03 03:32:08 +00001984 va_start(ap, msg);
1985
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001986 /* Curses mode is turned off. If we use wmove() now, it will muck
1987 * up the terminal settings. So we just use vfprintf(). */
Chris Allegrettaa0d89972003-02-03 03:32:08 +00001988 if (curses_ended) {
1989 vfprintf(stderr, msg, ap);
1990 va_end(ap);
1991 return;
1992 }
1993
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001994 /* Blank out the line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001995 blank_statusbar();
1996
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00001997 if (COLS >= 4) {
1998 char *bar;
1999 char *foo;
2000 int start_x = 0;
2001 size_t foo_len;
2002 bar = charalloc(COLS - 3);
2003 vsnprintf(bar, COLS - 3, msg, ap);
2004 va_end(ap);
2005 foo = display_string(bar, 0, COLS - 4);
2006 free(bar);
2007 foo_len = strlen(foo);
2008 start_x = (COLS - foo_len - 4) / 2;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002009
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002010 wmove(bottomwin, 0, start_x);
2011 wattron(bottomwin, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002012
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002013 waddstr(bottomwin, "[ ");
2014 waddstr(bottomwin, foo);
2015 free(foo);
2016 waddstr(bottomwin, " ]");
2017 wattroff(bottomwin, A_REVERSE);
2018 wnoutrefresh(bottomwin);
2019 wrefresh(edit);
2020 /* Leave the cursor at its position in the edit window, not
2021 * in the statusbar. */
2022 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002023
Chris Allegrettad26ab912003-01-28 01:16:47 +00002024 SET(DISABLE_CURPOS);
2025 statblank = 26;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002026}
2027
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002028/* If constant is false, the user typed ^C so we unconditionally display
Chris Allegrettad26ab912003-01-28 01:16:47 +00002029 * the cursor position. Otherwise, we display it only if the character
2030 * position changed, and DISABLE_CURPOS is not set.
2031 *
2032 * If constant and DISABLE_CURPOS is set, we unset it and update old_i and
2033 * old_totsize. That way, we leave the current statusbar alone, but next
2034 * time we will display. */
Chris Allegretta2084acc2001-11-29 03:43:08 +00002035int do_cursorpos(int constant)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002036{
Chris Allegrettad26ab912003-01-28 01:16:47 +00002037 const filestruct *fileptr;
2038 unsigned long i = 0;
2039 static unsigned long old_i = 0;
2040 static long old_totsize = -1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002041
Chris Allegrettad26ab912003-01-28 01:16:47 +00002042 assert(current != NULL && fileage != NULL && totlines != 0);
Chris Allegretta2084acc2001-11-29 03:43:08 +00002043
2044 if (old_totsize == -1)
2045 old_totsize = totsize;
2046
Chris Allegrettad26ab912003-01-28 01:16:47 +00002047 for (fileptr = fileage; fileptr != current; fileptr = fileptr->next) {
2048 assert(fileptr != NULL);
Chris Allegrettaf27c6972002-02-12 01:57:24 +00002049 i += strlen(fileptr->data) + 1;
Chris Allegrettad26ab912003-01-28 01:16:47 +00002050 }
Chris Allegrettaf27c6972002-02-12 01:57:24 +00002051 i += current_x;
Chris Allegretta14b3ca92002-01-25 21:59:02 +00002052
Chris Allegrettad26ab912003-01-28 01:16:47 +00002053 if (constant && ISSET(DISABLE_CURPOS)) {
2054 UNSET(DISABLE_CURPOS);
2055 old_i = i;
2056 old_totsize = totsize;
2057 return 0;
2058 }
Chris Allegretta14b3ca92002-01-25 21:59:02 +00002059
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002060 /* If constant is false, display the position on the statusbar
2061 * unconditionally; otherwise, only display the position when the
2062 * character values have changed. */
Chris Allegrettad26ab912003-01-28 01:16:47 +00002063 if (!constant || old_i != i || old_totsize != totsize) {
2064 unsigned long xpt = xplustabs() + 1;
2065 unsigned long cur_len = strlenpt(current->data) + 1;
2066 int linepct = 100 * current->lineno / totlines;
2067 int colpct = 100 * xpt / cur_len;
2068 int bytepct = totsize == 0 ? 0 : 100 * i / totsize;
2069
2070 statusbar(
2071 _("line %ld/%ld (%d%%), col %lu/%lu (%d%%), char %lu/%ld (%d%%)"),
2072 current->lineno, totlines, linepct,
2073 xpt, cur_len, colpct,
2074 i, totsize, bytepct);
2075 UNSET(DISABLE_CURPOS);
Chris Allegretta2084acc2001-11-29 03:43:08 +00002076 }
2077
2078 old_i = i;
2079 old_totsize = totsize;
2080
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002081 reset_cursor();
Chris Allegrettad26ab912003-01-28 01:16:47 +00002082 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002083}
2084
Chris Allegretta2084acc2001-11-29 03:43:08 +00002085int do_cursorpos_void(void)
2086{
2087 return do_cursorpos(0);
2088}
2089
Chris Allegretta4640fe32003-02-10 03:10:03 +00002090/* Calculate the next line of help_text, starting at ptr. */
2091int line_len(const char *ptr)
2092{
2093 int j = 0;
2094
2095 while (*ptr != '\n' && *ptr != '\0' && j < COLS - 5) {
2096 ptr++;
2097 j++;
2098 }
2099 if (j == COLS - 5) {
2100 /* Don't wrap at the first of two spaces following a period. */
2101 if (*ptr == ' ' && *(ptr + 1) == ' ')
2102 j++;
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002103 /* Don't print half a word if we've run out of space. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00002104 while (*ptr != ' ' && j > 0) {
2105 ptr--;
2106 j--;
2107 }
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002108 /* Word longer than COLS - 5 chars just gets broken. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00002109 if (j == 0)
2110 j = COLS - 5;
2111 }
2112 assert(j >= 0 && j <= COLS - 4 && (j > 0 || *ptr == '\n'));
2113 return j;
2114}
2115
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002116/* Our shortcut-list-compliant help function, which is better than
2117 * nothing, and dynamic! */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002118int do_help(void)
2119{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002120#ifndef DISABLE_HELP
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00002121 int i, page = 0, kbinput = -1, meta, no_more = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002122 int no_help_flag = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002123 const shortcut *oldshortcut;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002124
2125 blank_edit();
2126 curs_set(0);
Chris Allegrettab3655b42001-10-22 03:15:31 +00002127 wattroff(bottomwin, A_REVERSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002128 blank_statusbar();
2129
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002130 /* Set help_text as the string to display. */
Chris Allegrettab3655b42001-10-22 03:15:31 +00002131 help_init();
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002132 assert(help_text != NULL);
Chris Allegrettab3655b42001-10-22 03:15:31 +00002133
2134 oldshortcut = currshortcut;
Chris Allegrettab3655b42001-10-22 03:15:31 +00002135
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002136 currshortcut = help_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00002137
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002138 if (ISSET(NO_HELP)) {
2139
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002140 /* Well, if we're going to do this, we should at least do it the
2141 * right way. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002142 no_help_flag = 1;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002143 UNSET(NO_HELP);
Chris Allegretta70444892001-01-07 23:02:02 +00002144 window_init();
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002145 bottombars(help_list);
Chris Allegretta70444892001-01-07 23:02:02 +00002146
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002147 } else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002148 bottombars(help_list);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002149
2150 do {
Chris Allegrettaf717f982003-02-13 22:25:01 +00002151 const char *ptr = help_text;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002152
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002153 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002154#ifndef DISABLE_MOUSE
Chris Allegretta598106e2002-01-19 01:59:37 +00002155 case KEY_MOUSE:
2156 do_mouse();
2157 break;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002158#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002159 case NANO_NEXTPAGE_KEY:
2160 case NANO_NEXTPAGE_FKEY:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002161 if (!no_more) {
2162 blank_edit();
2163 page++;
2164 }
2165 break;
2166 case NANO_PREVPAGE_KEY:
2167 case NANO_PREVPAGE_FKEY:
Chris Allegretta4640fe32003-02-10 03:10:03 +00002168 if (page > 0) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002169 no_more = 0;
2170 blank_edit();
2171 page--;
2172 }
2173 break;
2174 }
2175
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002176 /* Calculate where in the text we should be, based on the
2177 * page. */
Chris Allegretta4640fe32003-02-10 03:10:03 +00002178 for (i = 1; i < page * (editwinrows - 1); i++) {
2179 ptr += line_len(ptr);
2180 if (*ptr == '\n')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002181 ptr++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002182 }
2183
Chris Allegretta4640fe32003-02-10 03:10:03 +00002184 for (i = 0; i < editwinrows && *ptr != '\0'; i++) {
2185 int j = line_len(ptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002186
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002187 mvwaddnstr(edit, i, 0, ptr, j);
Chris Allegretta4640fe32003-02-10 03:10:03 +00002188 ptr += j;
2189 if (*ptr == '\n')
2190 ptr++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002191 }
Chris Allegretta4640fe32003-02-10 03:10:03 +00002192
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002193 if (*ptr == '\0') {
2194 no_more = 1;
2195 continue;
2196 }
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002197 } while ((kbinput = get_kbinput(edit, &meta)) != NANO_EXIT_KEY && kbinput != NANO_EXIT_FKEY);
Chris Allegrettad1627cf2000-12-18 05:03:16 +00002198
Chris Allegrettab3655b42001-10-22 03:15:31 +00002199 currshortcut = oldshortcut;
Chris Allegrettab3655b42001-10-22 03:15:31 +00002200
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002201 if (no_help_flag) {
Chris Allegretta70444892001-01-07 23:02:02 +00002202 blank_bottombars();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002203 wrefresh(bottomwin);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002204 SET(NO_HELP);
Chris Allegretta70444892001-01-07 23:02:02 +00002205 window_init();
Chris Allegretta598106e2002-01-19 01:59:37 +00002206 } else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002207 bottombars(currshortcut);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002208
2209 curs_set(1);
2210 edit_refresh();
Chris Allegrettac08f50d2001-01-06 18:12:43 +00002211
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002212 /* The help_init() at the beginning allocated help_text, which has
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002213 * now been written to the screen. */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002214 free(help_text);
2215 help_text = NULL;
2216
Chris Allegretta6df90f52002-07-19 01:08:59 +00002217#elif defined(DISABLE_HELP)
2218 nano_disabled_msg();
2219#endif
2220
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002221 return 1;
2222}
2223
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002224/* Highlight the current word being replaced or spell checked. We
2225 * expect word to have tabs and control characters expanded. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002226void do_replace_highlight(int highlight_flag, const char *word)
Chris Allegrettafb62f732000-12-05 11:36:41 +00002227{
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002228 int y = xplustabs();
2229 size_t word_len = strlen(word);
Chris Allegrettafb62f732000-12-05 11:36:41 +00002230
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002231 y = get_page_start(y) + COLS - y;
2232 /* Now y is the number of characters we can display on this
2233 * line. */
Chris Allegrettafb62f732000-12-05 11:36:41 +00002234
2235 reset_cursor();
Chris Allegretta598106e2002-01-19 01:59:37 +00002236
Chris Allegrettafb62f732000-12-05 11:36:41 +00002237 if (highlight_flag)
2238 wattron(edit, A_REVERSE);
2239
David Lawrence Ramsey2a4ab6d2003-12-24 08:29:49 +00002240#ifdef HAVE_REGEX_H
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00002241 /* This is so we can show zero-length regexes. */
2242 if (word_len == 0)
2243 waddstr(edit, " ");
2244 else
David Lawrence Ramsey2a4ab6d2003-12-24 08:29:49 +00002245#endif
David Lawrence Ramsey76c4b332003-12-24 08:17:54 +00002246 waddnstr(edit, word, y - 1);
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002247
2248 if (word_len > y)
2249 waddch(edit, '$');
2250 else if (word_len == y)
2251 waddch(edit, word[word_len - 1]);
Chris Allegrettafb62f732000-12-05 11:36:41 +00002252
2253 if (highlight_flag)
2254 wattroff(edit, A_REVERSE);
Chris Allegrettafb62f732000-12-05 11:36:41 +00002255}
2256
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002257/* Fix editbot, based on the assumption that edittop is correct. */
2258void fix_editbot(void)
2259{
2260 int i;
2261
2262 editbot = edittop;
2263 for (i = 0; i < editwinrows && editbot->next != NULL; i++)
2264 editbot = editbot->next;
2265}
2266
2267#ifdef DEBUG
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002268/* Dump the passed-in file structure to stderr. */
2269void dump_buffer(const filestruct *inptr)
2270{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002271 if (inptr == fileage)
Jordi Mallachf9390af2003-08-05 19:31:12 +00002272 fprintf(stderr, "Dumping file buffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002273 else if (inptr == cutbuffer)
Jordi Mallachf9390af2003-08-05 19:31:12 +00002274 fprintf(stderr, "Dumping cutbuffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002275 else
Jordi Mallachf9390af2003-08-05 19:31:12 +00002276 fprintf(stderr, "Dumping a buffer to stderr...\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002277
2278 while (inptr != NULL) {
2279 fprintf(stderr, "(%d) %s\n", inptr->lineno, inptr->data);
2280 inptr = inptr->next;
2281 }
2282}
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002283
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +00002284/* Dump the file structure to stderr in reverse. */
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00002285void dump_buffer_reverse(void)
2286{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002287 const filestruct *fileptr = filebot;
2288
2289 while (fileptr != NULL) {
2290 fprintf(stderr, "(%d) %s\n", fileptr->lineno, fileptr->data);
2291 fileptr = fileptr->prev;
2292 }
2293}
2294#endif /* DEBUG */
2295
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002296#ifdef NANO_EXTRA
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002297#define CREDIT_LEN 53
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002298#define XLCREDIT_LEN 8
2299
David Lawrence Ramseyfdece462004-01-19 18:15:03 +00002300/* Easter egg: Display credits. Assume nodelay(edit) is FALSE. */
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002301void do_credits(void)
2302{
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002303 int i, j = 0, k, place = 0, start_x;
David Lawrence Ramseye97c8d52004-01-14 19:26:29 +00002304 struct timespec scrolldelay;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002305
Chris Allegrettaf717f982003-02-13 22:25:01 +00002306 const char *what;
2307 const char *xlcredits[XLCREDIT_LEN];
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002308
Chris Allegrettaf717f982003-02-13 22:25:01 +00002309 const char *credits[CREDIT_LEN] = {
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002310 "0", /* "The nano text editor" */
2311 "1", /* "version" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002312 VERSION,
2313 "",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002314 "2", /* "Brought to you by:" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002315 "Chris Allegretta",
2316 "Jordi Mallach",
2317 "Adam Rogoyski",
2318 "Rob Siemborski",
2319 "Rocco Corsi",
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002320 "David Lawrence Ramsey",
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002321 "David Benbennick",
Chris Allegretta598106e2002-01-19 01:59:37 +00002322 "Ken Tyler",
2323 "Sven Guckes",
2324 "Florian König",
2325 "Pauli Virtanen",
2326 "Daniele Medri",
2327 "Clement Laforet",
2328 "Tedi Heriyanto",
2329 "Bill Soudan",
2330 "Christian Weisgerber",
2331 "Erik Andersen",
2332 "Big Gaute",
2333 "Joshua Jensen",
2334 "Ryan Krebs",
2335 "Albert Chin",
Chris Allegretta598106e2002-01-19 01:59:37 +00002336 "",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002337 "3", /* "Special thanks to:" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002338 "Plattsburgh State University",
2339 "Benet Laboratories",
2340 "Amy Allegretta",
2341 "Linda Young",
2342 "Jeremy Robichaud",
2343 "Richard Kolb II",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002344 "4", /* "The Free Software Foundation" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002345 "Linus Torvalds",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002346 "5", /* "For ncurses:" */
Chris Allegrettadce44ab2002-03-16 01:03:41 +00002347 "Thomas Dickey",
2348 "Pavel Curtis",
2349 "Zeyd Ben-Halim",
2350 "Eric S. Raymond",
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002351 "6", /* "and anyone else we forgot..." */
2352 "7", /* "Thank you for using nano!\n" */
Chris Allegretta598106e2002-01-19 01:59:37 +00002353 "", "", "", "",
David Lawrence Ramsey6481c3f2004-01-09 23:06:54 +00002354 "(c) 1999-2004 Chris Allegretta",
Chris Allegretta598106e2002-01-19 01:59:37 +00002355 "", "", "", "",
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002356 "http://www.nano-editor.org/"
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002357 };
2358
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002359 xlcredits[0] = _("The nano text editor");
2360 xlcredits[1] = _("version ");
2361 xlcredits[2] = _("Brought to you by:");
2362 xlcredits[3] = _("Special thanks to:");
2363 xlcredits[4] = _("The Free Software Foundation");
2364 xlcredits[5] = _("For ncurses:");
2365 xlcredits[6] = _("and anyone else we forgot...");
2366 xlcredits[7] = _("Thank you for using nano!\n");
2367
David Lawrence Ramsey9da08312004-01-14 22:40:38 +00002368 scrolldelay.tv_sec = 0;
David Lawrence Ramsey62187d92004-01-14 22:45:05 +00002369 scrolldelay.tv_nsec = 700000000;
David Lawrence Ramseye97c8d52004-01-14 19:26:29 +00002370
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002371 curs_set(0);
2372 nodelay(edit, TRUE);
2373 blank_bottombars();
2374 mvwaddstr(topwin, 0, 0, hblank);
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002375 blank_edit();
2376 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002377 wrefresh(bottomwin);
2378 wrefresh(topwin);
2379
2380 while (wgetch(edit) == ERR) {
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002381 for (k = 0; k <= 1; k++) {
2382 blank_edit();
Chris Allegretta598106e2002-01-19 01:59:37 +00002383 for (i = editwinrows / 2 - 1; i >= (editwinrows / 2 - 1 - j);
2384 i--) {
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002385 mvwaddstr(edit, i * 2 - k, 0, hblank);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002386
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002387 if (place - (editwinrows / 2 - 1 - i) < CREDIT_LEN) {
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002388 what = credits[place - (editwinrows / 2 - 1 - i)];
Chris Allegrettac4e3d9e2002-07-21 15:44:13 +00002389
2390 /* God I've missed hacking. If what is exactly
2391 1 char long, it's a sentinel for a translated
2392 string, so use that instead. This means no
2393 thanking people with 1 character long names ;-) */
2394 if (strlen(what) == 1)
2395 what = xlcredits[atoi(what)];
2396 } else
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002397 what = "";
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002398
Chris Allegretta17dcb722001-01-20 21:40:07 +00002399 start_x = COLS / 2 - strlen(what) / 2 - 1;
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002400 mvwaddstr(edit, i * 2 - k, start_x, what);
2401 }
David Lawrence Ramseye97c8d52004-01-14 19:26:29 +00002402 nanosleep(&scrolldelay, NULL);
Chris Allegretta8b4ca4a2000-11-25 18:21:37 +00002403 wrefresh(edit);
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002404 }
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002405 if (j < editwinrows / 2 - 1)
2406 j++;
2407
2408 place++;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002409
2410 if (place >= CREDIT_LEN + editwinrows / 2)
2411 break;
2412 }
2413
2414 nodelay(edit, FALSE);
2415 curs_set(1);
2416 display_main_list();
2417 total_refresh();
Chris Allegretta598106e2002-01-19 01:59:37 +00002418}
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00002419#endif