winio.c 44.5 KB
Newer Older
Chris Allegretta's avatar
Chris Allegretta committed
1
/* $Id$ */
Chris Allegretta's avatar
Chris Allegretta committed
2
3
4
/**************************************************************************
 *   winio.c                                                              *
 *                                                                        *
5
 *   Copyright (C) 1999-2002 Chris Allegretta                             *
Chris Allegretta's avatar
Chris Allegretta committed
6
7
 *   This program is free software; you can redistribute it and/or modify *
 *   it under the terms of the GNU General Public License as published by *
8
 *   the Free Software Foundation; either version 2, or (at your option)  *
Chris Allegretta's avatar
Chris Allegretta committed
9
10
11
12
13
14
15
16
17
18
19
20
21
 *   any later version.                                                   *
 *                                                                        *
 *   This program is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of       *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
 *   GNU General Public License for more details.                         *
 *                                                                        *
 *   You should have received a copy of the GNU General Public License    *
 *   along with this program; if not, write to the Free Software          *
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
 *                                                                        *
 **************************************************************************/

22
23
#include "config.h"

Chris Allegretta's avatar
Chris Allegretta committed
24
25
#include <stdarg.h>
#include <string.h>
26
#include <stdlib.h>
27
#include <unistd.h>
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
28
#include <ctype.h>
29
#include <assert.h>
Chris Allegretta's avatar
Chris Allegretta committed
30
31
32
33
#include "proto.h"
#include "nano.h"

static int statblank = 0;	/* Number of keystrokes left after
34
				   we call statusbar(), before we
Chris Allegretta's avatar
Chris Allegretta committed
35
				   actually blank the statusbar */
36

Chris Allegretta's avatar
Chris Allegretta committed
37
38
39
40
41
int do_first_line(void)
{
    current = fileage;
    placewewant = 0;
    current_x = 0;
42
    edit_update(current, CENTER);
Chris Allegretta's avatar
Chris Allegretta committed
43
44
45
46
47
48
49
50
    return 1;
}

int do_last_line(void)
{
    current = filebot;
    placewewant = 0;
    current_x = 0;
51
    edit_update(current, CENTER);
Chris Allegretta's avatar
Chris Allegretta committed
52
53
54
    return 1;
}

Chris Allegretta's avatar
Chris Allegretta committed
55
56
57
58
/* Return the placewewant associated with current_x.  That is, xplustabs
 * is the zero-based column position of the cursor.  Value is no smaller
 * than current_x. */
size_t xplustabs(void)
Chris Allegretta's avatar
Chris Allegretta committed
59
{
Chris Allegretta's avatar
Chris Allegretta committed
60
    return strnlenpt(current->data, current_x);
Chris Allegretta's avatar
Chris Allegretta committed
61
62
}

Chris Allegretta's avatar
Chris Allegretta committed
63
64
/* Return what current_x should be, given xplustabs() for the line. */
size_t actual_x(const filestruct *fileptr, size_t xplus)
Chris Allegretta's avatar
Chris Allegretta committed
65
{
Chris Allegretta's avatar
Chris Allegretta committed
66
67
68
69
70
71
72
73
74
75
76
77
    size_t i = 0;
	/* the position in fileptr->data, returned */
    size_t length = 0;
	/* the screen display width to data[i] */
    char *c;
	/* fileptr->data + i */

    assert(fileptr != NULL && fileptr->data != NULL);

    for (c = fileptr->data; length < xplus && *c != '\0'; i++, c++) {
	if (*c == '\t')
	    length += tabsize - length % tabsize;
Chris Allegretta's avatar
Chris Allegretta committed
78
	else if (is_cntrl_char((int)*c))
Chris Allegretta's avatar
Chris Allegretta committed
79
80
81
82
83
84
	    length += 2;
	else
	    length++;
    }
    assert(length == strnlenpt(fileptr->data, i));
    assert(i <= strlen(fileptr->data));
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
85

Chris Allegretta's avatar
Chris Allegretta committed
86
87
    if (length > xplus)
	i--;
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
88

Chris Allegretta's avatar
Chris Allegretta committed
89
#ifdef DEBUG
Chris Allegretta's avatar
Chris Allegretta committed
90
    fprintf(stderr, _("actual_x for xplus=%d returns %d\n"), xplus, i);
Chris Allegretta's avatar
Chris Allegretta committed
91
#endif
Chris Allegretta's avatar
Chris Allegretta committed
92

Chris Allegretta's avatar
Chris Allegretta committed
93
    return i;
94
95
}

Chris Allegretta's avatar
Chris Allegretta committed
96
97
/* A strlen with tabs factored in, similar to xplustabs(). */
size_t strnlenpt(const char *buf, size_t size)
98
{
Chris Allegretta's avatar
Chris Allegretta committed
99
100
101
102
103
104
    size_t length = 0;

    if (buf != NULL)
	for (; *buf != '\0' && size != 0; size--, buf++) {
	    if (*buf == '\t')
		length += tabsize - (length % tabsize);
Chris Allegretta's avatar
Chris Allegretta committed
105
	    else if (is_cntrl_char((int)*buf))
Chris Allegretta's avatar
Chris Allegretta committed
106
		length += 2;
Chris Allegretta's avatar
Chris Allegretta committed
107
	    else
Chris Allegretta's avatar
Chris Allegretta committed
108
109
110
		length++;
	}
    return length;
Chris Allegretta's avatar
Chris Allegretta committed
111
112
}

Chris Allegretta's avatar
Chris Allegretta committed
113
size_t strlenpt(const char *buf)
114
{
Chris Allegretta's avatar
Chris Allegretta committed
115
    return strnlenpt(buf, -1);
116
117
}

Chris Allegretta's avatar
Chris Allegretta committed
118
119
void blank_bottombars(void)
{
Chris Allegretta's avatar
Chris Allegretta committed
120
121
122
123
    if (!no_help()) {
	mvwaddstr(bottomwin, 1, 0, hblank);
	mvwaddstr(bottomwin, 2, 0, hblank);
    }
Chris Allegretta's avatar
Chris Allegretta committed
124
125
}

126
127
128
129
130
131
132
133
134
void blank_bottomwin(void)
{
    if (ISSET(NO_HELP))
	return;

    mvwaddstr(bottomwin, 1, 0, hblank);
    mvwaddstr(bottomwin, 2, 0, hblank);
}

Chris Allegretta's avatar
Chris Allegretta committed
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
void blank_edit(void)
{
    int i;
    for (i = 0; i <= editwinrows - 1; i++)
	mvwaddstr(edit, i, 0, hblank);
}


void blank_statusbar(void)
{
    mvwaddstr(bottomwin, 0, 0, hblank);
}

void blank_statusbar_refresh(void)
{
    blank_statusbar();
    wrefresh(bottomwin);
}

void check_statblank(void)
{
    if (statblank > 1)
	statblank--;
    else if (statblank == 1 && !ISSET(CONSTUPDATE)) {
	statblank--;
	blank_statusbar_refresh();
    }
}

Chris Allegretta's avatar
Chris Allegretta committed
164
165
166
167
168
/* Repaint the statusbar when getting a character in nanogetstr.  buf
 * should be no longer than COLS - 4.
 *
 * Note that we must turn on A_REVERSE here, since do_help turns it
 * off! */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
169
void nanoget_repaint(const char *buf, const char *inputbuf, int x)
170
{
Chris Allegretta's avatar
Chris Allegretta committed
171
    int len = strlen(buf) + 2;
172
    int wid = COLS - len;
173

Chris Allegretta's avatar
Chris Allegretta committed
174
175
176
    assert(wid >= 2);
    assert(0 <= x && x <= strlen(inputbuf));

177
    wattron(bottomwin, A_REVERSE);
178
    blank_statusbar();
Chris Allegretta's avatar
Chris Allegretta committed
179
180
181
182
183
    mvwaddstr(bottomwin, 0, 0, buf);
    waddch(bottomwin, ':');
    waddch(bottomwin, x < wid ? ' ' : '$');
    waddnstr(bottomwin, &inputbuf[wid * (x / wid)], wid);
    wmove(bottomwin, 0, (x % wid) + len);
184
    wattroff(bottomwin, A_REVERSE);
185
186
}

Chris Allegretta's avatar
Chris Allegretta committed
187
188
/* Get the input from the kb; this should only be called from
 * statusq(). */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
189
int nanogetstr(int allowtabs, const char *buf, const char *def,
190
191
192
#ifndef NANO_SMALL
		historyheadtype *history_list,
#endif
193
		const shortcut *s
194
#ifndef DISABLE_TABCOMP
195
		, int *list
196
#endif
197
		)
Chris Allegretta's avatar
Chris Allegretta committed
198
199
200
201
202
203
204
205
206
207
{
    int kbinput;
    int x;
	/* the cursor position in 'answer' */
    int xend;
	/* length of 'answer', the status bar text */
    int tabbed = 0;
	/* used by input_tab() */
    const shortcut *t;

208
209
210
#ifndef NANO_SMALL
   /* for history */
    char *history = NULL;
211
    char *currentbuf = NULL;
212
    char *complete = NULL;
213
    int last_kbinput = 0, ret2cb = 0;
214
#endif
Chris Allegretta's avatar
Chris Allegretta committed
215
216
217
218
219
220
221
    xend = strlen(def);
    x = xend;
    answer = (char *)nrealloc(answer, xend + 1);
    if (xend > 0)
	strcpy(answer, def);
    else
	answer[0] = '\0';
Chris Allegretta's avatar
Chris Allegretta committed
222

223
#if !defined(DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
224
    currshortcut = s;
225
226
#endif

Chris Allegretta's avatar
Chris Allegretta committed
227
    /* Get the input! */
228

Chris Allegretta's avatar
Chris Allegretta committed
229
    nanoget_repaint(buf, answer, x);
Chris Allegretta's avatar
Chris Allegretta committed
230

231
232
    /* Make sure any editor screen updates are displayed before getting
       input */
233
234
    wrefresh(edit);

Chris Allegretta's avatar
Chris Allegretta committed
235
    while ((kbinput = wgetch(bottomwin)) != 13) {
236
	for (t = s; t != NULL; t = t->next) {
237
238
239
240
#ifdef DEBUG
	    fprintf(stderr, _("Aha! \'%c\' (%d)\n"), kbinput, kbinput);
#endif

241
	    if (kbinput == t->val && kbinput < 32) {
242

243
#ifndef DISABLE_HELP
244
245
		/* Have to do this here, it would be too late to do it
		   in statusq() */
Chris Allegretta's avatar
Chris Allegretta committed
246
		if (kbinput == NANO_HELP_KEY || kbinput == NANO_HELP_FKEY) {
247
248
249
250
		    do_help();
		    break;
		}
#endif
251
		return t->val;
Chris Allegretta's avatar
Chris Allegretta committed
252
253
	    }
	}
Chris Allegretta's avatar
Chris Allegretta committed
254
	assert(0 <= x && x <= xend && xend == strlen(answer));
Chris Allegretta's avatar
Chris Allegretta committed
255

Chris Allegretta's avatar
Chris Allegretta committed
256
257
258
	if (kbinput != '\t')
	    tabbed = 0;

Chris Allegretta's avatar
Chris Allegretta committed
259
	switch (kbinput) {
260

Chris Allegretta's avatar
Chris Allegretta committed
261
	    /* Stuff we want to equate with <enter>, ASCII 13 */
262
	case 343:
263
264
	    ungetch(13);	/* Enter on iris-ansi $TERM, sometimes */
	    break;
Chris Allegretta's avatar
Chris Allegretta committed
265
	    /* Stuff we want to ignore */
266
267
268
#ifdef PDCURSES
	case 541:
	case 542:
Chris Allegretta's avatar
Chris Allegretta committed
269
	case 543:		/* Right ctrl again */
270
	case 544:
Chris Allegretta's avatar
Chris Allegretta committed
271
	case 545:		/* Right alt again */
272
273
	    break;
#endif
274
#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
275
276
277
	case KEY_MOUSE:
	    do_mouse();
	    break;
278
#endif
279
	case NANO_HOME_KEY:
Chris Allegretta's avatar
Chris Allegretta committed
280
	case KEY_HOME:
Chris Allegretta's avatar
Chris Allegretta committed
281
	    x = 0;
Chris Allegretta's avatar
Chris Allegretta committed
282
	    break;
283
	case NANO_END_KEY:
Chris Allegretta's avatar
Chris Allegretta committed
284
	case KEY_END:
Chris Allegretta's avatar
Chris Allegretta committed
285
	    x = xend;
Chris Allegretta's avatar
Chris Allegretta committed
286
287
	    break;
	case KEY_RIGHT:
288
	case NANO_FORWARD_KEY:
Chris Allegretta's avatar
Chris Allegretta committed
289
290
291
292
	    if (x < xend)
		x++;
	    break;
	case NANO_CONTROL_D:
Chris Allegretta's avatar
Chris Allegretta committed
293
294
295
	    if (x < xend) {
		memmove(answer + x, answer + x + 1, xend - x);
		xend--;
Chris Allegretta's avatar
Chris Allegretta committed
296
297
298
299
	    }
	    break;
	case NANO_CONTROL_K:
	case NANO_CONTROL_U:
Chris Allegretta's avatar
Chris Allegretta committed
300
301
302
	    null_at(&answer, 0);
	    xend = 0;
	    x = 0;
Chris Allegretta's avatar
Chris Allegretta committed
303
304
305
306
	    break;
	case KEY_BACKSPACE:
	case 127:
	case NANO_CONTROL_H:
Chris Allegretta's avatar
Chris Allegretta committed
307
308
	    if (x > 0) {
		memmove(answer + x - 1, answer + x, xend - x + 1);
Chris Allegretta's avatar
Chris Allegretta committed
309
		x--;
Chris Allegretta's avatar
Chris Allegretta committed
310
311
		xend--;
	    }
Chris Allegretta's avatar
Chris Allegretta committed
312
313
	    break;
	case NANO_CONTROL_I:
314
315
316
317
318
319
320
#ifndef NANO_SMALL
	    /* tab history completion */
	    if (history_list) {
		if ((!complete) || (last_kbinput != NANO_CONTROL_I)) {
		    history_list->current = (historytype *)history_list;
		    history_list->len = strlen(answer);
		}
Chris Allegretta's avatar
Chris Allegretta committed
321

322
323
324
		if (history_list->len) {
		    complete = get_history_completion(history_list, answer);
		    xend = strlen(complete);
Chris Allegretta's avatar
Chris Allegretta committed
325
		    x = xend;
326
327
		    answer = mallocstrcpy(answer, complete);
		}
328
	    }
329
330
331
#ifndef DISABLE_TABCOMP
	    else {
#endif
332
#endif
333
334
335
336
337
338
339
340
341
342
343
344
345
#ifndef DISABLE_TABCOMP
		if (allowtabs) {
		    int shift = 0;

		    answer = input_tab(answer, x, &tabbed, &shift, list);
		    xend = strlen(answer);
		    x += shift;
		    if (x > xend)
			x = xend;
		}
	    }
#endif
	    break;
Chris Allegretta's avatar
Chris Allegretta committed
346
	case KEY_LEFT:
347
	case NANO_BACK_KEY:
Chris Allegretta's avatar
Chris Allegretta committed
348
	    if (x > 0)
Chris Allegretta's avatar
Chris Allegretta committed
349
350
351
		x--;
	    break;
	case KEY_UP:
352
353
#ifndef NANO_SMALL
	    if (history_list) {
354
355
356
357
358
359
360
361

		/* If there's no previous temp holder, or if we already arrowed 
		   back down to it and (possibly edited ir), update the holder  */
		if (currentbuf == NULL || (ret2cb == 1 && strcmp(currentbuf, answer))) {
		    currentbuf = mallocstrcpy(currentbuf, answer);
		    ret2cb = 0;
		}

362
363
364
365
366
367
368
369
370
371
372
		/* get older search from the history list */
		if ((history = get_history_older(history_list))) {
		    answer = mallocstrcpy(answer, history);
		    xend = strlen(history);
		} else {
		    answer = mallocstrcpy(answer, "");
		    xend = 0;
		}
		x = xend;
	    }
#endif
373
	    break;
Chris Allegretta's avatar
Chris Allegretta committed
374
	case KEY_DOWN:
375
376
377
378
379
380
#ifndef NANO_SMALL
	    if (history_list) {
		/* get newer search from the history list */
		if ((history = get_history_newer(history_list))) {
		    answer = mallocstrcpy(answer, history);
		    xend = strlen(history);
381
382
383
384
385
386
387

		/* Else if we ran out of history, regurgitate the temporary
		   buffer */
		} else if (currentbuf != NULL) {
		    answer = mallocstrcpy(answer, currentbuf);
		    xend = strlen(currentbuf);
		    ret2cb = 1;
388
389
390
391
392
393
394
		} else {
		    answer = mallocstrcpy(answer, "");
		    xend = 0;
		}
		x = xend;
	    }
#endif
Chris Allegretta's avatar
Chris Allegretta committed
395
	    break;
396
397
398
	case KEY_DC:
	    goto do_deletekey;

Chris Allegretta's avatar
Chris Allegretta committed
399
400
	case 27:
	    switch (kbinput = wgetch(edit)) {
401
	    case 'O':
Chris Allegretta's avatar
Chris Allegretta committed
402
		switch (kbinput = wgetch(edit)) {
403
		case 'F':
Chris Allegretta's avatar
Chris Allegretta committed
404
		    x = xend;
Chris Allegretta's avatar
Chris Allegretta committed
405
		    break;
406
		case 'H':
Chris Allegretta's avatar
Chris Allegretta committed
407
		    x = 0;
Chris Allegretta's avatar
Chris Allegretta committed
408
409
410
		    break;
		}
		break;
411
	    case '[':
Chris Allegretta's avatar
Chris Allegretta committed
412
413
414
415
416
417
		switch (kbinput = wgetch(edit)) {
		case 'C':
		    if (x < xend)
			x++;
		    break;
		case 'D':
Chris Allegretta's avatar
Chris Allegretta committed
418
		    if (x > 0)
Chris Allegretta's avatar
Chris Allegretta committed
419
420
			x--;
		    break;
421
422
		case '1':
		case '7':
Chris Allegretta's avatar
Chris Allegretta committed
423
		    x = 0;
424
425
426
		    goto skip_tilde;
		case '3':
		  do_deletekey:
Chris Allegretta's avatar
Chris Allegretta committed
427
428
429
		    if (x < xend) {
			memmove(answer + x, answer + x + 1, xend - x);
			xend--;
Chris Allegretta's avatar
Chris Allegretta committed
430
		    }
431
432
433
		    goto skip_tilde;
		case '4':
		case '8':
Chris Allegretta's avatar
Chris Allegretta committed
434
		    x = xend;
435
436
		    goto skip_tilde;
		  skip_tilde:
Chris Allegretta's avatar
Chris Allegretta committed
437
438
		    nodelay(edit, TRUE);
		    kbinput = wgetch(edit);
439
		    if (kbinput == '~' || kbinput == ERR)
Chris Allegretta's avatar
Chris Allegretta committed
440
441
442
443
			kbinput = -1;
		    nodelay(edit, FALSE);
		    break;
		}
Chris Allegretta's avatar
Chris Allegretta committed
444
		break;
445
446
	    default:

447
		for (t = s; t != NULL; t = t->next) {
448
#ifdef DEBUG
Chris Allegretta's avatar
Chris Allegretta committed
449
450
		    fprintf(stderr, _("Aha! \'%c\' (%d)\n"), kbinput,
			    kbinput);
451
#endif
452
		    if (kbinput == t->val || kbinput == t->val - 32) {
453
454
455
			/* We hit an Alt key.   Do like above.  We don't
			   just ungetch the letter and let it get caught
			   above cause that screws the keypad... */
456
			return t->val;
457
458
		    }
		}
Chris Allegretta's avatar
Chris Allegretta committed
459
460
461
462
463
464
	    }
	    break;

	default:
	    if (kbinput < 32)
		break;
Chris Allegretta's avatar
Chris Allegretta committed
465
466
467
468
	    answer = nrealloc(answer, xend + 2);
	    memmove(answer + x + 1, answer + x, xend - x + 1);
	    xend++;
	    answer[x] = kbinput;
Chris Allegretta's avatar
Chris Allegretta committed
469
470
471
472
473
	    x++;

#ifdef DEBUG
	    fprintf(stderr, _("input \'%c\' (%d)\n"), kbinput, kbinput);
#endif
474
	} /* switch (kbinput) */
475
#ifndef NANO_SMALL
476
	last_kbinput = kbinput;
477
#endif
Chris Allegretta's avatar
Chris Allegretta committed
478
	nanoget_repaint(buf, answer, x);
Chris Allegretta's avatar
Chris Allegretta committed
479
	wrefresh(bottomwin);
Chris Allegretta's avatar
Chris Allegretta committed
480
    } /* while (kbinput ...) */
Chris Allegretta's avatar
Chris Allegretta committed
481

Chris Allegretta's avatar
Chris Allegretta committed
482
    /* In Pico mode, just check for a blank answer here */
483
    if (answer[0] == '\0')
Chris Allegretta's avatar
Chris Allegretta committed
484
485
486
487
488
	return -2;
    else
	return 0;
}

489
490
491
492
493
494
495
496
497
498
/* If modified is not already set, set it and update titlebar. */
void set_modified(void)
{
    if (!ISSET(MODIFIED)) {
	SET(MODIFIED);
	titlebar(NULL);
	wrefresh(topwin);
    }
}

Chris Allegretta's avatar
Chris Allegretta committed
499
void titlebar(const char *path)
Chris Allegretta's avatar
Chris Allegretta committed
500
501
{
    int namelen, space;
Chris Allegretta's avatar
Chris Allegretta committed
502
    const char *what = path;
Chris Allegretta's avatar
Chris Allegretta committed
503
504
505

    if (path == NULL)
	what = filename;
Chris Allegretta's avatar
Chris Allegretta committed
506
507

    wattron(topwin, A_REVERSE);
508

Chris Allegretta's avatar
Chris Allegretta committed
509
    mvwaddstr(topwin, 0, 0, hblank);
510
    mvwaddnstr(topwin, 0, 2, VERMSG, COLS - 3);
Chris Allegretta's avatar
Chris Allegretta committed
511

Chris Allegretta's avatar
Chris Allegretta committed
512
    space = COLS - sizeof(VERMSG) - 22;
Chris Allegretta's avatar
Chris Allegretta committed
513

Chris Allegretta's avatar
Chris Allegretta committed
514
    namelen = strlen(what);
Chris Allegretta's avatar
Chris Allegretta committed
515

516
517
    if (space > 0) {
        if (what[0] == '\0')
Chris Allegretta's avatar
Chris Allegretta committed
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
      	    mvwaddnstr(topwin, 0, COLS / 2 - 6, _("New Buffer"),
			COLS / 2 + COLS % 2 - 6);
        else if (namelen > space) {
	    if (path == NULL)
		waddstr(topwin, _("  File: ..."));
	    else
		waddstr(topwin, _("   DIR: ..."));
	    waddstr(topwin, &what[namelen - space]);
	} else {
	    if (path == NULL)
		mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
				_("File: "));
	    else
		mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
				_(" DIR: "));
	    waddstr(topwin, what);
Chris Allegretta's avatar
Chris Allegretta committed
534
	}
535
    } /* If we don't have space, we shouldn't bother */
Chris Allegretta's avatar
Chris Allegretta committed
536
    if (ISSET(MODIFIED))
Chris Allegretta's avatar
Chris Allegretta committed
537
	mvwaddnstr(topwin, 0, COLS - 11, _(" Modified "), 11);
Chris Allegretta's avatar
Chris Allegretta committed
538
    else if (ISSET(VIEW_MODE))
Chris Allegretta's avatar
Chris Allegretta committed
539
	mvwaddnstr(topwin, 0, COLS - 11, _(" View "), 11);
540

Chris Allegretta's avatar
Chris Allegretta committed
541
    wattroff(topwin, A_REVERSE);
542

Chris Allegretta's avatar
Chris Allegretta committed
543
544
545
546
    wrefresh(topwin);
    reset_cursor();
}

547
void bottombars(const shortcut *s)
Chris Allegretta's avatar
Chris Allegretta committed
548
{
549
    int i, j, numcols;
550
    char keystr[4];
551
552
    int slen;

Chris Allegretta's avatar
Chris Allegretta committed
553
554
555
    if (ISSET(NO_HELP))
	return;

556
557
558
559
560
561
562
563
    if (s == main_list) {
	slen = MAIN_VISIBLE;
	assert(MAIN_VISIBLE <= length_of_list(s));
    } else
	slen = length_of_list(s);

    /* There will be this many columns of shortcuts */
    numcols = (slen + (slen % 2)) / 2;
Chris Allegretta's avatar
Chris Allegretta committed
564

565
    blank_bottomwin();
566

567
568
    for (i = 0; i < numcols; i++) {
	for (j = 0; j <= 1; j++) {
Chris Allegretta's avatar
Chris Allegretta committed
569

570
	    wmove(bottomwin, 1 + j, i * (COLS / numcols));
571

572
	    /* Yucky sentinel values we can't handle a better way */
573
574
	    if (s->val == NANO_CONTROL_SPACE)
		strcpy(keystr, "^ ");
575
#ifndef NANO_SMALL
576
577
578
579
	    else if (s->val == KEY_UP)
		strcpy(keystr, _("Up"));
#endif /* NANO_SMALL */
	    else if (s->val > 0) {
580
581
582
583
584
585
		if (s->val < 64)
		    sprintf(keystr, "^%c", s->val + 64);
		else
		    sprintf(keystr, "M-%c", s->val - 32);
	    } else if (s->altval > 0)
		sprintf(keystr, "M-%c", s->altval);
586

587
	    onekey(keystr, s->desc, COLS / numcols);
Chris Allegretta's avatar
Chris Allegretta committed
588

589
590
591
	    s = s->next;
	    if (s == NULL)
		goto break_completely_out;
592
	}
Chris Allegretta's avatar
Chris Allegretta committed
593
    }
594

Chris Allegretta's avatar
Chris Allegretta committed
595
  break_completely_out:
Chris Allegretta's avatar
Chris Allegretta committed
596
597
598
    wrefresh(bottomwin);
}

599
600
601
602
603
/* Write a shortcut key to the help area at the bottom of the window. 
 * keystroke is e.g. "^G" and desc is e.g. "Get Help".
 * We are careful to write exactly len characters, even if len is
 * very small and keystroke and desc are long. */
void onekey(const char *keystroke, const char *desc, int len)
Chris Allegretta's avatar
Chris Allegretta committed
604
{
605

606
607
608
609
610
611
612
613
614
615
616
    wattron(bottomwin, A_REVERSE);
    waddnstr(bottomwin, keystroke, len);
    wattroff(bottomwin, A_REVERSE);
    len -= strlen(keystroke);
    if (len > 0) {
	waddch(bottomwin, ' ');
	len--;
	waddnstr(bottomwin, desc, len);
	len -= strlen(desc);
	for (; len > 0; len--)
	    waddch(bottomwin, ' ');
Chris Allegretta's avatar
Chris Allegretta committed
617
618
619
    }
}

620
/* And so start the display update routines. */
Chris Allegretta's avatar
Chris Allegretta committed
621

622
623
#ifndef NDEBUG
int check_linenumbers(const filestruct *fileptr)
Chris Allegretta's avatar
Chris Allegretta committed
624
{
625
626
    int check_line = 0;
    const filestruct *filetmp;
627

628
629
630
    for (filetmp = edittop; filetmp != fileptr; filetmp = filetmp->next)
	check_line++;
    return check_line;
631
}
632
#endif
633

634
635
636
 /* nano scrolls horizontally within a line in chunks.  This function
  * returns the column number of the first character displayed in the
  * window when the cursor is at the given column. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
637
int get_page_start(int column)
Chris Allegretta's avatar
Chris Allegretta committed
638
639
640
641
642
{
    assert(COLS > 9);
    return column < COLS - 1 ? 0 : column - 7 - (column - 8) % (COLS - 9);
}

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
643
644
645
646
647
648
649
/* Resets current_y, based on the position of current, and puts the
 * cursor at (current_y, current_x). */
void reset_cursor(void)
{
    const filestruct *ptr = edittop;
    size_t x;

650
651
    /* Yuck.  This condition can be true after open_file() when opening
     * the first file. */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
652
653
654
655
656
657
658
659
660
661
662
663
664
    if (edittop == NULL)
	return;

    current_y = 0;

    while (ptr != current && ptr != editbot && ptr->next != NULL) {
	ptr = ptr->next;
	current_y++;
    }

    x = xplustabs();
    wmove(edit, current_y, x - get_page_start(x));
}
Chris Allegretta's avatar
Chris Allegretta committed
665

666
667
668
/* edit_add() takes care of the job of actually painting a line into
 * the edit window.  Called only from update_line().  Expects a
 * converted-to-not-have-tabs line. */
669
670
671
672
673
void edit_add(const filestruct *fileptr, int yval, int start
#ifndef NANO_SMALL
		, int virt_mark_beginx,	int virt_cur_x
#endif
		)
Chris Allegretta's avatar
Chris Allegretta committed
674
{
675
676
677
#ifdef DEBUG
    fprintf(stderr, "Painting line %d, current is %d\n", fileptr->lineno,
		current->lineno);
678
679
680
#endif

    /* Just paint the string in any case (we'll add color or reverse on
Chris Allegretta's avatar
Chris Allegretta committed
681
       just the text that needs it */
682
    mvwaddnstr(edit, yval, 0, &fileptr->data[start], COLS);
683

Chris Allegretta's avatar
Chris Allegretta committed
684
#ifdef ENABLE_COLOR
685
    if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) {
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
	const colortype *tmpcolor = colorstrings;

	for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
	    int x_start;
		/* Starting column for mvwaddnstr.  Zero-based. */
	    int paintlen;
		/* number of chars to paint on this line.  There are COLS
		 * characters on a whole line. */
	    regex_t start_regexp;	/* Compiled search regexp */
	    regmatch_t startmatch;	/* match position for start_regexp*/
	    regmatch_t endmatch;	/* match position for end_regexp*/

	    regcomp(&start_regexp, tmpcolor->start, REG_EXTENDED);

	    if (tmpcolor->bright)
		wattron(edit, A_BOLD);
	    wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
	    /* Two notes about regexec.  Return value 0 means there is a
	     * match.  Also, rm_eo is the first non-matching character
	     * after the match. */

	    /* First case, tmpcolor is a single-line expression. */
708
	    if (tmpcolor->end == NULL) {
709
710
711
712
713
714
715
716
717
		size_t k = 0;

		/* We increment k by rm_eo, to move past the end of the
		   last match.  Even though two matches may overlap, we
		   want to ignore them, so that we can highlight C-strings
		   correctly. */
		while (k < start + COLS) {
		    /* Note the fifth parameter to regexec.  It says not to
		     * match the beginning-of-line character unless
718
719
		     * k == 0.  If regexec returns nonzero, there are no
		     * more matches in the line. */
720
721
		    if (regexec(&start_regexp, &fileptr->data[k], 1,
				&startmatch, k == 0 ? 0 : REG_NOTBOL))
722
			break;
723
724
725
		    /* Translate the match to the beginning of the line. */
		    startmatch.rm_so += k;
		    startmatch.rm_eo += k;
726
727
		    if (startmatch.rm_so == startmatch.rm_eo) {
			startmatch.rm_eo++;
728
			statusbar(_("Refusing 0 length regex match"));
729
		    } else if (startmatch.rm_so < start + COLS &&
730
731
732
733
734
735
736
737
738
739
740
741
742
743
				startmatch.rm_eo > start) {
			x_start = startmatch.rm_so - start;
			if (x_start < 0)
			    x_start = 0;
			paintlen = startmatch.rm_eo - start - x_start;
			if (paintlen > COLS - x_start)
			    paintlen = COLS - x_start;

			assert(0 <= x_start && 0 < paintlen &&
				x_start + paintlen <= COLS);
			mvwaddnstr(edit, yval, x_start,
				fileptr->data + start + x_start, paintlen);
 		    }
		    k = startmatch.rm_eo;
Chris Allegretta's avatar
Chris Allegretta committed
744
		}
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
	    } else {
		/* This is a multi-line regexp.  There are two steps. 
		 * First, we have to see if the beginning of the line is
		 * colored by a start on an earlier line, and an end on
		 * this line or later.
		 *
		 * We find the first line before fileptr matching the
		 * start.  If every match on that line is followed by an
		 * end, then go to step two.  Otherwise, find the next line
		 * after start_line matching the end.  If that line is not
		 * before fileptr, then paint the beginning of this line. */

		regex_t end_regexp;	/* Compiled search regexp */
		const filestruct *start_line = fileptr->prev;
		    /* the first line before fileptr matching start*/
		regoff_t start_col;
		    /* where it starts in that line */
		const filestruct *end_line;
		int searched_later_lines = 0;
		    /* Used in step 2.  Have we looked for an end on
		     * lines after fileptr? */

		regcomp(&end_regexp, tmpcolor->end, REG_EXTENDED);

		while (start_line != NULL &&
			regexec(&start_regexp, start_line->data, 1,
				&startmatch, 0)) {
		    /* If there is an end on this line, there is no need
		     * to look for starts on earlier lines. */
		    if (!regexec(&end_regexp, start_line->data, 1,
				&endmatch, 0))
			goto step_two;
		    start_line = start_line->prev;
		}
		/* No start found, so skip to the next step. */
		if (start_line == NULL)
		    goto step_two;
		/* Now start_line is the first line before fileptr
		 * containing a start match.  Is there a start on this
		 * line not followed by an end on this line? */

		start_col = 0;
		while (1) {
		    start_col += startmatch.rm_so;
		    startmatch.rm_eo -= startmatch.rm_so;
		    if (regexec(&end_regexp,
			    start_line->data + start_col + startmatch.rm_eo,
			    1, &endmatch,
			    start_col + startmatch.rm_eo == 0 ? 0 : REG_NOTBOL))
			/* No end found after this start */
795
			break;
796
797
798
799
800
801
		    start_col++;
		    if (regexec(&start_regexp,
			    start_line->data + start_col, 1, &startmatch,
			    REG_NOTBOL))
			/* No later start on this line. */
			goto step_two;
802
		}
803
804
805
806
807
808
809
		/* Indeed, there is a start not followed on this line by an
		 * end. */

		/* We have already checked that there is no end before
		 * fileptr and after the start.  Is there an end after
		 * the start at all?  We don't paint unterminated starts. */
		end_line = fileptr;
810
811
		while (end_line != NULL && regexec(&end_regexp, end_line->data,
				1, &endmatch, 0))
812
813
814
		    end_line = end_line->next;

		/* No end found, or it is too early. */
815
		if (end_line == NULL || end_line->lineno < fileptr->lineno ||
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
			(end_line == fileptr && endmatch.rm_eo <= start))
		    goto step_two;

		/* Now paint the start of fileptr. */
		paintlen = end_line != fileptr
				? COLS : endmatch.rm_eo - start;
		if (paintlen > COLS)
		    paintlen = COLS;

		assert(0 < paintlen && paintlen <= COLS);
		mvwaddnstr(edit, yval, 0, fileptr->data + start, paintlen);

		/* We have already painted the whole line. */
		if (paintlen == COLS)
		    goto skip_step_two;


  step_two:	/* Second step, we look for starts on this line. */
		start_col = 0;
		while (start_col < start + COLS) {
		    if (regexec(&start_regexp, fileptr->data + start_col, 1,
				&startmatch, start_col == 0 ? 0 : REG_NOTBOL)
			    || start_col + startmatch.rm_so >= start + COLS)
			/* No more starts on this line. */
			break;
		    /* Translate the match to be relative to the
		     * beginning of the line. */
		    startmatch.rm_so += start_col;
		    startmatch.rm_eo += start_col;

		    x_start = startmatch.rm_so - start;
		    if (x_start < 0) {
			x_start = 0;
			startmatch.rm_so = start;
850
		    }
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
		    if (!regexec(&end_regexp, fileptr->data + startmatch.rm_eo,
				1, &endmatch,
				startmatch.rm_eo == 0 ? 0 : REG_NOTBOL)) {
			/* Translate the end match to be relative to the
			   beginning of the line. */
			endmatch.rm_so += startmatch.rm_eo;
			endmatch.rm_eo += startmatch.rm_eo;
			/* There is an end on this line.  But does it
			   appear on this page, and is the match more than
			   zero characters long? */
			if (endmatch.rm_eo > start &&
				endmatch.rm_eo > startmatch.rm_so) {
			    paintlen = endmatch.rm_eo - start - x_start;
			    if (x_start + paintlen > COLS)
				paintlen = COLS - x_start;

			    assert(0 <= x_start && 0 < paintlen &&
				    x_start + paintlen <= COLS);
			    mvwaddnstr(edit, yval, x_start,
				fileptr->data + start + x_start, paintlen);
871
			}
872
873
874
875
876
		    } else if (!searched_later_lines) {
			searched_later_lines = 1;
			/* There is no end on this line.  But we haven't
			 * yet looked for one on later lines. */
			end_line = fileptr->next;
877
878
			while (end_line != NULL && regexec(&end_regexp,
				end_line->data, 1, &endmatch, 0))
879
880
881
882
883
884
885
886
887
			    end_line = end_line->next;
			if (end_line != NULL) {
			    assert(0 <= x_start && x_start < COLS);
			    mvwaddnstr(edit, yval, x_start,
			    		fileptr->data + start + x_start,
			    		COLS - x_start);
			    /* We painted to the end of the line, so
			     * don't bother checking any more starts. */
			    break;
888
889
			}
		    }
890
891
		    start_col = startmatch.rm_so + 1;
		} /* while start_col < start + COLS */
892

893
894
895
  skip_step_two:
		regfree(&end_regexp);
	    } /* if (tmp_color->end != NULL) */
896

897
898
899
900
901
	    regfree(&start_regexp);
	    wattroff(edit, A_BOLD);
	    wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
	} /* for tmpcolor in colorstrings */
    }
Chris Allegretta's avatar
Chris Allegretta committed
902
#endif				/* ENABLE_COLOR */
903

904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
#ifndef NANO_SMALL
    if (ISSET(MARK_ISSET)
	    && (fileptr->lineno <= mark_beginbuf->lineno
		|| fileptr->lineno <= current->lineno)
	    && (fileptr->lineno >= mark_beginbuf->lineno
		|| fileptr->lineno >= current->lineno)) {
	/* fileptr is at least partially selected. */

	int x_start;
	    /* Starting column for mvwaddnstr.  Zero-based. */
	int paintlen;
	    /* number of chars to paint on this line.  There are COLS
	     * characters on a whole line. */

	if (mark_beginbuf == fileptr && current == fileptr) {
	    x_start = virt_mark_beginx < virt_cur_x ? virt_mark_beginx
	    					    : virt_cur_x;
	    paintlen = abs(virt_mark_beginx - virt_cur_x);
	} else {
	    if (mark_beginbuf->lineno < fileptr->lineno ||
		    current->lineno < fileptr->lineno)
		x_start = 0;
	    else
		x_start = mark_beginbuf == fileptr ? virt_mark_beginx
						   : virt_cur_x;
Chris Allegretta's avatar
Chris Allegretta committed
929

930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
	    if (mark_beginbuf->lineno > fileptr->lineno ||
		    current->lineno > fileptr->lineno)
		paintlen = start + COLS;
	    else
		paintlen = mark_beginbuf == fileptr ? virt_mark_beginx
						    : virt_cur_x;
	}
	x_start -= start;
	if (x_start < 0) {
	    paintlen += x_start;
	    x_start = 0;
	}
	if (x_start + paintlen > COLS)
	    paintlen = COLS - x_start;
	if (paintlen > 0) {
945
	    wattron(edit, A_REVERSE);
946
947
948
	    assert(x_start >= 0 && paintlen > 0 && x_start + paintlen <= COLS);
	    mvwaddnstr(edit, yval, x_start,
			fileptr->data + start + x_start, paintlen);
949
	    wattroff(edit, A_REVERSE);
Chris Allegretta's avatar
Chris Allegretta committed
950
	}
951
    }
952
#endif /* !NANO_SMALL */
Chris Allegretta's avatar
Chris Allegretta committed
953
954
}

955
956
957
958
/* Just update one line in the edit buffer.  Basically a wrapper for
 * edit_add().  If fileptr != current, then index is considered 0.
 * The line will be displayed starting with fileptr->data[index].
 * Likely args are current_x or 0. */
959
void update_line(filestruct *fileptr, int index)
Chris Allegretta's avatar
Chris Allegretta committed
960
{
961
962
963
964
965
966
967
968
969
970
971
972
973
    int line;
	/* line in the edit window for CURSES calls */
#ifndef NANO_SMALL
    int virt_cur_x;
    int virt_mark_beginx;
#endif
    char *original;
	/* The original string fileptr->data. */
    char *converted;
	/* fileptr->data converted to have tabs and control characters
	 * expanded. */
    size_t pos;
    size_t page_start;
Chris Allegretta's avatar
Chris Allegretta committed
974

975
    if (fileptr == NULL)
Chris Allegretta's avatar
Chris Allegretta committed
976
	return;
977

978
    line = fileptr->lineno - edittop->lineno;
Chris Allegretta's avatar
Chris Allegretta committed
979

980
981
    /* We assume the line numbers are valid.  Is that really true? */
    assert(line < 0 || line == check_linenumbers(fileptr));
982

983
984
    if (line < 0 || line >= editwinrows)
	return;
985

986
987
988
989
990
    /* First, blank out the line (at a minimum) */
    mvwaddstr(edit, line, 0, hblank);

    original = fileptr->data;
    converted = charalloc(strlenpt(original) + 1);
991
992

    /* Next, convert all the tabs to spaces, so everything else is easy.
993
994
995
996
997
998
     * Note the internal speller sends us index == -1. */
    index = fileptr == current && index > 0 ? strnlenpt(original, index) : 0;
#ifndef NANO_SMALL
    virt_cur_x = fileptr == current ? strnlenpt(original, current_x) : current_x;
    virt_mark_beginx = fileptr == mark_beginbuf ? strnlenpt(original, mark_beginx) : mark_beginx;
#endif
999
1000

    pos = 0;
1001
1002
    for (; *original != '\0'; original++) {
	if (*original == '\t')
1003
	    do {
1004
		converted[pos++] = ' ';
1005
	    } while (pos % tabsize);
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
	else if (is_cntrl_char(*original)) {
	    converted[pos++] = '^';
	    if (*original == 127)
		converted[pos++] = '?';
	    else if (*original == '\n')
		/* Treat newlines (ASCII 10's) embedded in a line as encoded
	   	 * nulls (ASCII 0's); the line in question should be run
		 * through unsunder() before reaching here */
		converted[pos++] = '@';
	    else
		converted[pos++] = *original + 64;
	} else
	    converted[pos++] = *original;
1019
    }
1020
    converted[pos] = '\0';
Chris Allegretta's avatar
Chris Allegretta committed
1021

Chris Allegretta's avatar
Chris Allegretta committed
1022
    /* Now, paint the line */
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
    original = fileptr->data;
    fileptr->data = converted;
    page_start = get_page_start(index);
    edit_add(fileptr, line, page_start
#ifndef NANO_SMALL
		, virt_mark_beginx, virt_cur_x
#endif
		);
    free(converted);
    fileptr->data = original;
Chris Allegretta's avatar
Chris Allegretta committed
1033

1034
    if (page_start > 0)
Chris Allegretta's avatar
Chris Allegretta committed
1035
	mvwaddch(edit, line, 0, '$');
1036
1037
    if (pos > page_start + COLS)
	mvwaddch(edit, line, COLS - 1, '$');
Chris Allegretta's avatar
Chris Allegretta committed
1038
1039
}

1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
/* This function updates current, based on where current_y is;
 * reset_cursor() does the opposite. */
void update_cursor(void)
{
    int i = 0;

#ifdef DEBUG
    fprintf(stderr, _("Moved to (%d, %d) in edit buffer\n"), current_y,
	    current_x);
#endif

    current = edittop;
    while (i < current_y && current->next != NULL) {
	current = current->next;
	i++;
    }

#ifdef DEBUG
    fprintf(stderr, _("current->data = \"%s\"\n"), current->data);
#endif
}

Chris Allegretta's avatar
Chris Allegretta committed
1062
1063
1064
1065
1066
1067
void center_cursor(void)
{
    current_y = editwinrows / 2;
    wmove(edit, current_y, current_x);
}

Chris Allegretta's avatar
Chris Allegretta committed
1068
/* Refresh the screen without changing the position of lines. */
Chris Allegretta's avatar
Chris Allegretta committed
1069
1070
void edit_refresh(void)
{
Chris Allegretta's avatar
Chris Allegretta committed
1071
1072
1073
    /* Neither of these conditions should occur, but they do.  edittop is
     * NULL when you open an existing file on the command line, and
     * ENABLE_COLOR is defined.  Yuck. */
Chris Allegretta's avatar
Chris Allegretta committed
1074
1075
    if (current == NULL)
	return;
Chris Allegretta's avatar
Chris Allegretta committed
1076
1077
    if (edittop == NULL)
	edittop = current;
Chris Allegretta's avatar
Chris Allegretta committed
1078

1079
1080
1081
1082
1083
    if (current->lineno >= edittop->lineno + editwinrows)
	/* Note that edit_update() changes edittop so that
	 * current->lineno = edittop->lineno + editwinrows / 2.  Thus
	 * when it then calls edit_refresh(), there is no danger of
	 * getting an infinite loop. */
1084
	edit_update(current, CENTER);
1085
1086
    else {
	int nlines = 0;
Chris Allegretta's avatar
Chris Allegretta committed
1087

1088
1089
	/* Don't make the cursor jump around the screen whilst updating */
	leaveok(edit, TRUE);
1090

1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
	editbot = edittop;
	while (nlines < editwinrows) {
	    update_line(editbot, current_x);
	    nlines++;
	    if (editbot->next == NULL)
		break;
	    editbot = editbot->next;
	}
	while (nlines < editwinrows) {
	    mvwaddstr(edit, nlines, 0, hblank);
	    nlines++;
	}
	/* What the hell are we expecting to update the screen if this
	   isn't here?  Luck?? */
	wrefresh(edit);
	leaveok(edit, FALSE);
    }
Chris Allegretta's avatar
Chris Allegretta committed
1108
1109
}

1110
/*
1111
 * Same as above, but touch the window first, so everything is redrawn.
1112
1113
1114
1115
1116
1117
1118
1119
 */
void edit_refresh_clearok(void)
{
    clearok(edit, TRUE);
    edit_refresh();
    clearok(edit, FALSE);
}

Chris Allegretta's avatar
Chris Allegretta committed
1120
/*
1121
 * Nice generic routine to update the edit buffer, given a pointer to the
Chris Allegretta's avatar
Chris Allegretta committed
1122
1123
 * file struct =) 
 */
Chris Allegretta's avatar
Chris Allegretta committed
1124
void edit_update(filestruct *fileptr, topmidbotnone location)
Chris Allegretta's avatar
Chris Allegretta committed
1125
1126
1127
1128
{
    if (fileptr == NULL)
	return;

Chris Allegretta's avatar
Chris Allegretta committed
1129
1130
    if (location != TOP) {
	int goal = location == NONE ? current_y - 1 : editwinrows / 2;
Chris Allegretta's avatar
Chris Allegretta committed
1131

Chris Allegretta's avatar
Chris Allegretta committed
1132
1133
1134
1135
	for (; goal >= 0 && fileptr->prev != NULL; goal--)
	    fileptr = fileptr->prev;
    }
    edittop = fileptr;
1136
    fix_editbot();
Chris Allegretta's avatar
Chris Allegretta committed
1137
1138
1139
1140
1141
1142
1143

    edit_refresh();
}

/*
 * Ask a question on the statusbar.  Answer will be stored in answer
 * global.  Returns -1 on aborted enter, -2 on a blank string, and 0
1144
 * otherwise, the valid shortcut key caught.  Def is any editable text we
Chris Allegretta's avatar
Chris Allegretta committed
1145
 * want to put up by default.
1146
1147
 *
 * New arg tabs tells whether or not to allow tab completion.
Chris Allegretta's avatar
Chris Allegretta committed
1148
 */
Chris Allegretta's avatar
Chris Allegretta committed
1149
int statusq(int tabs, const shortcut *s, const char *def,
1150
1151
1152
#ifndef NANO_SMALL
		historyheadtype *which_history,
#endif
Chris Allegretta's avatar
Chris Allegretta committed
1153
		const char *msg, ...)
Chris Allegretta's avatar
Chris Allegretta committed
1154
1155
{
    va_list ap;
Chris Allegretta's avatar
Chris Allegretta committed
1156
    char *foo = charalloc(COLS - 3);
1157
    int ret;
1158
#ifndef DISABLE_TABCOMP
1159
    int list = 0;
1160
1161
#endif

1162
    bottombars(s);
Chris Allegretta's avatar
Chris Allegretta committed
1163
1164

    va_start(ap, msg);
Chris Allegretta's avatar
Chris Allegretta committed
1165
    vsnprintf(foo, COLS - 4, msg, ap);
Chris Allegretta's avatar
Chris Allegretta committed
1166
    va_end(ap);
Chris Allegretta's avatar
Chris Allegretta committed
1167
    foo[COLS - 4] = '\0';
1168

1169
1170
1171
1172
1173
    ret = nanogetstr(tabs, foo, def,
#ifndef NANO_SMALL
		which_history,
#endif
		s
1174
#ifndef DISABLE_TABCOMP
1175
		, &list
1176
#endif
1177
		);
Chris Allegretta's avatar
Chris Allegretta committed
1178
    free(foo);
Chris Allegretta's avatar
Chris Allegretta committed
1179
1180
1181
1182
1183
1184
1185
1186
1187

    switch (ret) {
    case NANO_FIRSTLINE_KEY:
	do_first_line();
	break;
    case NANO_LASTLINE_KEY:
	do_last_line();
	break;
    case NANO_CANCEL_KEY:
Chris Allegretta's avatar
Chris Allegretta committed
1188
1189
	ret = -1;
	break;
Chris Allegretta's avatar
Chris Allegretta committed
1190
    default:
1191
	blank_statusbar();
Chris Allegretta's avatar
Chris Allegretta committed
1192
1193
1194
1195
1196
1197
    }

#ifdef DEBUG
    fprintf(stderr, _("I got \"%s\"\n"), answer);
#endif

Chris Allegretta's avatar
Chris Allegretta committed
1198
1199
1200
1201
1202
1203
1204
1205
#ifndef DISABLE_TABCOMP
	/* if we've done tab completion, there might be a list of
	   filename matches on the edit window at this point; make sure
	   they're cleared off */
	if (list)
	    edit_refresh();
#endif

Chris Allegretta's avatar
Chris Allegretta committed
1206
1207
1208
1209
    return ret;
}

/*
1210
 * Ask a simple yes/no question on the statusbar.  Returns 1 for Y, 0
1211
1212
 * for N, 2 for All (if all is nonzero when passed in) and -1 for abort
 * (^C).
Chris Allegretta's avatar
Chris Allegretta committed
1213
 */
Chris Allegretta's avatar
Chris Allegretta committed
1214
int do_yesno(int all, int leavecursor, const char *msg, ...)
Chris Allegretta's avatar
Chris Allegretta committed
1215
1216
1217
{
    va_list ap;
    char foo[133];
1218
    int kbinput, ok = -1, i;
Chris Allegretta's avatar
Chris Allegretta committed
1219
1220
1221
    const char *yesstr;		/* String of yes characters accepted */
    const char *nostr;		/* Same for no */
    const char *allstr;		/* And all, surprise! */
1222
#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta's avatar
Chris Allegretta committed
1223
1224
1225
    MEVENT mevent;
#endif

1226
    /* Yes, no and all are strings of any length.  Each string consists of
Chris Allegretta's avatar
Chris Allegretta committed
1227
1228
       all characters accepted as a valid character for that value.
       The first value will be the one displayed in the shortcuts. */
1229
1230
1231
    yesstr = _("Yy");
    nostr = _("Nn");
    allstr = _("Aa");
Chris Allegretta's avatar
Chris Allegretta committed
1232
1233

    /* Write the bottom of the screen */
1234
    blank_bottomwin();
1235

Jordi Mallach's avatar
   
Jordi Mallach committed
1236
    /* Remove gettext call for keybindings until we clear the thing up */
Chris Allegretta's avatar
Chris Allegretta committed
1237
    if (!ISSET(NO_HELP)) {
1238
1239
	char shortstr[3];		/* Temp string for Y, N, A */

Chris Allegretta's avatar
Chris Allegretta committed
1240
	wmove(bottomwin, 1, 0);
1241

1242
	sprintf(shortstr, " %c", yesstr[0]);
1243
	onekey(shortstr, _("Yes"), 16);
1244
1245

	if (all) {
1246
	    shortstr[1] = allstr[0];
1247
	    onekey(shortstr, _("All"), 16);
1248
	}
Chris Allegretta's avatar
Chris Allegretta committed
1249
	wmove(bottomwin, 2, 0);
1250

1251
	shortstr[1] = nostr[0];
1252
	onekey(shortstr, _("No"), 16);
1253

1254
	onekey("^C", _("Cancel"), 16);
Chris Allegretta's avatar
Chris Allegretta committed
1255
1256
1257
1258
    }
    va_start(ap, msg);
    vsnprintf(foo, 132, msg, ap);
    va_end(ap);
1259

Chris Allegretta's avatar
Chris Allegretta committed
1260
    wattron(bottomwin, A_REVERSE);
1261
1262

    blank_statusbar();
Chris Allegretta's avatar
Chris Allegretta committed
1263
    mvwaddstr(bottomwin, 0, 0, foo);
1264

Chris Allegretta's avatar
Chris Allegretta committed
1265
    wattroff(bottomwin, A_REVERSE);
1266

Chris Allegretta's avatar
Chris Allegretta committed
1267
1268
1269
1270
1271
1272
1273
1274
1275
    wrefresh(bottomwin);

    if (leavecursor == 1)
	reset_cursor();

    while (ok == -1) {
	kbinput = wgetch(edit);

	switch (kbinput) {
1276
#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta's avatar
Chris Allegretta committed
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
	case KEY_MOUSE:

	    /* Look ma!  We get to duplicate lots of code from do_mouse!! */
	    if (getmouse(&mevent) == ERR)
		break;
	    if (!wenclose(bottomwin, mevent.y, mevent.x) || ISSET(NO_HELP))
		break;
	    mevent.y -= editwinrows + 3;
	    if (mevent.y < 0)
		break;
	    else {

		/* Rather than a bunch of if statements, set up a matrix
Chris Allegretta's avatar
Chris Allegretta committed
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
		   of possible return keystrokes based on the x and y
		   values */ 
		char yesnosquare[2][2];
		yesnosquare[0][0] = yesstr[0];
		if (all)
		    yesnosquare[0][1] = allstr[0];
		else
		    yesnosquare[0][1] = '\0';
		yesnosquare[1][0] = nostr[0];
		yesnosquare[1][1] = NANO_CONTROL_C;
		ungetch(yesnosquare[mevent.y][mevent.x / (COLS / 6)]);
Chris Allegretta's avatar
Chris Allegretta committed
1301
1302
1303
	    }
	    break;
#endif
Chris Allegretta's avatar
Chris Allegretta committed
1304
1305
1306
	case NANO_CONTROL_C:
	    ok = -2;
	    break;
1307
1308
	default:

1309
	    /* Look for the kbinput in the yes, no and (optimally) all str */
Chris Allegretta's avatar
Chris Allegretta committed
1310
	    for (i = 0; yesstr[i] != 0 && yesstr[i] != kbinput; i++);
1311
	    if (yesstr[i] != 0) {
1312
		ok = 1;
Chris Allegretta's avatar
Chris Allegretta committed
1313
		break;
1314
1315
	    }

Chris Allegretta's avatar
Chris Allegretta committed
1316
	    for (i = 0; nostr[i] != 0 && nostr[i] != kbinput; i++);
1317
1318
	    if (nostr[i] != 0) {
		ok = 0;
Chris Allegretta's avatar
Chris Allegretta committed
1319
		break;
1320
1321
1322
	    }

	    if (all) {
Chris Allegretta's avatar
Chris Allegretta committed
1323
		for (i = 0; allstr[i] != 0 && allstr[i] != kbinput; i++);
1324
1325
		if (allstr[i] != 0) {
		    ok = 2;
Chris Allegretta's avatar
Chris Allegretta committed
1326
		    break;
1327
1328
		}
	    }
Chris Allegretta's avatar
Chris Allegretta committed
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
	}
    }

    /* Then blank the screen */
    blank_statusbar_refresh();

    if (ok == -2)
	return -1;
    else
	return ok;
}

1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
int total_refresh(void)
{
    clearok(edit, TRUE);
    clearok(topwin, TRUE);
    clearok(bottomwin, TRUE);
    wnoutrefresh(edit);
    wnoutrefresh(topwin);
    wnoutrefresh(bottomwin);
    doupdate();
    clearok(edit, FALSE);
    clearok(topwin, FALSE);
    clearok(bottomwin, FALSE);
    edit_refresh();
    titlebar(NULL);
    return 1;
}

void display_main_list(void)
{
    bottombars(main_list);
}

Chris Allegretta's avatar
Chris Allegretta committed
1363
void statusbar(const char *msg, ...)
Chris Allegretta's avatar
Chris Allegretta committed
1364
1365
{
    va_list ap;
Chris Allegretta's avatar
Chris Allegretta committed
1366
    char *foo;
Chris Allegretta's avatar
Chris Allegretta committed
1367
    int start_x = 0;
Chris Allegretta's avatar
Chris Allegretta committed
1368
1369
1370
1371
    size_t foo_len;

    assert(COLS >= 4);
    foo = charalloc(COLS - 3);
Chris Allegretta's avatar
Chris Allegretta committed
1372
1373

    va_start(ap, msg);
Chris Allegretta's avatar
Chris Allegretta committed
1374
    vsnprintf(foo, COLS - 3, msg, ap);
Chris Allegretta's avatar
Chris Allegretta committed
1375
1376
    va_end(ap);

Chris Allegretta's avatar
Chris Allegretta committed
1377
1378
1379
    foo[COLS - 4] = '\0';
    foo_len = strlen(foo);
    start_x = (COLS - foo_len - 4) / 2;
Chris Allegretta's avatar
Chris Allegretta committed
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389

    /* Blank out line */
    blank_statusbar();

    wmove(bottomwin, 0, start_x);

    wattron(bottomwin, A_REVERSE);

    waddstr(bottomwin, "[ ");
    waddstr(bottomwin, foo);
Chris Allegretta's avatar
Chris Allegretta committed
1390
    free(foo);
Chris Allegretta's avatar
Chris Allegretta committed
1391
    waddstr(bottomwin, " ]");
1392

Chris Allegretta's avatar
Chris Allegretta committed
1393
    wattroff(bottomwin, A_REVERSE);
1394

Chris Allegretta's avatar
Chris Allegretta committed
1395
1396
1397
1398
1399
1400
1401
1402
    wrefresh(bottomwin);

    if (ISSET(CONSTUPDATE))
	statblank = 1;
    else
	statblank = 25;
}

1403
int do_cursorpos(int constant)
Chris Allegretta's avatar
Chris Allegretta committed
1404
1405
{
    filestruct *fileptr;
1406
    float linepct = 0.0, bytepct = 0.0, colpct = 0.0;
1407
    long i = 0, j = 0;
1408
    static long old_i = -1, old_totsize = -1;
Chris Allegretta's avatar
Chris Allegretta committed
1409
1410
1411
1412

    if (current == NULL || fileage == NULL)
	return 0;

1413
1414
1415
1416
1417
1418
    if (old_i == -1)
	old_i = i;

    if (old_totsize == -1)
	old_totsize = totsize;

Chris Allegretta's avatar
Chris Allegretta committed
1419
    colpct = 100 * (xplustabs() + 1) / (strlenpt(current->data) + 1);
Chris Allegretta's avatar
Chris Allegretta committed
1420

1421
1422
1423
    for (fileptr = fileage; fileptr != current && fileptr != NULL;
	 fileptr = fileptr->next)
	i += strlen(fileptr->data) + 1;
1424

1425
1426
    if (fileptr == NULL)
	return -1;
1427

1428
    i += current_x;
1429

1430
    j = totsize;
1431

1432
1433
    if (totsize > 0)
	bytepct = 100 * i / totsize;
1434
1435
1436

    if (totlines > 0)
	 linepct = 100 * current->lineno / totlines;
Chris Allegretta's avatar
Chris Allegretta committed
1437
1438
1439
1440
1441
1442

#ifdef DEBUG
    fprintf(stderr, _("do_cursorpos: linepct = %f, bytepct = %f\n"),
	    linepct, bytepct);
#endif

1443
1444
1445
1446
    /* if constant is zero, display the position on the statusbar
       unconditionally; otherwise, only display the position when the
       character values have changed */
    if (!constant || (old_i != i || old_totsize != totsize)) {
Chris Allegretta's avatar
Chris Allegretta committed
1447
	statusbar(_
1448
		  ("line %d/%d (%.0f%%), col %ld/%ld (%.0f%%), char %ld/%ld (%.0f%%)"),
1449
		  current->lineno, totlines, linepct, xplustabs() + 1, 
Chris Allegretta's avatar
Chris Allegretta committed
1450
		  strlenpt(current->data) + 1, colpct, i, j, bytepct);
1451
1452
1453
1454
1455
    }

    old_i = i;
    old_totsize = totsize;

Chris Allegretta's avatar
Chris Allegretta committed
1456
1457
1458
1459
    reset_cursor();
    return 1;
}

1460
1461
1462
1463
1464
int do_cursorpos_void(void)
{
    return do_cursorpos(0);
}

1465
1466
/* Our shortcut-list-compliant help function, which is
 * better than nothing, and dynamic! */
Chris Allegretta's avatar
Chris Allegretta committed
1467
1468
int do_help(void)
{
1469
#ifndef DISABLE_HELP
1470
    int i, j, row = 0, page = 1, kbinput = 0, no_more = 0, kp, kp2;
Chris Allegretta's avatar
Chris Allegretta committed
1471
    int no_help_flag = 0;
Chris Allegretta's avatar
Chris Allegretta committed
1472
    const shortcut *oldshortcut;
Chris Allegretta's avatar
Chris Allegretta committed
1473
1474
1475

    blank_edit();
    curs_set(0);
1476
    wattroff(bottomwin, A_REVERSE);
Chris Allegretta's avatar
Chris Allegretta committed
1477
1478
    blank_statusbar();

1479
    /* set help_text as the string to display */
1480
    help_init();
1481
    assert(help_text != NULL);
1482
1483
1484

    oldshortcut = currshortcut;

1485
    currshortcut = help_list;
1486

1487
    kp = keypad_on(edit, 1);
1488
    kp2 = keypad_on(bottomwin, 1);
1489

Chris Allegretta's avatar
Chris Allegretta committed
1490
1491
    if (ISSET(NO_HELP)) {

1492
	/* Well, if we're going to do this, we should at least
1493
	   do it the right way */
Chris Allegretta's avatar
Chris Allegretta committed
1494
	no_help_flag = 1;
Chris Allegretta's avatar
Chris Allegretta committed
1495
	UNSET(NO_HELP);
1496
	window_init();
1497
	bottombars(help_list);
1498

Chris Allegretta's avatar
Chris Allegretta committed
1499
    } else
1500
	bottombars(help_list);
Chris Allegretta's avatar
Chris Allegretta committed
1501
1502

    do {
1503
1504
	const char *ptr = help_text;

Chris Allegretta's avatar
Chris Allegretta committed
1505
	switch (kbinput) {
1506
#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta's avatar
Chris Allegretta committed
1507
1508
1509
	case KEY_MOUSE:
	    do_mouse();
	    break;
1510
#endif
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
	case 27:
	    kbinput = wgetch(edit);
	    switch(kbinput) {
	    case '[':
		kbinput = wgetch(edit);
		switch(kbinput) {
		    case '5':	/* Alt-[-5 = Page Up */
			wgetch(edit);
			goto do_pageupkey;
			break;
		    case 'V':	/* Alt-[-V = Page Up in Hurd Console */
		    case 'I':	/* Alt-[-I = Page Up - FreeBSD Console */
			goto do_pageupkey;
			break;
		    case '6':	/* Alt-[-6 = Page Down */
			wgetch(edit);
			goto do_pagedownkey;
			break;
		    case 'U':	/* Alt-[-U = Page Down in Hurd Console */
		    case 'G':	/* Alt-[-G = Page Down - FreeBSD Console */
			goto do_pagedownkey;
			break;
		}
		break;
	    }
	    break;
Chris Allegretta's avatar
Chris Allegretta committed
1537
1538
1539
	case NANO_NEXTPAGE_KEY:
	case NANO_NEXTPAGE_FKEY:
	case KEY_NPAGE:
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1540
	  do_pagedownkey:
Chris Allegretta's avatar
Chris Allegretta committed
1541
1542
1543
1544
1545
1546
1547
1548
	    if (!no_more) {
		blank_edit();
		page++;
	    }
	    break;
	case NANO_PREVPAGE_KEY:
	case NANO_PREVPAGE_FKEY:
	case KEY_PPAGE:
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1549
	  do_pageupkey:
Chris Allegretta's avatar
Chris Allegretta committed
1550
1551
1552
1553
1554
1555
1556
1557
	    if (page > 1) {
		no_more = 0;
		blank_edit();
		page--;
	    }
	    break;
	}

1558
	/* Calculate where in the text we should be, based on the page */
Chris Allegretta's avatar
Chris Allegretta committed
1559
1560
1561
	for (i = 1; i < page; i++) {
	    row = 0;
	    j = 0;
1562
1563

	    while (row < editwinrows - 2 && *ptr != '\0') {
Chris Allegretta's avatar
Chris Allegretta committed
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
		if (*ptr == '\n' || j == COLS - 5) {
		    j = 0;
		    row++;
		}
		ptr++;
		j++;
	    }
	}

	i = 0;
	j = 0;
	while (i < editwinrows && *ptr != '\0') {
1576
	    const char *end = ptr;
Chris Allegretta's avatar
Chris Allegretta committed
1577
1578
1579
1580
1581
1582
	    while (*end != '\n' && *end != '\0' && j != COLS - 5) {
		end++;
		j++;
	    }
	    if (j == COLS - 5) {

1583
		/* Don't print half a word if we've run out of space */
Chris Allegretta's avatar
Chris Allegretta committed
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
		while (*end != ' ' && *end != '\0') {
		    end--;
		    j--;
		}
	    }
	    mvwaddnstr(edit, i, 0, ptr, j);
	    j = 0;
	    i++;
	    if (*end == '\n')
		end++;
	    ptr = end;
	}
	if (*ptr == '\0') {
	    no_more = 1;
	    continue;
	}
Chris Allegretta's avatar
Chris Allegretta committed
1600
1601
    } while ((kbinput = wgetch(edit)) != NANO_EXIT_KEY &&
	     kbinput != NANO_EXIT_FKEY);
Chris Allegretta's avatar
Chris Allegretta committed
1602

1603
1604
    currshortcut = oldshortcut;

Chris Allegretta's avatar
Chris Allegretta committed
1605
    if (no_help_flag) {
1606
	blank_bottombars();
Chris Allegretta's avatar
Chris Allegretta committed
1607
	wrefresh(bottomwin);
Chris Allegretta's avatar
Chris Allegretta committed
1608
	SET(NO_HELP);
1609
	window_init();
Chris Allegretta's avatar
Chris Allegretta committed
1610
    } else
1611
	bottombars(currshortcut);
Chris Allegretta's avatar
Chris Allegretta committed
1612
1613
1614

    curs_set(1);
    edit_refresh();
1615
    kp = keypad_on(edit, kp);
1616
    kp2 = keypad_on(bottomwin, kp2);
1617

1618
1619
1620
1621
1622
    /* The help_init() at the beginning allocated help_text, which has
       now been written to screen. */
    free(help_text);
    help_text = NULL;

Chris Allegretta's avatar
Chris Allegretta committed
1623
1624
1625
1626
#elif defined(DISABLE_HELP)
    nano_disabled_msg();
#endif

Chris Allegretta's avatar
Chris Allegretta committed
1627
1628
1629
    return 1;
}

1630
int keypad_on(WINDOW *win, int newval)
1631
{
1632
1633
1634
1635
1636
1637
1638
1639
1640
/* This is taken right from aumix.  Don't sue me. */
#ifdef HAVE_USEKEYPAD
    int old = win->_use_keypad;
    keypad(win, newval);
    return old;
#else
    keypad(win, newval);
    return 1;
#endif /* HAVE_USEKEYPAD */
Robert Siemborski's avatar
Robert Siemborski committed
1641
}
1642

1643
/* Highlight the current word being replaced or spell checked. */
Chris Allegretta's avatar
Chris Allegretta committed
1644
void do_replace_highlight(int highlight_flag, const char *word)
Chris Allegretta's avatar
Chris Allegretta committed
1645
1646
{
    char *highlight_word = NULL;
Chris Allegretta's avatar
Chris Allegretta committed
1647
    int x, y, word_len;
Chris Allegretta's avatar
Chris Allegretta committed
1648

Chris Allegretta's avatar
Chris Allegretta committed
1649
1650
    highlight_word =
	mallocstrcpy(highlight_word, &current->data[current_x]);
Chris Allegretta's avatar
Chris Allegretta committed
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661

#ifdef HAVE_REGEX_H
    if (ISSET(USE_REGEXP))
	/* if we're using regexps, the highlight is the length of the
	   search result, not the length of the regexp string */
	word_len = regmatches[0].rm_eo - regmatches[0].rm_so;
    else
#endif
	word_len = strlen(word);

    highlight_word[word_len] = '\0';
Chris Allegretta's avatar
Chris Allegretta committed
1662

1663
    /* adjust output when word extends beyond screen */
Chris Allegretta's avatar
Chris Allegretta committed
1664
1665

    x = xplustabs();
Chris Allegretta's avatar
Chris Allegretta committed
1666
    y = get_page_start(x) + COLS;
Chris Allegretta's avatar
Chris Allegretta committed
1667

Chris Allegretta's avatar
Chris Allegretta committed
1668
    if ((COLS - (y - x) + word_len) > COLS) {
Chris Allegretta's avatar
Chris Allegretta committed
1669
1670
1671
1672
1673
1674
1675
	highlight_word[y - x - 1] = '$';
	highlight_word[y - x] = '\0';
    }

    /* OK display the output */

    reset_cursor();
Chris Allegretta's avatar
Chris Allegretta committed
1676

Chris Allegretta's avatar
Chris Allegretta committed
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
    if (highlight_flag)
	wattron(edit, A_REVERSE);

    waddstr(edit, highlight_word);

    if (highlight_flag)
	wattroff(edit, A_REVERSE);

    free(highlight_word);
}

1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
/* Fix editbot, based on the assumption that edittop is correct. */
void fix_editbot(void)
{
    int i;

    editbot = edittop;
    for (i = 0; i < editwinrows && editbot->next != NULL; i++)
	editbot = editbot->next;
}

#ifdef DEBUG
/* Dump the current file structure to stderr */
void dump_buffer(const filestruct *inptr) {
    if (inptr == fileage)
	fprintf(stderr, _("Dumping file buffer to stderr...\n"));
    else if (inptr == cutbuffer)
	fprintf(stderr, _("Dumping cutbuffer to stderr...\n"));
    else
	fprintf(stderr, _("Dumping a buffer to stderr...\n"));

    while (inptr != NULL) {
	fprintf(stderr, "(%d) %s\n", inptr->lineno, inptr->data);
	inptr = inptr->next;
    }
}
#endif /* DEBUG */

#ifdef DEBUG
void dump_buffer_reverse(void) {
    const filestruct *fileptr = filebot;

    while (fileptr != NULL) {
	fprintf(stderr, "(%d) %s\n", fileptr->lineno, fileptr->data);
	fileptr = fileptr->prev;
    }
}
#endif /* DEBUG */

1726
#ifdef NANO_EXTRA
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1727
#define CREDIT_LEN 53
1728
1729
#define XLCREDIT_LEN 8

1730
1731
void do_credits(void)
{
Chris Allegretta's avatar
Chris Allegretta committed
1732
    int i, j = 0, k, place = 0, start_x;
1733

1734
1735
    const char *what;
    const char *xlcredits[XLCREDIT_LEN];
1736

1737
    const char *credits[CREDIT_LEN] = { 
1738
1739
	"0",				/* "The nano text editor" */
	"1",				/* "version" */
Chris Allegretta's avatar
Chris Allegretta committed
1740
1741
	VERSION,
	"",
1742
	"2",				/* "Brought to you by:" */
Chris Allegretta's avatar
Chris Allegretta committed
1743
1744
1745
1746
1747
	"Chris Allegretta",
	"Jordi Mallach",
	"Adam Rogoyski",
	"Rob Siemborski",
	"Rocco Corsi",
1748
	"David Lawrence Ramsey",
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1749
	"David Benbennick",
Chris Allegretta's avatar
Chris Allegretta committed
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
	"Ken Tyler",
	"Sven Guckes",
	"Florian Knig",
	"Pauli Virtanen",
	"Daniele Medri",
	"Clement Laforet",
	"Tedi Heriyanto",
	"Bill Soudan",
	"Christian Weisgerber",
	"Erik Andersen",
	"Big Gaute",
	"Joshua Jensen",
	"Ryan Krebs",
	"Albert Chin",
	"",
1765
	"3",				/* "Special thanks to:" */
Chris Allegretta's avatar
Chris Allegretta committed
1766
1767
1768
1769
1770
1771
	"Plattsburgh State University",
	"Benet Laboratories",
	"Amy Allegretta",
	"Linda Young",
	"Jeremy Robichaud",
	"Richard Kolb II",
1772
	"4",				/* "The Free Software Foundation" */
Chris Allegretta's avatar
Chris Allegretta committed
1773
	"Linus Torvalds",
1774
	"5",				/* "For ncurses:" */
1775
1776
1777
1778
	"Thomas Dickey",
	"Pavel Curtis",
	"Zeyd Ben-Halim",
	"Eric S. Raymond",
1779
1780
	"6",				/* "and anyone else we forgot..." */
	"7",				/* "Thank you for using nano!\n" */
Chris Allegretta's avatar
Chris Allegretta committed
1781
1782
1783
	"", "", "", "",
	"(c) 1999-2002 Chris Allegretta",
	"", "", "", "",
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1784
	"http://www.nano-editor.org/"
1785
1786
    };

1787
1788
1789
1790
1791
1792
1793
1794
1795
    xlcredits[0] = _("The nano text editor");
    xlcredits[1] = _("version ");
    xlcredits[2] = _("Brought to you by:");
    xlcredits[3] = _("Special thanks to:");
    xlcredits[4] = _("The Free Software Foundation");
    xlcredits[5] = _("For ncurses:");
    xlcredits[6] = _("and anyone else we forgot...");
    xlcredits[7] = _("Thank you for using nano!\n");

1796
1797
1798
1799
    curs_set(0);
    nodelay(edit, TRUE);
    blank_bottombars();
    mvwaddstr(topwin, 0, 0, hblank);
Chris Allegretta's avatar
Chris Allegretta committed
1800
1801
    blank_edit();
    wrefresh(edit);
1802
1803
1804
1805
    wrefresh(bottomwin);
    wrefresh(topwin);

    while (wgetch(edit) == ERR) {
Chris Allegretta's avatar
Chris Allegretta committed
1806
1807
	for (k = 0; k <= 1; k++) {
	    blank_edit();
Chris Allegretta's avatar
Chris Allegretta committed
1808
1809
	    for (i = editwinrows / 2 - 1; i >= (editwinrows / 2 - 1 - j);
		 i--) {
Chris Allegretta's avatar
Chris Allegretta committed
1810
1811
		mvwaddstr(edit, i * 2 - k, 0, hblank);

1812
		if (place - (editwinrows / 2 - 1 - i) < CREDIT_LEN) {
Chris Allegretta's avatar
Chris Allegretta committed
1813
		    what = credits[place - (editwinrows / 2 - 1 - i)];
1814
1815
1816
1817
1818
1819
1820
1821

		    /* God I've missed hacking.  If what is exactly
			1 char long, it's a sentinel for a translated
			string, so use that instead.  This means no
			thanking people with 1 character long names ;-) */
		    if (strlen(what) == 1)
			what = xlcredits[atoi(what)];
		} else
Chris Allegretta's avatar
Chris Allegretta committed
1822
1823
		    what = "";

1824
		start_x = COLS / 2 - strlen(what) / 2 - 1;
Chris Allegretta's avatar
Chris Allegretta committed
1825
1826
1827
1828
		mvwaddstr(edit, i * 2 - k, start_x, what);
	    }
	    usleep(700000);
	    wrefresh(edit);
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
	}
	if (j < editwinrows / 2 - 1)
	    j++;

	place++;

	if (place >= CREDIT_LEN + editwinrows / 2)
	    break;
    }

    nodelay(edit, FALSE);
    curs_set(1);
    display_main_list();
    total_refresh();
Chris Allegretta's avatar
Chris Allegretta committed
1843
}
1844
#endif