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_set = FALSE;
openfile->mark_begin = NULL; openfile->mark_begin = NULL;
openfile->mark_begin_x = 0; openfile->mark_begin_x = 0;
openfile->kind_of_mark = SOFTMARK;
openfile->fmt = NIX_FILE; openfile->fmt = NIX_FILE;

View File

@ -40,6 +40,8 @@ bool console;
bool meta_key; bool meta_key;
/* Whether the current keystroke is a 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; bool focusing = TRUE;
/* Whether an update of the edit window should center the cursor. */ /* Whether an update of the edit window should center the cursor. */
@ -48,6 +50,8 @@ message_type lastmessage = HUSH;
#ifndef NANO_TINY #ifndef NANO_TINY
int controlleft, controlright, controlup, controldown; int controlleft, controlright, controlup, controldown;
int shiftcontrolleft, shiftcontrolright, shiftcontrolup, shiftcontroldown;
int shiftaltleft, shiftaltright, shiftaltup, shiftaltdown;
#endif #endif
#ifndef DISABLE_WRAPJUSTIFY #ifndef DISABLE_WRAPJUSTIFY

View File

@ -1689,8 +1689,26 @@ int do_input(bool allow_funcs)
} else } else
#endif #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. */ /* Execute the function of the shortcut. */
s->scfunc(); 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 #ifndef DISABLE_COLOR
if (f && !f->viewok) if (f && !f->viewok)
reset_multis(openfile->current, FALSE); reset_multis(openfile->current, FALSE);
@ -2539,6 +2557,16 @@ int main(int argc, char **argv)
controlright = get_keycode("kRIT5", CONTROL_RIGHT); controlright = get_keycode("kRIT5", CONTROL_RIGHT);
controlup = get_keycode("kUP5", CONTROL_UP); controlup = get_keycode("kUP5", CONTROL_UP);
controldown = get_keycode("kDN5", CONTROL_DOWN); 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 #endif
#ifndef USE_SLANG #ifndef USE_SLANG

View File

@ -179,6 +179,10 @@ typedef enum {
OVERWRITE, APPEND, PREPEND OVERWRITE, APPEND, PREPEND
} kind_of_writing_type; } kind_of_writing_type;
typedef enum {
SOFTMARK, HARDMARK
} mark_type;
typedef enum { typedef enum {
UPWARD, DOWNWARD UPWARD, DOWNWARD
} scroll_dir; } scroll_dir;
@ -402,6 +406,8 @@ typedef struct openfilestruct {
/* The file's line where the mark is, if any. */ /* The file's line where the mark is, if any. */
size_t mark_begin_x; size_t mark_begin_x;
/* The file's mark's x-coordinate position, if any. */ /* 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; file_format fmt;
/* The file's format. */ /* The file's format. */
undo *undotop; undo *undotop;
@ -560,6 +566,16 @@ enum
#define CONTROL_RIGHT 0x402 #define CONTROL_RIGHT 0x402
#define CONTROL_UP 0x403 #define CONTROL_UP 0x403
#define CONTROL_DOWN 0x404 #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 #ifndef NANO_TINY
/* An imaginary key for when we get a SIGWINCH (window resize). */ /* An imaginary key for when we get a SIGWINCH (window resize). */

View File

@ -35,6 +35,8 @@ extern bool console;
#endif #endif
extern bool meta_key; extern bool meta_key;
extern bool shift_held;
extern bool focusing; extern bool focusing;
extern message_type lastmessage; extern message_type lastmessage;
@ -44,6 +46,14 @@ extern int controlleft;
extern int controlright; extern int controlright;
extern int controlup; extern int controlup;
extern int controldown; 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 #endif
#ifndef DISABLE_WRAPJUSTIFY #ifndef DISABLE_WRAPJUSTIFY

View File

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

View File

@ -336,6 +336,7 @@ int parse_kbinput(WINDOW *win)
int *kbinput, keycode, retval = ERR; int *kbinput, keycode, retval = ERR;
meta_key = FALSE; meta_key = FALSE;
shift_held = FALSE;
/* Read in a character. */ /* Read in a character. */
kbinput = get_input(win, 1); kbinput = get_input(win, 1);
@ -504,25 +505,65 @@ int parse_kbinput(WINDOW *win)
return sc_seq_or(do_prev_block, 0); return sc_seq_or(do_prev_block, 0);
else if (retval == controldown) else if (retval == controldown)
return sc_seq_or(do_next_block, 0); 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 #endif
#if defined(__linux__) && !defined(NANO_TINY) #if defined(__linux__) && !defined(NANO_TINY)
/* When not running under X, check for the bare arrow keys whether /* When not running under X, check for the bare arrow keys whether
* the Ctrl key is being held together with them. */ * Shift/Ctrl/Alt are being held together with them. */
if (console && (retval == KEY_UP || retval == KEY_DOWN || unsigned char modifiers = 6;
retval == KEY_LEFT || retval == KEY_RIGHT)) {
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) if (retval == KEY_UP)
return sc_seq_or(do_prev_block, 0); return sc_seq_or(do_prev_block, 0);
else if (retval == KEY_DOWN) else if (retval == KEY_DOWN)
return sc_seq_or(do_next_block, 0); return sc_seq_or(do_next_block, 0);
else if (retval == KEY_LEFT) else if (retval == KEY_LEFT)
return sc_seq_or(do_prev_word_void, 0); return sc_seq_or(do_prev_word_void, 0);
else else if (retval == KEY_RIGHT)
return sc_seq_or(do_next_word_void, 0); 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 */ #endif /* __linux__ && !NANO_TINY */
@ -530,37 +571,53 @@ int parse_kbinput(WINDOW *win)
#ifdef KEY_SLEFT #ifdef KEY_SLEFT
/* Slang doesn't support KEY_SLEFT. */ /* Slang doesn't support KEY_SLEFT. */
case KEY_SLEFT: case KEY_SLEFT:
shift_held = TRUE;
return sc_seq_or(do_left, keycode); return sc_seq_or(do_left, keycode);
#endif #endif
#ifdef KEY_SRIGHT #ifdef KEY_SRIGHT
/* Slang doesn't support KEY_SRIGHT. */ /* Slang doesn't support KEY_SRIGHT. */
case KEY_SRIGHT: case KEY_SRIGHT:
shift_held = TRUE;
return sc_seq_or(do_right, keycode); return sc_seq_or(do_right, keycode);
#endif #endif
#ifdef KEY_SUP #ifdef KEY_SUP
/* ncurses and Slang don't support KEY_SUP. */ /* ncurses and Slang don't support KEY_SUP. */
case KEY_SUP: case KEY_SUP:
return sc_seq_or(do_up_void, keycode);
#endif #endif
case KEY_SR: /* Scroll backward, on Xfce4-terminal. */
shift_held = TRUE;
return sc_seq_or(do_up_void, keycode);
#ifdef KEY_SDOWN #ifdef KEY_SDOWN
/* ncurses and Slang don't support KEY_SDOWN. */ /* ncurses and Slang don't support KEY_SDOWN. */
case KEY_SDOWN: case KEY_SDOWN:
return sc_seq_or(do_down_void, keycode);
#endif #endif
case KEY_SF: /* Scroll forward, on Xfce4-terminal. */
shift_held = TRUE;
return sc_seq_or(do_down_void, keycode);
#ifdef KEY_SHOME #ifdef KEY_SHOME
/* HP-UX 10-11 and Slang don't support KEY_SHOME. */ /* HP-UX 10-11 and Slang don't support KEY_SHOME. */
case KEY_SHOME: case KEY_SHOME:
shift_held = TRUE;
#endif #endif
case KEY_A1: /* Home (7) on keypad with NumLock off. */ case KEY_A1: /* Home (7) on keypad with NumLock off. */
return sc_seq_or(do_home, keycode); return sc_seq_or(do_home, keycode);
#ifdef KEY_SEND #ifdef KEY_SEND
/* HP-UX 10-11 and Slang don't support KEY_SEND. */ /* HP-UX 10-11 and Slang don't support KEY_SEND. */
case KEY_SEND: case KEY_SEND:
shift_held = TRUE;
#endif #endif
case KEY_C1: /* End (1) on keypad with NumLock off. */ case KEY_C1: /* End (1) on keypad with NumLock off. */
return sc_seq_or(do_end, keycode); 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. */ case KEY_A3: /* PageUp (9) on keypad with NumLock off. */
return sc_seq_or(do_page_up, keycode); 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. */ case KEY_C3: /* PageDown (3) on keypad with NumLock off. */
return sc_seq_or(do_page_down, keycode); return sc_seq_or(do_page_down, keycode);
#ifdef KEY_SDC #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 'B': /* Esc O 1 ; 2 B == Shift-Down on Terminal. */
case 'C': /* Esc O 1 ; 2 C == Shift-Right on Terminal. */ case 'C': /* Esc O 1 ; 2 C == Shift-Right on Terminal. */
case 'D': /* Esc O 1 ; 2 D == Shift-Left on Terminal. */ case 'D': /* Esc O 1 ; 2 D == Shift-Left on Terminal. */
shift_held = TRUE;
return arrow_from_abcd(seq[4]); return arrow_from_abcd(seq[4]);
case 'P': /* Esc O 1 ; 2 P == F13 on Terminal. */ case 'P': /* Esc O 1 ; 2 P == F13 on Terminal. */
return KEY_F(13); 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 'B': /* Esc [ 1 ; 2 B == Shift-Down on xterm. */
case 'C': /* Esc [ 1 ; 2 C == Shift-Right on xterm. */ case 'C': /* Esc [ 1 ; 2 C == Shift-Right on xterm. */
case 'D': /* Esc [ 1 ; 2 D == Shift-Left on xterm. */ case 'D': /* Esc [ 1 ; 2 D == Shift-Left on xterm. */
shift_held = TRUE;
return arrow_from_abcd(seq[4]); return arrow_from_abcd(seq[4]);
} }
break; 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': case '5':
switch (seq[4]) { switch (seq[4]) {
case 'A': /* Esc [ 1 ; 5 A == Ctrl-Up on xterm. */ 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; return CONTROL_LEFT;
} }
break; 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] == '~') } 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 'b': /* Esc [ b == Shift-Down on rxvt/Eterm. */
case 'c': /* Esc [ c == Shift-Right on rxvt/Eterm. */ case 'c': /* Esc [ c == Shift-Right on rxvt/Eterm. */
case 'd': /* Esc [ d == Shift-Left on rxvt/Eterm. */ case 'd': /* Esc [ d == Shift-Left on rxvt/Eterm. */
shift_held = TRUE;
return arrow_from_abcd(seq[1]); return arrow_from_abcd(seq[1]);
case '[': case '[':
if (seq_len > 2 ) { if (seq_len > 2 ) {