new feature: allow text selection by holding Shift with the cursor keys

Add the keycodes and routines to allow the user to forego setting the
mark explicitly (with M-A / ^6) and instead quickly select a few words
or lines by holding down Shift together with the movement keys.

(Some combinations with Shift are swallowed by some terminal emulators.
To work around some of those, the combinations Shift+Alt+Left/Right work
as Shift+Home/End and Shift+Alt+Up/Down work as Shift+PageUp/PageDown.)
master
Benno Schulenberg 2016-04-24 11:28:28 +02:00
parent aeb49a8013
commit 382c9d792d
7 changed files with 160 additions and 9 deletions

View File

@ -100,6 +100,7 @@ void make_new_buffer(void)
openfile->mark_set = FALSE;
openfile->mark_begin = NULL;
openfile->mark_begin_x = 0;
openfile->kind_of_mark = SOFTMARK;
openfile->fmt = NIX_FILE;

View File

@ -40,6 +40,8 @@ bool console;
bool meta_key;
/* Whether the current keystroke is a Meta key. */
bool shift_held;
/* Whether Shift was being held together with a movement key. */
bool focusing = TRUE;
/* Whether an update of the edit window should center the cursor. */
@ -48,6 +50,8 @@ message_type lastmessage = HUSH;
#ifndef NANO_TINY
int controlleft, controlright, controlup, controldown;
int shiftcontrolleft, shiftcontrolright, shiftcontrolup, shiftcontroldown;
int shiftaltleft, shiftaltright, shiftaltup, shiftaltdown;
#endif
#ifndef DISABLE_WRAPJUSTIFY

View File

@ -1689,8 +1689,26 @@ int do_input(bool allow_funcs)
} else
#endif
{
#ifndef NANO_TINY
/* If Shifted movement occurs, set the mark. */
if (shift_held && !openfile->mark_set) {
openfile->mark_set = TRUE;
openfile->mark_begin = openfile->current;
openfile->mark_begin_x = openfile->current_x;
openfile->kind_of_mark = SOFTMARK;
}
#endif
/* Execute the function of the shortcut. */
s->scfunc();
#ifndef NANO_TINY
/* If Shiftless movement occurred, discard a soft mark. */
if (openfile->mark_set && !shift_held &&
openfile->kind_of_mark == SOFTMARK) {
openfile->mark_set = FALSE;
openfile->mark_begin = NULL;
refresh_needed = TRUE;
}
#endif
#ifndef DISABLE_COLOR
if (f && !f->viewok)
reset_multis(openfile->current, FALSE);
@ -2539,6 +2557,16 @@ int main(int argc, char **argv)
controlright = get_keycode("kRIT5", CONTROL_RIGHT);
controlup = get_keycode("kUP5", CONTROL_UP);
controldown = get_keycode("kDN5", CONTROL_DOWN);
/* Ask for the codes for Shift+Control+Left/Right/Up/Down. */
shiftcontrolleft = get_keycode("kLFT6", SHIFT_CONTROL_LEFT);
shiftcontrolright = get_keycode("kRIT6", SHIFT_CONTROL_RIGHT);
shiftcontrolup = get_keycode("kUP6", SHIFT_CONTROL_UP);
shiftcontroldown = get_keycode("kDN6", SHIFT_CONTROL_DOWN);
/* Ask for the codes for Shift+Alt+Left/Right/Up/Down. */
shiftaltleft = get_keycode("kLFT4", SHIFT_ALT_LEFT);
shiftaltright = get_keycode("kRIT4", SHIFT_ALT_RIGHT);
shiftaltup = get_keycode("kUP4", SHIFT_ALT_UP);
shiftaltdown = get_keycode("kDN4", SHIFT_ALT_DOWN);
#endif
#ifndef USE_SLANG

View File

@ -179,6 +179,10 @@ typedef enum {
OVERWRITE, APPEND, PREPEND
} kind_of_writing_type;
typedef enum {
SOFTMARK, HARDMARK
} mark_type;
typedef enum {
UPWARD, DOWNWARD
} scroll_dir;
@ -402,6 +406,8 @@ typedef struct openfilestruct {
/* The file's line where the mark is, if any. */
size_t mark_begin_x;
/* The file's mark's x-coordinate position, if any. */
mark_type kind_of_mark;
/* Whether this is a soft or a hard mark. */
file_format fmt;
/* The file's format. */
undo *undotop;
@ -560,6 +566,16 @@ enum
#define CONTROL_RIGHT 0x402
#define CONTROL_UP 0x403
#define CONTROL_DOWN 0x404
#define SHIFT_CONTROL_LEFT 0x405
#define SHIFT_CONTROL_RIGHT 0x406
#define SHIFT_CONTROL_UP 0x407
#define SHIFT_CONTROL_DOWN 0x408
#define SHIFT_ALT_LEFT 0x409
#define SHIFT_ALT_RIGHT 0x40a
#define SHIFT_ALT_UP 0x40b
#define SHIFT_ALT_DOWN 0x40c
#define SHIFT_PAGEUP 0x40d
#define SHIFT_PAGEDOWN 0x40e
#ifndef NANO_TINY
/* An imaginary key for when we get a SIGWINCH (window resize). */

View File

@ -35,6 +35,8 @@ extern bool console;
#endif
extern bool meta_key;
extern bool shift_held;
extern bool focusing;
extern message_type lastmessage;
@ -44,6 +46,14 @@ extern int controlleft;
extern int controlright;
extern int controlup;
extern int controldown;
extern int shiftcontrolleft;
extern int shiftcontrolright;
extern int shiftcontrolup;
extern int shiftcontroldown;
extern int shiftaltleft;
extern int shiftaltright;
extern int shiftaltup;
extern int shiftaltdown;
#endif
#ifndef DISABLE_WRAPJUSTIFY

View File

@ -49,16 +49,18 @@ static filestruct *jusbottom = NULL;
void do_mark(void)
{
openfile->mark_set = !openfile->mark_set;
if (openfile->mark_set) {
statusbar(_("Mark Set"));
openfile->mark_begin = openfile->current;
openfile->mark_begin_x = openfile->current_x;
openfile->kind_of_mark = HARDMARK;
} else {
statusbar(_("Mark Unset"));
openfile->mark_begin = NULL;
openfile->mark_begin_x = 0;
edit_refresh();
}
edit_refresh();
}
#endif /* !NANO_TINY */

View File

@ -336,6 +336,7 @@ int parse_kbinput(WINDOW *win)
int *kbinput, keycode, retval = ERR;
meta_key = FALSE;
shift_held = FALSE;
/* Read in a character. */
kbinput = get_input(win, 1);
@ -504,25 +505,65 @@ int parse_kbinput(WINDOW *win)
return sc_seq_or(do_prev_block, 0);
else if (retval == controldown)
return sc_seq_or(do_next_block, 0);
else if (retval == shiftcontrolleft) {
shift_held = TRUE;
return sc_seq_or(do_prev_word_void, 0);
} else if (retval == shiftcontrolright) {
shift_held = TRUE;
return sc_seq_or(do_next_word_void, 0);
} else if (retval == shiftcontrolup) {
shift_held = TRUE;
return sc_seq_or(do_prev_block, 0);
} else if (retval == shiftcontroldown) {
shift_held = TRUE;
return sc_seq_or(do_next_block, 0);
} else if (retval == shiftaltleft) {
shift_held = TRUE;
return sc_seq_or(do_home, 0);
} else if (retval == shiftaltright) {
shift_held = TRUE;
return sc_seq_or(do_end, 0);
} else if (retval == shiftaltup) {
shift_held = TRUE;
return sc_seq_or(do_page_up, 0);
} else if (retval == shiftaltdown) {
shift_held = TRUE;
return sc_seq_or(do_page_down, 0);
}
#endif
#if defined(__linux__) && !defined(NANO_TINY)
/* When not running under X, check for the bare arrow keys whether
* the Ctrl key is being held together with them. */
if (console && (retval == KEY_UP || retval == KEY_DOWN ||
retval == KEY_LEFT || retval == KEY_RIGHT)) {
unsigned char modifiers = 6;
* Shift/Ctrl/Alt are being held together with them. */
unsigned char modifiers = 6;
if (ioctl(0, TIOCLINUX, &modifiers) >= 0 && (modifiers & 0x04)) {
if (console && ioctl(0, TIOCLINUX, &modifiers) >= 0) {
if (modifiers & 0x01)
shift_held =TRUE;
/* Is Ctrl being held? */
if (modifiers & 0x04) {
if (retval == KEY_UP)
return sc_seq_or(do_prev_block, 0);
else if (retval == KEY_DOWN)
return sc_seq_or(do_next_block, 0);
else if (retval == KEY_LEFT)
return sc_seq_or(do_prev_word_void, 0);
else
else if (retval == KEY_RIGHT)
return sc_seq_or(do_next_word_void, 0);
}
/* Are both Shift and Alt being held? */
if ((modifiers & 0x09) == 0x09) {
if (retval == KEY_UP)
return sc_seq_or(do_page_up, 0);
else if (retval == KEY_DOWN)
return sc_seq_or(do_page_down, 0);
else if (retval == KEY_LEFT)
return sc_seq_or(do_home, 0);
else if (retval == KEY_RIGHT)
return sc_seq_or(do_end, 0);
}
}
#endif /* __linux__ && !NANO_TINY */
@ -530,37 +571,53 @@ int parse_kbinput(WINDOW *win)
#ifdef KEY_SLEFT
/* Slang doesn't support KEY_SLEFT. */
case KEY_SLEFT:
shift_held = TRUE;
return sc_seq_or(do_left, keycode);
#endif
#ifdef KEY_SRIGHT
/* Slang doesn't support KEY_SRIGHT. */
case KEY_SRIGHT:
shift_held = TRUE;
return sc_seq_or(do_right, keycode);
#endif
#ifdef KEY_SUP
/* ncurses and Slang don't support KEY_SUP. */
case KEY_SUP:
return sc_seq_or(do_up_void, keycode);
#endif
case KEY_SR: /* Scroll backward, on Xfce4-terminal. */
shift_held = TRUE;
return sc_seq_or(do_up_void, keycode);
#ifdef KEY_SDOWN
/* ncurses and Slang don't support KEY_SDOWN. */
case KEY_SDOWN:
return sc_seq_or(do_down_void, keycode);
#endif
case KEY_SF: /* Scroll forward, on Xfce4-terminal. */
shift_held = TRUE;
return sc_seq_or(do_down_void, keycode);
#ifdef KEY_SHOME
/* HP-UX 10-11 and Slang don't support KEY_SHOME. */
case KEY_SHOME:
shift_held = TRUE;
#endif
case KEY_A1: /* Home (7) on keypad with NumLock off. */
return sc_seq_or(do_home, keycode);
#ifdef KEY_SEND
/* HP-UX 10-11 and Slang don't support KEY_SEND. */
case KEY_SEND:
shift_held = TRUE;
#endif
case KEY_C1: /* End (1) on keypad with NumLock off. */
return sc_seq_or(do_end, keycode);
#ifndef NANO_TINY
case SHIFT_PAGEUP: /* Fake key, from Shift+Alt+Up. */
shift_held = TRUE;
#endif
case KEY_A3: /* PageUp (9) on keypad with NumLock off. */
return sc_seq_or(do_page_up, keycode);
#ifndef NANO_TINY
case SHIFT_PAGEDOWN: /* Fake key, from Shift+Alt+Down. */
shift_held = TRUE;
#endif
case KEY_C3: /* PageDown (3) on keypad with NumLock off. */
return sc_seq_or(do_page_down, keycode);
#ifdef KEY_SDC
@ -646,6 +703,7 @@ int convert_sequence(const int *seq, size_t seq_len)
case 'B': /* Esc O 1 ; 2 B == Shift-Down on Terminal. */
case 'C': /* Esc O 1 ; 2 C == Shift-Right on Terminal. */
case 'D': /* Esc O 1 ; 2 D == Shift-Left on Terminal. */
shift_held = TRUE;
return arrow_from_abcd(seq[4]);
case 'P': /* Esc O 1 ; 2 P == F13 on Terminal. */
return KEY_F(13);
@ -851,9 +909,26 @@ int convert_sequence(const int *seq, size_t seq_len)
case 'B': /* Esc [ 1 ; 2 B == Shift-Down on xterm. */
case 'C': /* Esc [ 1 ; 2 C == Shift-Right on xterm. */
case 'D': /* Esc [ 1 ; 2 D == Shift-Left on xterm. */
shift_held = TRUE;
return arrow_from_abcd(seq[4]);
}
break;
#ifndef NANO_TINY
case '4':
/* When the arrow keys are held together with Shift+Meta,
* act as if they are Home/End/PgUp/PgDown with Shift. */
switch (seq[4]) {
case 'A': /* Esc [ 1 ; 4 A == Shift-Alt-Up on xterm. */
return SHIFT_PAGEUP;
case 'B': /* Esc [ 1 ; 4 B == Shift-Alt-Down on xterm. */
return SHIFT_PAGEDOWN;
case 'C': /* Esc [ 1 ; 4 C == Shift-Alt-Right on xterm. */
return KEY_SEND;
case 'D': /* Esc [ 1 ; 4 D == Shift-Alt-Left on xterm. */
return KEY_SHOME;
}
break;
#endif
case '5':
switch (seq[4]) {
case 'A': /* Esc [ 1 ; 5 A == Ctrl-Up on xterm. */
@ -866,6 +941,20 @@ int convert_sequence(const int *seq, size_t seq_len)
return CONTROL_LEFT;
}
break;
#ifndef NANO_TINY
case '6':
switch (seq[4]) {
case 'A': /* Esc [ 1 ; 6 A == Shift-Ctrl-Up on xterm. */
return shiftcontrolup;
case 'B': /* Esc [ 1 ; 6 B == Shift-Ctrl-Down on xterm. */
return shiftcontroldown;
case 'C': /* Esc [ 1 ; 6 C == Shift-Ctrl-Right on xterm. */
return shiftcontrolright;
case 'D': /* Esc [ 1 ; 6 D == Shift-Ctrl-Left on xterm. */
return shiftcontrolleft;
}
break;
#endif
}
} else if (seq_len > 2 && seq[2] == '~')
@ -1001,6 +1090,7 @@ int convert_sequence(const int *seq, size_t seq_len)
case 'b': /* Esc [ b == Shift-Down on rxvt/Eterm. */
case 'c': /* Esc [ c == Shift-Right on rxvt/Eterm. */
case 'd': /* Esc [ d == Shift-Left on rxvt/Eterm. */
shift_held = TRUE;
return arrow_from_abcd(seq[1]);
case '[':
if (seq_len > 2 ) {