Commit 7483571f authored by David Lawrence Ramsey's avatar David Lawrence Ramsey
Browse files

massive overhaul to support buffered input and output, the first steps

toward proper wide character input and output, etc.


git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2157 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
No related merge requests found
Showing with 1143 additions and 800 deletions
+1143 -800
......@@ -28,6 +28,26 @@ CVS code -
by DLR)
- Change references to "open files" to "open file buffers", for
consistency. (DLR)
- Add option to disable UTF-8 sequence interpretation:
-O/--noutf8 on the command line, Meta-O as a toggle, and
"noutf8" in the rcfile. This is so people using single-byte
encodings such as KOI8-R can type properly again. (DLR, found
by Arthur Ivanov)
- Massively overhaul the input and output routines to support
buffered input and output, the first steps toward wide
character input and output, and double-Escape/verbatim input
of double-byte Unicode characters instead of single-byte ASCII
characters. New functions do_input(), do_mouse(),
do_output(), get_buffer(), get_buffer_len(), buffer_to_keys(),
unget_input(), get_input(), parse_kbinput(), and
parse_verbatim_kbinput(); new macro charcpy(); changes to
do_char() (renamed to do_output()), get_edit_input() (renamed
to do_input() and moved to nano.c), get_edit_mouse() (renamed
do_mouse() and moved to nano.c), do_verbatim_input(),
do_tab(), main(), and get_ascii_kbinput() (renamed to
get_word_kbinput()). (DLR; buffered input/output based on
ideas from mutt 1.4.2.1; double-Escape input of Unicode
characters suggested by Michael Piefel)
- cut.c:
do_cut_text()
- If keep_cutbuffer is FALSE, only blow away the text in the
......
......@@ -2583,7 +2583,7 @@ char *do_browser(const char *inpath)
selected = numents - 1;
else if (selectedbackup == selected)
/* Put back the 'select' key */
unget_kbinput('s', FALSE);
unget_kbinput('s', FALSE, FALSE);
} else {
/* Must be clicking a shortcut */
int mouse_x, mouse_y;
......
......@@ -1074,15 +1074,19 @@ void toggle_init(void)
#ifndef DISABLE_MOUSE
toggle_init_one(TOGGLE_MOUSE_KEY, N_("Mouse support"), USE_MOUSE);
#endif
/* If we're using restricted mode, the no-conversion and backup
* backup toggles are disabled. The former is useless since
* inserting files is disabled, and the latter is useless since
* backups are disabled. */
if (!ISSET(RESTRICTED)) {
/* If we're using restricted mode, the DOS/Mac conversion toggle is
* disabled. It's useless since inserting files is disabled. */
if (!ISSET(RESTRICTED))
toggle_init_one(TOGGLE_NOCONVERT_KEY,
N_("No conversion from DOS/Mac format"), NO_CONVERT);
#ifdef NANO_WIDE
toggle_init_one(TOGGLE_NOUTF8_KEY,
N_("No conversion from UTF-8 format"), NO_UTF8);
#endif
/* If we're using restricted mode, the backup toggle is disabled.
* It's useless since backups are disabled. */
if (!ISSET(RESTRICTED))
toggle_init_one(TOGGLE_BACKUP_KEY, N_("Backup files"), BACKUP_FILE);
}
toggle_init_one(TOGGLE_SMOOTH_KEY, N_("Smooth scrolling"), SMOOTHSCROLL);
toggle_init_one(TOGGLE_SMARTHOME_KEY, N_("Smart home key"), SMART_HOME);
#ifdef ENABLE_COLOR
......
......@@ -929,6 +929,9 @@ void usage(void)
#ifndef NANO_SMALL
print1opt("-N", "--noconvert", N_("Don't convert files from DOS/Mac format"));
#endif
#ifdef NANO_WIDE
print1opt("-O", "--noutf8", N_("Don't convert files from UTF-8 format"));
#endif
#ifndef DISABLE_JUSTIFY
print1opt(_("-Q [str]"), _("--quotestr=[str]"), N_("Quoting string, default \"> \""));
#endif
......@@ -1146,87 +1149,20 @@ bool open_pipe(const char *command)
}
#endif /* !NANO_SMALL */
/* The user typed a character; add it to the edit buffer. */
void do_char(char ch)
{
size_t current_len = strlen(current->data);
#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
bool do_refresh = FALSE;
/* Do we have to call edit_refresh(), or can we get away with
* update_line()? */
#endif
if (ch == '\0') /* Null to newline, if needed. */
ch = '\n';
else if (ch == '\n') { /* Newline to Enter, if needed. */
do_enter();
return;
}
assert(current != NULL && current->data != NULL);
/* When a character is inserted on the current magicline, it means
* we need a new one! */
if (filebot == current)
new_magicline();
/* More dangerousness fun =) */
current->data = charealloc(current->data, current_len + 2);
assert(current_x <= current_len);
charmove(&current->data[current_x + 1], &current->data[current_x],
current_len - current_x + 1);
current->data[current_x] = ch;
totsize++;
set_modified();
#ifndef NANO_SMALL
/* Note that current_x has not yet been incremented. */
if (current == mark_beginbuf && current_x < mark_beginx)
mark_beginx++;
#endif
do_right(FALSE);
#ifndef DISABLE_WRAPPING
/* If we're wrapping text, we need to call edit_refresh(). */
if (!ISSET(NO_WRAP) && ch != '\t')
do_refresh = do_wrap(current);
#endif
#ifdef ENABLE_COLOR
/* If color syntaxes are turned on, we need to call
* edit_refresh(). */
if (ISSET(COLOR_SYNTAX))
do_refresh = TRUE;
#endif
#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
if (do_refresh)
edit_refresh();
else
#endif
update_line(current, current_x);
}
void do_verbatim_input(void)
{
int *v_kbinput = NULL; /* Used to hold verbatim input. */
size_t v_len; /* Length of verbatim input. */
size_t i;
int *kbinput; /* Used to hold verbatim input. */
size_t kbinput_len; /* Length of verbatim input. */
statusbar(_("Verbatim input"));
v_kbinput = get_verbatim_kbinput(edit, &v_len, TRUE);
/* Read in all the verbatim characters. */
kbinput = get_verbatim_kbinput(edit, &kbinput_len);
/* Turn on DISABLE_CURPOS while inserting character(s) and turn it
* off afterwards, so that if constant cursor position display is
* on, it will be updated properly. */
SET(DISABLE_CURPOS);
for (i = 0; i < v_len; i++)
do_char((char)v_kbinput[i]);
UNSET(DISABLE_CURPOS);
/* Display all the verbatim characters at once. */
do_output(kbinput, kbinput_len);
free(v_kbinput);
free(kbinput);
}
void do_backspace(void)
......@@ -1315,7 +1251,8 @@ void do_delete(void)
void do_tab(void)
{
do_char('\t');
int kbinput = '\t';
do_output(&kbinput, 1);
}
/* Someone hits return *gasp!* */
......@@ -2753,7 +2690,7 @@ void do_justify(bool full_justify)
size_t mark_beginx_save = mark_beginx;
#endif
int kbinput;
bool meta_key, func_key;
bool meta_key, func_key, s_or_t;
/* If we're justifying the entire file, start at the beginning. */
if (full_justify)
......@@ -3019,9 +2956,10 @@ void do_justify(bool full_justify)
/* Now get a keystroke and see if it's unjustify. If not, put back
* the keystroke and return. */
kbinput = get_edit_input(&meta_key, &func_key, FALSE);
kbinput = do_input(&meta_key, &func_key, &s_or_t, FALSE);
if (!meta_key && !func_key && kbinput == NANO_UNJUSTIFY_KEY) {
if (!meta_key && !func_key && s_or_t &&
kbinput == NANO_UNJUSTIFY_KEY) {
/* Restore the justify we just did (ungrateful user!). */
current = current_save;
current_x = current_x_save;
......@@ -3073,7 +3011,7 @@ void do_justify(bool full_justify)
edit_refresh();
}
} else {
unget_kbinput(kbinput, meta_key);
unget_kbinput(kbinput, meta_key, func_key);
/* Blow away the text in the justify buffer. */
free_filestruct(jusbuffer);
......@@ -3418,6 +3356,322 @@ void terminal_init(void)
disable_flow_control();
}
int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool
allow_funcs)
{
int input;
/* The character we read in. */
static int *kbinput = NULL;
/* The input buffer. */
static size_t kbinput_len = 0;
/* The length of the input buffer. */
const shortcut *s;
bool have_shortcut;
#ifndef NANO_SMALL
const toggle *t;
bool have_toggle;
#endif
*s_or_t = FALSE;
/* Read in a character. */
input = get_kbinput(edit, meta_key, func_key);
#ifndef DISABLE_MOUSE
/* If we got a mouse click and it was on a shortcut, read in the
* shortcut character. */
if (allow_funcs && func_key && input == KEY_MOUSE) {
if (do_mouse())
input = get_kbinput(edit, meta_key, func_key);
else
input = ERR;
}
#endif
/* Check for a shortcut in the main list. */
s = get_shortcut(main_list, &input, meta_key, func_key);
/* If we got a shortcut from the main list, or a "universal"
* edit window shortcut, set have_shortcut to TRUE. */
have_shortcut = (s != NULL || input == NANO_XON_KEY ||
input == NANO_XOFF_KEY || input == NANO_SUSPEND_KEY);
#ifndef NANO_SMALL
/* Check for a toggle in the main list. */
t = get_toggle(input, *meta_key);
/* If we got a toggle from the main list, set have_toggle to
* TRUE. */
have_toggle = (t != NULL);
#endif
/* Set s_or_t to TRUE if we got a shortcut or toggle. */
*s_or_t = (have_shortcut
#ifndef NANO_SMALL
|| have_toggle
#endif
);
if (allow_funcs) {
/* If we got a character, and it isn't a shortcut, toggle, or
* control character, it's a normal text character. Display the
* warning if we're in view mode, or add the character to the
* input buffer if we're not. */
if (input != ERR && *s_or_t == FALSE && !is_cntrl_char(input)) {
if (ISSET(VIEW_MODE))
print_view_warning();
else {
kbinput_len++;
kbinput = (int *)nrealloc(kbinput, kbinput_len *
sizeof(int));
kbinput[kbinput_len - 1] = input;
}
}
/* If we got a shortcut or toggle, or if there aren't any other
* characters waiting after the one we read in, we need to
* display all the characters in the input buffer if it isn't
* empty. Note that it should be empty if we're in view
* mode. */
if (*s_or_t == TRUE || get_buffer_len() == 0) {
if (kbinput != NULL) {
/* Display all the characters in the input buffer at
* once. */
do_output(kbinput, kbinput_len);
/* Empty the input buffer. */
kbinput_len = 0;
free(kbinput);
kbinput = NULL;
}
}
if (have_shortcut) {
switch (input) {
/* Handle the "universal" edit window shortcuts. */
case NANO_XON_KEY:
statusbar(_("XON ignored, mumble mumble."));
break;
case NANO_XOFF_KEY:
statusbar(_("XOFF ignored, mumble mumble."));
break;
#ifndef NANO_SMALL
case NANO_SUSPEND_KEY:
if (ISSET(SUSPEND))
do_suspend(0);
break;
#endif
/* Handle the normal edit window shortcuts. */
default:
/* Blow away the text in the cutbuffer if we aren't
* cutting text. */
if (s->func != do_cut_text)
cutbuffer_reset();
/* Run the function associated with this shortcut,
* if there is one. */
if (s->func != NULL) {
if (ISSET(VIEW_MODE) && !s->viewok)
print_view_warning();
else
s->func();
}
break;
}
}
#ifndef NANO_SMALL
else if (have_toggle) {
/* Blow away the text in the cutbuffer, since we aren't
* cutting text. */
cutbuffer_reset();
/* Toggle the flag associated with this shortcut. */
if (allow_funcs)
do_toggle(t);
}
#endif
else
/* Blow away the text in the cutbuffer, since we aren't
* cutting text. */
cutbuffer_reset();
}
return input;
}
#ifndef DISABLE_MOUSE
bool do_mouse(void)
{
int mouse_x, mouse_y;
bool retval;
retval = get_mouseinput(&mouse_x, &mouse_y, TRUE);
if (!retval) {
/* We can click in the edit window to move the cursor. */
if (wenclose(edit, mouse_y, mouse_x)) {
bool sameline;
/* Did they click on the line with the cursor? If they
* clicked on the cursor, we set the mark. */
size_t xcur;
/* The character they clicked on. */
/* Subtract out the size of topwin. Perhaps we need a
* constant somewhere? */
mouse_y -= 2;
sameline = (mouse_y == current_y);
/* Move to where the click occurred. */
for (; current_y < mouse_y && current->next != NULL; current_y++)
current = current->next;
for (; current_y > mouse_y && current->prev != NULL; current_y--)
current = current->prev;
xcur = actual_x(current->data, get_page_start(xplustabs()) +
mouse_x);
#ifndef NANO_SMALL
/* Clicking where the cursor is toggles the mark, as does
* clicking beyond the line length with the cursor at the
* end of the line. */
if (sameline && xcur == current_x) {
if (ISSET(VIEW_MODE)) {
print_view_warning();
return retval;
}
do_mark();
}
#endif
current_x = xcur;
placewewant = xplustabs();
edit_refresh();
}
}
/* FIXME: If we clicked on a location in the statusbar, the cursor
* should move to the location we clicked on. This functionality
* should be in do_statusbar_mouse() when it's written. */
return retval;
}
#endif /* !DISABLE_MOUSE */
/* The user typed kbinput_len characters. Add them to the edit
* buffer. */
void do_output(int *kbinput, size_t kbinput_len)
{
size_t i, current_len = strlen(current->data);
bool old_constupdate = ISSET(CONSTUPDATE);
bool do_refresh = FALSE;
/* Do we have to call edit_refresh(), or can we get away with
* update_line()? */
char key[
#ifdef NANO_WIDE
MB_LEN_MAX
#else
1
#endif
]; /* The current character we have. */
int key_len; /* The length of the current character. */
assert(current != NULL && current->data != NULL);
/* Turn off constant cursor position display if it's on. */
if (old_constupdate)
UNSET(CONSTUPDATE);
for (i = 0; i < kbinput_len; i++) {
#ifdef NANO_WIDE
/* Change the wide character to its multibyte value. If it's
* invalid, go on to the next character. */
if (!ISSET(NO_UTF8)) {
key_len = wctomb(key, kbinput[i]);
if (key_len == -1)
continue;
} else {
#endif
/* Interpret the character as a single-byte sequence. */
key_len = 1;
key[0] = (char)kbinput[i];
#ifdef NANO_WIDE
}
#endif
/* Null to newline, if needed. */
if (key[0] == '\0' && key_len == 1)
key[0] = '\n';
/* Newline to Enter, if needed. */
else if (key[0] == '\n' && key_len == 1) {
do_enter();
continue;
}
/* When a character is inserted on the current magicline, it
* means we need a new one! */
if (filebot == current)
new_magicline();
/* More dangerousness fun =) */
current->data = charealloc(current->data,
current_len + key_len + 1);
assert(current_x <= current_len);
charmove(&current->data[current_x + key_len],
&current->data[current_x],
current_len - current_x + key_len);
charcpy(&current->data[current_x], key, key_len);
current_len += key_len;
/* FIXME: Should totsize be the number of single-byte characters
* or the number of multibyte characters? Assume for former for
* now. */
totsize += key_len;
set_modified();
#ifndef NANO_SMALL
/* Note that current_x has not yet been incremented. */
if (current == mark_beginbuf && current_x < mark_beginx)
mark_beginx += key_len;
#endif
{
int j;
for (j = 0; j < key_len; j++)
do_right(FALSE);
}
#ifndef DISABLE_WRAPPING
/* If we're wrapping text, we need to call edit_refresh(). */
if (!ISSET(NO_WRAP) && (key[0] != '\t' || key_len != 1)) {
bool do_refresh_save = do_refresh;
do_refresh = do_wrap(current);
/* If we needed to call edit_refresh() before this, we'll
* still need to after this. */
if (do_refresh_save)
do_refresh = TRUE;
}
#endif
#ifdef ENABLE_COLOR
/* If color syntaxes are turned on, we need to call
* edit_refresh(). */
if (ISSET(COLOR_SYNTAX))
do_refresh = TRUE;
#endif
}
/* Turn constant cursor position display back on if it was on. */
if (old_constupdate)
SET(CONSTUPDATE);
if (do_refresh)
edit_refresh();
else
update_line(current, current_x);
}
int main(int argc, char **argv)
{
int optchr;
......@@ -3432,9 +3686,6 @@ int main(int argc, char **argv)
/* The old value of the multibuffer option, restored after we
* load all files on the command line. */
#endif
int kbinput;
/* Input from keyboard. */
bool meta_key, func_key;
#ifdef HAVE_GETOPT_LONG
const struct option long_options[] = {
{"help", 0, 0, 'h'},
......@@ -3447,6 +3698,9 @@ int main(int argc, char **argv)
#endif
{"ignorercfiles", 0, 0, 'I'},
#endif
#ifdef NANO_WIDE
{"noutf8", 0, 0, 'O'},
#endif
#ifndef DISABLE_JUSTIFY
{"quotestr", 1, 0, 'Q'},
#endif
......@@ -3510,9 +3764,9 @@ int main(int argc, char **argv)
while ((optchr =
#ifdef HAVE_GETOPT_LONG
getopt_long(argc, argv, "h?ABE:FHINQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz", long_options, NULL)
getopt_long(argc, argv, "h?ABE:FHINOQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz", long_options, NULL)
#else
getopt(argc, argv, "h?ABE:FHINQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")
getopt(argc, argv, "h?ABE:FHINOQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")
#endif
) != -1) {
......@@ -3556,6 +3810,9 @@ int main(int argc, char **argv)
SET(NO_CONVERT);
break;
#endif
case 'O':
SET(NO_UTF8);
break;
#ifndef DISABLE_JUSTIFY
case 'Q':
quotestr = mallocstrcpy(quotestr, optarg);
......@@ -3929,7 +4186,18 @@ int main(int argc, char **argv)
edit_refresh();
while (TRUE) {
bool meta_key;
/* Whether we got a meta key sequence. */
bool func_key;
/* Whether we got a function key. */
bool s_or_t;
/* Whether we got a shortcut or toggle. */
/* Make sure the cursor is in the edit window. */
reset_cursor();
/* If constant cursor position display is on, display the cursor
* position. */
if (ISSET(CONSTUPDATE))
do_cursorpos(TRUE);
......@@ -3937,17 +4205,8 @@ int main(int argc, char **argv)
currshortcut = main_list;
#endif
kbinput = get_edit_input(&meta_key, &func_key, TRUE);
/* Last gasp, stuff that's not in the main lists. */
if (kbinput != ERR && !is_cntrl_char(kbinput)) {
/* Don't stop unhandled printable sequences, so that people
* with odd character sets can type. */
if (ISSET(VIEW_MODE))
print_view_warning();
else
do_char(kbinput);
}
/* Read in and interpret characters. */
do_input(&meta_key, &func_key, &s_or_t, TRUE);
}
assert(FALSE);
}
......@@ -44,6 +44,7 @@
#define charalloc(howmuch) (char *)nmalloc((howmuch) * sizeof(char))
#define charealloc(ptr, howmuch) (char *)nrealloc(ptr, (howmuch) * sizeof(char))
#define charmove(dest, src, n) memmove(dest, src, (n) * sizeof(char))
#define charcpy(dest, src, n) memcpy(dest, src, (n) * sizeof(char))
#ifdef BROKEN_REGEXEC
#define regexec(preg, string, nmatch, pmatch, eflags) regexec_safe(preg, string, nmatch, pmatch, eflags)
......@@ -134,6 +135,10 @@
#define VERMSG "GNU nano " VERSION
/* FIXME: We should be checking for this instead of unconditionally
* using it. */
#define NANO_WIDE 1
/* If we aren't using ncurses, turn the mouse support off, as it's
* ncurses-specific. */
#ifndef NCURSES_MOUSE_VERSION
......@@ -158,6 +163,11 @@ typedef enum {
} topmidnone;
/* Structure types. */
typedef struct buffer {
int key;
bool key_code;
} buffer;
typedef struct filestruct {
char *data;
struct filestruct *next; /* Next node. */
......@@ -317,6 +327,7 @@ typedef struct historyheadtype {
#define RESTRICTED (1<<26)
#define SMART_HOME (1<<27)
#define WHITESPACE_DISPLAY (1<<28)
#define NO_UTF8 (1<<29)
/* Control key sequences, changing these would be very very bad. */
#define NANO_CONTROL_SPACE 0
......@@ -501,6 +512,7 @@ typedef struct historyheadtype {
#define TOGGLE_SYNTAX_KEY NANO_ALT_Y
#define TOGGLE_SMARTHOME_KEY NANO_ALT_H
#define TOGGLE_WHITESPACE_KEY NANO_ALT_P
#define TOGGLE_NOUTF8_KEY NANO_ALT_O
#endif /* !NANO_SMALL */
#define MAIN_VISIBLE 12
......
......@@ -327,7 +327,6 @@ void nano_disabled_msg(void);
RETSIGTYPE cancel_fork(int signal);
bool open_pipe(const char *command);
#endif
void do_char(char ch);
void do_verbatim_input(void);
void do_backspace(void);
void do_delete(void);
......@@ -391,6 +390,12 @@ void enable_signals(void);
void disable_flow_control(void);
void enable_flow_control(void);
void terminal_init(void);
int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool
allow_funcs);
#ifndef DISABLE_MOUSE
bool do_mouse(void);
#endif
void do_output(int *kbinput, size_t kbinput_len);
/* Public functions in rcfile.c. */
#ifdef ENABLE_NANORC
......@@ -468,6 +473,7 @@ int regexp_bol_or_eol(const regex_t *preg, const char *string);
int is_blank_char(int c);
#endif
int is_cntrl_char(int c);
bool is_byte_char(int c);
int num_of_digits(int n);
bool parse_num(const char *str, ssize_t *val);
void align(char **strp);
......@@ -524,29 +530,29 @@ int check_wildcard_match(const char *text, const char *pattern);
#ifndef NANO_SMALL
void reset_kbinput(void);
#endif
void unget_kbinput(int kbinput, bool meta_key);
void get_buffer(WINDOW *win);
size_t get_buffer_len(void);
int *buffer_to_keys(buffer *input, size_t input_len);
void unget_input(buffer *input, size_t input_len);
void unget_kbinput(int kbinput, bool meta_key, bool func_key);
buffer *get_input(WINDOW *win, size_t input_len);
int get_kbinput(WINDOW *win, bool *meta_key, bool *func_key);
int get_translated_kbinput(int kbinput, bool *escape_seq
#ifndef NANO_SMALL
, bool reset
#endif
);
int get_ascii_kbinput(int kbinput, int ascii_digits
int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key
#ifndef NANO_SMALL
, bool reset
#endif
);
int get_control_kbinput(int kbinput);
int get_escape_seq_kbinput(const int *escape_seq, size_t es_len, bool
int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool
*ignore_seq);
int get_escape_seq_abcd(int kbinput);
int *get_verbatim_kbinput(WINDOW *win, size_t *v_len, bool allow_ascii);
int get_untranslated_kbinput(int kbinput, size_t position, bool
allow_ascii
int get_word_kbinput(int kbinput
#ifndef NANO_SMALL
, bool reset
#endif
);
int get_control_kbinput(int kbinput);
int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len);
int *parse_verbatim_kbinput(WINDOW *win, size_t *kbinput_len);
#ifndef DISABLE_MOUSE
bool get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts);
#endif
......@@ -555,10 +561,6 @@ const shortcut *get_shortcut(const shortcut *s_list, int *kbinput, bool
#ifndef NANO_SMALL
const toggle *get_toggle(int kbinput, bool meta_key);
#endif
int get_edit_input(bool *meta_key, bool *func_key, bool allow_funcs);
#ifndef DISABLE_MOUSE
bool get_edit_mouse(void);
#endif
size_t xplustabs(void);
size_t actual_x(const char *str, size_t xplus);
size_t strnlenpt(const char *buf, size_t size);
......
......@@ -68,6 +68,9 @@ const static rcoption rcopts[] = {
#endif
{"nofollow", NOFOLLOW_SYMLINKS},
{"nohelp", NO_HELP},
#ifdef NANO_WIDE
{"noutf8", NO_UTF8},
#endif
#ifndef DISABLE_WRAPPING
{"nowrap", NO_WRAP},
#endif
......
......@@ -70,6 +70,13 @@ int is_cntrl_char(int c)
(127 <= c && c < 160);
}
/* Return TRUE if the character c is in byte range, and FALSE
* otherwise. */
bool is_byte_char(int c)
{
return (unsigned int)c == (unsigned char)c;
}
int num_of_digits(int n)
{
int i = 1;
......
......@@ -32,7 +32,14 @@
#include "proto.h"
#include "nano.h"
static int statusblank = 0; /* Number of keystrokes left after
static buffer *key_buffer = NULL;
/* The default keystroke buffer,
* containing all the keystrokes we have
* at a given point. */
static size_t key_buffer_len = 0;
/* The length of the default keystroke
* buffer. */
static int statusblank = 0; /* The number of keystrokes left after
* we call statusbar(), before we
* actually blank the statusbar. */
static bool resetstatuspos = FALSE;
......@@ -105,446 +112,565 @@ static bool resetstatuspos = FALSE;
/* Reset all the input routines that rely on character sequences. */
void reset_kbinput(void)
{
get_translated_kbinput(0, NULL, TRUE);
get_ascii_kbinput(0, 0, TRUE);
get_untranslated_kbinput(0, 0, FALSE, TRUE);
#ifdef NANO_WIDE
/* Reset the multibyte and wide character interpreter states. */
if (!ISSET(NO_UTF8)) {
mbtowc(NULL, NULL, 0);
wctomb(NULL, 0);
}
#endif
parse_kbinput(NULL, NULL, NULL, TRUE);
get_word_kbinput(0, TRUE);
}
#endif
/* Put back the input character stored in kbinput. If meta_key is TRUE,
* put back the Escape character after putting back kbinput. */
void unget_kbinput(int kbinput, bool meta_key)
/* Read in a sequence of keystrokes from win and save them in the
* default keystroke buffer. This should only be called when the
* default keystroke buffer is empty. */
void get_buffer(WINDOW *win)
{
ungetch(kbinput);
if (meta_key)
ungetch(NANO_CONTROL_3);
}
int input;
size_t i = 0;
/* Read in a single input character. If it's ignored, swallow it and go
* on. Otherwise, try to translate it from ASCII, extended keypad
* values, and/or escape sequences. Set meta_key to TRUE when we get a
* meta sequence, and set func_key to TRUE when we get an extended
* keypad sequence. Supported extended keypad values consist of [arrow
* key], Ctrl-[arrow key], Shift-[arrow key], Enter, Backspace, the
* editing keypad (Insert, Delete, Home, End, PageUp, and PageDown), the
* function keypad (F1-F16), and the numeric keypad with NumLock off.
* Assume nodelay(win) is FALSE. */
int get_kbinput(WINDOW *win, bool *meta_key, bool *func_key)
{
int kbinput, retval = ERR;
bool escape_seq;
#ifdef NANO_WIDE
size_t wide_key_buffer_len = 0;
buffer *wide_key_buffer = NULL;
#endif
/* If the keystroke buffer isn't empty, get out. */
if (key_buffer != NULL)
return;
/* Read in the first character using blocking input. */
nodelay(win, FALSE);
#ifndef NANO_SMALL
allow_pending_sigwinch(TRUE);
#endif
input = wgetch(win);
#ifndef NANO_SMALL
allow_pending_sigwinch(FALSE);
#endif
*meta_key = FALSE;
*func_key = FALSE;
/* Increment the length of the keystroke buffer, save the value of
* the keystroke in key, and set key_code to TRUE if the keystroke
* is an extended keypad value and hence shouldn't be treated as a
* multibyte character. */
key_buffer_len++;
key_buffer = (buffer *)nmalloc(sizeof(buffer));
key_buffer[0].key = input;
key_buffer[0].key_code = !is_byte_char(input);
while (retval == ERR) {
/* Read a character using blocking input, since using
* non-blocking input will eat up all unused CPU. Then pass it
* to get_translated_kbinput(). Continue until we get a
* complete sequence. */
kbinput = wgetch(win);
retval = get_translated_kbinput(kbinput, &escape_seq
/* Read in the remaining characters using non-blocking input. */
nodelay(win, TRUE);
while (TRUE) {
#ifndef NANO_SMALL
, FALSE
allow_pending_sigwinch(TRUE);
#endif
);
input = wgetch(win);
#ifndef NANO_SMALL
allow_pending_sigwinch(FALSE);
#endif
/* If there aren't any more characters, stop reading. */
if (input == ERR)
break;
/* Otherwise, increment the length of the keystroke buffer, save
* the value of the keystroke in key, and set key_code to TRUE
* if the keystroke is an extended keypad value and hence
* shouldn't be treated as a multibyte character. */
key_buffer_len++;
key_buffer = (buffer *)nrealloc(key_buffer, key_buffer_len *
sizeof(buffer));
key_buffer[key_buffer_len - 1].key = input;
key_buffer[key_buffer_len - 1].key_code = !is_byte_char(input);
}
/* Switch back to non-blocking input. */
nodelay(win, FALSE);
/* If we got a complete non-escape sequence, interpret the
* translated value instead of the value of the last character
* we got. Set func_key to TRUE if the translated value is
* outside byte range. */
if (retval != ERR) {
*func_key = (retval > 255);
kbinput = retval;
#ifdef NANO_WIDE
if (!ISSET(NO_UTF8)) {
/* Change all incomplete or invalid multibyte keystrokes to -1,
* and change all complete and valid multibyte keystrokes to
* their wide character value. */
for (i = 0; i < key_buffer_len; i++) {
wchar_t wide_key;
if (!key_buffer[i].key_code) {
key_buffer[i].key = mbtowc(&wide_key,
(const char *)&key_buffer[i].key, 1);
if (key_buffer[i].key != -1)
key_buffer[i].key = wide_key;
}
}
/* If we got an incomplete escape sequence, put back the initial
* non-escape and then read the entire sequence in as verbatim
* input. */
if (escape_seq) {
int *sequence;
size_t seq_len;
unget_kbinput(kbinput, FALSE);
sequence = get_verbatim_kbinput(win, &seq_len, FALSE);
/* If the escape sequence is one character long, set
* meta_key to TRUE, make the sequence character lowercase,
* and save that as the result. */
if (seq_len == 1) {
*meta_key = TRUE;
retval = tolower(kbinput);
/* If the escape sequence is more than one character long,
* set func_key to TRUE, translate the escape sequence into
* the corresponding key value, and save that as the
* result. */
} else if (seq_len > 1) {
bool ignore_seq;
*func_key = TRUE;
retval = get_escape_seq_kbinput(sequence, seq_len,
&ignore_seq);
if (retval == ERR && !ignore_seq) {
/* This escape sequence is unrecognized. Send it
* back. */
for (; seq_len > 1; seq_len--)
unget_kbinput(sequence[seq_len - 1], FALSE);
retval = sequence[0];
}
/* Save all of the non-(-1) keystrokes in another buffer. */
for (i = 0; i < key_buffer_len; i++) {
if (key_buffer[i].key != -1) {
wide_key_buffer_len++;
wide_key_buffer = (buffer *)nrealloc(wide_key_buffer,
wide_key_buffer_len * sizeof(buffer));
wide_key_buffer[wide_key_buffer_len - 1].key =
key_buffer[i].key;
wide_key_buffer[wide_key_buffer_len - 1].key_code =
key_buffer[i].key_code;
}
free(sequence);
}
/* Replace the default keystroke buffer with the non-(-1)
* keystroke buffer. */
key_buffer_len = wide_key_buffer_len;
free(key_buffer);
key_buffer = wide_key_buffer;
}
#endif
}
#ifdef DEBUG
fprintf(stderr, "get_kbinput(): kbinput = %d, meta_key = %d, func_key = %d\n", kbinput, (int)*meta_key, (int)*func_key);
/* Return the length of the default keystroke buffer. */
size_t get_buffer_len(void)
{
return key_buffer_len;
}
/* Return the key values stored in the keystroke buffer input,
* discarding the key_code values in it. */
int *buffer_to_keys(buffer *input, size_t input_len)
{
int *sequence = (int *)nmalloc(input_len * sizeof(int));
size_t i;
for (i = 0; i < input_len; i++)
sequence[i] = input[i].key;
return sequence;
}
/* Add the contents of the keystroke buffer input to the default
* keystroke buffer. */
void unget_input(buffer *input, size_t input_len)
{
#ifndef NANO_SMALL
allow_pending_sigwinch(TRUE);
allow_pending_sigwinch(FALSE);
#endif
/* If input is empty, get out. */
if (input_len == 0)
return;
/* If adding input would put the default keystroke buffer beyond
* maximum capacity, only add enough of input to put it at maximum
* capacity. */
if (key_buffer_len + input_len < key_buffer_len)
input_len = (size_t)-1 - key_buffer_len;
/* Add the length of input to the length of the default keystroke
* buffer, and reallocate the default keystroke buffer so that it
* has enough room for input. */
key_buffer_len += input_len;
key_buffer = (buffer *)nrealloc(key_buffer, key_buffer_len *
sizeof(buffer));
/* If the default keystroke buffer wasn't empty before, move its
* beginning forward far enough so that we can add input to its
* beginning. */
if (key_buffer_len > input_len)
memmove(key_buffer + input_len, key_buffer,
(key_buffer_len - input_len) * sizeof(buffer));
/* Copy input to the beginning of the default keystroke buffer. */
memcpy(key_buffer, input, input_len * sizeof(buffer));
}
/* Put back the character stored in kbinput. If func_key is TRUE and
* the character is out of byte range, interpret it as an extended
* keypad value. If meta_key is TRUE, put back the Escape character
* after putting back kbinput. */
void unget_kbinput(int kbinput, bool meta_key, bool func_key)
{
buffer input;
input.key = kbinput;
input.key_code = (func_key && !is_byte_char(kbinput));
unget_input(&input, 1);
if (meta_key) {
input.key = NANO_CONTROL_3;
input.key_code = FALSE;
unget_input(&input, 1);
}
}
/* Try to read input_len characters from the default keystroke buffer.
* If the default keystroke buffer is empty and win isn't NULL, try to
* read in more characters from win and add them to the default
* keystroke buffer before doing anything else. If the default
* keystroke buffer is empty and win is NULL, return NULL. */
buffer *get_input(WINDOW *win, size_t input_len)
{
buffer *input;
#ifndef NANO_SMALL
allow_pending_sigwinch(TRUE);
allow_pending_sigwinch(FALSE);
#endif
return retval;
if (key_buffer_len == 0) {
if (win != NULL)
get_buffer(win);
if (key_buffer_len == 0)
return NULL;
}
/* If input_len is greater than the length of the default keystroke
* buffer, only read the number of characters in the default
* keystroke buffer. */
if (input_len > key_buffer_len)
input_len = key_buffer_len;
/* Subtract input_len from the length of the default keystroke
* buffer, and allocate the keystroke buffer input so that it
* has enough room for input_len keystrokes. */
key_buffer_len -= input_len;
input = (buffer *)nmalloc(input_len * sizeof(buffer));
/* Copy input_len characters from the beginning of the default
* keystroke buffer into input. */
memcpy(input, key_buffer, input_len * sizeof(buffer));
/* If the default keystroke buffer is empty, mark it as such. */
if (key_buffer_len == 0) {
free(key_buffer);
key_buffer = NULL;
/* If the default keystroke buffer isn't empty, move its
* beginning forward far enough back so that the keystrokes in input
* are no longer at its beginning. */
} else {
memmove(key_buffer, key_buffer + input_len, key_buffer_len *
sizeof(buffer));
key_buffer = (buffer *)nrealloc(key_buffer, key_buffer_len *
sizeof(buffer));
}
return input;
}
/* Translate acceptable ASCII, extended keypad values, and escape
* sequences into their corresponding key values. Set escape_seq to
* TRUE when we get an incomplete escape sequence. Assume nodelay(win)
* is FALSE. */
int get_translated_kbinput(int kbinput, bool *escape_seq
/* Read in a single character. If it's ignored, swallow it and go on.
* Otherwise, try to translate it from ASCII, meta key sequences, escape
* sequences, and/or extended keypad values. Set meta_key to TRUE when
* we get a meta key sequence, and set func_key to TRUE when we get an
* extended keypad value. Supported extended keypad values consist of
* [arrow key], Ctrl-[arrow key], Shift-[arrow key], Enter, Backspace,
* the editing keypad (Insert, Delete, Home, End, PageUp, and PageDown),
* the function keypad (F1-F16), and the numeric keypad with NumLock
* off. Assume nodelay(win) is FALSE. */
int get_kbinput(WINDOW *win, bool *meta_key, bool *func_key)
{
int kbinput;
/* Read in a character and interpret it. Continue doing this until
* we get a recognized value or sequence. */
while ((kbinput = parse_kbinput(win, meta_key, func_key
#ifndef NANO_SMALL
, FALSE
#endif
)) == ERR);
return kbinput;
}
/* Translate ASCII characters, extended keypad values, and escape
* sequences into their corresponding key values. Set meta_key to TRUE
* when we get a meta key sequence, and set func_key to TRUE when we get
* a function key. Assume nodelay(win) is FALSE. */
int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key
#ifndef NANO_SMALL
, bool reset
#endif
)
{
static int escapes = 0;
static int ascii_digits = 0;
static int word_digits = 0;
buffer *kbinput;
int retval = ERR;
bool no_func_key = FALSE;
#ifndef NANO_SMALL
if (reset) {
escapes = 0;
ascii_digits = 0;
word_digits = 0;
return ERR;
}
#endif
*escape_seq = FALSE;
*meta_key = FALSE;
*func_key = FALSE;
switch (kbinput) {
case ERR:
break;
case NANO_CONTROL_3:
/* Increment the escape counter. */
escapes++;
switch (escapes) {
case 1:
/* One escape: wait for more input. */
case 2:
/* Two escapes: wait for more input. */
break;
default:
/* More than two escapes: reset the escape counter
* and wait for more input. */
escapes = 0;
}
break;
/* Read in a character. */
while ((kbinput = get_input(win, 1)) == NULL);
/* If we got an extended keypad value or an ASCII character,
* translate it. */
if (kbinput->key_code || is_byte_char(kbinput->key)) {
switch (kbinput->key) {
case ERR:
break;
case NANO_CONTROL_3:
/* Increment the escape counter. */
escapes++;
switch (escapes) {
case 1:
/* One escape: wait for more input. */
case 2:
/* Two escapes: wait for more input. */
break;
default:
/* More than two escapes: reset the escape
* counter and wait for more input. */
escapes = 0;
}
break;
#if !defined(NANO_SMALL) && defined(KEY_RESIZE)
/* Since we don't change the default SIGWINCH handler when
* NANO_SMALL is defined, KEY_RESIZE is never generated. Also,
* Slang and SunOS 5.7-5.9 don't support KEY_RESIZE. */
case KEY_RESIZE:
break;
/* Since we don't change the default SIGWINCH handler when
* NANO_SMALL is defined, KEY_RESIZE is never generated.
* Also, Slang and SunOS 5.7-5.9 don't support
* KEY_RESIZE. */
case KEY_RESIZE:
break;
#endif
#ifdef PDCURSES
case KEY_SHIFT_L:
case KEY_SHIFT_R:
case KEY_CONTROL_L:
case KEY_CONTROL_R:
case KEY_ALT_L:
case KEY_ALT_R:
break;
case KEY_SHIFT_L:
case KEY_SHIFT_R:
case KEY_CONTROL_L:
case KEY_CONTROL_R:
case KEY_ALT_L:
case KEY_ALT_R:
break;
#endif
default:
switch (escapes) {
case 0:
switch (kbinput) {
case NANO_CONTROL_8:
retval = ISSET(REBIND_DELETE) ?
NANO_DELETE_KEY : NANO_BACKSPACE_KEY;
break;
case KEY_DOWN:
retval = NANO_NEXTLINE_KEY;
break;
case KEY_UP:
retval = NANO_PREVLINE_KEY;
break;
case KEY_LEFT:
retval = NANO_BACK_KEY;
break;
case KEY_RIGHT:
retval = NANO_FORWARD_KEY;
break;
default:
switch (escapes) {
case 0:
switch (kbinput->key) {
case NANO_CONTROL_8:
retval = ISSET(REBIND_DELETE) ?
NANO_DELETE_KEY :
NANO_BACKSPACE_KEY;
break;
case KEY_DOWN:
retval = NANO_NEXTLINE_KEY;
break;
case KEY_UP:
retval = NANO_PREVLINE_KEY;
break;
case KEY_LEFT:
retval = NANO_BACK_KEY;
break;
case KEY_RIGHT:
retval = NANO_FORWARD_KEY;
break;
#ifdef KEY_HOME
/* HP-UX 10 and 11 don't support KEY_HOME. */
case KEY_HOME:
retval = NANO_HOME_KEY;
break;
#endif
case KEY_BACKSPACE:
retval = NANO_BACKSPACE_KEY;
break;
case KEY_DC:
retval = ISSET(REBIND_DELETE) ?
NANO_BACKSPACE_KEY : NANO_DELETE_KEY;
break;
case KEY_IC:
retval = NANO_INSERTFILE_KEY;
break;
case KEY_NPAGE:
retval = NANO_NEXTPAGE_KEY;
break;
case KEY_PPAGE:
retval = NANO_PREVPAGE_KEY;
break;
case KEY_ENTER:
retval = NANO_ENTER_KEY;
break;
case KEY_A1: /* Home (7) on numeric keypad
* with NumLock off. */
retval = NANO_HOME_KEY;
break;
case KEY_A3: /* PageUp (9) on numeric keypad
* with NumLock off. */
retval = NANO_PREVPAGE_KEY;
break;
case KEY_B2: /* Center (5) on numeric keypad
* with NumLock off. */
break;
case KEY_C1: /* End (1) on numeric keypad
* with NumLock off. */
retval = NANO_END_KEY;
break;
case KEY_C3: /* PageDown (4) on numeric
* keypad with NumLock off. */
retval = NANO_NEXTPAGE_KEY;
break;
/* HP-UX 10 and 11 don't support
* KEY_HOME. */
case KEY_HOME:
retval = NANO_HOME_KEY;
break;
#endif
case KEY_BACKSPACE:
retval = NANO_BACKSPACE_KEY;
break;
case KEY_DC:
retval = ISSET(REBIND_DELETE) ?
NANO_BACKSPACE_KEY :
NANO_DELETE_KEY;
break;
case KEY_IC:
retval = NANO_INSERTFILE_KEY;
break;
case KEY_NPAGE:
retval = NANO_NEXTPAGE_KEY;
break;
case KEY_PPAGE:
retval = NANO_PREVPAGE_KEY;
break;
case KEY_ENTER:
retval = NANO_ENTER_KEY;
break;
case KEY_A1: /* Home (7) on numeric
* keypad with NumLock
* off. */
retval = NANO_HOME_KEY;
break;
case KEY_A3: /* PageUp (9) on numeric
* keypad with NumLock
* off. */
retval = NANO_PREVPAGE_KEY;
break;
case KEY_B2: /* Center (5) on numeric
* keypad with NumLock
* off. */
break;
case KEY_C1: /* End (1) on numeric
* keypad with NumLock
* off. */
retval = NANO_END_KEY;
break;
case KEY_C3: /* PageDown (4) on
* numeric keypad with
* NumLock off. */
retval = NANO_NEXTPAGE_KEY;
break;
#ifdef KEY_BEG
/* Slang doesn't support KEY_BEG. */
case KEY_BEG: /* Center (5) on numeric keypad
* with NumLock off. */
break;
/* Slang doesn't support KEY_BEG. */
case KEY_BEG: /* Center (5) on numeric
* keypad with NumLock
* off. */
break;
#endif
#ifdef KEY_END
/* HP-UX 10 and 11 don't support KEY_END. */
case KEY_END:
retval = NANO_END_KEY;
break;
/* HP-UX 10 and 11 don't support KEY_END. */
case KEY_END:
retval = NANO_END_KEY;
break;
#endif
#ifdef KEY_SUSPEND
/* Slang doesn't support KEY_SUSPEND. */
case KEY_SUSPEND:
retval = NANO_SUSPEND_KEY;
break;
/* Slang doesn't support KEY_SUSPEND. */
case KEY_SUSPEND:
retval = NANO_SUSPEND_KEY;
break;
#endif
#ifdef KEY_SLEFT
/* Slang doesn't support KEY_SLEFT. */
case KEY_SLEFT:
retval = NANO_BACK_KEY;
break;
/* Slang doesn't support KEY_SLEFT. */
case KEY_SLEFT:
retval = NANO_BACK_KEY;
break;
#endif
#ifdef KEY_SRIGHT
/* Slang doesn't support KEY_SRIGHT. */
case KEY_SRIGHT:
retval = NANO_FORWARD_KEY;
break;
#endif
default:
retval = kbinput;
break;
}
break;
case 1:
/* One escape followed by a non-escape: escape
* sequence mode. Reset the escape counter and set
* escape_seq to TRUE. */
escapes = 0;
*escape_seq = TRUE;
break;
case 2:
if (kbinput >= '0' && kbinput <= '9') {
/* Slang doesn't support KEY_SRIGHT. */
case KEY_SRIGHT:
retval = NANO_FORWARD_KEY;
break;
#endif
default:
retval = kbinput->key;
break;
}
break;
case 1:
/* One escape followed by a non-escape: escape
* sequence mode. Reset the escape counter. If
* there aren't any other keys waiting, we have
* a meta key sequence, so set meta_key to TRUE
* and save the lowercase version of the
* non-escape character as the result. If there
* are other keys waiting, we have a true escape
* sequence, so interpret it. */
escapes = 0;
if (get_buffer_len() == 0) {
*meta_key = TRUE;
retval = tolower(kbinput->key);
} else {
buffer *escape_kbinput;
int *sequence;
size_t seq_len;
bool ignore_seq;
/* Put back the non-escape character, get
* the complete escape sequence, translate
* its key values into the corresponding key
* value, and save that as the result. */
unget_input(kbinput, 1);
seq_len = get_buffer_len();
escape_kbinput = get_input(NULL, seq_len);
sequence = buffer_to_keys(escape_kbinput,
seq_len);
retval = get_escape_seq_kbinput(sequence,
seq_len, &ignore_seq);
/* If the escape sequence is unrecognized
* and not ignored, put back all of its
* characters except for the initial
* escape. */
if (retval == ERR && !ignore_seq)
unget_input(escape_kbinput, seq_len);
free(escape_kbinput);
}
break;
case 2:
/* Two escapes followed by one or more decimal
* digits: ASCII character sequence mode. If
* the digit sequence's range is limited to 2XX
* (the first digit is in the '0' to '2' range
* and it's the first digit, or if it's in the
* full digit range and it's not the first
* digit), increment the ASCII digit counter and
* interpret the digit. If the digit sequence's
* range is not limited to 2XX, fall through. */
if (kbinput <= '2' || ascii_digits > 0) {
ascii_digits++;
kbinput = get_ascii_kbinput(kbinput,
ascii_digits
* digits: word sequence mode. If the word
* sequence's range is limited to 6XXXX (the
* first digit is in the '0' to '6' range and
* it's the first digit, or it's in the '0' to
* '9' range and it's not the first digit),
* increment the word sequence counter,
* interpret the digit, and save the
* corresponding word value as the result. If
* the word sequence's range is not limited to
* 6XXXX, fall through. */
if (('0' <= kbinput->key && kbinput->key <= '6'
&& word_digits == 0) ||
('0' <= kbinput->key && kbinput->key <= '9'
&& word_digits > 0)) {
word_digits++;
retval = get_word_kbinput(kbinput->key
#ifndef NANO_SMALL
, FALSE
#endif
);
if (kbinput != ERR) {
/* If we've read in a complete ASCII
* digit sequence, reset the ASCII digit
* counter and the escape counter and
* save the corresponding ASCII
* character as the result. */
ascii_digits = 0;
if (retval != ERR) {
/* If we've read in a complete word
* sequence, reset the word sequence
* counter and the escape counter, and
* mark it so that it isn't interpreted
* as an extended keypad value. */
word_digits = 0;
escapes = 0;
retval = kbinput;
no_func_key = TRUE;
}
} else {
/* Reset the escape counter. */
escapes = 0;
if (word_digits == 0)
/* Two escapes followed by a non-decimal
* digit or a decimal digit that would
* create a word sequence greater than
* 6XXXX, and we're not in the middle of
* a word sequence: control character
* sequence mode. Interpret the control
* sequence and save the corresponding
* control character as the result. */
retval = get_control_kbinput(kbinput->key);
else {
/* If we're in the middle of a word
* sequence, reset the word sequence
* counter and save the character we got
* as the result. */
word_digits = 0;
retval = kbinput->key;
}
}
} else {
/* Reset the escape counter. */
escapes = 0;
if (ascii_digits == 0)
/* Two escapes followed by a non-decimal
* digit or a decimal digit that would
* create an ASCII digit sequence greater
* than 2XX, and we're not in the middle of
* an ASCII character sequence: control
* character sequence mode. Interpret the
* control sequence and save the
* corresponding control character as the
* result. */
retval = get_control_kbinput(kbinput);
else {
/* If we were in the middle of an ASCII
* character sequence, reset the ASCII digit
* counter and save the character we got as
* the result. */
ascii_digits = 0;
retval = kbinput;
}
}
break;
}
}
#ifdef DEBUG
fprintf(stderr, "get_translated_kbinput(): kbinput = %d, escape_seq = %d, escapes = %d, ascii_digits = %d, retval = %d\n", kbinput, (int)*escape_seq, escapes, ascii_digits, retval);
#endif
/* Return the result. */
return retval;
}
/* Translate an ASCII character sequence: turn a three-digit decimal
* ASCII code from 000-255 into its corresponding ASCII character. */
int get_ascii_kbinput(int kbinput, int ascii_digits
#ifndef NANO_SMALL
, bool reset
#endif
)
{
static int ascii_kbinput = 0;
int retval = ERR;
#ifndef NANO_SMALL
if (reset) {
ascii_kbinput = 0;
return ERR;
}
#endif
switch (ascii_digits) {
case 1:
/* Read in the first of the three ASCII digits. */
/* Add the digit we got to the 100's position of the ASCII
* character sequence holder. */
if ('0' <= kbinput && kbinput <= '2')
ascii_kbinput += (kbinput - '0') * 100;
else
retval = kbinput;
break;
case 2:
/* Read in the second of the three ASCII digits. */
/* Add the digit we got to the 10's position of the ASCII
* character sequence holder. */
if (('0' <= kbinput && kbinput <= '5') ||
(ascii_kbinput < 200 && '6' <= kbinput &&
kbinput <= '9'))
ascii_kbinput += (kbinput - '0') * 10;
else
retval = kbinput;
break;
case 3:
/* Read in the third of the three ASCII digits. */
/* Add the digit we got to the 1's position of the ASCII
* character sequence holder, and save the corresponding
* ASCII character as the result. */
if (('0' <= kbinput && kbinput <= '5') ||
(ascii_kbinput < 250 && '6' <= kbinput &&
kbinput <= '9')) {
ascii_kbinput += (kbinput - '0');
retval = ascii_kbinput;
} else
retval = kbinput;
break;
default:
retval = kbinput;
break;
break;
}
}
}
#ifdef DEBUG
fprintf(stderr, "get_ascii_kbinput(): kbinput = %d, ascii_digits = %d, ascii_kbinput = %d, retval = %d\n", kbinput, ascii_digits, ascii_kbinput, retval);
#endif
/* If the result is an ASCII character, reset the ASCII character
* sequence holder. */
/* If we have a result and it's an extended keypad value, set
* func_key to TRUE. */
if (retval != ERR)
ascii_kbinput = 0;
return retval;
}
/* Translate a control character sequence: turn an ASCII non-control
* character into its corresponding control character. */
int get_control_kbinput(int kbinput)
{
int retval = ERR;
/* We don't handle Ctrl-2 here, since Esc Esc 2 could be the first
* part of an ASCII character sequence. */
/* Ctrl-2 (Ctrl-Space) == Ctrl-@ == Ctrl-` */
if (kbinput == ' ' || kbinput == '@' || kbinput == '`')
retval = NANO_CONTROL_SPACE;
/* Ctrl-3 (Ctrl-[, Esc) to Ctrl-7 (Ctrl-_) */
else if (kbinput >= '3' && kbinput <= '7')
retval = kbinput - 24;
/* Ctrl-8 (Ctrl-?) */
else if (kbinput == '8' || kbinput == '?')
retval = NANO_CONTROL_8;
/* Ctrl-A to Ctrl-_ */
else if (kbinput >= 'A' && kbinput <= '_')
retval = kbinput - 64;
/* Ctrl-a to Ctrl-~ */
else if (kbinput >= 'a' && kbinput <= '~')
retval = kbinput - 96;
else
retval = kbinput;
*func_key = !is_byte_char(retval);
#ifdef DEBUG
fprintf(stderr, "get_control_kbinput(): kbinput = %d, retval = %d\n", kbinput, retval);
fprintf(stderr, "parse_kbinput(): kbinput->key = %d, meta_key = %d, func_key = %d, escapes = %d, word_digits = %d, retval = %d\n", kbinput->key, (int)*meta_key, (int)*func_key, escapes, word_digits, retval);
#endif
/* Return the result. */
return retval;
}
......@@ -555,20 +681,20 @@ int get_control_kbinput(int kbinput)
* ERR and set ignore_seq to TRUE; if it's unrecognized, return ERR and
* set ignore_seq to FALSE. Assume that Escape has already been read
* in. */
int get_escape_seq_kbinput(const int *escape_seq, size_t es_len, bool
int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool
*ignore_seq)
{
int retval = ERR;
*ignore_seq = FALSE;
if (es_len > 1) {
switch (escape_seq[0]) {
if (seq_len > 1) {
switch (sequence[0]) {
case 'O':
switch (escape_seq[1]) {
switch (sequence[1]) {
case '2':
if (es_len >= 3) {
switch (escape_seq[2]) {
if (seq_len >= 3) {
switch (sequence[2]) {
case 'P': /* Esc O 2 P == F13 on
* xterm. */
retval = KEY_F(13);
......@@ -595,7 +721,7 @@ int get_escape_seq_kbinput(const int *escape_seq, size_t es_len, bool
* VT100/VT320/xterm. */
case 'D': /* Esc O D == Left on
* VT100/VT320/xterm. */
retval = get_escape_seq_abcd(escape_seq[1]);
retval = get_escape_seq_abcd(sequence[1]);
break;
case 'E': /* Esc O E == Center (5) on numeric keypad
* with NumLock off on xterm. */
......@@ -650,7 +776,7 @@ int get_escape_seq_kbinput(const int *escape_seq, size_t es_len, bool
case 'b': /* Esc O b == Ctrl-Down on rxvt. */
case 'c': /* Esc O c == Ctrl-Right on rxvt. */
case 'd': /* Esc O d == Ctrl-Left on rxvt. */
retval = get_escape_seq_abcd(escape_seq[1]);
retval = get_escape_seq_abcd(sequence[1]);
break;
case 'j': /* Esc O j == '*' on numeric keypad with
* NumLock off on VT100/VT220/VT320/xterm/
......@@ -735,20 +861,20 @@ int get_escape_seq_kbinput(const int *escape_seq, size_t es_len, bool
}
break;
case 'o':
switch (escape_seq[1]) {
switch (sequence[1]) {
case 'a': /* Esc o a == Ctrl-Up on Eterm. */
case 'b': /* Esc o b == Ctrl-Down on Eterm. */
case 'c': /* Esc o c == Ctrl-Right on Eterm. */
case 'd': /* Esc o d == Ctrl-Left on Eterm. */
retval = get_escape_seq_abcd(escape_seq[1]);
retval = get_escape_seq_abcd(sequence[1]);
break;
}
break;
case '[':
switch (escape_seq[1]) {
switch (sequence[1]) {
case '1':
if (es_len >= 3) {
switch (escape_seq[2]) {
if (seq_len >= 3) {
switch (sequence[2]) {
case '1': /* Esc [ 1 1 ~ == F1 on rxvt/
* Eterm. */
retval = KEY_F(1);
......@@ -785,11 +911,11 @@ int get_escape_seq_kbinput(const int *escape_seq, size_t es_len, bool
retval = KEY_F(8);
break;
case ';':
if (es_len >= 4) {
switch (escape_seq[3]) {
if (seq_len >= 4) {
switch (sequence[3]) {
case '2':
if (es_len >= 5) {
switch (escape_seq[4]) {
if (seq_len >= 5) {
switch (sequence[4]) {
case 'A': /* Esc [ 1 ; 2 A == Shift-Up on
* xterm. */
case 'B': /* Esc [ 1 ; 2 B == Shift-Down on
......@@ -798,14 +924,14 @@ int get_escape_seq_kbinput(const int *escape_seq, size_t es_len, bool
* xterm. */
case 'D': /* Esc [ 1 ; 2 D == Shift-Left on
* xterm. */
retval = get_escape_seq_abcd(escape_seq[4]);
retval = get_escape_seq_abcd(sequence[4]);
break;
}
}
break;
case '5':
if (es_len >= 5) {
switch (escape_seq[4]) {
if (seq_len >= 5) {
switch (sequence[4]) {
case 'A': /* Esc [ 1 ; 5 A == Ctrl-Up on
* xterm. */
case 'B': /* Esc [ 1 ; 5 B == Ctrl-Down on
......@@ -814,7 +940,7 @@ int get_escape_seq_kbinput(const int *escape_seq, size_t es_len, bool
* xterm. */
case 'D': /* Esc [ 1 ; 5 D == Ctrl-Left on
* xterm. */
retval = get_escape_seq_abcd(escape_seq[4]);
retval = get_escape_seq_abcd(sequence[4]);
break;
}
}
......@@ -830,8 +956,8 @@ int get_escape_seq_kbinput(const int *escape_seq, size_t es_len, bool
}
break;
case '2':
if (es_len >= 3) {
switch (escape_seq[2]) {
if (seq_len >= 3) {
switch (sequence[2]) {
case '0': /* Esc [ 2 0 ~ == F9 on
* VT220/VT320/Linux console/
* xterm/rxvt/Eterm. */
......@@ -922,7 +1048,7 @@ int get_escape_seq_kbinput(const int *escape_seq, size_t es_len, bool
case 'D': /* Esc [ D == Left on ANSI/VT220/Linux
* console/FreeBSD console/Mach console/
* rxvt/Eterm. */
retval = get_escape_seq_abcd(escape_seq[1]);
retval = get_escape_seq_abcd(sequence[1]);
break;
case 'E': /* Esc [ E == Center (5) on numeric keypad
* with NumLock off on FreeBSD console. */
......@@ -955,8 +1081,8 @@ int get_escape_seq_kbinput(const int *escape_seq, size_t es_len, bool
retval = KEY_F(2);
break;
case 'O':
if (es_len >= 3) {
switch (escape_seq[2]) {
if (seq_len >= 3) {
switch (sequence[2]) {
case 'P': /* Esc [ O P == F1 on
* xterm. */
retval = KEY_F(1);
......@@ -1017,11 +1143,11 @@ int get_escape_seq_kbinput(const int *escape_seq, size_t es_len, bool
case 'c': /* Esc [ c == Shift-Right on rxvt/
* Eterm. */
case 'd': /* Esc [ d == Shift-Left on rxvt/Eterm. */
retval = get_escape_seq_abcd(escape_seq[1]);
retval = get_escape_seq_abcd(sequence[1]);
break;
case '[':
if (es_len >= 3) {
switch (escape_seq[2]) {
if (seq_len >= 3) {
switch (sequence[2]) {
case 'A': /* Esc [ [ A == F1 on Linux
* console. */
retval = KEY_F(1);
......@@ -1076,103 +1202,165 @@ int get_escape_seq_abcd(int kbinput)
}
}
/* Read in a string of input characters (e.g. an escape sequence)
* verbatim. Return the length of the string in v_len. Assume
* nodelay(win) is FALSE. */
int *get_verbatim_kbinput(WINDOW *win, size_t *v_len, bool allow_ascii)
/* Translate a word sequence: turn a three-digit decimal number from
* 000 to 255 into its corresponding word value. */
int get_word_kbinput(int kbinput
#ifndef NANO_SMALL
, bool reset
#endif
)
{
int kbinput, *v_kbinput;
size_t i = 0, v_newlen = 0;
static int word_digits = 0;
static int word_kbinput = 0;
int retval = ERR;
#ifndef NANO_SMALL
allow_pending_sigwinch(TRUE);
if (reset) {
word_digits = 0;
word_kbinput = 0;
return ERR;
}
#endif
*v_len = 0;
v_kbinput = (int *)nmalloc(sizeof(int));
/* Increment the word digit counter. */
word_digits++;
/* Turn off flow control characters if necessary so that we can type
* them in verbatim, and turn the keypad off so that we don't get
* extended keypad values outside the ASCII range. */
if (ISSET(PRESERVE))
disable_flow_control();
keypad(win, FALSE);
switch (word_digits) {
case 1:
/* One digit: reset the word sequence holder and add the
* digit we got to the 10000's position of the word sequence
* holder. */
word_kbinput = 0;
if ('0' <= kbinput && kbinput <= '6')
word_kbinput += (kbinput - '0') * 10000;
else
/* If the character we got isn't a decimal digit, or if
* it is and it would put the word sequence out of word
* range, save it as the result. */
retval = kbinput;
break;
case 2:
/* Two digits: add the digit we got to the 1000's position
* of the word sequence holder. */
if (('0' <= kbinput && kbinput <= '5') ||
(word_kbinput < 60000 && '6' <= kbinput &&
kbinput <= '9'))
word_kbinput += (kbinput - '0') * 1000;
else
/* If the character we got isn't a decimal digit, or if
* it is and it would put the word sequence out of word
* range, save it as the result. */
retval = kbinput;
break;
case 3:
/* Three digits: add the digit we got to the 100's position
* of the word sequence holder. */
if (('0' <= kbinput && kbinput <= '5') ||
(word_kbinput < 65000 && '6' <= kbinput &&
kbinput <= '9'))
word_kbinput += (kbinput - '0') * 100;
else
/* If the character we got isn't a decimal digit, or if
* it is and it would put the word sequence out of word
* range, save it as the result. */
retval = kbinput;
break;
case 4:
/* Four digits: add the digit we got to the 10's position of
* the word sequence holder. */
if (('0' <= kbinput && kbinput <= '3') ||
(word_kbinput < 65500 && '4' <= kbinput &&
kbinput <= '9'))
word_kbinput += (kbinput - '0') * 10;
else
/* If the character we got isn't a decimal digit, or if
* it is and it would put the word sequence out of word
* range, save it as the result. */
retval = kbinput;
break;
case 5:
/* Five digits: add the digit we got to the 1's position of
* the word sequence holder, and save the corresponding word
* value as the result. */
if (('0' <= kbinput && kbinput <= '5') ||
(word_kbinput < 65530 && '6' <= kbinput &&
kbinput <= '9')) {
word_kbinput += (kbinput - '0');
retval = word_kbinput;
} else
/* If the character we got isn't a decimal digit, or if
* it is and it would put the word sequence out of word
* range, save it as the result. */
retval = kbinput;
break;
default:
/* More than three digits: save the character we got as the
* result. */
retval = kbinput;
break;
}
/* If first is ERR, read the first character using blocking input,
* since using non-blocking input will eat up all unused CPU. Then
* increment v_len and save the character in v_kbinput. */
kbinput = wgetch(win);
(*v_len)++;
v_kbinput[0] = kbinput;
/* If we have a result, reset the word digit counter and the word
* sequence holder. */
if (retval != ERR) {
word_digits = 0;
word_kbinput = 0;
}
#ifdef DEBUG
fprintf(stderr, "get_verbatim_kbinput(): kbinput = %d, v_len = %lu\n", kbinput, (unsigned long)*v_len);
fprintf(stderr, "get_word_kbinput(): kbinput = %d, word_digits = %d, word_kbinput = %d, retval = %d\n", kbinput, word_digits, word_kbinput, retval);
#endif
/* Read any following characters using non-blocking input, until
* there aren't any left to be read, and save the complete string of
* characters in v_kbinput, incrementing v_len accordingly. We read
* them all at once in order to minimize the chance that there might
* be a delay greater than nodelay() provides for between them, in
* which case we'll stop before all of them are read. */
nodelay(win, TRUE);
while ((kbinput = wgetch(win)) != ERR) {
(*v_len)++;
v_kbinput = (int *)nrealloc(v_kbinput, *v_len * sizeof(int));
v_kbinput[*v_len - 1] = kbinput;
return retval;
}
/* Translate a control character sequence: turn an ASCII non-control
* character into its corresponding control character. */
int get_control_kbinput(int kbinput)
{
int retval;
/* Ctrl-2 (Ctrl-Space, Ctrl-@, Ctrl-`) */
if (kbinput == '2' || kbinput == ' ' || kbinput == '@' ||
kbinput == '`')
retval = NANO_CONTROL_SPACE;
/* Ctrl-3 (Ctrl-[, Esc) to Ctrl-7 (Ctrl-_) */
else if ('3' <= kbinput && kbinput <= '7')
retval = kbinput - 24;
/* Ctrl-8 (Ctrl-?) */
else if (kbinput == '8' || kbinput == '?')
retval = NANO_CONTROL_8;
/* Ctrl-A to Ctrl-_ */
else if ('A' <= kbinput && kbinput <= '_')
retval = kbinput - 64;
/* Ctrl-a to Ctrl-~ */
else if ('a' <= kbinput && kbinput <= '~')
retval = kbinput - 96;
else
retval = kbinput;
#ifdef DEBUG
fprintf(stderr, "get_verbatim_kbinput(): kbinput = %d, v_len = %lu\n", kbinput, (unsigned long)*v_len);
fprintf(stderr, "get_control_kbinput(): kbinput = %d, retval = %d\n", kbinput, retval);
#endif
}
nodelay(win, FALSE);
/* Pass the string of characters to get_untranslated_kbinput(), one
* by one, so it can handle them as ASCII character sequences and/or
* escape sequences. Filter out ERR's from v_kbinput in the
* process; they shouldn't occur in the string of characters unless
* we're reading an incomplete sequence, in which case we only want
* to keep the complete sequence. */
for (; i < *v_len; i++) {
v_kbinput[v_newlen] = get_untranslated_kbinput(v_kbinput[i], i,
allow_ascii
#ifndef NANO_SMALL
, FALSE
#endif
);
if (v_kbinput[i] != ERR && v_kbinput[v_newlen] != ERR)
v_newlen++;
}
return retval;
}
if (v_newlen == 0) {
/* If there were no characters after the ERR's were filtered
* out, set v_len and reallocate v_kbinput to account for
* one character, and set that character to ERR. */
*v_len = 1;
v_kbinput = (int *)nrealloc(v_kbinput, sizeof(int));
v_kbinput[0] = ERR;
} else if (v_newlen != *v_len) {
/* If there were fewer characters after the ERR's were filtered
* out, set v_len and reallocate v_kbinput to account for
* the new number of characters. */
*v_len = v_newlen;
v_kbinput = (int *)nrealloc(v_kbinput, *v_len * sizeof(int));
}
/* Read in a string of characters verbatim, and return the length of the
* string in kbinput_len. Assume nodelay(win) is FALSE. */
int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len)
{
int *retval;
/* If allow_ascii is TRUE and v_kbinput[0] is ERR, we need to
* complete an ASCII character sequence. Keep reading in characters
* using blocking input until we get a complete sequence. */
if (allow_ascii && v_kbinput[0] == ERR) {
while (v_kbinput[0] == ERR) {
kbinput = wgetch(win);
v_kbinput[0] = get_untranslated_kbinput(kbinput, i,
allow_ascii
#ifndef NANO_SMALL
, FALSE
#endif
);
i++;
}
}
/* Turn off flow control characters if necessary so that we can type
* them in verbatim, and turn the keypad off so that we don't get
* extended keypad values. */
if (ISSET(PRESERVE))
disable_flow_control();
keypad(win, FALSE);
/* Read in a stream of characters and interpret it if possible. */
retval = parse_verbatim_kbinput(win, kbinput_len);
/* Turn flow control characters back on if necessary and turn the
* keypad back on now that we're done. */
......@@ -1180,69 +1368,57 @@ int *get_verbatim_kbinput(WINDOW *win, size_t *v_len, bool allow_ascii)
enable_flow_control();
keypad(win, TRUE);
#ifndef NANO_SMALL
allow_pending_sigwinch(FALSE);
#endif
return v_kbinput;
return retval;
}
int get_untranslated_kbinput(int kbinput, size_t position, bool
allow_ascii
#ifndef NANO_SMALL
, bool reset
#endif
)
/* Read in a stream of all available characters. Translate the first
* few characters of the input into the corresponding word value if
* possible. After that, leave the input as-is. */
int *parse_verbatim_kbinput(WINDOW *win, size_t *kbinput_len)
{
static int ascii_digits = 0;
int retval;
buffer *kbinput, *sequence;
int word, *retval;
/* Read in the first keystroke. */
while ((kbinput = get_input(win, 1)) == NULL);
/* Check whether the first keystroke is a decimal digit. */
word = get_word_kbinput(kbinput->key
#ifndef NANO_SMALL
if (reset) {
ascii_digits = 0;
return ERR;
}
, FALSE
#endif
);
/* If the first keystroke isn't a decimal digit, put back the first
* keystroke. */
if (word != ERR)
unget_input(kbinput, 1);
/* Otherwise, read in keystrokes until we have a complete word
* sequence, and put back the corresponding word value. */
else {
buffer word_kbinput;
if (allow_ascii) {
/* position is equal to the number of ASCII digits we've read so
* far, and kbinput is a digit from '0' to '9': ASCII character
* sequence mode. If the digit sequence's range is limited to
* 2XX (the first digit is in the '0' to '2' range and it's the
* first digit, or if it's in the full digit range and it's not
* the first digit), increment the ASCII digit counter and
* interpret the digit. If the digit sequence's range is not
* limited to 2XX, fall through. */
if (position == ascii_digits && kbinput >= '0' &&
kbinput <= '9') {
if (kbinput <= '2' || ascii_digits > 0) {
ascii_digits++;
kbinput = get_ascii_kbinput(kbinput, ascii_digits
while (word == ERR) {
while ((kbinput = get_input(win, 1)) == NULL);
word = get_word_kbinput(kbinput->key
#ifndef NANO_SMALL
, FALSE
, FALSE
#endif
);
if (kbinput != ERR)
/* If we've read in a complete ASCII digit sequence,
* reset the ASCII digit counter. */
ascii_digits = 0;
}
} else if (ascii_digits > 0)
/* position is not equal to the number of ASCII digits we've
* read or kbinput is a non-digit, and we're in the middle
* of an ASCII character sequence. Reset the ASCII digit
* counter. */
ascii_digits = 0;
}
);
}
/* Save the corresponding ASCII character as the result if we've
* read in a complete ASCII digit sequence, or the passed-in
* character if we haven't. */
retval = kbinput;
word_kbinput.key = word;
word_kbinput.key_code = FALSE;
#ifdef DEBUG
fprintf(stderr, "get_untranslated_kbinput(): kbinput = %d, position = %lu, ascii_digits = %d\n", kbinput, (unsigned long)position, ascii_digits);
#endif
unget_input(&word_kbinput, 1);
}
/* Get the complete sequence, and save the key values in it as the
* result. */
*kbinput_len = get_buffer_len();
sequence = get_input(NULL, *kbinput_len);
retval = buffer_to_keys(sequence, *kbinput_len);
free(sequence);
return retval;
}
......@@ -1325,9 +1501,9 @@ bool get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts)
* has, at the very least, an equivalent control key, an
* equivalent primary meta key sequence, or both. */
if (s->ctrlval != NANO_NO_KEY)
unget_kbinput(s->ctrlval, FALSE);
unget_kbinput(s->ctrlval, FALSE, FALSE);
else if (s->metaval != NANO_NO_KEY)
unget_kbinput(s->metaval, TRUE);
unget_kbinput(s->metaval, TRUE, FALSE);
return TRUE;
}
......@@ -1372,9 +1548,11 @@ const shortcut *get_shortcut(const shortcut *s_list, int *kbinput, bool
if (slen > 0) {
if (s->ctrlval != NANO_NO_KEY) {
*meta_key = FALSE;
*func_key = FALSE;
*kbinput = s->ctrlval;
} else if (s->metaval != NANO_NO_KEY) {
*meta_key = TRUE;
*func_key = FALSE;
*kbinput = s->metaval;
}
return s;
......@@ -1404,149 +1582,6 @@ const toggle *get_toggle(int kbinput, bool meta_key)
}
#endif /* !NANO_SMALL */
int get_edit_input(bool *meta_key, bool *func_key, bool allow_funcs)
{
bool keyhandled = FALSE;
int kbinput, retval;
const shortcut *s;
#ifndef NANO_SMALL
const toggle *t;
#endif
kbinput = get_kbinput(edit, meta_key, func_key);
/* Universal shortcuts. These aren't in any shortcut lists, but we
* should handle them anyway. */
switch (kbinput) {
case NANO_XON_KEY:
statusbar(_("XON ignored, mumble mumble."));
return ERR;
case NANO_XOFF_KEY:
statusbar(_("XOFF ignored, mumble mumble."));
return ERR;
#ifndef NANO_SMALL
case NANO_SUSPEND_KEY:
if (ISSET(SUSPEND))
do_suspend(0);
return ERR;
#endif
#ifndef DISABLE_MOUSE
case KEY_MOUSE:
if (get_edit_mouse()) {
kbinput = get_kbinput(edit, meta_key, func_key);
break;
} else
return ERR;
#endif
}
/* Check for a shortcut in the main list. */
s = get_shortcut(main_list, &kbinput, meta_key, func_key);
if (s != NULL) {
/* We got a shortcut. Run the shortcut's corresponding function
* if it has one. */
if (s->func != do_cut_text)
cutbuffer_reset();
if (s->func != NULL) {
if (allow_funcs) {
if (ISSET(VIEW_MODE) && !s->viewok)
print_view_warning();
else
s->func();
}
keyhandled = TRUE;
}
}
#ifndef NANO_SMALL
else {
/* If we didn't get a shortcut, check for a toggle. */
t = get_toggle(kbinput, *meta_key);
/* We got a toggle. Switch the value of the toggle's
* corresponding flag. */
if (t != NULL) {
cutbuffer_reset();
if (allow_funcs)
do_toggle(t);
keyhandled = TRUE;
}
}
#endif
/* If we got a shortcut with a corresponding function or a toggle,
* reset meta_key and retval. If we didn't, keep the value of
* meta_key and return the key we got in retval. */
if (allow_funcs && keyhandled) {
*meta_key = FALSE;
retval = ERR;
} else {
cutbuffer_reset();
retval = kbinput;
}
return retval;
}
#ifndef DISABLE_MOUSE
bool get_edit_mouse(void)
{
int mouse_x, mouse_y;
bool retval;
retval = get_mouseinput(&mouse_x, &mouse_y, TRUE);
if (!retval) {
/* We can click in the edit window to move the cursor. */
if (wenclose(edit, mouse_y, mouse_x)) {
bool sameline;
/* Did they click on the line with the cursor? If they
* clicked on the cursor, we set the mark. */
size_t xcur;
/* The character they clicked on. */
/* Subtract out the size of topwin. Perhaps we need a
* constant somewhere? */
mouse_y -= 2;
sameline = (mouse_y == current_y);
/* Move to where the click occurred. */
for (; current_y < mouse_y && current->next != NULL; current_y++)
current = current->next;
for (; current_y > mouse_y && current->prev != NULL; current_y--)
current = current->prev;
xcur = actual_x(current->data, get_page_start(xplustabs()) +
mouse_x);
#ifndef NANO_SMALL
/* Clicking where the cursor is toggles the mark, as does
* clicking beyond the line length with the cursor at the
* end of the line. */
if (sameline && xcur == current_x) {
if (ISSET(VIEW_MODE)) {
print_view_warning();
return retval;
}
do_mark();
}
#endif
current_x = xcur;
placewewant = xplustabs();
edit_refresh();
}
}
/* FIXME: If we clicked on a location in the statusbar, the cursor
* should move to the location we clicked on. This functionality
* should be in get_statusbar_mouse() when it's written. */
return retval;
}
#endif /* !DISABLE_MOUSE */
/* 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. */
......@@ -3141,14 +3176,14 @@ int do_yesno(bool all, const char *msg)
if (kbinput == NANO_CANCEL_KEY)
ok = -1;
#ifndef DISABLE_MOUSE
/* Look ma! We get to duplicate lots of code from
* get_edit_mouse()!! */
/* Look, ma! We get to duplicate lots of code from
* do_mouse()!! */
else if (kbinput == KEY_MOUSE) {
get_mouseinput(&mouse_x, &mouse_y, FALSE);
if (mouse_x != -1 && mouse_y != -1 && !ISSET(NO_HELP) &&
wenclose(bottomwin, mouse_y, mouse_x) && mouse_x <
(width * 2) && mouse_y >= editwinrows + 3) {
wenclose(bottomwin, mouse_y, mouse_x) &&
mouse_x < (width * 2) && mouse_y >= editwinrows + 3) {
int x = mouse_x / width;
/* Did we click in the first column of shortcuts, or
* the second? */
......@@ -3191,8 +3226,9 @@ void total_refresh(void)
clearok(topwin, FALSE);
clearok(edit, FALSE);
clearok(bottomwin, FALSE);
edit_refresh();
titlebar(NULL);
edit_refresh();
/* FIXME: bottomwin needs to be refreshed too. */
}
void display_main_list(void)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment