diff --git a/doc/man/nanorc.5 b/doc/man/nanorc.5 index 7c26b59c..c9279c46 100644 --- a/doc/man/nanorc.5 +++ b/doc/man/nanorc.5 @@ -510,6 +510,13 @@ Moves the cursor to the beginning of the current paragraph. .B endpara Moves the cursor to the end of the current paragraph. .TP +.B prevblock +Moves the cursor to the beginning of the current or preceding block of text. +(Blocks are separated by one or more blank lines.) +.TP +.B nextblock +Moves the cursor to the beginning of the next block of text. +.TP .B prevpage Goes up one screenful. .TP diff --git a/doc/texinfo/nano.texi b/doc/texinfo/nano.texi index 509d749a..fdc5ae33 100644 --- a/doc/texinfo/nano.texi +++ b/doc/texinfo/nano.texi @@ -1102,6 +1102,13 @@ Moves the cursor to the beginning of the current paragraph. @item endpara Moves the cursor to the end of the current paragraph. +@item prevblock +Moves the cursor to the beginning of the current or preceding block of text. +(Blocks are separated by one or more blank lines.) + +@item nextblock +Moves the cursor to the beginning of the next block of text. + @item prevpage Goes up one screenful. diff --git a/src/global.c b/src/global.c index ca7d4e1e..e2d8749f 100644 --- a/src/global.c +++ b/src/global.c @@ -46,6 +46,8 @@ message_type lastmessage = HUSH; #ifndef NANO_TINY int controlleft = CONTROL_LEFT; int controlright = CONTROL_RIGHT; +int controlup = CONTROL_UP; +int controldown = CONTROL_DOWN; #endif #ifndef DISABLE_WRAPJUSTIFY @@ -573,6 +575,10 @@ void shortcut_init(void) const char *nano_nextline_msg = N_("Go to next line"); const char *nano_home_msg = N_("Go to beginning of current line"); const char *nano_end_msg = N_("Go to end of current line"); +#ifndef NANO_TINY + const char *nano_prevblock_msg = N_("Go to previous block of text"); + const char *nano_nextblock_msg = N_("Go to next block of text"); +#endif #ifndef DISABLE_JUSTIFY const char *nano_parabegin_msg = N_("Go to beginning of paragraph; then of previous paragraph"); @@ -872,6 +878,13 @@ void shortcut_init(void) add_to_funcs(do_down_void, MMAIN|MBROWSER, next_line_tag, IFSCHELP(nano_nextline_msg), BLANKAFTER, VIEW); +#ifndef NANO_TINY + add_to_funcs(do_prev_block, MMAIN, + N_("Prev Block"), IFSCHELP(nano_prevblock_msg), TOGETHER, VIEW); + add_to_funcs(do_next_block, MMAIN, + N_("Next Block"), IFSCHELP(nano_nextblock_msg), TOGETHER, VIEW); +#endif + #ifndef DISABLE_JUSTIFY add_to_funcs(do_para_begin_void, MMAIN|MWHEREIS, N_("Beg of Par"), IFSCHELP(nano_parabegin_msg), TOGETHER, VIEW); @@ -1133,6 +1146,10 @@ void shortcut_init(void) add_to_sclist(MMAIN|MHELP|MBROWSER, "Up", do_up_void, 0); add_to_sclist(MMAIN|MHELP|MBROWSER, "^N", do_down_void, 0); add_to_sclist(MMAIN|MHELP|MBROWSER, "Down", do_down_void, 0); +#ifndef NANO_TINY + add_to_sclist(MMAIN, "M-7", do_prev_block, 0); + add_to_sclist(MMAIN, "M-8", do_next_block, 0); +#endif #ifndef DISABLE_JUSTIFY add_to_sclist(MMAIN, "M-(", do_para_begin_void, 0); add_to_sclist(MMAIN, "M-9", do_para_begin_void, 0); @@ -1453,6 +1470,10 @@ sc *strtosc(const char *input) s->scfunc = do_cut_prev_word; else if (!strcasecmp(input, "cutwordright")) s->scfunc = do_cut_next_word; + else if (!strcasecmp(input, "prevblock")) + s->scfunc = do_prev_block; + else if (!strcasecmp(input, "nextblock")) + s->scfunc = do_next_block; else if (!strcasecmp(input, "findbracket")) s->scfunc = do_find_bracket; else if (!strcasecmp(input, "wordcount")) diff --git a/src/move.c b/src/move.c index 2f234e51..9d3bd797 100644 --- a/src/move.c +++ b/src/move.c @@ -210,6 +210,48 @@ void do_para_end_void(void) #endif /* !DISABLE_JUSTIFY */ #ifndef NANO_TINY +/* Move to the preceding block of text in the file. */ +void do_prev_block(void) +{ + filestruct *was_current = openfile->current; + bool is_text = FALSE, seen_text = FALSE; + + /* Skip backward until first blank line after some nonblank line(s). */ + while (openfile->current->prev != NULL && (!seen_text || is_text)) { + openfile->current = openfile->current->prev; + is_text = !white_string(openfile->current->data); + seen_text = seen_text || is_text; + } + + /* Step forward one line again if this one is blank. */ + if (openfile->current->next != NULL && + white_string(openfile->current->data)) + openfile->current = openfile->current->next; + + openfile->current_x = 0; + edit_redraw(was_current); + do_home(); +} + +/* Move to the next block of text in the file. */ +void do_next_block(void) +{ + filestruct *was_current = openfile->current; + bool is_white = white_string(openfile->current->data); + bool seen_white = is_white; + + /* Skip forward until first nonblank line after some blank line(s). */ + while (openfile->current->next != NULL && (!seen_white || is_white)) { + openfile->current = openfile->current->next; + is_white = white_string(openfile->current->data); + seen_white = seen_white || is_white; + } + + openfile->current_x = 0; + edit_redraw(was_current); + do_home(); +} + /* Move to the previous word in the file. If allow_punct is TRUE, treat * punctuation as part of a word. If allow_update is TRUE, update the * screen afterwards. */ diff --git a/src/nano.c b/src/nano.c index d6846b74..74e1e60a 100644 --- a/src/nano.c +++ b/src/nano.c @@ -2527,13 +2527,19 @@ int main(int argc, char **argv) #if !defined(NANO_TINY) && defined(HAVE_KEY_DEFINED) const char *keyvalue; - /* Ask ncurses for the key codes for Control+Left and Control+Right. */ + /* Ask ncurses for the key codes for Control+Left/Right/Up/Down. */ keyvalue = tigetstr("kLFT5"); if (keyvalue != 0 && keyvalue != (char *)-1) controlleft = key_defined(keyvalue); keyvalue = tigetstr("kRIT5"); if (keyvalue != 0 && keyvalue != (char *)-1) controlright = key_defined(keyvalue); + keyvalue = tigetstr("kUP5"); + if (keyvalue != 0 && keyvalue != (char *)-1) + controlup = key_defined(keyvalue); + keyvalue = tigetstr("kDN5"); + if (keyvalue != 0 && keyvalue != (char *)-1) + controldown = key_defined(keyvalue); #endif #ifndef USE_SLANG diff --git a/src/nano.h b/src/nano.h index b2e154a1..7403833d 100644 --- a/src/nano.h +++ b/src/nano.h @@ -564,6 +564,8 @@ enum /* Codes for "modified" Arrow keys, beyond KEY_MAX of ncurses. */ #define CONTROL_LEFT 0x401 #define CONTROL_RIGHT 0x402 +#define CONTROL_UP 0x403 +#define CONTROL_DOWN 0x404 #ifndef NANO_TINY /* An imaginary key for when we get a SIGWINCH (window resize). */ diff --git a/src/proto.h b/src/proto.h index 9ce7feea..6b938cb6 100644 --- a/src/proto.h +++ b/src/proto.h @@ -39,6 +39,8 @@ extern message_type lastmessage; #ifndef NANO_TINY extern int controlleft; extern int controlright; +extern int controlup; +extern int controldown; #endif #ifndef DISABLE_WRAPJUSTIFY @@ -397,6 +399,8 @@ void do_para_end(bool allow_update); void do_para_end_void(void); #endif #ifndef NANO_TINY +void do_prev_block(void); +void do_next_block(void); void do_prev_word(bool allow_punct, bool allow_update); void do_prev_word_void(void); bool do_next_word(bool allow_punct, bool allow_update); @@ -647,6 +651,7 @@ void do_tab(void); void do_indent(ssize_t cols); void do_indent_void(void); void do_unindent(void); +bool white_string(const char *s); void do_undo(void); void do_redo(void); #endif diff --git a/src/winio.c b/src/winio.c index c9786679..1ae8a910 100644 --- a/src/winio.c +++ b/src/winio.c @@ -635,6 +635,10 @@ int parse_kbinput(WINDOW *win) retval = sc_seq_or(do_prev_word_void, 0); else if (retval == controlright) retval = sc_seq_or(do_next_word_void, 0); + else if (retval == controlup) + retval = sc_seq_or(do_prev_block, 0); + else if (retval == controldown) + retval = sc_seq_or(do_next_block, 0); #endif /* If our result is an extended keypad value (i.e. a value @@ -696,8 +700,9 @@ int convert_sequence(const int *seq, size_t seq_len) if (seq_len >= 5) { switch (seq[4]) { case 'A': /* Esc O 1 ; 5 A == Ctrl-Up on Terminal. */ + return CONTROL_UP; case 'B': /* Esc O 1 ; 5 B == Ctrl-Down on Terminal. */ - return arrow_from_abcd(seq[4]); + return CONTROL_DOWN; case 'C': /* Esc O 1 ; 5 C == Ctrl-Right on Terminal. */ return CONTROL_RIGHT; case 'D': /* Esc O 1 ; 5 D == Ctrl-Left on Terminal. */ @@ -766,8 +771,9 @@ int convert_sequence(const int *seq, size_t seq_len) case 'Y': /* Esc O Y == F10 on Mach console. */ return KEY_F(10); case 'a': /* Esc O a == Ctrl-Up on rxvt. */ + return CONTROL_UP; case 'b': /* Esc O b == Ctrl-Down on rxvt. */ - return arrow_from_abcd(seq[1]); + return CONTROL_DOWN; case 'c': /* Esc O c == Ctrl-Right on rxvt. */ return CONTROL_RIGHT; case 'd': /* Esc O d == Ctrl-Left on rxvt. */ @@ -841,8 +847,9 @@ int convert_sequence(const int *seq, size_t seq_len) case 'o': switch (seq[1]) { case 'a': /* Esc o a == Ctrl-Up on Eterm. */ + return CONTROL_UP; case 'b': /* Esc o b == Ctrl-Down on Eterm. */ - return arrow_from_abcd(seq[1]); + return CONTROL_DOWN; case 'c': /* Esc o c == Ctrl-Right on Eterm. */ return CONTROL_RIGHT; case 'd': /* Esc o d == Ctrl-Left on Eterm. */ @@ -895,8 +902,9 @@ int convert_sequence(const int *seq, size_t seq_len) if (seq_len >= 5) { switch (seq[4]) { case 'A': /* Esc [ 1 ; 5 A == Ctrl-Up on xterm. */ + return CONTROL_UP; case 'B': /* Esc [ 1 ; 5 B == Ctrl-Down on xterm. */ - return arrow_from_abcd(seq[4]); + return CONTROL_DOWN; case 'C': /* Esc [ 1 ; 5 C == Ctrl-Right on xterm. */ return CONTROL_RIGHT; case 'D': /* Esc [ 1 ; 5 D == Ctrl-Left on xterm. */