nano/winio.c
Robert Siemborski d8510b2732 Substantial changes to winio.c that appear to fix the display problems
that we have been seeing on lines with tabs.

It introduces the concept of "pages" which might not be the best choice
for them.... Basically, it's the part of a line that would be visible on
screen at once.  the first part (visible when you open a file) is page
1... the second (you have to scroll to the right approx COLS, is 2.  The
third is at approx (2 * COLS) - 7 and so on...)

It's not terribly efficient as of yet, there are probabally quite a few
redundant calls to xpt(), for instance.


git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@6 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
2000-06-06 23:04:06 +00:00

1242 lines
28 KiB
C

/**************************************************************************
* winio.c *
* *
* Copyright (C) 1999 Chris Allegretta *
* 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 *
* the Free Software Foundation; either version 1, or (at your option) *
* 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. *
* *
**************************************************************************/
#include <stdarg.h>
#include <string.h>
#include "config.h"
#include "proto.h"
#include "nano.h"
#ifndef NANO_SMALL
#include <libintl.h>
#define _(string) gettext(string)
#else
#define _(string) (string)
#endif
static int statblank = 0; /* Number of keystrokes left after
we call statubar() before we
actually blank the statusbar */
/* Local Function Prototypes for only winio.c */
inline int get_page_from_virtual(int virtual);
inline int get_page_start_virtual(int page);
inline int get_page_end_virtual(int page);
/* Window I/O */
int do_first_line(void)
{
current = fileage;
placewewant = 0;
current_x = 0;
edit_update(current);
return 1;
}
int do_last_line(void)
{
current = filebot;
placewewant = 0;
current_x = 0;
edit_update(current);
return 1;
}
/* Like xplustabs, but for a specifc index of a speficific filestruct */
int xpt(filestruct * fileptr, int index)
{
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) {
if (tabs % 8 == 0);
else
tabs += 8 - (tabs % 8);
} else if (fileptr->data[i] & 0x80)
/* Make 8 bit chars only 1 collumn! */
;
else if (fileptr->data[i] < 32)
tabs++;
}
return tabs;
}
/* Return the actual place on the screen of current->data[current_x], which
should always be > current_x */
int xplustabs(void)
{
return xpt(current, current_x);
}
/* Return what current_x should be, given xplustabs() for the line,
* given a start position in the filestruct's data */
int actual_x_from_start(filestruct * fileptr, int xplus, int start)
{
int i, tot = 1;
if (fileptr == NULL || fileptr->data == NULL)
return 0;
for (i = start; tot <= xplus && fileptr->data[i] != 0; i++,tot++)
if (fileptr->data[i] == NANO_CONTROL_I) {
if (tot % 8 == 0) tot++;
else tot += 8 - (tot % 8);
} else if (fileptr->data[i] & 0x80)
tot++; /* Make 8 bit chars only 1 column (again) */
else if (fileptr->data[i] < 32)
tot += 2;
#ifdef DEBUG
fprintf(stderr, _("actual_x for xplus=%d returned %d\n"), xplus, i);
#endif
return i - start;
}
/* Opposite of xplustabs */
inline int actual_x(filestruct * fileptr, int xplus)
{
return actual_x_from_start(fileptr, xplus, 0);
}
/* a strlen with tabs factored in, similar to xplustabs() */
int strlenpt(char *buf)
{
int i, tabs = 0;
if (buf == NULL)
return 0;
for (i = 0; buf[i] != 0; i++) {
tabs++;
if (buf[i] == NANO_CONTROL_I) {
if (tabs % 8 == 0);
else
tabs += 8 - (tabs % 8);
} else if (buf[i] & 0x80)
/* Make 8 bit chars only 1 collumn! */
;
else if (buf[i] < 32)
tabs++;
}
return tabs;
}
/* resets current_y based on the position of current and puts the cursor at
(current_y, current_x) */
void reset_cursor(void)
{
filestruct *ptr = edittop;
int x;
current_y = 0;
while (ptr != current && ptr != editbot && ptr->next != NULL) {
ptr = ptr->next;
current_y++;
}
x = xplustabs();
if (x <= COLS - 2)
wmove(edit, current_y, x);
else
wmove(edit, current_y, x -
get_page_start_virtual(get_page_from_virtual(xplustabs())));
}
void blank_bottombars(void)
{
int i = no_help()? 3 : 1;
for (; i <= 2; i++)
mvwaddstr(bottomwin, i, 0, hblank);
}
void blank_edit(void)
{
int i;
for (i = 0; i <= editwinrows - 1; i++)
mvwaddstr(edit, i, 0, hblank);
wrefresh(edit);
}
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();
}
}
/* Get the input from the kb, this should only be called from statusq */
int nanogetstr(char *buf, char *def, shortcut s[], int slen, int start_x)
{
int kbinput = 0, j = 0, x = 0, xend;
int x_left = 0;
char inputstr[132], inputbuf[132] = "";
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
if (strlen(def) > 0)
waddstr(bottomwin, def);
wrefresh(bottomwin);
x_left = strlen(buf);
x = strlen(def) + x_left;
/* Get the input! */
if (strlen(def) > 0) {
strcpy(answer, def);
strcpy(inputbuf, def);
}
/* Go into raw mode so we can actually get ^C, for example */
raw();
while ((kbinput = wgetch(bottomwin)) != 13) {
for (j = 0; j <= slen - 1; j++) {
if (kbinput == s[j].val) {
noraw();
cbreak();
strcpy(answer, "");
return s[j].val;
}
}
xend = strlen(buf) + strlen(inputbuf);
switch (kbinput) {
case KEY_HOME:
x = x_left;
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
waddstr(bottomwin, inputbuf);
wmove(bottomwin, 0, x);
break;
case KEY_END:
x = x_left + strlen(inputbuf);
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
waddstr(bottomwin, inputbuf);
wmove(bottomwin, 0, x);
break;
case KEY_RIGHT:
if (x < xend)
x++;
wmove(bottomwin, 0, x);
break;
case NANO_CONTROL_D:
if (strlen(inputbuf) > 0 && (x - x_left) != strlen(inputbuf)) {
memmove(inputbuf + (x - x_left),
inputbuf + (x - x_left) + 1,
strlen(inputbuf) - (x - x_left) - 1);
inputbuf[strlen(inputbuf) - 1] = 0;
}
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
waddstr(bottomwin, inputbuf);
wmove(bottomwin, 0, x);
break;
case NANO_CONTROL_K:
case NANO_CONTROL_U:
*inputbuf = 0;
x = x_left;
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
waddstr(bottomwin, inputbuf);
wmove(bottomwin, 0, x);
break;
case KEY_BACKSPACE:
case KEY_DC:
case 127:
case NANO_CONTROL_H:
if (strlen(inputbuf) > 0) {
if (x == (x_left + strlen(inputbuf)))
inputbuf[strlen(inputbuf) - 1] = 0;
else if (x - x_left) {
memmove(inputbuf + (x - x_left) - 1,
inputbuf + (x - x_left),
strlen(inputbuf) - (x - x_left));
inputbuf[strlen(inputbuf) - 1] = 0;
}
}
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
waddstr(bottomwin, inputbuf);
case KEY_LEFT:
if (x > strlen(buf))
x--;
wmove(bottomwin, 0, x);
break;
case KEY_UP:
case KEY_DOWN:
break;
case 27:
switch (kbinput = wgetch(edit)) {
case 79:
switch (kbinput = wgetch(edit)) {
case 70:
x = x_left + strlen(inputbuf);
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
waddstr(bottomwin, inputbuf);
wmove(bottomwin, 0, x);
break;
case 72:
x = x_left;
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
waddstr(bottomwin, inputbuf);
wmove(bottomwin, 0, x);
break;
}
break;
case 91:
switch (kbinput = wgetch(edit)) {
case 'C':
if (x < xend)
x++;
wmove(bottomwin, 0, x);
break;
case 'D':
if (x > strlen(buf))
x--;
wmove(bottomwin, 0, x);
break;
case 49:
x = x_left;
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
waddstr(bottomwin, inputbuf);
wmove(bottomwin, 0, x);
goto skip_126;
case 51:
if (strlen(inputbuf) > 0
&& (x - x_left) != strlen(inputbuf)) {
memmove(inputbuf + (x - x_left),
inputbuf + (x - x_left) + 1,
strlen(inputbuf) - (x - x_left) - 1);
inputbuf[strlen(inputbuf) - 1] = 0;
}
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
waddstr(bottomwin, inputbuf);
wmove(bottomwin, 0, x);
goto skip_126;
case 52:
x = x_left + strlen(inputbuf);
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
waddstr(bottomwin, inputbuf);
wmove(bottomwin, 0, x);
goto skip_126;
skip_126:
nodelay(edit, TRUE);
kbinput = wgetch(edit);
if (kbinput == 126 || kbinput == ERR)
kbinput = -1;
nodelay(edit, FALSE);
break;
}
}
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
waddstr(bottomwin, inputbuf);
wmove(bottomwin, 0, x);
break;
default:
if (kbinput < 32)
break;
strcpy(inputstr, inputbuf);
inputstr[x - strlen(buf)] = kbinput;
strcpy(&inputstr[x - strlen(buf) + 1],
&inputbuf[x - strlen(buf)]);
strcpy(inputbuf, inputstr);
x++;
mvwaddstr(bottomwin, 0, 0, buf);
waddstr(bottomwin, inputbuf);
wmove(bottomwin, 0, x);
#ifdef DEBUG
fprintf(stderr, _("input \'%c\' (%d)\n"), kbinput, kbinput);
#endif
}
wrefresh(bottomwin);
}
strncpy(answer, inputbuf, 132);
noraw();
cbreak();
if (!strcmp(answer, ""))
return -2;
else
return 0;
}
void horizbar(WINDOW * win, int y)
{
wattron(win, A_REVERSE);
mvwaddstr(win, 0, 0, hblank);
wattroff(win, A_REVERSE);
}
void titlebar(void)
{
int namelen, space;
horizbar(topwin, 0);
wattron(topwin, A_REVERSE);
mvwaddstr(topwin, 0, 3, VERMSG);
space = COLS - strlen(VERMSG) - strlen(VERSION) - 21;
namelen = strlen(filename);
if (!strcmp(filename, ""))
mvwaddstr(topwin, 0, center_x - 6, _("New Buffer"));
else {
if (namelen > space) {
waddstr(topwin, _(" File: ..."));
waddstr(topwin, &filename[namelen - space]);
} else {
mvwaddstr(topwin, 0, center_x - (namelen / 2 + 1), "File: ");
waddstr(topwin, filename);
}
}
if (ISSET(MODIFIED))
mvwaddstr(topwin, 0, COLS - 10, _("Modified"));
wattroff(topwin, A_REVERSE);
wrefresh(topwin);
reset_cursor();
}
void onekey(char *keystroke, char *desc)
{
char description[80];
snprintf(description, 12, " %-11s", desc);
wattron(bottomwin, A_REVERSE);
waddstr(bottomwin, keystroke);
wattroff(bottomwin, A_REVERSE);
waddstr(bottomwin, description);
}
void clear_bottomwin(void)
{
if (ISSET(NO_HELP))
return;
mvwaddstr(bottomwin, 1, 0, hblank);
mvwaddstr(bottomwin, 2, 0, hblank);
wrefresh(bottomwin);
}
void bottombars(shortcut s[], int slen)
{
int i, j, k;
char keystr[10];
if (ISSET(NO_HELP))
return;
/* Determine how many extra spaces are needed to fill the bottom of the screen */
k = COLS / 6 - 13;
clear_bottomwin();
wmove(bottomwin, 1, 0);
for (i = 0; i <= slen - 1; i += 2) {
sprintf(keystr, "^%c", s[i].val + 64);
onekey(keystr, s[i].desc);
for (j = 0; j < k; j++)
waddch(bottomwin, ' ');
}
wmove(bottomwin, 2, 0);
for (i = 1; i <= slen - 1; i += 2) {
sprintf(keystr, "^%c", s[i].val + 64);
onekey(keystr, s[i].desc);
for (j = 0; j < k; j++)
waddch(bottomwin, ' ');
}
wrefresh(bottomwin);
}
/* If modified is not already set, set it and update titlebar */
void set_modified(void)
{
if (!ISSET(MODIFIED)) {
SET(MODIFIED);
titlebar();
wrefresh(topwin);
}
}
inline int get_page_from_virtual(int virtual) {
int page = 2;
if(virtual <= COLS - 2) return 1;
virtual -= (COLS - 2);
while (virtual > COLS - 2 - 7) {
virtual -= (COLS - 2 - 7);
page++;
}
return page;
}
inline int get_page_start_virtual(int page) {
int virtual;
virtual = --page * (COLS - 7);
if(page) virtual -= 2 * page - 1;
return virtual;
}
inline int get_page_end_virtual(int page) {
return get_page_start_virtual(page) + COLS - 1;
}
#ifndef NANO_SMALL
/* begin, end: beginning and end of mark in data
* fileptr: the data
* y: the line on screen */
void add_marked_sameline(int begin, int end, filestruct *fileptr, int y)
{
/* where we are on the line */
int virtual_col = xplustabs();
/* actual_col is beginning of the line in the data */
int this_page = get_page_from_virtual(virtual_col),
this_page_start = get_page_start_virtual(this_page),
this_page_end = get_page_end_virtual(this_page),
actual_col = actual_x(fileptr, this_page_start);
/* 3 start points: 0 -> begin, begin->end, end->strlen(data) */
/* in data : pre sel post */
int virtual_sel_start = xpt(fileptr, begin),
sel_start = 0,
virtual_post_start = xpt(fileptr, end),
post_start = 0;
/* likewise, 3 data lengths */
int pre_data_len = begin,
sel_data_len = end - begin,
post_data_len = 0;
/* now fix the start locations & lengths according to the cursor's
* position (ie: our page) */
if(xpt(fileptr,pre_data_len) < this_page_start) pre_data_len = 0;
else pre_data_len -= actual_col;
if(virtual_sel_start < this_page_start) {
begin = actual_col;
virtual_sel_start = this_page_start;
}
if(virtual_post_start < this_page_start) {
end = actual_col;
virtual_post_start = this_page_start;
}
/* we don't care about end, because it will just get cropped
* due to length */
if(virtual_sel_start > this_page_end)
virtual_sel_start = this_page_end;
if(virtual_post_start > this_page_end)
virtual_post_start = this_page_end;
sel_data_len = actual_x(fileptr, virtual_post_start) -
actual_x(fileptr, virtual_sel_start);
post_data_len = actual_x(fileptr, this_page_end) -
actual_x(fileptr, virtual_post_start);
sel_start = virtual_sel_start - this_page_start;
post_start = virtual_post_start - this_page_start;
mvwaddnstr(edit, y, 0, &fileptr->data[actual_col], pre_data_len);
wattron(edit, A_REVERSE);
mvwaddnstr(edit, y, sel_start, &fileptr->data[begin], sel_data_len);
wattroff(edit, A_REVERSE);
mvwaddnstr(edit, y, post_start, &fileptr->data[end], post_data_len);
}
#endif
void edit_add(filestruct * fileptr, int yval, int xval, int start)
{
#ifndef NANO_SMALL
int col;
if (ISSET(MARK_ISSET)) {
/* Our horribly ugly marker code */
if ((fileptr->lineno > mark_beginbuf->lineno
&& fileptr->lineno > current->lineno)
|| (fileptr->lineno < mark_beginbuf->lineno
&& fileptr->lineno < current->lineno)) {
/* We're on a normal, unselected line */
mvwaddnstr(edit, yval, 0, fileptr->data,
actual_x(fileptr, COLS));
} else {
/* We're on selected text */
if (fileptr != mark_beginbuf && fileptr != current) {
wattron(edit, A_REVERSE);
mvwaddnstr(edit, yval, 0, fileptr->data, actual_x(fileptr,COLS));
wattroff(edit, A_REVERSE);
}
/* Special case, we're still on the same line we started marking */
else if (fileptr == mark_beginbuf && fileptr == current) {
if (current_x < mark_beginx)
add_marked_sameline(current_x, mark_beginx, fileptr, yval);
else
add_marked_sameline(mark_beginx, current_x, fileptr, yval);
} else if (fileptr == mark_beginbuf) {
int target;
/* we're at the line that was first marked */
if (mark_beginbuf->lineno > current->lineno)
wattron(edit, A_REVERSE);
target = (xpt(fileptr,mark_beginx) < COLS - 1) ? mark_beginx : COLS - 1;
mvwaddnstr(edit, yval, 0, fileptr->data,
actual_x(fileptr, target));
if (mark_beginbuf->lineno < current->lineno)
wattron(edit, A_REVERSE);
else
wattroff(edit, A_REVERSE);
target = (COLS - 1) - xpt(fileptr,mark_beginx);
if(target < 0) target = 0;
mvwaddnstr(edit, yval, xpt(fileptr,mark_beginx),
&fileptr->data[mark_beginx],
actual_x_from_start(fileptr, target, mark_beginx));
if (mark_beginbuf->lineno < current->lineno)
wattroff(edit, A_REVERSE);
} else if (fileptr == current) {
/* we're on the cursors line, but it's not the first
* one we marked... */
int this_page = get_page_from_virtual(xplustabs()),
this_page_start = get_page_start_virtual(this_page),
this_page_end = get_page_end_virtual(this_page);
if (mark_beginbuf->lineno < current->lineno)
wattron(edit, A_REVERSE);
if (xplustabs() > COLS - 2) {
col = actual_x(current, this_page_start);
mvwaddnstr(edit, yval, 0, &fileptr->data[col],
current_x - col);
} else
mvwaddnstr(edit, yval, 0, fileptr->data, current_x);
if (mark_beginbuf->lineno > current->lineno)
wattron(edit, A_REVERSE);
else
wattroff(edit, A_REVERSE);
if (xplustabs() > COLS - 2) {
mvwaddnstr(edit, yval, xplustabs() - this_page_start,
&fileptr->data[current_x],
actual_x(current,this_page_end) - current_x);
} else
mvwaddnstr(edit, yval, xplustabs(),
&fileptr->data[current_x],
actual_x_from_start(fileptr,
COLS - xpt(fileptr,current_x), current_x));
if (mark_beginbuf->lineno > current->lineno)
wattroff(edit, A_REVERSE);
}
}
} else
#endif
mvwaddnstr(edit, yval, xval, &fileptr->data[start],
actual_x_from_start(fileptr,COLS - xval,start));
}
/*
* Just update one line in the edit buffer
*
* index gives is a place in the string to update starting from.
* Likely args are current_x or 0.
*/
void update_line(filestruct * fileptr, int index)
{
filestruct *filetmp;
int line = 0, col = 0, actual_col = 0, x;
for (filetmp = edittop; filetmp != fileptr && filetmp != editbot;
filetmp = filetmp->next)
line++;
mvwaddstr(edit, line, 0, hblank);
if (current == fileptr && (x = xpt(current, index)) > COLS - 2) {
int page = get_page_from_virtual(x);
col = get_page_start_virtual(page);
actual_col = actual_x(filetmp, col);
edit_add(filetmp, line, 0, actual_col);
mvwaddch(edit, line, 0, '$');
if (strlenpt(fileptr->data) > get_page_end_virtual(page))
mvwaddch(edit, line, COLS - 1, '$');
} else {
edit_add(filetmp, line, 0, 0);
if (strlenpt(&filetmp->data[actual_col]) > COLS)
mvwaddch(edit, line, COLS - 1, '$');
}
}
void center_cursor(void)
{
current_y = editwinrows / 2;
wmove(edit, current_y, current_x);
}
/* Refresh the screen without changing the position of lines */
void edit_refresh(void)
{
int lines = 0, i = 0;
filestruct *temp, *hold = current;
if (current == NULL)
return;
temp = edittop;
while (lines <= editwinrows - 1 && lines <= totlines && temp != NULL) {
hold = temp;
update_line(temp, current_x);
temp = temp->next;
lines++;
}
if (lines <= editwinrows - 1)
while (lines <= editwinrows - 1) {
mvwaddstr(edit, lines, i, hblank);
lines++;
}
if (temp == NULL)
editbot = hold;
else
editbot = temp;
}
/*
* Nice generic routine to update the edit buffer given a pointer to the
* file struct =)
*/
void edit_update(filestruct * fileptr)
{
int lines = 0, i = 0;
filestruct *temp;
if (fileptr == NULL)
return;
temp = fileptr;
while (i <= editwinrows / 2 && temp->prev != NULL) {
i++;
temp = temp->prev;
}
edittop = temp;
while (lines <= editwinrows - 1 && lines <= totlines && temp != NULL
&& temp != filebot) {
temp = temp->next;
lines++;
}
editbot = temp;
edit_refresh();
}
/* Now we want to update the screen using this struct as the top of the edit buffer */
void edit_update_top(filestruct * fileptr)
{
int i;
filestruct *temp = fileptr;
if (fileptr->next == NULL || fileptr == NULL)
return;
i = 0;
while (i <= editwinrows / 2 && temp->next != NULL) {
i++;
temp = temp->next;
}
edit_update(temp);
}
/* And also for the bottom... */
void edit_update_bot(filestruct * fileptr)
{
int i;
filestruct *temp = fileptr;
i = 0;
while (i <= editwinrows / 2 - 1 && temp->prev != NULL) {
i++;
temp = temp->prev;
}
edit_update(temp);
}
/* 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 - 1 && current->next != NULL) {
current = current->next;
i++;
}
#ifdef DEBUG
fprintf(stderr, _("current->data = \"%s\"\n"), current->data);
#endif
}
/*
* 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
* otherwise, the valid shortcut key caught, Def is any editable text we
* want to put up by default.
*/
int statusq(shortcut s[], int slen, char *def, char *msg, ...)
{
va_list ap;
char foo[133];
int ret;
bottombars(s, slen);
va_start(ap, msg);
vsnprintf(foo, 132, msg, ap);
strncat(foo, ": ", 132);
va_end(ap);
wattron(bottomwin, A_REVERSE);
ret = nanogetstr(foo, def, s, slen, (strlen(foo) + 3));
wattroff(bottomwin, A_REVERSE);
switch (ret) {
case NANO_FIRSTLINE_KEY:
do_first_line();
break;
case NANO_LASTLINE_KEY:
do_last_line();
break;
case NANO_CANCEL_KEY:
return -1;
default:
blank_statusbar_refresh();
}
#ifdef DEBUG
fprintf(stderr, _("I got \"%s\"\n"), answer);
#endif
return ret;
}
/*
* 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)
*/
int do_yesno(int all, int leavecursor, char *msg, ...)
{
va_list ap;
char foo[133];
int kbinput, ok = -1;
/* Write the bottom of the screen */
clear_bottomwin();
wattron(bottomwin, A_REVERSE);
blank_statusbar_refresh();
wattroff(bottomwin, A_REVERSE);
if (!ISSET(NO_HELP)) {
wmove(bottomwin, 1, 0);
onekey(_(" Y"), _("Yes"));
if (all)
onekey(_(" A"), _("All"));
wmove(bottomwin, 2, 0);
onekey(_(" N"), _("No"));
onekey(_("^C"), _("Cancel"));
}
va_start(ap, msg);
vsnprintf(foo, 132, msg, ap);
va_end(ap);
wattron(bottomwin, A_REVERSE);
mvwaddstr(bottomwin, 0, 0, foo);
wattroff(bottomwin, A_REVERSE);
wrefresh(bottomwin);
if (leavecursor == 1)
reset_cursor();
raw();
while (ok == -1) {
kbinput = wgetch(edit);
switch (kbinput) {
case 'Y':
case 'y':
ok = 1;
break;
case 'N':
case 'n':
ok = 0;
break;
case 'A':
case 'a':
if (all)
ok = 2;
break;
case NANO_CONTROL_C:
ok = -2;
break;
}
}
noraw();
cbreak();
/* Then blank the screen */
blank_statusbar_refresh();
if (ok == -2)
return -1;
else
return ok;
}
void statusbar(char *msg, ...)
{
va_list ap;
char foo[133];
int start_x = 0;
va_start(ap, msg);
vsnprintf(foo, 132, msg, ap);
va_end(ap);
start_x = center_x - strlen(foo) / 2 - 1;
/* Blank out line */
blank_statusbar();
wmove(bottomwin, 0, start_x);
wattron(bottomwin, A_REVERSE);
waddstr(bottomwin, "[ ");
waddstr(bottomwin, foo);
waddstr(bottomwin, " ]");
wattroff(bottomwin, A_REVERSE);
wrefresh(bottomwin);
if (ISSET(CONSTUPDATE))
statblank = 1;
else
statblank = 25;
}
void display_main_list(void)
{
bottombars(main_list, MAIN_VISIBLE);
}
int total_refresh(void)
{
display_main_list();
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);
return 1;
}
void previous_line(void)
{
if (current_y > 0)
current_y--;
}
int do_cursorpos(void)
{
filestruct *fileptr;
float linepct, bytepct;
int i, tot = 0;
if (current == NULL || fileage == NULL)
return 0;
for (fileptr = fileage; fileptr != current && fileptr != NULL; fileptr = fileptr->next)
tot += strlen(fileptr->data) + 1;
if (fileptr == NULL)
return -1;
i = tot + current_x;;
for (fileptr = current->next; fileptr != NULL; fileptr = fileptr->next)
tot += strlen(fileptr->data) + 1;
/* FIXME - This is gardly elegant */
/* if (current == fileage && strlen(current->data) == 0)
i = 0;
*/
if (totlines > 0)
linepct = 100 * current->lineno / totlines;
else
linepct = 0;
if (totsize > 0)
bytepct = 100 * i / totsize;
else
bytepct = 0;
#ifdef DEBUG
fprintf(stderr, _("do_cursorpos: linepct = %f, bytepct = %f\n"),
linepct, bytepct);
#endif
statusbar(_("line %d of %d (%.0f%%), character %d of %d (%.0f%%)"),
current->lineno, totlines, linepct, i, totsize, bytepct);
reset_cursor();
return 1;
}
/* Our broken, non-shortcut list compliant help function.
But hey, it's better than nothing, and it's dynamic! */
int do_help(void)
{
#ifndef NANO_SMALL
char *ptr = help_text, *end;
int i, j, row = 0, page = 1, kbinput = 0, no_more = 0;
int no_help_flag = 0;
blank_edit();
curs_set(0);
blank_statusbar();
if (ISSET(NO_HELP)) {
no_help_flag = 1;
delwin (bottomwin);
bottomwin = newwin(3, COLS, LINES - 3, 0);
keypad(bottomwin, TRUE);
editwinrows -= no_help ();
UNSET(NO_HELP);
bottombars(help_list, HELP_LIST_LEN);
}
else
bottombars(help_list, HELP_LIST_LEN);
do {
ptr = help_text;
switch (kbinput) {
case NANO_NEXTPAGE_KEY:
case NANO_NEXTPAGE_FKEY:
case KEY_NPAGE:
if (!no_more) {
blank_edit();
page++;
}
break;
case NANO_PREVPAGE_KEY:
case NANO_PREVPAGE_FKEY:
case KEY_PPAGE:
if (page > 1) {
no_more = 0;
blank_edit();
page--;
}
break;
}
/* Calculate where in the text we should be based on the page */
for (i = 1; i < page; i++) {
row = 0;
j = 0;
while (row < editwinrows && *ptr != '\0') {
if (*ptr == '\n' || j == COLS - 5) {
j = 0;
row++;
}
ptr++;
j++;
}
}
i = 0;
j = 0;
while (i < editwinrows && *ptr != '\0') {
end = ptr;
while (*end != '\n' && *end != '\0' && j != COLS - 5) {
end++;
j++;
}
if (j == COLS - 5) {
/* Don't print half a word if we've run of of space */
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;
}
} while ((kbinput = wgetch(edit)) != NANO_EXIT_KEY);
if (no_help_flag) {
werase(bottomwin);
wrefresh(bottomwin);
delwin (bottomwin);
SET(NO_HELP);
bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
keypad(bottomwin, TRUE);
editwinrows += no_help();
}
else
display_main_list();
curs_set(1);
edit_refresh();
#else
nano_small_msg();
#endif
return 1;
}
/* Dump the current file structure to stderr */
void dump_buffer(filestruct * inptr)
{
#ifdef DEBUG
filestruct *fileptr;
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"));
fileptr = inptr;
while (fileptr != NULL) {
fprintf(stderr, "(%ld) %s\n", fileptr->lineno, fileptr->data);
fflush(stderr);
fileptr = fileptr->next;
}
#endif /* DEBUG */
}
void dump_buffer_reverse(filestruct * inptr)
{
#ifdef DEBUG
filestruct *fileptr;
fileptr = filebot;
while (fileptr != NULL) {
fprintf(stderr, "(%ld) %s\n", fileptr->lineno, fileptr->data);
fflush(stderr);
fileptr = fileptr->prev;
}
#endif /* DEBUG */
}