From: Eli Zaretskii Date: Sat, 12 Feb 2022 18:38:51 +0000 (+0200) Subject: Optionally allow point to enter composed character sequences X-Git-Tag: emacs-29.0.90~2357 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=b5997c0f108d265917f899f6558ac56a8638451d;p=emacs.git Optionally allow point to enter composed character sequences This changeset is based on code originally posted by Kenichi Handa as part of discussing bug#20140, with a few adjustments and changes, mainly to support R2L text and provide a user option to control the feature. * src/xdisp.c (compute_stop_pos, next_element_from_buffer) (composition_reseat_it): Don't allow auto-composing characters past point when 'composition-break-at-point' is non-nil. (syms_of_xdisp) : New boolean variable. (redisplay_internal, redisplay_window): Disable "just move the cursor" optimizations when 'composition-break-at-point' is non-nil. * src/keyboard.c (command_loop_1): Force redisplay when 'composition-break-at-point' is non-nil. * lisp/cus-start.el (standard): Provide customization form for 'composition-break-at-point'. * etc/NEWS: Announce the new feature. --- diff --git a/etc/NEWS b/etc/NEWS index 6f19224026e..1b0e26da9b9 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -476,6 +476,17 @@ The options 'mouse-wheel-down-alternate-event', 'mouse-wheel-up-alternate-event' been added to better support systems where two kinds of wheel events can be received. +** Editing complex text layout (CTL) scripts + +*** The function key now allows deleting the entire composed sequence. +For the details, see the item about the 'delete-forward-char' command +above. + +*** New user option 'composition-break-at-point'. +Setting it to a non-nil value temporarily disables automatic +composition of character sequences at point, and thus makes it easier +to edit such sequences by allowing point to "enter" the sequence. + * Changes in Specialized Modes and Packages in Emacs 29.1 diff --git a/lisp/cus-start.el b/lisp/cus-start.el index afdbd82457b..f8bab89e902 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -811,6 +811,7 @@ since it could result in memory overflow and make Emacs crash." character) "27.1" :safe (lambda (value) (or (characterp value) (null value)))) + (composition-break-at-point display boolean "29.1") ;; xfaces.c (scalable-fonts-allowed display (choice (const :tag "Don't allow scalable fonts" nil) diff --git a/src/composite.c b/src/composite.c index 17563201e27..c3e9afc8078 100644 --- a/src/composite.c +++ b/src/composite.c @@ -1292,6 +1292,16 @@ composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos, if (cmp_it->lookback > 0) { cpos = charpos - cmp_it->lookback; + /* Reject the composition if it starts before ENDPOS, + which here can only happen if + composition-break-at-point is non-nil and point is + inside the composition. */ + if (cpos < endpos) + { + eassert (composition_break_at_point); + eassert (endpos == PT); + goto no_composition; + } if (STRINGP (string)) bpos = string_char_to_byte (string, cpos); else diff --git a/src/keyboard.c b/src/keyboard.c index 6b66a715933..be9fb665d76 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1603,23 +1603,33 @@ command_loop_1 (void) if (current_buffer == prev_buffer && XBUFFER (XWINDOW (selected_window)->contents) == current_buffer - && last_point_position != PT - && NILP (Vdisable_point_adjustment) - && NILP (Vglobal_disable_point_adjustment)) + && last_point_position != PT) { - if (last_point_position > BEGV - && last_point_position < ZV - && (composition_adjust_point (last_point_position, - last_point_position) - != last_point_position)) - /* The last point was temporarily set within a grapheme - cluster to prevent automatic composition. To recover - the automatic composition, we must update the - display. */ - windows_or_buffers_changed = 21; - if (!already_adjusted) - adjust_point_for_property (last_point_position, - MODIFF != prev_modiff); + if (NILP (Vdisable_point_adjustment) + && NILP (Vglobal_disable_point_adjustment) + && !composition_break_at_point) + { + if (last_point_position > BEGV + && last_point_position < ZV + && (composition_adjust_point (last_point_position, + last_point_position) + != last_point_position)) + /* The last point was temporarily set within a grapheme + cluster to prevent automatic composition. To recover + the automatic composition, we must update the + display. */ + windows_or_buffers_changed = 21; + if (!already_adjusted) + adjust_point_for_property (last_point_position, + MODIFF != prev_modiff); + } + else if (PT > BEGV && PT < ZV + && (composition_adjust_point (last_point_position, PT) + != PT)) + /* Now point is within a grapheme cluster. We must update + the display so that this cluster is de-composed on the + screen and the cursor is correctly placed at point. */ + windows_or_buffers_changed = 39; } /* Install chars successfully executed in kbd macro. */ diff --git a/src/xdisp.c b/src/xdisp.c index cc1da24acaf..ec8d53e5ccb 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3984,6 +3984,12 @@ compute_stop_pos (struct it *it) pos = next_overlay_change (charpos); if (pos < it->stop_charpos) it->stop_charpos = pos; + /* If we are breaking compositions at point, stop at point. */ + if (!NILP (BVAR (current_buffer, enable_multibyte_characters)) + && !NILP (Vauto_composition_mode) + && composition_break_at_point + && charpos < PT && PT < it->stop_charpos) + it->stop_charpos = PT; /* Set up variables for computing the stop position from text property changes. */ @@ -3995,7 +4001,8 @@ compute_stop_pos (struct it *it) chunks. We play safe here by assuming that only SPC, TAB, FF, and NL cannot be in some composition; in particular, most ASCII punctuation characters could be composed into ligatures. */ - if (!NILP (BVAR (current_buffer, enable_multibyte_characters)) + if (!composition_break_at_point + && !NILP (BVAR (current_buffer, enable_multibyte_characters)) && !NILP (Vauto_composition_mode)) { ptrdiff_t endpos = charpos + 10 * TEXT_PROP_DISTANCE_LIMIT; @@ -9186,7 +9193,19 @@ next_element_from_buffer (struct it *it) && IT_CHARPOS (*it) >= it->redisplay_end_trigger_charpos) run_redisplay_end_trigger_hook (it); - stop = it->bidi_it.scan_dir < 0 ? -1 : it->end_charpos; + if (composition_break_at_point + && !NILP (BVAR (current_buffer, enable_multibyte_characters)) + && !NILP (Vauto_composition_mode)) + { + /* Limit search for composable characters to point's position. */ + if (it->bidi_it.scan_dir < 0) + stop = (PT <= IT_CHARPOS (*it)) ? PT : -1; + else + stop = (IT_CHARPOS (*it) < PT + && PT < it->end_charpos) ? PT : it->end_charpos; + } + else + stop = it->bidi_it.scan_dir < 0 ? -1 : it->end_charpos; if (CHAR_COMPOSED_P (it, IT_CHARPOS (*it), IT_BYTEPOS (*it), stop) && next_element_from_composition (it)) @@ -16390,7 +16409,8 @@ redisplay_internal (void) /* If highlighting the region, or if the cursor is in the echo area, then we can't just move the cursor. */ else if (NILP (Vshow_trailing_whitespace) - && !cursor_in_echo_area) + && !cursor_in_echo_area + && !composition_break_at_point) { struct it it; struct glyph_row *row; @@ -18928,6 +18948,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) && !current_buffer->clip_changed && !current_buffer->prevent_redisplay_optimizations_p && !window_outdated (w) + && !composition_break_at_point && !hscrolling_current_line_p (w)); beg_unchanged = BEG_UNCHANGED; @@ -36527,6 +36548,13 @@ Otherwise, use custom-tailored code after resizing minibuffer windows to try and display the most important part of the minibuffer. */); /* See bug#43519 for some discussion around this. */ redisplay_adhoc_scroll_in_resize_mini_windows = true; + + DEFVAR_BOOL ("composition-break-at-point", + composition_break_at_point, + doc: /* If non-nil, prevent auto-composition of characters around point. +This makes it easier to edit character sequences that are +composed on display. */); + composition_break_at_point = false; }