? wordchars.diff Index: chared.c =================================================================== RCS file: /cvsroot/src/lib/libedit/chared.c,v retrieving revision 1.64 diff -u -p -u -r1.64 chared.c --- chared.c 29 Jun 2024 14:13:14 -0000 1.64 +++ chared.c 4 Nov 2025 18:55:54 -0000 @@ -202,9 +202,9 @@ c_delbefore1(EditLine *el) * Return if p is part of a word according to emacs */ libedit_private int -ce__isword(wint_t p) +ce__isword(EditLine *el, wint_t p) { - return iswalnum(p) || wcschr(L"*?_-.[]~=", p) != NULL; + return iswalnum(p) || wcschr(el->el_map.wordchars, p) != NULL; } @@ -212,9 +212,9 @@ ce__isword(wint_t p) * Return if p is part of a word according to vi */ libedit_private int -cv__isword(wint_t p) +cv__isword(EditLine *el, wint_t p) { - if (iswalnum(p) || p == L'_') + if (iswalnum(p) || wcschr(el->el_map.wordchars, p) != NULL) return 1; if (iswgraph(p)) return 2; @@ -226,7 +226,7 @@ cv__isword(wint_t p) * Return if p is part of a big word according to vi */ libedit_private int -cv__isWord(wint_t p) +cv__isWord(EditLine *el __attribute__((__unused__)), wint_t p) { return !iswspace(p); } @@ -236,14 +236,15 @@ cv__isWord(wint_t p) * Find the previous word */ libedit_private wchar_t * -c__prev_word(wchar_t *p, wchar_t *low, int n, int (*wtest)(wint_t)) +c__prev_word(EditLine *el, wchar_t *p, wchar_t *low, int n, + int (*wtest)(EditLine *, wint_t)) { p--; while (n--) { - while ((p >= low) && !(*wtest)(*p)) + while ((p >= low) && !(*wtest)(el, *p)) p--; - while ((p >= low) && (*wtest)(*p)) + while ((p >= low) && (*wtest)(el, *p)) p--; } @@ -260,12 +261,13 @@ c__prev_word(wchar_t *p, wchar_t *low, i * Find the next word */ libedit_private wchar_t * -c__next_word(wchar_t *p, wchar_t *high, int n, int (*wtest)(wint_t)) +c__next_word(EditLine *el, wchar_t *p, wchar_t *high, int n, + int (*wtest)(EditLine *, wint_t)) { while (n--) { - while ((p < high) && !(*wtest)(*p)) + while ((p < high) && !(*wtest)(el, *p)) p++; - while ((p < high) && (*wtest)(*p)) + while ((p < high) && (*wtest)(el, *p)) p++; } if (p > high) @@ -279,13 +281,13 @@ c__next_word(wchar_t *p, wchar_t *high, */ libedit_private wchar_t * cv_next_word(EditLine *el, wchar_t *p, wchar_t *high, int n, - int (*wtest)(wint_t)) + int (*wtest)(EditLine *el, wint_t)) { int test; while (n--) { - test = (*wtest)(*p); - while ((p < high) && (*wtest)(*p) == test) + test = (*wtest)(el, *p); + while ((p < high) && (*wtest)(el, *p) == test) p++; /* * vi historically deletes with cw only the word preserving the @@ -308,7 +310,8 @@ cv_next_word(EditLine *el, wchar_t *p, w * Find the previous word vi style */ libedit_private wchar_t * -cv_prev_word(wchar_t *p, wchar_t *low, int n, int (*wtest)(wint_t)) +cv_prev_word(EditLine *el, wchar_t *p, wchar_t *low, int n, + int (*wtest)(EditLine *el, wint_t)) { int test; @@ -316,8 +319,8 @@ cv_prev_word(wchar_t *p, wchar_t *low, i while (n--) { while ((p > low) && iswspace(*p)) p--; - test = (*wtest)(*p); - while ((p >= low) && (*wtest)(*p) == test) + test = (*wtest)(el, *p); + while ((p >= low) && (*wtest)(el, *p) == test) p--; if (p < low) return low; @@ -374,7 +377,8 @@ cv_delfini(EditLine *el) * Go to the end of this word according to vi */ libedit_private wchar_t * -cv__endword(wchar_t *p, wchar_t *high, int n, int (*wtest)(wint_t)) +cv__endword(EditLine *el, wchar_t *p, wchar_t *high, int n, + int (*wtest)(EditLine *, wint_t)) { int test; @@ -384,8 +388,8 @@ cv__endword(wchar_t *p, wchar_t *high, i while ((p < high) && iswspace(*p)) p++; - test = (*wtest)(*p); - while ((p < high) && (*wtest)(*p) == test) + test = (*wtest)(el, *p); + while ((p < high) && (*wtest)(el, *p) == test) p++; } p--; Index: chared.h =================================================================== RCS file: /cvsroot/src/lib/libedit/chared.h,v retrieving revision 1.30 diff -u -p -u -r1.30 chared.h --- chared.h 22 May 2016 19:44:26 -0000 1.30 +++ chared.h 4 Nov 2025 18:55:54 -0000 @@ -125,18 +125,22 @@ typedef struct el_chared_t { #define MODE_REPLACE_1 2 -libedit_private int cv__isword(wint_t); -libedit_private int cv__isWord(wint_t); +libedit_private int cv__isword(EditLine *, wint_t); +libedit_private int cv__isWord(EditLine *, wint_t); libedit_private void cv_delfini(EditLine *); -libedit_private wchar_t *cv__endword(wchar_t *, wchar_t *, int, int (*)(wint_t)); -libedit_private int ce__isword(wint_t); +libedit_private wchar_t *cv__endword(EditLine *, wchar_t *, wchar_t *, int, + int (*)(EditLine *, wint_t)); +libedit_private int ce__isword(EditLine *, wint_t); libedit_private void cv_undo(EditLine *); libedit_private void cv_yank(EditLine *, const wchar_t *, int); libedit_private wchar_t *cv_next_word(EditLine*, wchar_t *, wchar_t *, int, - int (*)(wint_t)); -libedit_private wchar_t *cv_prev_word(wchar_t *, wchar_t *, int, int (*)(wint_t)); -libedit_private wchar_t *c__next_word(wchar_t *, wchar_t *, int, int (*)(wint_t)); -libedit_private wchar_t *c__prev_word(wchar_t *, wchar_t *, int, int (*)(wint_t)); + int (*)(EditLine *, wint_t)); +libedit_private wchar_t *cv_prev_word(EditLine *, wchar_t *, wchar_t *, int, + int (*)(EditLine *, wint_t)); +libedit_private wchar_t *c__next_word(EditLine *, wchar_t *, wchar_t *, int, + int (*)(EditLine *, wint_t)); +libedit_private wchar_t *c__prev_word(EditLine *, wchar_t *, wchar_t *, int, + int (*)(EditLine *, wint_t)); libedit_private void c_insert(EditLine *, int); libedit_private void c_delbefore(EditLine *, int); libedit_private void c_delbefore1(EditLine *); Index: common.c =================================================================== RCS file: /cvsroot/src/lib/libedit/common.c,v retrieving revision 1.50 diff -u -p -u -r1.50 common.c --- common.c 30 Jun 2024 16:29:42 -0000 1.50 +++ common.c 4 Nov 2025 18:55:54 -0000 @@ -123,7 +123,7 @@ ed_delete_prev_word(EditLine *el, wint_t if (el->el_line.cursor == el->el_line.buffer) return CC_ERROR; - cp = c__prev_word(el->el_line.cursor, el->el_line.buffer, + cp = c__prev_word(el, el->el_line.cursor, el->el_line.buffer, el->el_state.argument, ce__isword); for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++) @@ -320,7 +320,7 @@ ed_prev_word(EditLine *el, wint_t c __at if (el->el_line.cursor == el->el_line.buffer) return CC_ERROR; - el->el_line.cursor = c__prev_word(el->el_line.cursor, + el->el_line.cursor = c__prev_word(el, el->el_line.cursor, el->el_line.buffer, el->el_state.argument, ce__isword); Index: editline.3 =================================================================== RCS file: /cvsroot/src/lib/libedit/editline.3,v retrieving revision 1.102 diff -u -p -u -r1.102 editline.3 --- editline.3 4 Feb 2024 18:47:27 -0000 1.102 +++ editline.3 4 Nov 2025 18:55:54 -0000 @@ -667,6 +667,18 @@ or .Fa fd = .Dv 2 . +.It Dv EL_WORDCHARS , Fa "Char *wordchars" +Define the list of characters that and be part of a word, in addition +to alphanumeric characters. +This list is +.Dq *?_-.[]~= +for +.Dv emacs +mode and +.Dq _ +for +.Dv vi +mode. .El .It Fn el_source Initialize Index: el.c =================================================================== RCS file: /cvsroot/src/lib/libedit/el.c,v retrieving revision 1.102 diff -u -p -u -r1.102 el.c --- el.c 3 Jan 2025 00:40:08 -0000 1.102 +++ el.c 4 Nov 2025 18:55:54 -0000 @@ -382,6 +382,9 @@ el_wset(EditLine *el, int op, ...) terminal__flush(el); break; + case EL_WORDCHARS: + rv = map_set_wordchars(el, va_arg(ap, wchar_t *)); + break; default: rv = -1; break; @@ -496,6 +499,11 @@ el_wget(EditLine *el, int op, ...) } break; } + + case EL_WORDCHARS: + rv = map_get_wordchars(el, va_arg(ap, const wchar_t **)); + break; + default: rv = -1; break; Index: eln.c =================================================================== RCS file: /cvsroot/src/lib/libedit/eln.c,v retrieving revision 1.38 diff -u -p -u -r1.38 eln.c --- eln.c 17 May 2024 02:59:08 -0000 1.38 +++ eln.c 4 Nov 2025 18:55:54 -0000 @@ -147,6 +147,7 @@ el_set(EditLine *el, int op, ...) break; case EL_EDITOR: /* const wchar_t * */ + case EL_WORDCHARS: /* const wchar_t * */ ret = el_wset(el, op, ct_decode_string(va_arg(ap, char *), &el->el_lgcyconv)); break; @@ -300,7 +301,8 @@ el_get(EditLine *el, int op, ...) break; } - case EL_EDITOR: { + case EL_EDITOR: + case EL_WORDCHARS: { const char **p = va_arg(ap, const char **); const wchar_t *pw; ret = el_wget(el, op, &pw); Index: emacs.c =================================================================== RCS file: /cvsroot/src/lib/libedit/emacs.c,v retrieving revision 1.38 diff -u -p -u -r1.38 emacs.c --- emacs.c 29 Jun 2024 17:28:07 -0000 1.38 +++ emacs.c 4 Nov 2025 18:55:54 -0000 @@ -99,7 +99,7 @@ em_delete_next_word(EditLine *el, wint_t if (el->el_line.cursor == el->el_line.lastchar) return CC_ERROR; - cp = c__next_word(el->el_line.cursor, el->el_line.lastchar, + cp = c__next_word(el, el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, ce__isword); for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++) @@ -266,7 +266,7 @@ em_next_word(EditLine *el, wint_t c __at if (el->el_line.cursor == el->el_line.lastchar) return CC_ERROR; - el->el_line.cursor = c__next_word(el->el_line.cursor, + el->el_line.cursor = c__next_word(el, el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, ce__isword); @@ -290,7 +290,7 @@ em_upper_case(EditLine *el, wint_t c __a { wchar_t *cp, *ep; - ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, + ep = c__next_word(el, el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) @@ -314,7 +314,7 @@ em_capitol_case(EditLine *el, wint_t c _ { wchar_t *cp, *ep; - ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, + ep = c__next_word(el, el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) { @@ -346,7 +346,7 @@ em_lower_case(EditLine *el, wint_t c __a { wchar_t *cp, *ep; - ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, + ep = c__next_word(el, el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) @@ -449,7 +449,7 @@ em_copy_prev_word(EditLine *el, wint_t c return CC_ERROR; /* does a bounds check */ - cp = c__prev_word(el->el_line.cursor, el->el_line.buffer, + cp = c__prev_word(el, el->el_line.cursor, el->el_line.buffer, el->el_state.argument, ce__isword); c_insert(el, (int)(el->el_line.cursor - cp)); Index: histedit.h =================================================================== RCS file: /cvsroot/src/lib/libedit/histedit.h,v retrieving revision 1.62 diff -u -p -u -r1.62 histedit.h --- histedit.h 3 Feb 2023 22:01:42 -0000 1.62 +++ histedit.h 4 Nov 2025 18:55:54 -0000 @@ -159,6 +159,7 @@ unsigned char _el_fn_sh_complete(EditLin #define EL_RESIZE 23 /* , el_zfunc_t, void *); set */ #define EL_ALIAS_TEXT 24 /* , el_afunc_t, void *); set */ #define EL_SAFEREAD 25 /* , int); set/get */ +#define EL_WORDCHARS 26 /* , const Char *); set/get */ #define EL_BUILTIN_GETCFN (NULL) Index: map.c =================================================================== RCS file: /cvsroot/src/lib/libedit/map.c,v retrieving revision 1.56 diff -u -p -u -r1.56 map.c --- map.c 3 Jan 2025 00:40:08 -0000 1.56 +++ map.c 4 Nov 2025 18:55:54 -0000 @@ -933,6 +933,7 @@ map_init(EditLine *el) memcpy(el->el_map.func, el_func, sizeof(*el->el_map.func) * EL_NUM_FCNS); el->el_map.nfunc = EL_NUM_FCNS; + el->el_map.wordchars = NULL; #ifdef VIDEFAULT map_init_vi(el); @@ -954,6 +955,7 @@ map_end(EditLine *el) { el_free(el->el_map.alt); + el_free(el->el_map.wordchars); el->el_map.alt = NULL; el_free(el->el_map.key); el->el_map.key = NULL; @@ -1051,6 +1053,8 @@ map_init_vi(EditLine *el) tty_bind_char(el, 1); terminal_bind_arrow(el); + el_free(el->el_map.wordchars); + el->el_map.wordchars = wcsdup(L"_"); } @@ -1085,6 +1089,8 @@ map_init_emacs(EditLine *el) tty_bind_char(el, 1); terminal_bind_arrow(el); + el_free(el->el_map.wordchars); + el->el_map.wordchars = wcsdup(L"*?_-.[]~="); } @@ -1128,6 +1134,33 @@ map_get_editor(EditLine *el, const wchar } +/* map_set_wordchars(): + * Set the wordchars + */ +libedit_private int +map_set_wordchars(EditLine *el, wchar_t *wordchars) +{ + + el_free(el->el_map.wordchars); + el->el_map.wordchars = wcsdup(wordchars); + return 0; +} + + +/* map_get_wordchars(): + * Retrieve the wordhars + */ +libedit_private int +map_get_wordchars(EditLine *el, const wchar_t **wordchars) +{ + + if (wordchars == NULL) + return -1; + *wordchars = el->el_map.wordchars; + return 0; +} + + /* map_print_key(): * Print the function description for 1 key */ Index: map.h =================================================================== RCS file: /cvsroot/src/lib/libedit/map.h,v retrieving revision 1.13 diff -u -p -u -r1.13 map.h --- map.h 9 May 2016 21:46:56 -0000 1.13 +++ map.h 4 Nov 2025 18:55:54 -0000 @@ -59,6 +59,7 @@ typedef struct el_map_t { el_bindings_t *help; /* The help for the editor functions */ el_func_t *func; /* List of available functions */ size_t nfunc; /* The number of functions/help items */ + wchar_t *wordchars; /* The word character separators */ } el_map_t; #define MAP_EMACS 0 @@ -73,6 +74,8 @@ libedit_private void map_init_vi(EditLin libedit_private void map_init_emacs(EditLine *); libedit_private int map_set_editor(EditLine *, wchar_t *); libedit_private int map_get_editor(EditLine *, const wchar_t **); +libedit_private int map_set_wordchars(EditLine *, wchar_t *); +libedit_private int map_get_wordchars(EditLine *, const wchar_t **); libedit_private int map_addfunc(EditLine *, const wchar_t *, const wchar_t *, el_func_t); Index: search.c =================================================================== RCS file: /cvsroot/src/lib/libedit/search.c,v retrieving revision 1.52 diff -u -p -u -r1.52 search.c --- search.c 30 Jun 2024 16:26:30 -0000 1.52 +++ search.c 4 Nov 2025 18:55:54 -0000 @@ -300,7 +300,8 @@ ce_inc_search(EditLine *el, int dir) break; el->el_line.cursor += el->el_search.patlen - LEN - 1; - cp = c__next_word(el->el_line.cursor, + cp = c__next_word(el, + el->el_line.cursor, el->el_line.lastchar, 1, ce__isword); while (el->el_line.cursor < cp && Index: vi.c =================================================================== RCS file: /cvsroot/src/lib/libedit/vi.c,v retrieving revision 1.64 diff -u -p -u -r1.64 vi.c --- vi.c 28 Aug 2021 17:17:47 -0000 1.64 +++ vi.c 4 Nov 2025 18:55:54 -0000 @@ -161,7 +161,7 @@ vi_prev_big_word(EditLine *el, wint_t c if (el->el_line.cursor == el->el_line.buffer) return CC_ERROR; - el->el_line.cursor = cv_prev_word(el->el_line.cursor, + el->el_line.cursor = cv_prev_word(el, el->el_line.cursor, el->el_line.buffer, el->el_state.argument, cv__isWord); @@ -186,7 +186,7 @@ vi_prev_word(EditLine *el, wint_t c __at if (el->el_line.cursor == el->el_line.buffer) return CC_ERROR; - el->el_line.cursor = cv_prev_word(el->el_line.cursor, + el->el_line.cursor = cv_prev_word(el, el->el_line.cursor, el->el_line.buffer, el->el_state.argument, cv__isword); @@ -478,7 +478,7 @@ vi_end_big_word(EditLine *el, wint_t c _ if (el->el_line.cursor == el->el_line.lastchar) return CC_ERROR; - el->el_line.cursor = cv__endword(el->el_line.cursor, + el->el_line.cursor = cv__endword(el, el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, cv__isWord); if (el->el_chared.c_vcmd.action != NOP) { @@ -502,7 +502,7 @@ vi_end_word(EditLine *el, wint_t c __att if (el->el_line.cursor == el->el_line.lastchar) return CC_ERROR; - el->el_line.cursor = cv__endword(el->el_line.cursor, + el->el_line.cursor = cv__endword(el, el->el_line.cursor, el->el_line.lastchar, el->el_state.argument, cv__isword); if (el->el_chared.c_vcmd.action != NOP) {