diff --git a/source/blender/blenlib/BLI_string_cursor_utf8.h b/source/blender/blenlib/BLI_string_cursor_utf8.h index 8fa0c4ec83f..9a0820b428e 100644 --- a/source/blender/blenlib/BLI_string_cursor_utf8.h +++ b/source/blender/blenlib/BLI_string_cursor_utf8.h @@ -42,6 +42,24 @@ void BLI_str_cursor_step_utf32(const char32_t *str, eStrCursorJumpType jump, bool use_init_step); + +/** + * Word/Sequence Selection. Given a position within a string, return the start and end of the + * closest sequence of delimited characters. Generally a word, but could be a sequence of spaces. + * + * \param str: The string with a cursor position + * \param str_maxlen: The maximum characters to consider + * \param pos: The starting cursor position (probably moved on completion) + * \param r_start: returned start of word/sequence boundary (0-based) + * \param r_end: returned end of word/sequence boundary (0-based) + */ + +void BLI_str_cursor_step_bounds_utf8( + const char *str, const size_t str_maxlen, int *pos, int *r_start, int *r_end); + +void BLI_str_cursor_step_bounds_utf32( + const char32_t *str, const size_t str_maxlen, int *pos, int *r_start, int *r_end); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/intern/string_cursor_utf8.c b/source/blender/blenlib/intern/string_cursor_utf8.c index 95442caa655..31119187536 100644 --- a/source/blender/blenlib/intern/string_cursor_utf8.c +++ b/source/blender/blenlib/intern/string_cursor_utf8.c @@ -314,3 +314,52 @@ void BLI_str_cursor_step_utf32(const char32_t *str, BLI_assert_unreachable(); } } + +void BLI_str_cursor_step_bounds_utf8( + const char *str, const size_t str_maxlen, int *pos, int *start, int *end) +{ + /* What type of characters are on either side of the current cursor position? */ + const eStrCursorDelimType prev = (*pos > 0) ? cursor_delim_type_utf8(str, str_maxlen, *pos - 1) : + STRCUR_DELIM_NONE; + const eStrCursorDelimType next = (*pos < str_maxlen) ? + cursor_delim_type_utf8(str, str_maxlen, *pos) : + STRCUR_DELIM_NONE; + *start = *pos; + *end = *pos; + + if (prev == next || ELEM(next, STRCUR_DELIM_WHITESPACE, STRCUR_DELIM_NONE)) { + /* Expand backward if we are between similar content, before whitespace, or at end. */ + BLI_str_cursor_step_utf8(str, str_maxlen, start, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, false); + } + if (prev == next || ELEM(prev, STRCUR_DELIM_WHITESPACE, STRCUR_DELIM_NONE)) { + /* Expand forward if we are between similar content, after whitespace, or at beginning. */ + BLI_str_cursor_step_utf8(str, str_maxlen, end, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, false); + } + + /* Move cursor position to the end of selection. */ + *pos = *end; +} + +void BLI_str_cursor_step_bounds_utf32( + const char32_t *str, const size_t str_maxlen, int *pos, int *start, int *end) +{ + /* What type of characters are on either side of the current cursor position? */ + const eStrCursorDelimType prev = (*pos > 0) ? cursor_delim_type_unicode(str[*pos - 1]) : + STRCUR_DELIM_NONE; + const eStrCursorDelimType next = (*pos < str_maxlen) ? cursor_delim_type_unicode(str[*pos]) : + STRCUR_DELIM_NONE; + *start = *pos; + *end = *pos; + + if (prev == next || ELEM(next, STRCUR_DELIM_WHITESPACE, STRCUR_DELIM_NONE)) { + /* Expand backward if we are between similar content, before whitespace, or at end. */ + BLI_str_cursor_step_utf32(str, str_maxlen, start, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, false); + } + if (prev == next || ELEM(prev, STRCUR_DELIM_WHITESPACE, STRCUR_DELIM_NONE)) { + /* Expand forward if we are between similar content, after whitespace, or at beginning. */ + BLI_str_cursor_step_utf32(str, str_maxlen, end, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, false); + } + + /* Move cursor position to the end of selection. */ + *pos = *end; +} diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 6d786fedf46..227d158497a 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -1920,9 +1920,18 @@ void FONT_OT_selection_set(struct wmOperatorType *ot) static int font_select_word_exec(bContext *C, wmOperator *UNUSED(op)) { - move_cursor(C, NEXT_CHAR, false); - move_cursor(C, PREV_WORD, false); - move_cursor(C, NEXT_WORD, true); + Object *obedit = CTX_data_edit_object(C); + Curve *cu = obedit->data; + EditFont *ef = cu->editfont; + + BLI_str_cursor_step_bounds_utf32(ef->textbuf, ef->len, &ef->pos, &ef->selstart, &ef->selend); + + /* XXX: Text object selection start is 1-based, unlike text processing elsewhere in Blender. */ + ef->selstart += 1; + + font_select_update_primary_clipboard(obedit); + text_update_edited(C, obedit, FO_CURS); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/interface/interface_handlers.cc b/source/blender/editors/interface/interface_handlers.cc index 9ba6b3247e7..0bec095455a 100644 --- a/source/blender/editors/interface/interface_handlers.cc +++ b/source/blender/editors/interface/interface_handlers.cc @@ -3730,8 +3730,12 @@ static void ui_do_but_textedit( /* only select a word in button if there was no selection before */ if (event->val == KM_DBL_CLICK && had_selection == false) { - ui_textedit_move(but, data, STRCUR_DIR_PREV, false, STRCUR_JUMP_DELIM); - ui_textedit_move(but, data, STRCUR_DIR_NEXT, true, STRCUR_JUMP_DELIM); + int pos = (int)but->pos; + int selsta, selend; + BLI_str_cursor_step_bounds_utf8(data->str, strlen(data->str), &pos, &selsta, &selend); + but->pos = (short)pos; + but->selsta = (short)selsta; + but->selend = (short)selend; retval = WM_UI_HANDLER_BREAK; changed = true; } diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c index 489562f0736..2654877c968 100644 --- a/source/blender/editors/space_console/console_ops.c +++ b/source/blender/editors/space_console/console_ops.c @@ -1258,9 +1258,7 @@ static int console_selectword_invoke(bContext *C, wmOperator *UNUSED(op), const if (console_line_column_from_index(sc, pos, &cl, &offset, &n)) { int sel[2] = {n, n}; - BLI_str_cursor_step_utf8(cl->line, cl->len, &sel[0], STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, true); - - BLI_str_cursor_step_utf8(cl->line, cl->len, &sel[1], STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, true); + BLI_str_cursor_step_bounds_utf8(cl->line, cl->len, &n, &sel[0], &sel[1]); sel[0] = offset - sel[0]; sel[1] = offset - sel[1]; diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index a44789e442f..94e861ccfb0 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -15,6 +15,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_math_base.h" +#include "BLI_string_cursor_utf8.h" #include "BLT_translation.h" @@ -1577,11 +1578,9 @@ void TEXT_OT_select_line(wmOperatorType *ot) static int text_select_word_exec(bContext *C, wmOperator *UNUSED(op)) { Text *text = CTX_data_edit_text(C); - /* don't advance cursor before stepping */ - const bool use_init_step = false; - txt_jump_left(text, false, use_init_step); - txt_jump_right(text, true, use_init_step); + BLI_str_cursor_step_bounds_utf8( + text->curl->line, text->curl->len, &text->selc, &text->curc, &text->selc); text_update_cursor_moved(C); text_select_update_primary_clipboard(text);