From 858663444ecb261d362222b8227065551cdfcc68 Mon Sep 17 00:00:00 2001 From: Mark-Weston Date: Mon, 30 Apr 2018 23:10:27 +0300 Subject: [PATCH] new feature: an option to make the 'nextword' function stop at word ends When 'afterends' is set and Ctrl+Right or Shift+Ctrl+Right is pressed, nano will stop at the ends of words instead of their beginnings. Signed-off-by: Mark-Weston Signed-off-by: Benno Schulenberg --- doc/nano.1 | 3 +++ doc/nano.texi | 7 +++++++ doc/nanorc.5 | 3 +++ doc/sample.nanorc.in | 4 ++++ src/move.c | 26 +++++++++++++++++++++----- src/nano.c | 11 ++++++++++- src/nano.h | 3 ++- src/prompt.c | 13 ++++++++++++- src/proto.h | 2 +- src/rcfile.c | 1 + src/text.c | 4 ++-- syntax/nanorc.nanorc | 2 +- 12 files changed, 67 insertions(+), 12 deletions(-) diff --git a/doc/nano.1 b/doc/nano.1 index c7fb7433..c0c45ee4 100644 --- a/doc/nano.1 +++ b/doc/nano.1 @@ -250,6 +250,9 @@ Disable the hard-wrapping of long lines. This option conflicts with .BR \-x ", " \-\-nohelp Don't show the two help lines at the bottom of the screen. .TP +.BR \-y ", " \-\-afterends +Make Ctrl+Right stop at word ends instead of beginnings. +.TP .BR \-z ", " \-\-suspend Enable the suspend ability. .TP diff --git a/doc/nano.texi b/doc/nano.texi index cfe01edb..fe118f18 100644 --- a/doc/nano.texi +++ b/doc/nano.texi @@ -392,6 +392,10 @@ is located at the very bottom of the editor. Note: When accessing the help system, Expert Mode is temporarily disabled to display the help-system navigation keys. +@item -y +@itemx --afterends +Make Ctrl+Right stop at word ends instead of beginnings. + @item -z @itemx --suspend Enable the ability to suspend @command{nano} using the system's suspend @@ -689,6 +693,9 @@ The supported settings in a nanorc file are: @table @code +@item set afterends +Make Ctrl+Right stop at word ends instead of beginnings. + @item set allow_insecure_backup When backing up files, allow the backup to succeed even if its permissions can't be (re)set due to special OS considerations. diff --git a/doc/nanorc.5 b/doc/nanorc.5 index cd6076f8..eba39e76 100644 --- a/doc/nanorc.5 +++ b/doc/nanorc.5 @@ -53,6 +53,9 @@ match \fB"\fP, \fB'\fP, \fB)\fP, \fB>\fP, \fB]\fP, and \fB}\fP. The supported commands and arguments are: .TP 3 +.B set afterends +Make Ctrl+Right stop at word ends instead of beginnings. +.TP .B set allow_insecure_backup When backing up files, allow the backup to succeed even if its permissions can't be (re)set due to special OS considerations. You should diff --git a/doc/sample.nanorc.in b/doc/sample.nanorc.in index f5d90f2f..c3018bbc 100644 --- a/doc/sample.nanorc.in +++ b/doc/sample.nanorc.in @@ -15,6 +15,10 @@ ## its end. For example, for the "brackets" option, ""')>]}" will match ## ", ', ), >, ], and }. +## Make the 'nextword' function (Ctrl+Right) stop at word ends +## instead of at beginnings. +# set afterends + ## When soft line wrapping is enabled, make it wrap lines at blanks ## (tabs and spaces) instead of always at the edge of the screen. # set atblanks diff --git a/src/move.c b/src/move.c index d4dd718f..b7d4fe30 100644 --- a/src/move.c +++ b/src/move.c @@ -314,15 +314,17 @@ void do_prev_word(bool allow_punct, bool update_screen) edit_redraw(was_current, FLOWING); } -/* Move to the next word. If allow_punct is TRUE, treat punctuation +/* Move to the next word. If after_ends is TRUE, stop at the ends of words + * instead of their beginnings. If allow_punct is TRUE, treat punctuation * as part of a word. When requested, update the screen afterwards. * Return TRUE if we started on a word, and FALSE otherwise. */ -bool do_next_word(bool allow_punct, bool update_screen) +bool do_next_word(bool after_ends, bool allow_punct, bool update_screen) { filestruct *was_current = openfile->current; bool started_on_word = is_word_mbchar(openfile->current->data + openfile->current_x, allow_punct); bool seen_space = !started_on_word; + bool seen_word = started_on_word; /* Move forward until we reach the start of a word. */ while (TRUE) { @@ -340,6 +342,18 @@ bool do_next_word(bool allow_punct, bool update_screen) openfile->current_x); } +#ifndef NANO_TINY + if (after_ends) { + /* If this is a word character, continue; else it's a separator, + * and if we've already seen a word, then it's a word end. */ + if (is_word_mbchar(openfile->current->data + openfile->current_x, + allow_punct)) + seen_word = TRUE; + else if (seen_word) + break; + } else +#endif + { /* If this is not a word character, then it's a separator; else * if we've already seen a separator, then it's a word start. */ if (!is_word_mbchar(openfile->current->data + openfile->current_x, @@ -347,6 +361,7 @@ bool do_next_word(bool allow_punct, bool update_screen) seen_space = TRUE; else if (seen_space) break; + } } if (update_screen) @@ -363,11 +378,12 @@ void do_prev_word_void(void) do_prev_word(ISSET(WORD_BOUNDS), TRUE); } -/* Move to the next word in the file, treating punctuation as part of a word - * if the WORD_BOUNDS flag is set, and update the screen afterwards. */ +/* Move to the next word in the file. If the AFTER_ENDS flag is set, stop + * at word ends instead of beginnings. If the WORD_BOUNDS flag is set, treat + * punctuation as part of a word. Update the screen afterwards. */ void do_next_word_void(void) { - do_next_word(ISSET(WORD_BOUNDS), TRUE); + do_next_word(ISSET(AFTER_ENDS), ISSET(WORD_BOUNDS), TRUE); } /* Move to the beginning of the current line (or softwrapped chunk). diff --git a/src/nano.c b/src/nano.c index 2620b418..4feb8524 100644 --- a/src/nano.c +++ b/src/nano.c @@ -888,6 +888,9 @@ void usage(void) print_opt("-w", "--nowrap", N_("Don't hard-wrap long lines")); #endif print_opt("-x", "--nohelp", N_("Don't show the two help lines")); +#ifndef NANO_TINY + print_opt("-y", "--afterends", N_("Make Ctrl+Right stop at word ends")); +#endif if (!ISSET(RESTRICTED)) print_opt("-z", "--suspend", N_("Enable suspension")); #ifndef NANO_TINY @@ -2003,6 +2006,7 @@ int main(int argc, char **argv) {"autoindent", 0, NULL, 'i'}, {"cutfromcursor", 0, NULL, 'k'}, {"unix", 0, NULL, 'u'}, + {"afterends", 0, NULL, 'y'}, {"softwrap", 0, NULL, '$'}, #endif {NULL, 0, NULL, 0} @@ -2061,7 +2065,7 @@ int main(int argc, char **argv) while ((optchr = getopt_long(argc, argv, - "ABC:DEFGHIKLMNOPQ:RST:UVWX:Y:abcdefghijklmno:pqr:s:tuvwxz$", + "ABC:DEFGHIKLMNOPQ:RST:UVWX:Y:abcdefghijklmno:pqr:s:tuvwxyz$", long_options, NULL)) != -1) { switch (optchr) { case 'b': @@ -2256,6 +2260,11 @@ int main(int argc, char **argv) case 'x': SET(NO_HELP); break; +#ifndef NANO_TINY + case 'y': + SET(AFTER_ENDS); + break; +#endif case 'z': SET(SUSPEND); break; diff --git a/src/nano.h b/src/nano.h index 17a52369..15eadd5d 100644 --- a/src/nano.h +++ b/src/nano.h @@ -543,7 +543,8 @@ enum SHOW_CURSOR, LINE_NUMBERS, NO_PAUSES, - AT_BLANKS + AT_BLANKS, + AFTER_ENDS }; /* Flags for the menus in which a given function should be present. */ diff --git a/src/prompt.c b/src/prompt.c index e7cb7418..b14e8592 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -292,17 +292,28 @@ void do_statusbar_cut_text(void) void do_statusbar_next_word(void) { bool seen_space = !is_word_mbchar(answer + statusbar_x, FALSE); + bool seen_word = !seen_space; - /* Move forward until we reach the start of a word. */ + /* Move forward until we reach either the end or the start of a word, + * depending on whether the AFTER_ENDS flag is set or not. */ while (answer[statusbar_x] != '\0') { statusbar_x = move_mbright(answer, statusbar_x); + if (ISSET(AFTER_ENDS)) { + /* If this is a word character, continue; else it's a separator, + * and if we've already seen a word, then it's a word end. */ + if (is_word_mbchar(answer + statusbar_x, FALSE)) + seen_word = TRUE; + else if (seen_word) + break; + } else { /* If this is not a word character, then it's a separator; else * if we've already seen a separator, then it's a word start. */ if (!is_word_mbchar(answer + statusbar_x, FALSE)) seen_space = TRUE; else if (seen_space) break; + } } update_the_statusbar(); diff --git a/src/proto.h b/src/proto.h index 440af6a0..8cc8d14f 100644 --- a/src/proto.h +++ b/src/proto.h @@ -380,7 +380,7 @@ void do_para_end_void(void); void do_prev_block(void); void do_next_block(void); void do_prev_word(bool allow_punct, bool update_screen); -bool do_next_word(bool allow_punct, bool update_screen); +bool do_next_word(bool after_ends, bool allow_punct, bool update_screen); void do_prev_word_void(void); void do_next_word_void(void); void do_home(void); diff --git a/src/rcfile.c b/src/rcfile.c index afa172ec..50a4e204 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -88,6 +88,7 @@ static const rcoption rcopts[] = { {"tempfile", TEMP_FILE}, {"view", VIEW_MODE}, #ifndef NANO_TINY + {"afterends", AFTER_ENDS}, {"allow_insecure_backup", INSECURE_BACKUP}, {"atblanks", AT_BLANKS}, {"autoindent", AUTOINDENT}, diff --git a/src/text.c b/src/text.c index 7f0bdb33..6d0cfac5 100644 --- a/src/text.c +++ b/src/text.c @@ -209,7 +209,7 @@ void do_cutword(bool backward) if (backward) do_prev_word(ISSET(WORD_BOUNDS), FALSE); else - do_next_word(ISSET(WORD_BOUNDS), FALSE); + do_next_word(FALSE, ISSET(WORD_BOUNDS), FALSE); /* Set the mark at the start of that word. */ openfile->mark = openfile->current; @@ -3459,7 +3459,7 @@ void do_wordlinechar_count(void) * count whenever we're on a word just before moving. */ while (openfile->current != openfile->filebot || openfile->current->data[openfile->current_x] != '\0') { - if (do_next_word(TRUE, FALSE)) + if (do_next_word(FALSE, TRUE, FALSE)) words++; } diff --git a/syntax/nanorc.nanorc b/syntax/nanorc.nanorc index f71088cc..5ce84efb 100644 --- a/syntax/nanorc.nanorc +++ b/syntax/nanorc.nanorc @@ -7,7 +7,7 @@ comment "#" icolor brightred "^[[:space:]]*((un)?(bind|set)|include|syntax|header|magic|comment|linter|formatter|i?color|extendsyntax).*$" # Keywords -icolor brightgreen "^[[:space:]]*(set|unset)[[:space:]]+(allow_insecure_backup|atblanks|autoindent|backup|backwards|boldtext|casesensitive|constantshow|cutfromcursor|fill[[:space:]]+-?[[:digit:]]+|historylog|linenumbers|locking|morespace|mouse|multibuffer|noconvert|nohelp|nopauses|nonewlines|nowrap|positionlog|preserve|quickblank|quiet|rebinddelete|rebindkeypad|regexp|showcursor|smarthome|smooth|softwrap|suspend|tabsize[[:space:]]+[1-9][0-9]*|tabstospaces|tempfile|trimblanks|unix|view|wordbounds)\>" +icolor brightgreen "^[[:space:]]*(set|unset)[[:space:]]+(afterends|allow_insecure_backup|atblanks|autoindent|backup|backwards|boldtext|casesensitive|constantshow|cutfromcursor|fill[[:space:]]+-?[[:digit:]]+|historylog|linenumbers|locking|morespace|mouse|multibuffer|noconvert|nohelp|nopauses|nonewlines|nowrap|positionlog|preserve|quickblank|quiet|rebinddelete|rebindkeypad|regexp|showcursor|smarthome|smooth|softwrap|suspend|tabsize[[:space:]]+[1-9][0-9]*|tabstospaces|tempfile|trimblanks|unix|view|wordbounds)\>" icolor yellow "^[[:space:]]*set[[:space:]]+((error|function|key|number|selected|status|title)color)[[:space:]]+(bright)?(white|black|red|blue|green|yellow|magenta|cyan|normal)?(,(white|black|red|blue|green|yellow|magenta|cyan|normal))?\>" icolor brightgreen "^[[:space:]]*set[[:space:]]+(backupdir|brackets|errorcolor|functioncolor|keycolor|matchbrackets|numbercolor|operatingdir|punct|quotestr|selectedcolor|speller|statuscolor|titlecolor|whitespace|wordchars)[[:space:]]+" icolor brightgreen "^[[:space:]]*bind[[:space:]]+((\^([[:alpha:]]|[]0-9\^_]|Space)|M-([[:alpha:]]|[]!"#$%&'()*+,./0-9:;<=>?@\^_`{|}~-]|Space))|F([1-9]|1[0-6])|Ins|Del)[[:space:]]+([[:alpha:]]+|".*")[[:space:]]+(all|main|search|replace(with)?|gotoline|writeout|insert|ext(ernal)?cmd|help|spell|linter|browser|whereisfile|gotodir)([[:space:]]+#|[[:space:]]*$)"