1238 lines
28 KiB
C
1238 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(x)));
|
|
|
|
}
|
|
|
|
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
|
|
|
|
/* we used to have xval. turns out it should always be zero */
|
|
void edit_add(filestruct * fileptr, int yval, 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, 0, &fileptr->data[start],
|
|
actual_x_from_start(fileptr,COLS,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, 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);
|
|
|
|
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;
|
|
|
|
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 */
|
|
}
|