winio.c 44.3 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
#include "proto.h"
#include "nano.h"

33
#ifdef ENABLE_NLS
Chris Allegretta's avatar
Chris Allegretta committed
34
35
36
37
38
39
40
#include <libintl.h>
#define _(string) gettext(string)
#else
#define _(string) (string)
#endif

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

Chris Allegretta's avatar
Chris Allegretta committed
44
45
46
47
48
int do_first_line(void)
{
    current = fileage;
    placewewant = 0;
    current_x = 0;
49
    edit_update(current, CENTER);
Chris Allegretta's avatar
Chris Allegretta committed
50
51
52
53
54
55
56
57
    return 1;
}

int do_last_line(void)
{
    current = filebot;
    placewewant = 0;
    current_x = 0;
58
    edit_update(current, CENTER);
Chris Allegretta's avatar
Chris Allegretta committed
59
60
61
    return 1;
}

Chris Allegretta's avatar
Chris Allegretta committed
62

63
/* Like xplustabs, but for a specific index of a specific filestruct */
64
int xpt(const filestruct *fileptr, int index)
Chris Allegretta's avatar
Chris Allegretta committed
65
66
67
68
69
70
71
72
73
74
{
    int i, tabs = 0;

    if (fileptr == NULL || fileptr->data == NULL)
	return 0;

    for (i = 0; i < index && fileptr->data[i] != 0; i++) {
	tabs++;

	if (fileptr->data[i] == NANO_CONTROL_I) {
75
	    if (tabs % tabsize == 0);
Chris Allegretta's avatar
Chris Allegretta committed
76
	    else
77
		tabs += tabsize - (tabs % tabsize);
Chris Allegretta's avatar
Chris Allegretta committed
78
79
80
	} else if (is_cntrl_char((int)fileptr->data[i]))
	    tabs++;
	else if (fileptr->data[i] & 0x80)
81
	    /* Make 8 bit chars only 1 column! */
Chris Allegretta's avatar
Chris Allegretta committed
82
	    ;
Chris Allegretta's avatar
Chris Allegretta committed
83
84
    }

Chris Allegretta's avatar
Chris Allegretta committed
85
86
87
    return tabs;
}

Chris Allegretta's avatar
Chris Allegretta committed
88
89
90
91
/* 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
92
{
Chris Allegretta's avatar
Chris Allegretta committed
93
    return strnlenpt(current->data, current_x);
Chris Allegretta's avatar
Chris Allegretta committed
94
95
}

Chris Allegretta's avatar
Chris Allegretta committed
96
97
/* 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
98
{
Chris Allegretta's avatar
Chris Allegretta committed
99
100
101
102
103
104
105
106
107
108
109
110
    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
111
	else if (is_cntrl_char((int)*c))
Chris Allegretta's avatar
Chris Allegretta committed
112
113
114
115
116
117
	    length += 2;
	else
	    length++;
    }
    assert(length == strnlenpt(fileptr->data, i));
    assert(i <= strlen(fileptr->data));
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
118

Chris Allegretta's avatar
Chris Allegretta committed
119
120
    if (length > xplus)
	i--;
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
121

Chris Allegretta's avatar
Chris Allegretta committed
122
#ifdef DEBUG
Chris Allegretta's avatar
Chris Allegretta committed
123
    fprintf(stderr, _("actual_x for xplus=%d returns %d\n"), xplus, i);
Chris Allegretta's avatar
Chris Allegretta committed
124
#endif
Chris Allegretta's avatar
Chris Allegretta committed
125

Chris Allegretta's avatar
Chris Allegretta committed
126
    return i;
127
128
}

Chris Allegretta's avatar
Chris Allegretta committed
129
130
/* A strlen with tabs factored in, similar to xplustabs(). */
size_t strnlenpt(const char *buf, size_t size)
131
{
Chris Allegretta's avatar
Chris Allegretta committed
132
133
134
135
136
137
    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
138
	    else if (is_cntrl_char((int)*buf))
Chris Allegretta's avatar
Chris Allegretta committed
139
		length += 2;
Chris Allegretta's avatar
Chris Allegretta committed
140
	    else
Chris Allegretta's avatar
Chris Allegretta committed
141
142
143
		length++;
	}
    return length;
Chris Allegretta's avatar
Chris Allegretta committed
144
145
}

Chris Allegretta's avatar
Chris Allegretta committed
146
size_t strlenpt(const char *buf)
147
{
Chris Allegretta's avatar
Chris Allegretta committed
148
    return strnlenpt(buf, -1);
149
150
}

Chris Allegretta's avatar
Chris Allegretta committed
151
152
void blank_bottombars(void)
{
Chris Allegretta's avatar
Chris Allegretta committed
153
154
155
156
    if (!no_help()) {
	mvwaddstr(bottomwin, 1, 0, hblank);
	mvwaddstr(bottomwin, 2, 0, hblank);
    }
Chris Allegretta's avatar
Chris Allegretta committed
157
158
}

159
160
161
162
163
164
165
166
167
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
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
197
198
199
200
201
/* 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
202
void nanoget_repaint(const char *buf, const char *inputbuf, int x)
203
{
Chris Allegretta's avatar
Chris Allegretta committed
204
    int len = strlen(buf) + 2;
205
    int wid = COLS - len;
206

Chris Allegretta's avatar
Chris Allegretta committed
207
208
209
    assert(wid >= 2);
    assert(0 <= x && x <= strlen(inputbuf));

210
    wattron(bottomwin, A_REVERSE);
211
    blank_statusbar();
Chris Allegretta's avatar
Chris Allegretta committed
212
213
214
215
216
    mvwaddstr(bottomwin, 0, 0, buf);
    waddch(bottomwin, ':');
    waddch(bottomwin, x < wid ? ' ' : '$');
    waddnstr(bottomwin, &inputbuf[wid * (x / wid)], wid);
    wmove(bottomwin, 0, (x % wid) + len);
217
    wattroff(bottomwin, A_REVERSE);
218
219
}

Chris Allegretta's avatar
Chris Allegretta committed
220
221
/* Get the input from the kb; this should only be called from
 * statusq(). */
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
222
int nanogetstr(int allowtabs, const char *buf, const char *def,
223
		const shortcut *s
224
#ifndef DISABLE_TABCOMP
225
		, int *list
226
#endif
227
		)
Chris Allegretta's avatar
Chris Allegretta committed
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
{
    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;

    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
245

246
#if !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
247
    currshortcut = s;
248
249
#endif

Chris Allegretta's avatar
Chris Allegretta committed
250
    /* Get the input! */
251

Chris Allegretta's avatar
Chris Allegretta committed
252
    nanoget_repaint(buf, answer, x);
Chris Allegretta's avatar
Chris Allegretta committed
253

254
255
    /* Make sure any editor screen updates are displayed before getting
       input */
256
257
    wrefresh(edit);

Chris Allegretta's avatar
Chris Allegretta committed
258
    while ((kbinput = wgetch(bottomwin)) != 13) {
259
	for (t = s; t != NULL; t = t->next) {
260
261
262
263
#ifdef DEBUG
	    fprintf(stderr, _("Aha! \'%c\' (%d)\n"), kbinput, kbinput);
#endif

264
	    if (kbinput == t->val && kbinput < 32) {
265

266
#ifndef DISABLE_HELP
267
268
		/* Have to do this here, it would be too late to do it
		   in statusq() */
Chris Allegretta's avatar
Chris Allegretta committed
269
		if (kbinput == NANO_HELP_KEY || kbinput == NANO_HELP_FKEY) {
270
271
272
273
		    do_help();
		    break;
		}
#endif
274
		return t->val;
Chris Allegretta's avatar
Chris Allegretta committed
275
276
	    }
	}
Chris Allegretta's avatar
Chris Allegretta committed
277
	assert(0 <= x && x <= xend && xend == strlen(answer));
Chris Allegretta's avatar
Chris Allegretta committed
278

Chris Allegretta's avatar
Chris Allegretta committed
279
280
281
	if (kbinput != '\t')
	    tabbed = 0;

Chris Allegretta's avatar
Chris Allegretta committed
282
	switch (kbinput) {
283

Chris Allegretta's avatar
Chris Allegretta committed
284
	    /* Stuff we want to equate with <enter>, ASCII 13 */
285
	case 343:
286
287
	    ungetch(13);	/* Enter on iris-ansi $TERM, sometimes */
	    break;
Chris Allegretta's avatar
Chris Allegretta committed
288
	    /* Stuff we want to ignore */
289
290
291
#ifdef PDCURSES
	case 541:
	case 542:
Chris Allegretta's avatar
Chris Allegretta committed
292
	case 543:		/* Right ctrl again */
293
	case 544:
Chris Allegretta's avatar
Chris Allegretta committed
294
	case 545:		/* Right alt again */
295
296
	    break;
#endif
297
#ifndef DISABLE_MOUSE
298
299
300
301
302
#ifdef NCURSES_MOUSE_VERSION
	case KEY_MOUSE:
	    do_mouse();
	    break;
#endif
303
#endif
304
	case NANO_HOME_KEY:
Chris Allegretta's avatar
Chris Allegretta committed
305
	case KEY_HOME:
Chris Allegretta's avatar
Chris Allegretta committed
306
	    x = 0;
Chris Allegretta's avatar
Chris Allegretta committed
307
	    break;
308
	case NANO_END_KEY:
Chris Allegretta's avatar
Chris Allegretta committed
309
	case KEY_END:
Chris Allegretta's avatar
Chris Allegretta committed
310
	    x = xend;
Chris Allegretta's avatar
Chris Allegretta committed
311
312
	    break;
	case KEY_RIGHT:
313
	case NANO_FORWARD_KEY:
Chris Allegretta's avatar
Chris Allegretta committed
314
315
316
317
	    if (x < xend)
		x++;
	    break;
	case NANO_CONTROL_D:
Chris Allegretta's avatar
Chris Allegretta committed
318
319
320
	    if (x < xend) {
		memmove(answer + x, answer + x + 1, xend - x);
		xend--;
Chris Allegretta's avatar
Chris Allegretta committed
321
322
323
324
	    }
	    break;
	case NANO_CONTROL_K:
	case NANO_CONTROL_U:
Chris Allegretta's avatar
Chris Allegretta committed
325
326
327
	    null_at(&answer, 0);
	    xend = 0;
	    x = 0;
Chris Allegretta's avatar
Chris Allegretta committed
328
329
330
331
	    break;
	case KEY_BACKSPACE:
	case 127:
	case NANO_CONTROL_H:
Chris Allegretta's avatar
Chris Allegretta committed
332
333
	    if (x > 0) {
		memmove(answer + x - 1, answer + x, xend - x + 1);
Chris Allegretta's avatar
Chris Allegretta committed
334
		x--;
Chris Allegretta's avatar
Chris Allegretta committed
335
336
		xend--;
	    }
Chris Allegretta's avatar
Chris Allegretta committed
337
	    break;
338
#ifndef DISABLE_TABCOMP
Chris Allegretta's avatar
Chris Allegretta committed
339
	case NANO_CONTROL_I:
340
	    if (allowtabs) {
Chris Allegretta's avatar
Chris Allegretta committed
341
342
343
344
		int shift = 0;

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

360
361
362
	case KEY_DC:
	    goto do_deletekey;

Chris Allegretta's avatar
Chris Allegretta committed
363
364
	case 27:
	    switch (kbinput = wgetch(edit)) {
365
	    case 'O':
Chris Allegretta's avatar
Chris Allegretta committed
366
		switch (kbinput = wgetch(edit)) {
367
		case 'F':
Chris Allegretta's avatar
Chris Allegretta committed
368
		    x = xend;
Chris Allegretta's avatar
Chris Allegretta committed
369
		    break;
370
		case 'H':
Chris Allegretta's avatar
Chris Allegretta committed
371
		    x = 0;
Chris Allegretta's avatar
Chris Allegretta committed
372
373
374
		    break;
		}
		break;
375
	    case '[':
Chris Allegretta's avatar
Chris Allegretta committed
376
377
378
379
380
381
		switch (kbinput = wgetch(edit)) {
		case 'C':
		    if (x < xend)
			x++;
		    break;
		case 'D':
Chris Allegretta's avatar
Chris Allegretta committed
382
		    if (x > 0)
Chris Allegretta's avatar
Chris Allegretta committed
383
384
			x--;
		    break;
385
386
		case '1':
		case '7':
Chris Allegretta's avatar
Chris Allegretta committed
387
		    x = 0;
388
389
390
		    goto skip_tilde;
		case '3':
		  do_deletekey:
Chris Allegretta's avatar
Chris Allegretta committed
391
392
393
		    if (x < xend) {
			memmove(answer + x, answer + x + 1, xend - x);
			xend--;
Chris Allegretta's avatar
Chris Allegretta committed
394
		    }
395
396
397
		    goto skip_tilde;
		case '4':
		case '8':
Chris Allegretta's avatar
Chris Allegretta committed
398
		    x = xend;
399
400
		    goto skip_tilde;
		  skip_tilde:
Chris Allegretta's avatar
Chris Allegretta committed
401
402
		    nodelay(edit, TRUE);
		    kbinput = wgetch(edit);
403
		    if (kbinput == '~' || kbinput == ERR)
Chris Allegretta's avatar
Chris Allegretta committed
404
405
406
407
			kbinput = -1;
		    nodelay(edit, FALSE);
		    break;
		}
Chris Allegretta's avatar
Chris Allegretta committed
408
		break;
409
410
	    default:

411
		for (t = s; t != NULL; t = t->next) {
412
#ifdef DEBUG
Chris Allegretta's avatar
Chris Allegretta committed
413
414
		    fprintf(stderr, _("Aha! \'%c\' (%d)\n"), kbinput,
			    kbinput);
415
#endif
416
		    if (kbinput == t->val || kbinput == t->val - 32) {
417
418
419
			/* 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... */
420
			return t->val;
421
422
		    }
		}
Chris Allegretta's avatar
Chris Allegretta committed
423
424
425
426
427
428
	    }
	    break;

	default:
	    if (kbinput < 32)
		break;
Chris Allegretta's avatar
Chris Allegretta committed
429
430
431
432
	    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
433
434
435
436
437
438
	    x++;

#ifdef DEBUG
	    fprintf(stderr, _("input \'%c\' (%d)\n"), kbinput, kbinput);
#endif
	}
Chris Allegretta's avatar
Chris Allegretta committed
439
	nanoget_repaint(buf, answer, x);
Chris Allegretta's avatar
Chris Allegretta committed
440
	wrefresh(bottomwin);
Chris Allegretta's avatar
Chris Allegretta committed
441
    } /* while (kbinput ...) */
Chris Allegretta's avatar
Chris Allegretta committed
442

Chris Allegretta's avatar
Chris Allegretta committed
443
    /* In Pico mode, just check for a blank answer here */
Chris Allegretta's avatar
Chris Allegretta committed
444
    if (ISSET(PICO_MODE) && answer[0] == '\0')
Chris Allegretta's avatar
Chris Allegretta committed
445
446
447
448
449
	return -2;
    else
	return 0;
}

450
451
452
453
454
455
456
457
458
459
/* 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
460
void titlebar(const char *path)
Chris Allegretta's avatar
Chris Allegretta committed
461
462
{
    int namelen, space;
Chris Allegretta's avatar
Chris Allegretta committed
463
    const char *what = path;
Chris Allegretta's avatar
Chris Allegretta committed
464
465
466

    if (path == NULL)
	what = filename;
Chris Allegretta's avatar
Chris Allegretta committed
467
468

    wattron(topwin, A_REVERSE);
469

Chris Allegretta's avatar
Chris Allegretta committed
470
    mvwaddstr(topwin, 0, 0, hblank);
471
    mvwaddnstr(topwin, 0, 2, VERMSG, COLS - 3);
Chris Allegretta's avatar
Chris Allegretta committed
472

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

Chris Allegretta's avatar
Chris Allegretta committed
475
    namelen = strlen(what);
Chris Allegretta's avatar
Chris Allegretta committed
476

477
478
    if (space > 0) {
        if (what[0] == '\0')
Chris Allegretta's avatar
Chris Allegretta committed
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
      	    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
495
	}
496
    } /* If we don't have space, we shouldn't bother */
Chris Allegretta's avatar
Chris Allegretta committed
497
    if (ISSET(MODIFIED))
Chris Allegretta's avatar
Chris Allegretta committed
498
	mvwaddnstr(topwin, 0, COLS - 11, _(" Modified "), 11);
Chris Allegretta's avatar
Chris Allegretta committed
499
    else if (ISSET(VIEW_MODE))
Chris Allegretta's avatar
Chris Allegretta committed
500
	mvwaddnstr(topwin, 0, COLS - 11, _(" View "), 11);
501

Chris Allegretta's avatar
Chris Allegretta committed
502
    wattroff(topwin, A_REVERSE);
503

Chris Allegretta's avatar
Chris Allegretta committed
504
505
506
507
    wrefresh(topwin);
    reset_cursor();
}

508
void bottombars(const shortcut *s)
Chris Allegretta's avatar
Chris Allegretta committed
509
{
510
    int i, j, numcols;
511
    char keystr[4];
512
513
    int slen;

Chris Allegretta's avatar
Chris Allegretta committed
514
515
516
    if (ISSET(NO_HELP))
	return;

517
518
519
520
521
522
523
524
    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
525

526
    blank_bottomwin();
527

528
529
    for (i = 0; i < numcols; i++) {
	for (j = 0; j <= 1; j++) {
Chris Allegretta's avatar
Chris Allegretta committed
530

531
	    wmove(bottomwin, 1 + j, i * (COLS / numcols));
532

533
534
535
#ifndef NANO_SMALL
	    if (s->val == NANO_CONTROL_SPACE)
		strcpy(keystr, "^ ");
536
	    else
537
538
539
540
541
542
543
544
#endif /* !NANO_SMALL */
	    if (s->val > 0) {
		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);
545

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

548
549
550
551
	    s = s->next;
	    if (s == NULL)
		goto break_completely_out;
	}	
Chris Allegretta's avatar
Chris Allegretta committed
552
    }
553

Chris Allegretta's avatar
Chris Allegretta committed
554
  break_completely_out:
Chris Allegretta's avatar
Chris Allegretta committed
555
556
557
    wrefresh(bottomwin);
}

558
559
560
561
562
/* 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
563
{
564
565
566
567
568
569
570
571
572
573
574
    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
575
576
577
    }
}

578
579
580
581
/* And so start the display update routines.  Given a column, this
 * returns the "page" it is on.  "page", in the case of the display
 * columns, means which set of 80 characters is viewable (e.g. page 1
 * shows from 1 to COLS). */
Chris Allegretta's avatar
Chris Allegretta committed
582
int get_page_from_virtual(int virtual)
Chris Allegretta's avatar
Chris Allegretta committed
583
{
584
    int page = 2;
Chris Allegretta's avatar
Chris Allegretta committed
585

Chris Allegretta's avatar
Chris Allegretta committed
586
587
    if (virtual <= COLS - 2)
	return 1;
588
    virtual -= (COLS - 2);
589
590

    while (virtual > COLS - 2 - 7) {
591
	virtual -= (COLS - 2 - 7);
592
	page++;
Chris Allegretta's avatar
Chris Allegretta committed
593
594
    }

595
596
597
    return page;
}

598
/* The inverse of the above function */
Chris Allegretta's avatar
Chris Allegretta committed
599
int get_page_start_virtual(int page)
Chris Allegretta's avatar
Chris Allegretta committed
600
{
601
602
    int virtual;
    virtual = --page * (COLS - 7);
Chris Allegretta's avatar
Chris Allegretta committed
603
604
    if (page)
	virtual -= 2 * page - 1;
605
    return virtual;
606
607
}

Chris Allegretta's avatar
Chris Allegretta committed
608
int get_page_end_virtual(int page)
Chris Allegretta's avatar
Chris Allegretta committed
609
{
610
611
612
    return get_page_start_virtual(page) + COLS - 1;
}

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
613
int get_page_start(int column)
Chris Allegretta's avatar
Chris Allegretta committed
614
615
616
617
618
{
    assert(COLS > 9);
    return column < COLS - 1 ? 0 : column - 7 - (column - 8) % (COLS - 9);
}

David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
/* 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;

    /* Yuck.  This condition can be true after open_file when opening the
     * first file. */
    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
641

642
#ifndef NANO_SMALL
643
644
645
646
/* This takes care of the case where there is a mark that covers only
 * the current line.  It expects a line with no tab characters (i.e.
 * the type that edit_add() deals with. */
void add_marked_sameline(int begin, int end, filestruct *fileptr, int y,
Chris Allegretta's avatar
Chris Allegretta committed
647
			 int virt_cur_x, int this_page)
648
{
649
650
651
    /*
     * The general idea is to break the line up into 3 sections: before
     * the mark, the mark, and after the mark.  We then paint each in
652
     * turn (for those that are currently visible, of course)
653
654
655
656
     *
     * 3 start points: 0 -> begin, begin->end, end->strlen(data)
     *    in data    :    pre          sel           post        
     */
Chris Allegretta's avatar
Chris Allegretta committed
657
    int this_page_start = get_page_start_virtual(this_page),
658
	this_page_end = get_page_end_virtual(this_page);
659
660

    /* likewise, 3 data lengths */
Chris Allegretta's avatar
Chris Allegretta committed
661
    int pre_data_len = begin, sel_data_len = end - begin, post_data_len = 0;	/* Determined from the other two */
662
663

    /* now fix the start locations & lengths according to the cursor's 
664
     * position (i.e.: our page) */
Chris Allegretta's avatar
Chris Allegretta committed
665
    if (pre_data_len < this_page_start)
666
667
668
	pre_data_len = 0;
    else
	pre_data_len -= this_page_start;
669

Chris Allegretta's avatar
Chris Allegretta committed
670
    if (begin < this_page_start)
671
672
	begin = this_page_start;

Chris Allegretta's avatar
Chris Allegretta committed
673
    if (end < this_page_start)
674
	end = this_page_start;
675

Chris Allegretta's avatar
Chris Allegretta committed
676
    if (begin > this_page_end)
677
	begin = this_page_end;
678

Chris Allegretta's avatar
Chris Allegretta committed
679
    if (end > this_page_end)
680
	end = this_page_end;
681

682
    /* Now calculate the lengths */
683
684
    sel_data_len = end - begin;
    post_data_len = this_page_end - end;
685
686

    wattron(edit, A_REVERSE);
687
    mvwaddnstr(edit, y, begin - this_page_start,
Chris Allegretta's avatar
Chris Allegretta committed
688
	       &fileptr->data[begin], sel_data_len);
689

690
    wattroff(edit, A_REVERSE);
691

Chris Allegretta's avatar
Chris Allegretta committed
692
693
694
}
#endif

695
696
697
698
/* 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. */
void edit_add(filestruct *fileptr, int yval, int start, int virt_cur_x,
Chris Allegretta's avatar
Chris Allegretta committed
699
	      int virt_mark_beginx, int this_page)
Chris Allegretta's avatar
Chris Allegretta committed
700
{
701

Chris Allegretta's avatar
Chris Allegretta committed
702
#ifdef ENABLE_COLOR
Chris Allegretta's avatar
Chris Allegretta committed
703
    const colortype *tmpcolor = NULL;
704
    int k, paintlen;
705
706
    filestruct *e, *s;
    regoff_t ematch, smatch;
707
708
709
#endif

    /* Just paint the string in any case (we'll add color or reverse on
Chris Allegretta's avatar
Chris Allegretta committed
710
       just the text that needs it */
711
    mvwaddnstr(edit, yval, 0, &fileptr->data[start],
Chris Allegretta's avatar
Chris Allegretta committed
712
	       get_page_end_virtual(this_page) - start + 1);
713

Chris Allegretta's avatar
Chris Allegretta committed
714
#ifdef ENABLE_COLOR
715
    if (colorstrings != NULL)
Chris Allegretta's avatar
Chris Allegretta committed
716
717
	for (tmpcolor = colorstrings; tmpcolor != NULL;
	     tmpcolor = tmpcolor->next) {
718

719
	    if (tmpcolor->end == NULL) {
720

721
722
		/* First, highlight all single-line regexes */
		k = start;
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
723
		regcomp(&color_regexp, tmpcolor->start, REG_EXTENDED);
724
725
		while (!regexec(&color_regexp, &fileptr->data[k], 1,
				colormatches, 0)) {
726

727
		    if (colormatches[0].rm_eo - colormatches[0].rm_so < 1) {
728
			statusbar(_("Refusing 0 length regex match"));
729
730
			break;
		    }
731
#ifdef DEBUG
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
732
		    fprintf(stderr, _("Match! (%d chars) \"%s\"\n"),
733
734
			    colormatches[0].rm_eo - colormatches[0].rm_so,
			    &fileptr->data[k + colormatches[0].rm_so]);
735
#endif
736
		    if (colormatches[0].rm_so < COLS - 1) {
737
738
739
740
			if (tmpcolor->bright)
			    wattron(edit, A_BOLD);
			wattron(edit, COLOR_PAIR(tmpcolor->pairnum));

741
			if (colormatches[0].rm_eo + k <= COLS) {
742
			    paintlen =
743
				colormatches[0].rm_eo - colormatches[0].rm_so;
744
#ifdef DEBUG
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
745
			    fprintf(stderr, _("paintlen (%d) = eo (%d) - so (%d)\n"), 
746
747
748
749
750
				paintlen, colormatches[0].rm_eo, colormatches[0].rm_so);
#endif

			}
			else {
751
			    paintlen = COLS - k - colormatches[0].rm_so - 1;
752
#ifdef DEBUG
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
753
			    fprintf(stderr, _("paintlen (%d) = COLS (%d) - k (%d), - rm.so (%d) - 1\n"), 
754
755
756
					paintlen, COLS, k, colormatches[0].rm_so);
#endif
			}
757

758
759
			mvwaddnstr(edit, yval, colormatches[0].rm_so + k,
				   &fileptr->data[k + colormatches[0].rm_so],
760
761
762
				   paintlen);

		    }
763

764
765
766
		    if (tmpcolor->bright)
			wattroff(edit, A_BOLD);
		    wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
767

768
		    k += colormatches[0].rm_eo;
769

Chris Allegretta's avatar
Chris Allegretta committed
770
		}
771
772
		regfree(&color_regexp);

773
774
775
776
777
778
779
780
781
782
	    }
	    /* Now, if there's an 'end' somewhere below, and a 'start'
	       somewhere above, things get really fun.  We have to look
	       down for an end, make sure there's not a start before 
	       the end after us, and then look up for a start, 
	       and see if there's an end after the start, before us :) */
	    else {

		s = fileptr;
		while (s != NULL) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
783
		    regcomp(&color_regexp, tmpcolor->start, REG_EXTENDED);
784
		    if (!regexec
785
786
			(&color_regexp, s->data, 1, colormatches, 0)) {
			regfree(&color_regexp);
787
			break;
788
		    }
789
		    s = s->prev;
790
		    regfree(&color_regexp);
791
792
793
794
		}

		if (s != NULL) {
		    /* We found a start, mark it */
795
		    smatch = colormatches[0].rm_so;
796
797
798

		    e = s;
		    while (e != NULL && e != fileptr) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
799
			regcomp(&color_regexp, tmpcolor->end, REG_EXTENDED);
800
			if (!regexec
801
802
			    (&color_regexp, e->data, 1, colormatches, 0)) {
			    regfree(&color_regexp);
803
			    break;
804
			}
805
			e = e->next;
806
			regfree(&color_regexp);
807
		    }
808

809
810
811
812
		    if (e != fileptr)
			continue;	/* There's an end before us */
		    else {	/* Keep looking for an end */
			while (e != NULL) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
813
			    regcomp(&color_regexp, tmpcolor->end, REG_EXTENDED);
814
			    if (!regexec
815
				(&color_regexp, e->data, 1, colormatches,
816
817
				 0)) {
				regfree(&color_regexp);
818
				break;
819
			    }
820
			    e = e->next;
821
			    regfree(&color_regexp);
822
823
824
825
826
			}

			if (e == NULL)
			    continue;	/* There's no start before the end :) */
			else {	/* Okay, we found an end, mark it! */
827
			    ematch = colormatches[0].rm_eo;
828
829

			    while (e != NULL) {
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
830
				regcomp(&color_regexp, tmpcolor->end, REG_EXTENDED);
831
				if (!regexec
832
				    (&color_regexp, e->data, 1,
833
834
				     colormatches, 0)) {
				    regfree(&color_regexp);
835
				    break;
836
837
				} e = e->next;
				regfree(&color_regexp);
838
839
840
841
842
843
844
845
846
847
848
849
850
			    }

			    if (e == NULL)
				continue;	/* No end, oh well :) */

			    /* Didn't find another end, we must be in the 
			       middle of a highlighted bit */

			    if (tmpcolor->bright)
				wattron(edit, A_BOLD);

			    wattron(edit, COLOR_PAIR(tmpcolor->pairnum));

851
			    if (s == fileptr && e == fileptr && ematch < COLS) {
852
853
854
				mvwaddnstr(edit, yval, start + smatch, 
					&fileptr->data[start + smatch],
					ematch - smatch);
855
#ifdef DEBUG
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
856
			fprintf(stderr, _("start = %d, smatch = %d, ematch = %d\n"), start,
857
858
859
860
				smatch, ematch);
#endif

		    	    } else if (s == fileptr)
861
862
863
864
865
866
				mvwaddnstr(edit, yval, start + smatch, 
					&fileptr->data[start + smatch],
					COLS - smatch);
			    else if (e == fileptr)
				mvwaddnstr(edit, yval, start, 
					&fileptr->data[start],
867
					COLS - start);
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
			    else
				mvwaddnstr(edit, yval, start, 
					&fileptr->data[start],
					COLS);

			    if (tmpcolor->bright)
				wattroff(edit, A_BOLD);

			    wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));

			}

		    }

		    /* Else go to the next string, yahoo! =) */
		}
884
885

	    }
886

887
	}
888

Chris Allegretta's avatar
Chris Allegretta committed
889
#endif				/* ENABLE_COLOR */
Chris Allegretta's avatar
Chris Allegretta committed
890
#ifndef NANO_SMALL
891

892
    /* There are quite a few cases that could take place; we'll deal
893
     * with them each in turn */
Chris Allegretta's avatar
Chris Allegretta committed
894
    if (ISSET(MARK_ISSET) &&
895
	!((fileptr->lineno > mark_beginbuf->lineno
Chris Allegretta's avatar
Chris Allegretta committed
896
897
898
	   && fileptr->lineno > current->lineno)
	  || (fileptr->lineno < mark_beginbuf->lineno
	      && fileptr->lineno < current->lineno))) {
899
	/* If we get here we are on a line that is at least
900
901
902
903
904
	 * partially selected.  The lineno checks above determined
	 * that */
	if (fileptr != mark_beginbuf && fileptr != current) {
	    /* We are on a completely marked line, paint it all
	     * inverse */
Chris Allegretta's avatar
Chris Allegretta committed
905

906
	    wattron(edit, A_REVERSE);
907

908
	    mvwaddnstr(edit, yval, 0, fileptr->data, COLS);
909

910
	    wattroff(edit, A_REVERSE);
911

912
913
914
915
916
917
918
919
920
921
922
923
924
925
	} else if (fileptr == mark_beginbuf && fileptr == current) {
	    /* Special case, we're still on the same line we started
	     * marking -- so we call our helper function */
	    if (virt_cur_x < virt_mark_beginx) {
		/* To the right of us is marked */
		add_marked_sameline(virt_cur_x, virt_mark_beginx,
				    fileptr, yval, virt_cur_x, this_page);
	    } else {
		/* To the left of us is marked */
		add_marked_sameline(virt_mark_beginx, virt_cur_x,
				    fileptr, yval, virt_cur_x, this_page);
	    }
	} else if (fileptr == mark_beginbuf) {
	    /*
926
	     * We're updating the line that was first marked,
927
	     * but we're not currently on it.  So we want to
928
	     * figure out which half to invert based on our
929
930
	     * relative line numbers.
	     *
931
932
933
	     * I.e. if we're above the "beginbuf" line, we want to
	     * mark the left side.  Otherwise, we're below, so we
	     * mark the right.
934
935
936
	     */
	    int target;

937
	    if (mark_beginbuf->lineno > current->lineno) {
Chris Allegretta's avatar
Chris Allegretta committed
938

Chris Allegretta's avatar
Chris Allegretta committed
939
		wattron(edit, A_REVERSE);
940

941
		target =
Chris Allegretta's avatar
Chris Allegretta committed
942
943
		    (virt_mark_beginx <
		     COLS - 1) ? virt_mark_beginx : COLS - 1;
944

945
		mvwaddnstr(edit, yval, 0, fileptr->data, target);
946

947
		wattroff(edit, A_REVERSE);
948

949
950
951
	    }

	    if (mark_beginbuf->lineno < current->lineno) {
952

Chris Allegretta's avatar
Chris Allegretta committed
953
		wattron(edit, A_REVERSE);
954
		target = (COLS - 1) - virt_mark_beginx;
955

956
957
		if (target < 0)
		    target = 0;
958

959
		mvwaddnstr(edit, yval, virt_mark_beginx,
Chris Allegretta's avatar
Chris Allegretta committed
960
			   &fileptr->data[virt_mark_beginx], target);
961
962

		wattroff(edit, A_REVERSE);
963
	    }
964
965

	} else if (fileptr == current) {
966
	    /* We're on the cursor's line, but it's not the first
967
968
969
970
	     * one we marked.  Similar to the previous logic. */
	    int this_page_start = get_page_start_virtual(this_page),
		this_page_end = get_page_end_virtual(this_page);

971
972
	    if (mark_beginbuf->lineno < current->lineno) {

973
		wattron(edit, A_REVERSE);
974

975
976
		if (virt_cur_x > COLS - 2) {
		    mvwaddnstr(edit, yval, 0,
Chris Allegretta's avatar
Chris Allegretta committed
977
978
			       &fileptr->data[this_page_start],
			       virt_cur_x - this_page_start);
979
980
		} else
		    mvwaddnstr(edit, yval, 0, fileptr->data, virt_cur_x);
981

982
		wattroff(edit, A_REVERSE);
983

984
985
986
	    }

	    if (mark_beginbuf->lineno > current->lineno) {
987

988
989
990
		wattron(edit, A_REVERSE);
		if (virt_cur_x > COLS - 2)
		    mvwaddnstr(edit, yval, virt_cur_x - this_page_start,
Chris Allegretta's avatar
Chris Allegretta committed
991
992
			       &fileptr->data[virt_cur_x],
			       this_page_end - virt_cur_x);
993
994
		else
		    mvwaddnstr(edit, yval, virt_cur_x,
Chris Allegretta's avatar
Chris Allegretta committed
995
996
			       &fileptr->data[virt_cur_x],
			       COLS - virt_cur_x);
997
998

		wattroff(edit, A_REVERSE);
999
1000

	    }
Chris Allegretta's avatar
Chris Allegretta committed
1001
	}
1002
1003
1004
    }
#endif

Chris Allegretta's avatar
Chris Allegretta committed
1005
1006
1007
}

/*
1008
 * Just update one line in the edit buffer.  Basically a wrapper for
1009
1010
 * edit_add().  index gives us a place in the string to update starting
 * from.  Likely args are current_x or 0.
Chris Allegretta's avatar
Chris Allegretta committed
1011
 */
1012
void update_line(filestruct *fileptr, int index)
Chris Allegretta's avatar
Chris Allegretta committed
1013
1014
{
    filestruct *filetmp;
1015
1016
1017
    int line = 0, col = 0;
    int virt_cur_x = current_x, virt_mark_beginx = mark_beginx;
    char *realdata, *tmp;
Chris Allegretta's avatar
Chris Allegretta committed
1018
    int i, pos, len, page;
Chris Allegretta's avatar
Chris Allegretta committed
1019

Chris Allegretta's avatar
Chris Allegretta committed
1020
1021
    if (!fileptr)
	return;
1022

1023
    /* First, blank out the line (at a minimum) */
Chris Allegretta's avatar
Chris Allegretta committed
1024
1025
1026
1027
1028
    for (filetmp = edittop; filetmp != fileptr && filetmp != editbot;
	 filetmp = filetmp->next)
	line++;

    mvwaddstr(edit, line, 0, hblank);
1029

1030
    /* Next, convert all the tabs to spaces, so everything else is easy */
1031
1032
1033
1034
    index = xpt(fileptr, index);

    realdata = fileptr->data;
    len = strlen(realdata);
1035
    fileptr->data = charalloc(xpt(fileptr, len) + 1);
1036
1037

    pos = 0;
Chris Allegretta's avatar
Chris Allegretta committed
1038
1039
    for (i = 0; i < len; i++) {
	if (realdata[i] == '\t') {
1040
1041
	    do {
		fileptr->data[pos++] = ' ';
Chris Allegretta's avatar
Chris Allegretta committed
1042
1043
1044
1045
		if (i < current_x)
		    virt_cur_x++;
		if (i < mark_beginx)
		    virt_mark_beginx++;
1046
	    } while (pos % tabsize);
1047
	    /* must decrement once to account for tab-is-one-character */
Chris Allegretta's avatar
Chris Allegretta committed
1048
1049
1050
1051
	    if (i < current_x)
		virt_cur_x--;
	    if (i < mark_beginx)
		virt_mark_beginx--;
Chris Allegretta's avatar
Chris Allegretta committed
1052
	} else if (realdata[i] == 127) {
Chris Allegretta's avatar
Chris Allegretta committed
1053
	    /* Treat delete characters (ASCII 127's) as ^?'s */
Chris Allegretta's avatar
Chris Allegretta committed
1054
1055
	    fileptr->data[pos++] = '^';
	    fileptr->data[pos++] = '?';
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
	    if (i < current_x)
		virt_cur_x++;
	    if (i < mark_beginx)
		virt_mark_beginx++;
	} else if (realdata[i] == 10) {
	    /* 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 */
	    fileptr->data[pos++] = '^';
	    fileptr->data[pos++] = '@';
	    if (i < current_x)
		virt_cur_x++;
	    if (i < mark_beginx)
		virt_mark_beginx++;
Chris Allegretta's avatar
Chris Allegretta committed
1070
1071
1072
1073
1074
1075
1076
1077
	} else if (is_cntrl_char(realdata[i])) {
	    /* Treat control characters as ^symbol's */
	    fileptr->data[pos++] = '^';
	    fileptr->data[pos++] = realdata[i] + 64;
	    if (i < current_x)
		virt_cur_x++;
	    if (i < mark_beginx)
		virt_mark_beginx++;
1078
1079
1080
1081
1082
1083
	} else {
	    fileptr->data[pos++] = realdata[i];
	}
    }

    fileptr->data[pos] = '\0';
Chris Allegretta's avatar
Chris Allegretta committed
1084

Chris Allegretta's avatar
Chris Allegretta committed
1085
    /* Now, paint the line */
1086
    if (current == fileptr && index > COLS - 2) {
1087
	/* This handles when the current line is beyond COLS */
1088
	/* It requires figuring out what page we're on      */
1089
	page = get_page_from_virtual(index);
1090
	col = get_page_start_virtual(page);
Chris Allegretta's avatar
Chris Allegretta committed
1091

1092
	edit_add(filetmp, line, col, virt_cur_x, virt_mark_beginx, page);
Chris Allegretta's avatar
Chris Allegretta committed
1093
1094
	mvwaddch(edit, line, 0, '$');

Chris Allegretta's avatar
Chris Allegretta committed
1095
	if (strlenpt(fileptr->data) > get_page_end_virtual(page) + 1)
Chris Allegretta's avatar
Chris Allegretta committed
1096
	    mvwaddch(edit, line, COLS - 1, '$');
1097
    } else {
1098
1099
1100
	/* It's not the current line means that it's at x=0 and page=1 */
	/* If it is the current line, then we're in the same boat      */
	edit_add(filetmp, line, 0, virt_cur_x, virt_mark_beginx, 1);
Chris Allegretta's avatar
Chris Allegretta committed
1101

1102
	if (strlenpt(&filetmp->data[col]) > COLS)
Chris Allegretta's avatar
Chris Allegretta committed
1103
	    mvwaddch(edit, line, COLS - 1, '$');
1104
    }
1105
1106
1107
1108
1109

    /* Clean up our mess */
    tmp = fileptr->data;
    fileptr->data = realdata;
    free(tmp);
Chris Allegretta's avatar
Chris Allegretta committed
1110
1111
}

1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
/* 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
1134
1135
1136
1137
1138
1139
void center_cursor(void)
{
    current_y = editwinrows / 2;
    wmove(edit, current_y, current_x);
}

Chris Allegretta's avatar
Chris Allegretta committed
1140
/* Refresh the screen without changing the position of lines. */
Chris Allegretta's avatar
Chris Allegretta committed
1141
1142
void edit_refresh(void)
{
Chris Allegretta's avatar
Chris Allegretta committed
1143
    static int noloop = 0;
Chris Allegretta's avatar
Chris Allegretta committed
1144
    int nlines = 0, currentcheck = 0;
Chris Allegretta's avatar
Chris Allegretta committed
1145

Chris Allegretta's avatar
Chris Allegretta committed
1146
1147
1148
    /* 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
1149
1150
    if (current == NULL)
	return;
Chris Allegretta's avatar
Chris Allegretta committed
1151
1152
    if (edittop == NULL)
	edittop = current;
Chris Allegretta's avatar
Chris Allegretta committed
1153

1154
1155
1156
    /* Don't make the cursor jump around the scrrn whilst updating */
    leaveok(edit, TRUE);

Chris Allegretta's avatar
Chris Allegretta committed
1157
1158
1159
1160
    editbot = edittop;
    while (nlines < editwinrows) {
	update_line(editbot, current_x);
	if (editbot == current)
1161
1162
	    currentcheck = 1;

1163
	nlines++;
Chris Allegretta's avatar
Chris Allegretta committed
1164
1165
1166
1167

	if (editbot->next == NULL)
	    break;
	editbot = editbot->next;
Chris Allegretta's avatar
Chris Allegretta committed
1168
    }
1169

Chris Allegretta's avatar
Chris Allegretta committed
1170
1171
    /* If noloop == 1, then we already did an edit_update without finishing
       this function.  So we don't run edit_update again */
Chris Allegretta's avatar
Chris Allegretta committed
1172
1173
    if (!currentcheck && !noloop) {
		/* Then current has run off the screen... */
1174
	edit_update(current, CENTER);
Chris Allegretta's avatar
Chris Allegretta committed
1175
	noloop = 1;
1176
    } else if (noloop)
Chris Allegretta's avatar
Chris Allegretta committed
1177
	noloop = 0;
Chris Allegretta's avatar
Chris Allegretta committed
1178

Chris Allegretta's avatar
Chris Allegretta committed
1179
1180
1181
1182
    while (nlines < editwinrows) {
	mvwaddstr(edit, nlines, 0, hblank);
	nlines++;
    }
1183
1184

    /* What the hell are we expecting to update the screen if this isn't 
Chris Allegretta's avatar
Chris Allegretta committed
1185
       here? Luck?? */
1186
    wrefresh(edit);
1187
    leaveok(edit, FALSE);
Chris Allegretta's avatar
Chris Allegretta committed
1188
1189
}

1190
/*
1191
 * Same as above, but touch the window first, so everything is redrawn.
1192
1193
1194
1195
1196
1197
1198
1199
 */
void edit_refresh_clearok(void)
{
    clearok(edit, TRUE);
    edit_refresh();
    clearok(edit, FALSE);
}

Chris Allegretta's avatar
Chris Allegretta committed
1200
/*
1201
 * Nice generic routine to update the edit buffer, given a pointer to the
Chris Allegretta's avatar
Chris Allegretta committed
1202
1203
 * file struct =) 
 */
Chris Allegretta's avatar
Chris Allegretta committed
1204
void edit_update(filestruct *fileptr, topmidbotnone location)
Chris Allegretta's avatar
Chris Allegretta committed
1205
1206
1207
1208
{
    if (fileptr == NULL)
	return;

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

Chris Allegretta's avatar
Chris Allegretta committed
1212
1213
1214
1215
	for (; goal >= 0 && fileptr->prev != NULL; goal--)
	    fileptr = fileptr->prev;
    }
    edittop = fileptr;
1216
    fix_editbot();
Chris Allegretta's avatar
Chris Allegretta committed
1217
1218
1219
1220
1221
1222
1223

    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
1224
 * otherwise, the valid shortcut key caught.  Def is any editable text we
Chris Allegretta's avatar
Chris Allegretta committed
1225
 * want to put up by default.
1226
1227
 *
 * New arg tabs tells whether or not to allow tab completion.
Chris Allegretta's avatar
Chris Allegretta committed
1228
 */
Chris Allegretta's avatar
Chris Allegretta committed
1229
1230
int statusq(int tabs, const shortcut *s, const char *def,
		const char *msg, ...)
Chris Allegretta's avatar
Chris Allegretta committed
1231
1232
{
    va_list ap;
Chris Allegretta's avatar
Chris Allegretta committed
1233
    char *foo = charalloc(COLS - 3);
1234
    int ret;
1235
#ifndef DISABLE_TABCOMP
1236
    int list = 0;
1237
1238
#endif

1239
    bottombars(s);
Chris Allegretta's avatar
Chris Allegretta committed
1240
1241

    va_start(ap, msg);
Chris Allegretta's avatar
Chris Allegretta committed
1242
    vsnprintf(foo, COLS - 4, msg, ap);
Chris Allegretta's avatar
Chris Allegretta committed
1243
    va_end(ap);
Chris Allegretta's avatar
Chris Allegretta committed
1244
    foo[COLS - 4] = '\0';
1245

1246
#ifndef DISABLE_TABCOMP
Chris Allegretta's avatar
Chris Allegretta committed
1247
    ret = nanogetstr(tabs, foo, def, s, &list);
1248
#else
Chris Allegretta's avatar
Chris Allegretta committed
1249
    ret = nanogetstr(tabs, foo, def, s);
1250
#endif
Chris Allegretta's avatar
Chris Allegretta committed
1251
    free(foo);
Chris Allegretta's avatar
Chris Allegretta committed
1252
1253
1254
1255
1256
1257
1258
1259
1260

    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
1261
1262
	ret = -1;
	break;
Chris Allegretta's avatar
Chris Allegretta committed
1263
    default:
1264
	blank_statusbar();
Chris Allegretta's avatar
Chris Allegretta committed
1265
1266
1267
1268
1269
1270
    }

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

Chris Allegretta's avatar
Chris Allegretta committed
1271
1272
1273
1274
1275
1276
1277
1278
#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
1279
1280
1281
1282
    return ret;
}

/*
1283
1284
1285
 * Ask a simple yes/no question on the statusbar.  Returns 1 for Y, 0
 * for N, 2 for All (if all is non-zero when passed in) and -1 for
 * abort (^C).
Chris Allegretta's avatar
Chris Allegretta committed
1286
 */
Chris Allegretta's avatar
Chris Allegretta committed
1287
int do_yesno(int all, int leavecursor, const char *msg, ...)
Chris Allegretta's avatar
Chris Allegretta committed
1288
1289
1290
{
    va_list ap;
    char foo[133];
1291
    int kbinput, ok = -1, i;
Chris Allegretta's avatar
Chris Allegretta committed
1292
1293
1294
    const char *yesstr;		/* String of yes characters accepted */
    const char *nostr;		/* Same for no */
    const char *allstr;		/* And all, surprise! */
1295
#ifndef DISABLE_MOUSE
Chris Allegretta's avatar
Chris Allegretta committed
1296
1297
1298
1299
1300
#ifdef NCURSES_MOUSE_VERSION
    MEVENT mevent;
#endif
#endif

1301
    /* Yes, no and all are strings of any length.  Each string consists of
Chris Allegretta's avatar
Chris Allegretta committed
1302
1303
       all characters accepted as a valid character for that value.
       The first value will be the one displayed in the shortcuts. */
1304
1305
1306
    yesstr = _("Yy");
    nostr = _("Nn");
    allstr = _("Aa");
Chris Allegretta's avatar
Chris Allegretta committed
1307
1308

    /* Write the bottom of the screen */
1309
    blank_bottomwin();
1310

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

Chris Allegretta's avatar
Chris Allegretta committed
1315
	wmove(bottomwin, 1, 0);
1316

1317
	sprintf(shortstr, " %c", yesstr[0]);
1318
	onekey(shortstr, _("Yes"), 16);
1319
1320

	if (all) {
1321
	    shortstr[1] = allstr[0];
1322
	    onekey(shortstr, _("All"), 16);
1323
	}
Chris Allegretta's avatar
Chris Allegretta committed
1324
	wmove(bottomwin, 2, 0);
1325

1326
	shortstr[1] = nostr[0];
1327
	onekey(shortstr, _("No"), 16);
1328

1329
	onekey("^C", _("Cancel"), 16);
Chris Allegretta's avatar
Chris Allegretta committed
1330
1331
1332
1333
    }
    va_start(ap, msg);
    vsnprintf(foo, 132, msg, ap);
    va_end(ap);
1334

Chris Allegretta's avatar
Chris Allegretta committed
1335
    wattron(bottomwin, A_REVERSE);
1336
1337

    blank_statusbar();
Chris Allegretta's avatar
Chris Allegretta committed
1338
    mvwaddstr(bottomwin, 0, 0, foo);
1339

Chris Allegretta's avatar
Chris Allegretta committed
1340
    wattroff(bottomwin, A_REVERSE);
1341

Chris Allegretta's avatar
Chris Allegretta committed
1342
1343
1344
1345
1346
1347
1348
1349
1350
    wrefresh(bottomwin);

    if (leavecursor == 1)
	reset_cursor();

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

	switch (kbinput) {
1351
#ifndef DISABLE_MOUSE
Chris Allegretta's avatar
Chris Allegretta committed
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
#ifdef NCURSES_MOUSE_VERSION
	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
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
		   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
1377
1378
1379
1380
	    }
	    break;
#endif
#endif
Chris Allegretta's avatar
Chris Allegretta committed
1381
1382
1383
	case NANO_CONTROL_C:
	    ok = -2;
	    break;
1384
1385
	default:

1386
	    /* Look for the kbinput in the yes, no and (optimally) all str */
Chris Allegretta's avatar
Chris Allegretta committed
1387
	    for (i = 0; yesstr[i] != 0 && yesstr[i] != kbinput; i++);
1388
	    if (yesstr[i] != 0) {
1389
		ok = 1;
Chris Allegretta's avatar
Chris Allegretta committed
1390
		break;
1391
1392
	    }

Chris Allegretta's avatar
Chris Allegretta committed
1393
	    for (i = 0; nostr[i] != 0 && nostr[i] != kbinput; i++);
1394
1395
	    if (nostr[i] != 0) {
		ok = 0;
Chris Allegretta's avatar
Chris Allegretta committed
1396
		break;
1397
1398
1399
	    }

	    if (all) {
Chris Allegretta's avatar
Chris Allegretta committed
1400
		for (i = 0; allstr[i] != 0 && allstr[i] != kbinput; i++);
1401
1402
		if (allstr[i] != 0) {
		    ok = 2;
Chris Allegretta's avatar
Chris Allegretta committed
1403
		    break;
1404
1405
		}
	    }
Chris Allegretta's avatar
Chris Allegretta committed
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
	}
    }

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

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

1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
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
1440
void statusbar(const char *msg, ...)
Chris Allegretta's avatar
Chris Allegretta committed
1441
1442
{
    va_list ap;
Chris Allegretta's avatar
Chris Allegretta committed
1443
    char *foo;
Chris Allegretta's avatar
Chris Allegretta committed
1444
    int start_x = 0;
Chris Allegretta's avatar
Chris Allegretta committed
1445
1446
1447
1448
    size_t foo_len;

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

    va_start(ap, msg);
Chris Allegretta's avatar
Chris Allegretta committed
1451
    vsnprintf(foo, COLS - 3, msg, ap);
Chris Allegretta's avatar
Chris Allegretta committed
1452
1453
    va_end(ap);

Chris Allegretta's avatar
Chris Allegretta committed
1454
1455
1456
    foo[COLS - 4] = '\0';
    foo_len = strlen(foo);
    start_x = (COLS - foo_len - 4) / 2;
Chris Allegretta's avatar
Chris Allegretta committed
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466

    /* 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
1467
    free(foo);
Chris Allegretta's avatar
Chris Allegretta committed
1468
    waddstr(bottomwin, " ]");
1469

Chris Allegretta's avatar
Chris Allegretta committed
1470
    wattroff(bottomwin, A_REVERSE);
1471

Chris Allegretta's avatar
Chris Allegretta committed
1472
1473
1474
1475
1476
1477
1478
1479
    wrefresh(bottomwin);

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

1480
int do_cursorpos(int constant)
Chris Allegretta's avatar
Chris Allegretta committed
1481
1482
{
    filestruct *fileptr;
1483
    float linepct = 0.0, bytepct = 0.0, colpct = 0.0;
1484
    long i = 0, j = 0;
1485
    static long old_i = -1, old_totsize = -1;
Chris Allegretta's avatar
Chris Allegretta committed
1486
1487
1488
1489

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

1490
1491
1492
1493
1494
1495
    if (old_i == -1)
	old_i = i;

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

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

1498
1499
1500
    for (fileptr = fileage; fileptr != current && fileptr != NULL;
	 fileptr = fileptr->next)
	i += strlen(fileptr->data) + 1;
1501

1502
1503
    if (fileptr == NULL)
	return -1;
1504

1505
    i += current_x;
1506

1507
    j = totsize;
1508

1509
1510
    if (totsize > 0)
	bytepct = 100 * i / totsize;
1511
1512
1513

    if (totlines > 0)
	 linepct = 100 * current->lineno / totlines;
Chris Allegretta's avatar
Chris Allegretta committed
1514
1515
1516
1517
1518
1519

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

1520
1521
1522
1523
    /* 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
1524
	statusbar(_
1525
		  ("line %d/%d (%.0f%%), col %ld/%ld (%.0f%%), char %ld/%ld (%.0f%%)"),
1526
		  current->lineno, totlines, linepct, xplustabs() + 1, 
Chris Allegretta's avatar
Chris Allegretta committed
1527
		  strlenpt(current->data) + 1, colpct, i, j, bytepct);
1528
1529
1530
1531
1532
    }

    old_i = i;
    old_totsize = totsize;

Chris Allegretta's avatar
Chris Allegretta committed
1533
1534
1535
1536
    reset_cursor();
    return 1;
}

1537
1538
1539
1540
1541
int do_cursorpos_void(void)
{
    return do_cursorpos(0);
}

1542
1543
/* Our shortcut-list-compliant help function, which is
 * better than nothing, and dynamic! */
Chris Allegretta's avatar
Chris Allegretta committed
1544
1545
int do_help(void)
{
1546
#ifndef DISABLE_HELP
1547
    int i, j, row = 0, page = 1, kbinput = 0, no_more = 0, kp, kp2;
Chris Allegretta's avatar
Chris Allegretta committed
1548
    int no_help_flag = 0;
Chris Allegretta's avatar
Chris Allegretta committed
1549
    const shortcut *oldshortcut;
Chris Allegretta's avatar
Chris Allegretta committed
1550
1551
1552

    blank_edit();
    curs_set(0);
1553
    wattroff(bottomwin, A_REVERSE);
Chris Allegretta's avatar
Chris Allegretta committed
1554
1555
    blank_statusbar();

1556
    /* set help_text as the string to display */
1557
    help_init();
1558
    assert(help_text != NULL);
1559
1560
1561

    oldshortcut = currshortcut;

1562
    currshortcut = help_list;
1563

1564
    kp = keypad_on(edit, 1);
1565
    kp2 = keypad_on(bottomwin, 1);
1566

Chris Allegretta's avatar
Chris Allegretta committed
1567
1568
    if (ISSET(NO_HELP)) {

1569
	/* Well, if we're going to do this, we should at least
1570
	   do it the right way */
Chris Allegretta's avatar
Chris Allegretta committed
1571
	no_help_flag = 1;
Chris Allegretta's avatar
Chris Allegretta committed
1572
	UNSET(NO_HELP);
1573
	window_init();
1574
	bottombars(help_list);
1575

Chris Allegretta's avatar
Chris Allegretta committed
1576
    } else
1577
	bottombars(help_list);
Chris Allegretta's avatar
Chris Allegretta committed
1578
1579

    do {
1580
1581
	const char *ptr = help_text;

Chris Allegretta's avatar
Chris Allegretta committed
1582
	switch (kbinput) {
1583
#ifndef DISABLE_MOUSE
1584
#ifdef NCURSES_MOUSE_VERSION
Chris Allegretta's avatar
Chris Allegretta committed
1585
1586
1587
	case KEY_MOUSE:
	    do_mouse();
	    break;
1588
1589
#endif
#endif
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
	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
1616
1617
1618
	case NANO_NEXTPAGE_KEY:
	case NANO_NEXTPAGE_FKEY:
	case KEY_NPAGE:
David Lawrence Ramsey's avatar
David Lawrence Ramsey committed
1619
	  do_pagedownkey:
Chris Allegretta's avatar
Chris Allegretta committed
1620
1621
1622
1623
1624
1625
1626
1627
	    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
1628
	  do_pageupkey:
Chris Allegretta's avatar
Chris Allegretta committed
1629
1630
1631
1632
1633
1634
1635
1636
	    if (page > 1) {
		no_more = 0;
		blank_edit();
		page--;
	    }
	    break;
	}

1637
	/* Calculate where in the text we should be, based on the page */
Chris Allegretta's avatar
Chris Allegretta committed
1638
1639
1640
	for (i = 1; i < page; i++) {
	    row = 0;
	    j = 0;
1641
1642

	    while (row < editwinrows - 2 && *ptr != '\0') {
Chris Allegretta's avatar
Chris Allegretta committed
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
		if (*ptr == '\n' || j == COLS - 5) {
		    j = 0;
		    row++;
		}
		ptr++;
		j++;
	    }
	}

	i = 0;
	j = 0;
	while (i < editwinrows && *ptr != '\0') {
1655
	    const char *end = ptr;
Chris Allegretta's avatar
Chris Allegretta committed
1656
1657
1658
1659
1660
1661
	    while (*end != '\n' && *end != '\0' && j != COLS - 5) {
		end++;
		j++;
	    }
	    if (j == COLS - 5) {

1662
		/* Don't print half a word if we've run out of space */
Chris Allegretta's avatar
Chris Allegretta committed
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
		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
1679
1680
    } while ((kbinput = wgetch(edit)) != NANO_EXIT_KEY &&
	     kbinput != NANO_EXIT_FKEY);
Chris Allegretta's avatar
Chris Allegretta committed
1681

1682
1683
    currshortcut = oldshortcut;

Chris Allegretta's avatar
Chris Allegretta committed
1684
    if (no_help_flag) {
1685
	blank_bottombars();
Chris Allegretta's avatar
Chris Allegretta committed
1686
	wrefresh(bottomwin);
Chris Allegretta's avatar
Chris Allegretta committed
1687
	SET(NO_HELP);
1688
	window_init();
Chris Allegretta's avatar
Chris Allegretta committed
1689
    } else
1690
	bottombars(currshortcut);
Chris Allegretta's avatar
Chris Allegretta committed
1691
1692
1693

    curs_set(1);
    edit_refresh();
1694
    kp = keypad_on(edit, kp);
1695
    kp2 = keypad_on(bottomwin, kp2);
1696

1697
1698
1699
1700
1701
    /* 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
1702
1703
1704
1705
#elif defined(DISABLE_HELP)
    nano_disabled_msg();
#endif

Chris Allegretta's avatar
Chris Allegretta committed
1706
1707
1708
    return 1;
}

1709
int keypad_on(WINDOW * win, int newval)
1710
{
1711
1712
1713
1714
1715
1716
1717
1718
1719
/* 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
1720
}
1721

1722
/* Highlight the current word being replaced or spell checked. */
Chris Allegretta's avatar
Chris Allegretta committed
1723
void do_replace_highlight(int highlight_flag, const char *word)
Chris Allegretta's avatar
Chris Allegretta committed
1724
1725
{
    char *highlight_word = NULL;
Chris Allegretta's avatar
Chris Allegretta committed
1726
    int x, y, word_len;
Chris Allegretta's avatar
Chris Allegretta committed
1727

Chris Allegretta's avatar
Chris Allegretta committed
1728
1729
    highlight_word =
	mallocstrcpy(highlight_word, &current->data[current_x]);
Chris Allegretta's avatar
Chris Allegretta committed
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740

#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
1741

1742
    /* adjust output when word extends beyond screen */
Chris Allegretta's avatar
Chris Allegretta committed
1743
1744

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

Chris Allegretta's avatar
Chris Allegretta committed
1747
    if ((COLS - (y - x) + word_len) > COLS) {
Chris Allegretta's avatar
Chris Allegretta committed
1748
1749
1750
1751
1752
1753
1754
	highlight_word[y - x - 1] = '$';
	highlight_word[y - x] = '\0';
    }

    /* OK display the output */

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

Chris Allegretta's avatar
Chris Allegretta committed
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
    if (highlight_flag)
	wattron(edit, A_REVERSE);

    waddstr(edit, highlight_word);

    if (highlight_flag)
	wattroff(edit, A_REVERSE);

    free(highlight_word);
}

1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
/* 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 */

1805
#ifdef NANO_EXTRA
1806
#define CREDIT_LEN 52
1807
1808
#define XLCREDIT_LEN 8

1809
1810
void do_credits(void)
{
Chris Allegretta's avatar
Chris Allegretta committed
1811
    int i, j = 0, k, place = 0, start_x;
1812

1813
1814
    const char *what;
    const char *xlcredits[XLCREDIT_LEN];
1815

1816
    const char *credits[CREDIT_LEN] = { 
1817
1818
	"0",				/* "The nano text editor" */
	"1",				/* "version" */
Chris Allegretta's avatar
Chris Allegretta committed
1819
1820
	VERSION,
	"",
1821
	"2",				/* "Brought to you by:" */
Chris Allegretta's avatar
Chris Allegretta committed
1822
1823
1824
1825
1826
	"Chris Allegretta",
	"Jordi Mallach",
	"Adam Rogoyski",
	"Rob Siemborski",
	"Rocco Corsi",
1827
	"David Lawrence Ramsey",
Chris Allegretta's avatar
Chris Allegretta committed
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
	"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",
	"",
1843
	"3",				/* "Special thanks to:" */
Chris Allegretta's avatar
Chris Allegretta committed
1844
1845
1846
1847
1848
1849
	"Plattsburgh State University",
	"Benet Laboratories",
	"Amy Allegretta",
	"Linda Young",
	"Jeremy Robichaud",
	"Richard Kolb II",
1850
	"4",				/* "The Free Software Foundation" */
Chris Allegretta's avatar
Chris Allegretta committed
1851
	"Linus Torvalds",
1852
	"5",				/* "For ncurses:" */
1853
1854
1855
1856
	"Thomas Dickey",
	"Pavel Curtis",
	"Zeyd Ben-Halim",
	"Eric S. Raymond",
1857
1858
	"6",				/* "and anyone else we forgot..." */
	"7",				/* "Thank you for using nano!\n" */
Chris Allegretta's avatar
Chris Allegretta committed
1859
1860
1861
1862
	"", "", "", "",
	"(c) 1999-2002 Chris Allegretta",
	"", "", "", "",
	"www.nano-editor.org"
1863
1864
    };

1865
1866
1867
1868
1869
1870
1871
1872
1873
    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");

1874
1875
1876
1877
    curs_set(0);
    nodelay(edit, TRUE);
    blank_bottombars();
    mvwaddstr(topwin, 0, 0, hblank);
Chris Allegretta's avatar
Chris Allegretta committed
1878
1879
    blank_edit();
    wrefresh(edit);
1880
1881
1882
1883
    wrefresh(bottomwin);
    wrefresh(topwin);

    while (wgetch(edit) == ERR) {
Chris Allegretta's avatar
Chris Allegretta committed
1884
1885
	for (k = 0; k <= 1; k++) {
	    blank_edit();
Chris Allegretta's avatar
Chris Allegretta committed
1886
1887
	    for (i = editwinrows / 2 - 1; i >= (editwinrows / 2 - 1 - j);
		 i--) {
Chris Allegretta's avatar
Chris Allegretta committed
1888
1889
		mvwaddstr(edit, i * 2 - k, 0, hblank);

1890
		if (place - (editwinrows / 2 - 1 - i) < CREDIT_LEN) {
Chris Allegretta's avatar
Chris Allegretta committed
1891
		    what = credits[place - (editwinrows / 2 - 1 - i)];
1892
1893
1894
1895
1896
1897
1898
1899

		    /* 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
1900
1901
		    what = "";

1902
		start_x = COLS / 2 - strlen(what) / 2 - 1;
Chris Allegretta's avatar
Chris Allegretta committed
1903
1904
1905
1906
		mvwaddstr(edit, i * 2 - k, start_x, what);
	    }
	    usleep(700000);
	    wrefresh(edit);
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
	}
	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
1921
}
1922
#endif