Extend word commands to use any Unicode whitespace character, GitHub

issue 5562 from Hongyi Zhao.
This commit is contained in:
nicm
2026-09-01 12:49:49 +00:00
committed by tmux update bot
parent b402687fcd
commit 8f3101d820
5 changed files with 105 additions and 24 deletions

34
grid.c
View File

@@ -1,4 +1,4 @@
/* $OpenBSD: grid.c,v 1.157 2026/08/28 08:11:08 nicm Exp $ */
/* $OpenBSD: grid.c,v 1.158 2026/09/01 12:49:49 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1660,21 +1660,29 @@ grid_in_set(struct grid *gd, u_int px, u_int py, const char *set)
{
struct grid_cell gc, tmp_gc;
u_int pxx;
int has_tab, has_space;
has_tab = (strchr(set, '\t') != NULL);
has_space = (strchr(set, ' ') != NULL);
grid_get_cell(gd, px, py, &gc);
if (strchr(set, '\t')) {
if (gc.flags & GRID_FLAG_PADDING) {
pxx = px;
do
grid_get_cell(gd, --pxx, py, &tmp_gc);
while (pxx > 0 && tmp_gc.flags & GRID_FLAG_PADDING);
if (tmp_gc.flags & GRID_FLAG_TAB)
return (tmp_gc.data.width - (px - pxx));
} else if (gc.flags & GRID_FLAG_TAB)
return (gc.data.width);
}
if (gc.flags & GRID_FLAG_PADDING)
if (gc.flags & GRID_FLAG_PADDING) {
if (!has_tab && !has_space)
return (0);
pxx = px;
do
grid_get_cell(gd, --pxx, py, &tmp_gc);
while (pxx > 0 && tmp_gc.flags & GRID_FLAG_PADDING);
if (((has_tab || has_space) &&
(tmp_gc.flags & GRID_FLAG_TAB)) ||
(has_space && utf8_has_whitespace(&tmp_gc.data)))
return (tmp_gc.data.width - (px - pxx));
return (0);
}
if ((has_tab || has_space) && (gc.flags & GRID_FLAG_TAB))
return (gc.data.width);
if (has_space && utf8_has_whitespace(&gc.data))
return (gc.data.width == 0 ? 1 : gc.data.width);
return (utf8_cstrhas(set, &gc.data));
}

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: options-table.c,v 1.243 2026/08/25 08:37:08 nicm Exp $ */
/* $OpenBSD: options-table.c,v 1.244 2026/09/01 12:49:49 nicm Exp $ */
/*
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1251,7 +1251,8 @@ const struct options_table_entry options_table[] = {
* underscore.
*/
.default_str = "!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~",
.text = "Characters considered to separate words."
.text = "Characters considered to separate words; a space matches "
"any character with the Unicode White_Space property."
},
/* Window options. */

19
tmux.1
View File

@@ -1,4 +1,4 @@
.\" $OpenBSD: tmux.1,v 1.1162 2026/08/31 19:34:09 nicm Exp $
.\" $OpenBSD: tmux.1,v 1.1163 2026/09/01 12:49:49 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
.\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: August 31 2026 $
.Dd $Mdocdate: September 1 2026 $
.Dt TMUX 1
.Os
.Sh NAME
@@ -2206,14 +2206,14 @@ Move to the end of the next word.
.Xc
Same as
.Ic next\-word
but use a space alone as the word separator.
but treat all non-whitespace characters as part of a word.
.It Xo
.Ic next\-space\-end
(vi: E)
.Xc
Same as
.Ic next\-word\-end
but use a space alone as the word separator.
but treat all non-whitespace characters as part of a word.
.It Xo
.Ic other\-end
(vi: o)
@@ -2287,7 +2287,7 @@ Move to the previous word.
.Xc
Same as
.Ic previous\-word
but use a space alone as the word separator.
but treat all non-whitespace characters as part of a word.
.It Xo
.Ic rectangle\-on
.Xc
@@ -2572,8 +2572,8 @@ Word separators can be customized with the
session option.
Next word moves to the start of the next word, next word end to the end of the
next word and previous word to the start of the previous word.
The three next and previous space keys work similarly but use a space alone as
the word separator.
The three next and previous space keys work similarly but treat all
non-whitespace characters as part of a word.
Setting
.Em word\-separators
to the empty string makes next/previous word equivalent to next/previous space.
@@ -5647,6 +5647,11 @@ If set to both, a bell and a message are produced.
Sets the session's conception of what characters are considered word
separators, for the purposes of the next and previous word commands in
copy mode.
A space in
.Ar string
matches any character with the Unicode
.Em White_Space
property.
.El
.Pp
Available window options are:

3
tmux.h
View File

@@ -1,4 +1,4 @@
/* $OpenBSD: tmux.h,v 1.1432 2026/08/31 19:34:09 nicm Exp $ */
/* $OpenBSD: tmux.h,v 1.1433 2026/09/01 12:49:49 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -4057,6 +4057,7 @@ void session_update_history(struct session *);
/* utf8.c */
enum utf8_state utf8_towc (const struct utf8_data *, wchar_t *);
enum utf8_state utf8_fromwc(wchar_t wc, struct utf8_data *);
int utf8_has_whitespace(const struct utf8_data *);
void utf8_update_width_cache(void);
utf8_char utf8_build_one(u_char);
enum utf8_state utf8_from_data(const struct utf8_data *, utf8_char *);

68
utf8.c
View File

@@ -1,4 +1,4 @@
/* $OpenBSD: utf8.c,v 1.71 2026/05/12 09:37:25 nicm Exp $ */
/* $OpenBSD: utf8.c,v 1.72 2026/09/01 12:49:49 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -594,6 +594,72 @@ utf8_towc(const struct utf8_data *ud, wchar_t *wc)
return (UTF8_DONE);
}
/* Check for a Unicode whitespace character. */
int
utf8_has_whitespace(const struct utf8_data *ud)
{
struct utf8_data tmp;
wchar_t wc;
u_int offset = 0, size;
u_char ch;
while (offset < ud->size) {
ch = ud->data[offset];
if (ch < 0x80) {
wc = ch;
size = 1;
} else {
if (ch >= 0xc2 && ch <= 0xdf)
size = 2;
else if (ch >= 0xe0 && ch <= 0xef)
size = 3;
else if (ch >= 0xf0 && ch <= 0xf4)
size = 4;
else
return (0);
if (size > ud->size - offset)
return (0);
memset(&tmp, 0, sizeof tmp);
memcpy(tmp.data, ud->data + offset, size);
tmp.size = tmp.have = size;
if (utf8_towc(&tmp, &wc) != UTF8_DONE)
return (0);
}
offset += size;
switch (wc) {
case 0x0009:
case 0x000A:
case 0x000B:
case 0x000C:
case 0x000D:
case 0x0020:
case 0x0085:
case 0x00A0:
case 0x1680:
case 0x2000:
case 0x2001:
case 0x2002:
case 0x2003:
case 0x2004:
case 0x2005:
case 0x2006:
case 0x2007:
case 0x2008:
case 0x2009:
case 0x200A:
case 0x2028:
case 0x2029:
case 0x202F:
case 0x205F:
case 0x3000:
return (1);
}
}
return (0);
}
/* Convert wide character to UTF-8 character. */
enum utf8_state
utf8_fromwc(wchar_t wc, struct utf8_data *ud)