Hi Thanks for the diff,
I think I'd prefer to see a change to add a vi-style next-word now and the nonspace stuff separately, if that is possible. If it is going to be too time-consuming don't worry. > Index: mode-key.c > =================================================================== > --- mode-key.c.orig > +++ mode-key.c > @@ -83,12 +83,16 @@ > { MODEKEYCOPY_COPYSELECTION, "copy-selection" }, > { MODEKEYCOPY_DOWN, "cursor-down" }, > { MODEKEYCOPY_ENDOFLINE, "end-of-line" }, > + { MODEKEYCOPY_ENDOFNONSPACEWORD, "end-of-nonspace-word" }, I don't like the use of "nonspace" in these commands, but I haven't thought of better names so far. > + { MODEKEYCOPY_ENDOFWORD, "end-of-word" }, > { MODEKEYCOPY_GOTOLINE, "goto-line" }, > { MODEKEYCOPY_LEFT, "cursor-left" }, > { MODEKEYCOPY_MIDDLELINE, "middle-line" }, > { MODEKEYCOPY_NEXTPAGE, "page-down" }, > + { MODEKEYCOPY_NEXTNONSPACEWORD, "next-nonspace-word" }, > { MODEKEYCOPY_NEXTWORD, "next-word" }, > { MODEKEYCOPY_PREVIOUSPAGE, "page-up" }, > + { MODEKEYCOPY_PREVIOUSNONSPACEWORD, "previous-nonspace-word" }, > { MODEKEYCOPY_PREVIOUSWORD, "previous-word" }, > { MODEKEYCOPY_RIGHT, "cursor-right" }, > { MODEKEYCOPY_SCROLLDOWN, "scroll-down" }, > @@ -164,11 +168,14 @@ > { '0', 0, MODEKEYCOPY_STARTOFLINE }, > { ':', 0, MODEKEYCOPY_GOTOLINE }, > { '?', 0, MODEKEYCOPY_SEARCHUP }, > + { 'B', 0, MODEKEYCOPY_PREVIOUSNONSPACEWORD }, > + { 'E', 0, MODEKEYCOPY_ENDOFNONSPACEWORD }, > { 'H', 0, MODEKEYCOPY_TOPLINE }, > { 'J', 0, MODEKEYCOPY_SCROLLDOWN }, > { 'K', 0, MODEKEYCOPY_SCROLLUP }, > { 'L', 0, MODEKEYCOPY_BOTTOMLINE }, > { 'M', 0, MODEKEYCOPY_MIDDLELINE }, > + { 'W', 0, MODEKEYCOPY_NEXTNONSPACEWORD }, > { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE }, > { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, > { '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN }, > @@ -181,6 +188,7 @@ > { '\r', 0, MODEKEYCOPY_COPYSELECTION }, > { '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, > { 'b', 0, MODEKEYCOPY_PREVIOUSWORD }, > + { 'e', 0, MODEKEYCOPY_ENDOFWORD }, > { 'h', 0, MODEKEYCOPY_LEFT }, > { 'j', 0, MODEKEYCOPY_DOWN }, > { 'k', 0, MODEKEYCOPY_UP }, > @@ -269,7 +277,7 @@ > { '\027' /* C-w */, 0, MODEKEYCOPY_COPYSELECTION }, > { '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL }, > { 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD }, > - { 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORD }, > + { 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_ENDOFWORD }, > { 'g', 0, MODEKEYCOPY_GOTOLINE }, > { 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION }, > { 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, > Index: tmux.h > =================================================================== > --- tmux.h.orig > +++ tmux.h > @@ -451,14 +451,18 @@ > MODEKEYCOPY_COPYSELECTION, > MODEKEYCOPY_DOWN, > MODEKEYCOPY_ENDOFLINE, > + MODEKEYCOPY_ENDOFNONSPACEWORD, > + MODEKEYCOPY_ENDOFWORD, > MODEKEYCOPY_GOTOLINE, > MODEKEYCOPY_HALFPAGEDOWN, > MODEKEYCOPY_HALFPAGEUP, > MODEKEYCOPY_LEFT, > MODEKEYCOPY_MIDDLELINE, > MODEKEYCOPY_NEXTPAGE, > + MODEKEYCOPY_NEXTNONSPACEWORD, > MODEKEYCOPY_NEXTWORD, > MODEKEYCOPY_PREVIOUSPAGE, > + MODEKEYCOPY_PREVIOUSNONSPACEWORD, > MODEKEYCOPY_PREVIOUSWORD, > MODEKEYCOPY_RIGHT, > MODEKEYCOPY_SCROLLDOWN, > Index: window-copy.c > =================================================================== > --- window-copy.c.orig > +++ window-copy.c > @@ -54,7 +54,7 @@ > void window_copy_copy_selection(struct window_pane *, struct client *); > void window_copy_copy_line( > struct window_pane *, char **, size_t *, u_int, u_int, u_int); > -int window_copy_is_space(struct window_pane *, u_int, u_int); > +int window_copy_strchr(struct window_pane *, u_int, u_int, const char *); > u_int window_copy_find_length(struct window_pane *, u_int); > void window_copy_cursor_start_of_line(struct window_pane *); > void window_copy_cursor_back_to_indentation(struct window_pane *); > @@ -63,8 +63,8 @@ > void window_copy_cursor_right(struct window_pane *); > void window_copy_cursor_up(struct window_pane *, int); > void window_copy_cursor_down(struct window_pane *, int); > -void window_copy_cursor_next_word(struct window_pane *); > -void window_copy_cursor_previous_word(struct window_pane *); > +void window_copy_cursor_next_word(struct window_pane *, const char *, int); > +void window_copy_cursor_previous_word(struct window_pane *, const char *); > void window_copy_scroll_up(struct window_pane *, u_int); > void window_copy_scroll_down(struct window_pane *, u_int); > > @@ -84,6 +84,11 @@ > WINDOW_COPY_GOTOLINE, > }; > > +enum word_search_mode { > + WORD_SEARCH_START_OF_WORD, > + WORD_SEARCH_END_OF_WORD, > +}; I'd make this something like enum window_copy_search_mode, WINDOW_COPY_WORDSTART, WINDOW_COPY_WORDEND. > + > struct window_copy_mode_data { > struct screen screen; > > @@ -108,6 +113,8 @@ > char *searchstr; > }; > > +const char *window_copy_word_delims = " -_@"; I think this is still only used in one function so it can remain local, although it could be static in there. > + > struct screen * > window_copy_init(struct window_pane *wp) > { > @@ -319,11 +326,27 @@ > case MODEKEYCOPY_ENDOFLINE: > window_copy_cursor_end_of_line(wp); > break; > + case MODEKEYCOPY_ENDOFNONSPACEWORD: > + window_copy_cursor_next_word( > + wp, " ", WORD_SEARCH_END_OF_WORD); > + break; > + case MODEKEYCOPY_ENDOFWORD: > + window_copy_cursor_next_word( > + wp, window_copy_word_delims, WORD_SEARCH_END_OF_WORD); > + break; > + case MODEKEYCOPY_NEXTNONSPACEWORD: > + window_copy_cursor_next_word( > + wp, " ", WORD_SEARCH_START_OF_WORD); > + break; > case MODEKEYCOPY_NEXTWORD: > - window_copy_cursor_next_word(wp); > + window_copy_cursor_next_word( > + wp, window_copy_word_delims, WORD_SEARCH_START_OF_WORD); > + break; > + case MODEKEYCOPY_PREVIOUSNONSPACEWORD: > + window_copy_cursor_previous_word(wp, " "); > break; > case MODEKEYCOPY_PREVIOUSWORD: > - window_copy_cursor_previous_word(wp); > + window_copy_cursor_previous_word(wp, window_copy_word_delims); > break; > case MODEKEYCOPY_SEARCHUP: > data->inputtype = WINDOW_COPY_SEARCHUP; > @@ -945,17 +968,17 @@ > } > > int > -window_copy_is_space(struct window_pane *wp, u_int px, u_int py) > +window_copy_strchr( > + struct window_pane *wp, u_int px, u_int py, const char *chars) > { > const struct grid_cell *gc; > - const char *spaces = " -_@"; > > gc = grid_peek_cell(wp->base.grid, px, py); > if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) > return (0); > if (gc->data == 0x00 || gc->data == 0x7f) > return (0); > - return (strchr(spaces, gc->data) != NULL); > + return (strchr(chars, gc->data) != NULL); > } > > u_int > @@ -1005,10 +1028,6 @@ > py = screen_hsize(&wp->base) + data->cy - data->oy; > xx = window_copy_find_length(wp, py); > > - /* > - * Don't use window_copy_is_space because that treats some word > - * delimiters as spaces. > - */ > while (px < xx) { > gc = grid_peek_cell(wp->base.grid, px, py); > if (gc->flags & GRID_FLAG_UTF8) > @@ -1133,26 +1152,31 @@ > } > > void > -window_copy_cursor_next_word(struct window_pane *wp) > +window_copy_cursor_next_word( > + struct window_pane *wp, const char *nonword, int mode) > { > struct window_copy_mode_data *data = wp->modedata; > struct screen *s = &data->screen; > - u_int px, py, xx, skip; > + u_int px, py, xx, search_for_nonword; > + u_int stop_at_end; > > px = data->cx; > py = screen_hsize(&wp->base) + data->cy - data->oy; > xx = window_copy_find_length(wp, py); > > - skip = 1; > + stop_at_end = (mode == WORD_SEARCH_END_OF_WORD); > + search_for_nonword = 1; > if (px < xx) { > /* If currently on a space, skip space. */ > - if (window_copy_is_space(wp, px, py)) > - skip = 0; > + if (window_copy_strchr(wp, px, py, nonword)) > + search_for_nonword = 0; > } else > - skip = 0; > + search_for_nonword = 0; > for (;;) { > + u_int is_space; > + > if (px >= xx) { > - if (skip) { > + if (search_for_nonword && stop_at_end) { > px = xx; > break; > } > @@ -1172,14 +1196,17 @@ > } > } > > - if (skip) { > - /* Currently skipping non-space (until space). */ > - if (window_copy_is_space(wp, px, py)) > - break; > - } else { > - /* Currently skipping space (until non-space). */ > - if (!window_copy_is_space(wp, px, py)) > - skip = 1; > + is_space = window_copy_strchr(wp, px, py, nonword); > + if ((is_space && search_for_nonword && stop_at_end) > + || (!is_space && !search_for_nonword && !stop_at_end)) { > + /* If we've reached the spot we're looking for, we're > + * done looking. Yay tautologies! :) */ > + break; > + } else if (is_space == search_for_nonword) { > + /* If we're not stopping yet, but we've just > + * reached a word-boundary, then toggle > + * search_for_nonword to indicate that. */ > + search_for_nonword = !search_for_nonword; > } I wonder if there is a way to do this that is easier to read than adding extra flags, although the current code isn't perfect. We got rid of the skip flag in window_copy_cursor_previous_word maybe it isn't still necessary in here. If you can break the diff into two I'll have a closer look at this. > > px++; > @@ -1193,7 +1220,7 @@ > > /* Move to the previous place where a word begins. */ > void > -window_copy_cursor_previous_word(struct window_pane *wp) > +window_copy_cursor_previous_word(struct window_pane *wp, const char *nonword) > { > struct window_copy_mode_data *data = wp->modedata; > u_int px, py; > @@ -1205,7 +1232,7 @@ > for (;;) { > if (px > 0) { > px--; > - if (!window_copy_is_space(wp, px, py)) > + if (!window_copy_strchr(wp, px, py, nonword)) > break; > } else { > if (data->cy == 0 && > @@ -1221,7 +1248,7 @@ > } > > /* Move back to the beginning of this word. */ > - while (px > 0 && !window_copy_is_space(wp, px - 1, py)) > + while (px > 0 && !window_copy_strchr(wp, px - 1, py, nonword)) > px--; > > out: > Index: tmux.1 > =================================================================== > --- tmux.1.orig > +++ tmux.1 > @@ -535,7 +535,7 @@ > .Ic mode-keys > option). > The following keys are supported as appropriate for the mode: > -.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent > +.Bl -column "FunctionXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent > .It Sy "Function" Ta Sy "vi" Ta Sy "emacs" > .It Li "Back to indentation" Ta "^" Ta "M-m" > .It Li "Clear selection" Ta "Escape" Ta "C-g" > @@ -550,14 +550,18 @@ > .It Li "Delete entire line" Ta "d" Ta "C-u" > .It Li "Delete to end of line" Ta "D" Ta "C-k" > .It Li "End of line" Ta "$" Ta "C-e" > +.It Li "End of non-space word" Ta "E" Ta "" > +.It Li "End of word" Ta "e" Ta "M-f" > .It Li "Goto line" Ta ":" Ta "g" > .It Li "Half page down" Ta "C-d" Ta "M-Down" > .It Li "Half page up" Ta "C-u" Ta "M-Up" > .It Li "Next page" Ta "C-f" Ta "Page down" > -.It Li "Next word" Ta "w" Ta "M-f" > +.It Li "Next non-space word" Ta "W" Ta "" > +.It Li "Next word" Ta "w" Ta "" > .It Li "Paste buffer" Ta "p" Ta "C-y" > .It Li "Previous page" Ta "C-b" Ta "Page up" > .It Li "Previous word" Ta "b" Ta "M-b" > +.It Li "Previous non-space word" Ta "B" Ta "" > .It Li "Quit mode" Ta "q" Ta "Escape" > .It Li "Scroll down" Ta "C-Down or C-e" Ta "C-Down" > .It Li "Scroll up" Ta "C-Up or C-y" Ta "C-Up" > On Sun, Jan 24, 2010 at 07:14:16PM -0800, Micah Cowan wrote: > = Background = > > I've noticed that the "next-word" copy-mode command, bound to "M-f" in > emacs-mode and to "w" in vi-mode, behaves more like vi's "e", which > skips to the next word-ending, than its "w", which skips to the next > word-beginning. > > Also, the vi copy mode currently lacks vi's uppercased equivalents to b, > w and e (B, W, and E), which behave the same, but treat all non-space > characters as "word" characters. > > = Functional changes = > > This patch remedies this situation, by renaming the current "next-word" > as "end-of-word", and using "next-word" to mean "go to the next start of > a word". Emacs' "M-f" is now bound to "end-of-word" (behaves exactly as > it has), vi's "e", rather than "w", is now bound to "end-of-word", and > "w" is bound to "next-word" (as it was, but the behavior of that command > is now different). The new "next-word" has nothing bound to it for emacs > (and Emacs has no equivalent word-movement; when I've wanted to move to > the beginning of the next word in Emacs, I've typically typed M-f M-f > M-b to get there). > > In addition, I've also introduced three new copy-mode commands, > "end-of-nonspace-word", "next-nonspace-word", and > "previous-nonspace-word". These behave the same as their non-"nonspace" > versions, but they also skip over '-', '_', and '@' characters as "word" > characters. These are bound to E, W, and B, respectively. None of these > functions are bound for the emacs copy mode. > > Note that there is _no_ change whatsoever for emacs-mode, except for a > change in command-name. If anyone had their own binding to "next-word", > that binding's functionality has changed (slightly). > > = Patch notes = > > The window_copy_is_space() function has been replaced by > window_copy_strchr(), which is exactly the same except that instead of > hardcoding a value for what "spaces" are (several of which could not > really be called "spaces"), it takes a string parameter and simply > returns whether the designated cell matches any of the characters > supplied. " " is used for the "nonspace" variants, " -_@" otherwise. Not wild about the name, since it isn't doing the same thing as strchr, it only checks one cell. > The functions window_copy_cursor_next_word() and > window_copy_cursor_previous() have both been given a string parameter to > pass to window_copy_strchr() to determine whether they've encountered a > "space" or not. > > window_copy_cursor_next_word() also has a new "mode" parameter, which > tells it whether it's searching for the beginning or end of a word. > Thus, this function is employed for both "next-(nonspace-)word" and > "end-of-(nonspace-)word". > > = Additional thoughts = > > The current " -_@" set of delimiters differ from what vi typically > considers to be word delimiters. Vi considers letters, digits and > underscores to be words, and all other characters to be delimiters. > Notably, this excludes periods, commas, hyphens, and all other > punctuation as word characters, and _includes_ the underscore as a > "word" character. Vi also considers a string of non-word, non-space > characters (e.g., "..." or "----") to be a word. Yes I want to add some more as well at some point, can't remember exactly what offhand but I've noticed it does the wrong thing sometimes. > > Since the current default set of delimiters is only a few characters > more than just the space itself, and since all our word-movement > functions now take an argument to specify the > set-of-delimiting-characters, I did toy with the idea of adding commands > like "vi-next-word", "vi-previous-word", etc, to pass a larger set of > "non-word" characters in, but probably much better would be to let the > user specify the set of characters to be considered "nonword" > characters. Chances are someone will ask for that anyway, and in that > case, vi-copy and emacs-copy could/should use that same set of > characters. (Would you accept a patch for such a feature, Nicholas?) Yes it can be a server or window option, dunno which. > > -- > Micah J. Cowan > http://micah.cowan.name/ > ------------------------------------------------------------------------------ > Throughout its 18-year history, RSA Conference consistently attracts the > world's best and brightest in the field, creating opportunities for Conference > attendees to learn about information security's most important issues through > interactions with peers, luminaries and emerging and established companies. > http://p.sf.net/sfu/rsaconf-dev2dev > _______________________________________________ > tmux-users mailing list > tmux-users@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/tmux-users ------------------------------------------------------------------------------ The Planet: dedicated and managed hosting, cloud storage, colocation Stay online with enterprise data centers and the best network in the business Choose flexible plans and management services without long-term contracts Personal 24x7 support from experience hosting pros just a phone call away. http://p.sf.net/sfu/theplanet-com _______________________________________________ tmux-users mailing list tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users