diff options
| author | Po Lu | 2024-04-21 21:51:09 +0800 |
|---|---|---|
| committer | Po Lu | 2024-04-29 12:34:39 +0800 |
| commit | 430088c9ccec5fe9be57d267f45acdc87aa3b28e (patch) | |
| tree | a953f845c4176e4a18a542c1e321f80ad34ab4af /src | |
| parent | ee2e0031d8cc32bb7837ea97ce07ef3b25463223 (diff) | |
| download | emacs-430088c9ccec5fe9be57d267f45acdc87aa3b28e.tar.gz emacs-430088c9ccec5fe9be57d267f45acdc87aa3b28e.zip | |
Take fields into account during text conversion
* lisp/cus-edit.el (Custom-mode): Enable text conversion, now
that fields are correctly treated.
* src/alloc.c (mark_frame): Mark f->conversion.field.
* src/androidterm.c (android_update_selection): Adjust
conversion region and selection position by the field start and
end.
* src/editfns.c (find_field): Export function.
* src/frame.c (make_frame): Clear f->conversion.field.
* src/frame.h (struct text_conversion_state) <field>: New field.
* src/lisp.h (find_fields, reset_frame_conversion): Export
functions.
* src/minibuf.c (Fread_from_minibuffer): Reset frame conversion
if Voverriding_text_conversion_style is set.
* src/textconv.c (textconv_query): Narrow to field.
(reset_frame_conversion): New function.
(reset_frame_state): Clear conversion field.
(really_delete_surrounding_text): Narrow to field.
(locate_and_save_position_in_field): New function.
(really_request_point_update, really_set_point_and_mark)
(complete_edit_check, handle_pending_conversion_events_1)
(handle_pending_conversion_events, get_conversion_field)
(set_composing_region, textconv_set_point_and_mark, replace_text)
(get_extracted_text, get_surrounding_text, report_point_change):
Compute, narrow to and offset by the currently active field
whenever point is updated or a command is received.
(syms_of_textconv): Revise doc strings.
* src/textconv.h (get_conversion_field): Export function.
Diffstat (limited to 'src')
| -rw-r--r-- | src/alloc.c | 1 | ||||
| -rw-r--r-- | src/androidterm.c | 39 | ||||
| -rw-r--r-- | src/editfns.c | 2 | ||||
| -rw-r--r-- | src/frame.c | 1 | ||||
| -rw-r--r-- | src/frame.h | 4 | ||||
| -rw-r--r-- | src/lisp.h | 3 | ||||
| -rw-r--r-- | src/minibuf.c | 14 | ||||
| -rw-r--r-- | src/textconv.c | 296 | ||||
| -rw-r--r-- | src/textconv.h | 1 |
9 files changed, 323 insertions, 38 deletions
diff --git a/src/alloc.c b/src/alloc.c index a8dfde56739..47a8e4f4bd2 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -7050,6 +7050,7 @@ mark_frame (struct Lisp_Vector *ptr) | |||
| 7050 | mark_object (f->conversion.compose_region_start); | 7050 | mark_object (f->conversion.compose_region_start); |
| 7051 | mark_object (f->conversion.compose_region_end); | 7051 | mark_object (f->conversion.compose_region_end); |
| 7052 | mark_object (f->conversion.compose_region_overlay); | 7052 | mark_object (f->conversion.compose_region_overlay); |
| 7053 | mark_object (f->conversion.field); | ||
| 7053 | 7054 | ||
| 7054 | for (tem = f->conversion.actions; tem; tem = tem->next) | 7055 | for (tem = f->conversion.actions; tem; tem = tem->next) |
| 7055 | mark_object (tem->data); | 7056 | mark_object (tem->data); |
diff --git a/src/androidterm.c b/src/androidterm.c index 4549941ee2e..f849f0d9919 100644 --- a/src/androidterm.c +++ b/src/androidterm.c | |||
| @@ -6265,14 +6265,24 @@ android_update_selection (struct frame *f, struct window *w) | |||
| 6265 | jobject extracted; | 6265 | jobject extracted; |
| 6266 | jstring string; | 6266 | jstring string; |
| 6267 | bool mark_active; | 6267 | bool mark_active; |
| 6268 | ptrdiff_t field_start, field_end; | ||
| 6269 | |||
| 6270 | /* Offset these values by the start offset of the field. */ | ||
| 6271 | get_conversion_field (f, &field_start, &field_end); | ||
| 6268 | 6272 | ||
| 6269 | if (MARKERP (f->conversion.compose_region_start)) | 6273 | if (MARKERP (f->conversion.compose_region_start)) |
| 6270 | { | 6274 | { |
| 6271 | eassert (MARKERP (f->conversion.compose_region_end)); | 6275 | eassert (MARKERP (f->conversion.compose_region_end)); |
| 6272 | 6276 | ||
| 6273 | /* Indexing in android starts from 0 instead of 1. */ | 6277 | /* Indexing in android starts from 0 instead of 1. */ |
| 6274 | start = marker_position (f->conversion.compose_region_start) - 1; | 6278 | start = marker_position (f->conversion.compose_region_start); |
| 6275 | end = marker_position (f->conversion.compose_region_end) - 1; | 6279 | end = marker_position (f->conversion.compose_region_end); |
| 6280 | |||
| 6281 | /* Offset and detect underflow. */ | ||
| 6282 | start = max (start, field_start) - field_start - 1; | ||
| 6283 | end = min (end, field_end) - field_start - 1; | ||
| 6284 | if (end < 0 || start < 0) | ||
| 6285 | end = start = -1; | ||
| 6276 | } | 6286 | } |
| 6277 | else | 6287 | else |
| 6278 | start = -1, end = -1; | 6288 | start = -1, end = -1; |
| @@ -6288,24 +6298,27 @@ android_update_selection (struct frame *f, struct window *w) | |||
| 6288 | /* Figure out where the point and mark are. If the mark is not | 6298 | /* Figure out where the point and mark are. If the mark is not |
| 6289 | active, then point is set to equal mark. */ | 6299 | active, then point is set to equal mark. */ |
| 6290 | b = XBUFFER (w->contents); | 6300 | b = XBUFFER (w->contents); |
| 6291 | point = min (w->ephemeral_last_point, | 6301 | point = min (min (max (w->ephemeral_last_point, |
| 6302 | field_start), | ||
| 6303 | field_end) - field_start, | ||
| 6292 | TYPE_MAXIMUM (jint)); | 6304 | TYPE_MAXIMUM (jint)); |
| 6293 | mark = ((!NILP (BVAR (b, mark_active)) | 6305 | mark = ((!NILP (BVAR (b, mark_active)) |
| 6294 | && w->last_mark != -1) | 6306 | && w->last_mark != -1) |
| 6295 | ? min (w->last_mark, TYPE_MAXIMUM (jint)) | 6307 | ? min (min (max (w->last_mark, field_start), |
| 6308 | field_end) - field_start, | ||
| 6309 | TYPE_MAXIMUM (jint)) | ||
| 6296 | : point); | 6310 | : point); |
| 6297 | 6311 | ||
| 6298 | /* Send the update. Android doesn't employ a concept of ``point'' | 6312 | /* Send the update. Android doesn't employ a concept of "point" and |
| 6299 | and ``mark''; instead, it only has a selection, where the start | 6313 | "mark"; instead, it only has a selection, where the start of the |
| 6300 | of the selection is less than or equal to the end, and the region | 6314 | selection is less than or equal to the end, and the region is |
| 6301 | is ``active'' when those two values differ. Also, convert the | 6315 | "active" when those two values differ. The indices will have been |
| 6302 | indices from 1-based Emacs indices to 0-based Android ones. */ | 6316 | converted from 1-based Emacs indices to 0-based Android ones. */ |
| 6303 | android_update_ic (FRAME_ANDROID_WINDOW (f), min (point, mark) - 1, | 6317 | android_update_ic (FRAME_ANDROID_WINDOW (f), min (point, mark), |
| 6304 | max (point, mark) - 1, start, end); | 6318 | max (point, mark), start, end); |
| 6305 | 6319 | ||
| 6306 | /* Update the extracted text as well, if the input method has asked | 6320 | /* Update the extracted text as well, if the input method has asked |
| 6307 | for updates. 1 is | 6321 | for updates. 1 is InputConnection.GET_EXTRACTED_TEXT_MONITOR. */ |
| 6308 | InputConnection.GET_EXTRACTED_TEXT_MONITOR. */ | ||
| 6309 | 6322 | ||
| 6310 | if (FRAME_ANDROID_OUTPUT (f)->extracted_text_flags & 1) | 6323 | if (FRAME_ANDROID_OUTPUT (f)->extracted_text_flags & 1) |
| 6311 | { | 6324 | { |
diff --git a/src/editfns.c b/src/editfns.c index 4ccf765bd4b..fbfaaf66644 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -370,7 +370,7 @@ at POSITION. */) | |||
| 370 | Either BEG or END may be 0, in which case the corresponding value | 370 | Either BEG or END may be 0, in which case the corresponding value |
| 371 | is not stored. */ | 371 | is not stored. */ |
| 372 | 372 | ||
| 373 | static void | 373 | void |
| 374 | find_field (Lisp_Object pos, Lisp_Object merge_at_boundary, | 374 | find_field (Lisp_Object pos, Lisp_Object merge_at_boundary, |
| 375 | Lisp_Object beg_limit, | 375 | Lisp_Object beg_limit, |
| 376 | ptrdiff_t *beg, Lisp_Object end_limit, ptrdiff_t *end) | 376 | ptrdiff_t *beg, Lisp_Object end_limit, ptrdiff_t *end) |
diff --git a/src/frame.c b/src/frame.c index ff99b0353af..a671dbaa31d 100644 --- a/src/frame.c +++ b/src/frame.c | |||
| @@ -1001,6 +1001,7 @@ make_frame (bool mini_p) | |||
| 1001 | f->conversion.compose_region_start = Qnil; | 1001 | f->conversion.compose_region_start = Qnil; |
| 1002 | f->conversion.compose_region_end = Qnil; | 1002 | f->conversion.compose_region_end = Qnil; |
| 1003 | f->conversion.compose_region_overlay = Qnil; | 1003 | f->conversion.compose_region_overlay = Qnil; |
| 1004 | f->conversion.field = Qnil; | ||
| 1004 | f->conversion.batch_edit_count = 0; | 1005 | f->conversion.batch_edit_count = 0; |
| 1005 | f->conversion.batch_edit_flags = 0; | 1006 | f->conversion.batch_edit_flags = 0; |
| 1006 | f->conversion.actions = NULL; | 1007 | f->conversion.actions = NULL; |
diff --git a/src/frame.h b/src/frame.h index e03362361a7..63bcce259af 100644 --- a/src/frame.h +++ b/src/frame.h | |||
| @@ -126,6 +126,10 @@ struct text_conversion_state | |||
| 126 | /* Overlay representing the composing region. */ | 126 | /* Overlay representing the composing region. */ |
| 127 | Lisp_Object compose_region_overlay; | 127 | Lisp_Object compose_region_overlay; |
| 128 | 128 | ||
| 129 | /* Cons of (START END . WINDOW) holding the field to which text | ||
| 130 | conversion should be confined, or nil if no such field exists. */ | ||
| 131 | Lisp_Object field; | ||
| 132 | |||
| 129 | /* The number of ongoing ``batch edits'' that are causing point | 133 | /* The number of ongoing ``batch edits'' that are causing point |
| 130 | reporting to be delayed. */ | 134 | reporting to be delayed. */ |
| 131 | int batch_edit_count; | 135 | int batch_edit_count; |
diff --git a/src/lisp.h b/src/lisp.h index 526248dd2ba..4487948b007 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4933,6 +4933,8 @@ extern void unmark_main_thread (void); | |||
| 4933 | 4933 | ||
| 4934 | /* Defined in editfns.c. */ | 4934 | /* Defined in editfns.c. */ |
| 4935 | extern void insert1 (Lisp_Object); | 4935 | extern void insert1 (Lisp_Object); |
| 4936 | extern void find_field (Lisp_Object, Lisp_Object, Lisp_Object, | ||
| 4937 | ptrdiff_t *, Lisp_Object, ptrdiff_t *); | ||
| 4936 | extern void save_excursion_save (union specbinding *); | 4938 | extern void save_excursion_save (union specbinding *); |
| 4937 | extern void save_excursion_restore (Lisp_Object, Lisp_Object); | 4939 | extern void save_excursion_restore (Lisp_Object, Lisp_Object); |
| 4938 | extern Lisp_Object save_restriction_save (void); | 4940 | extern Lisp_Object save_restriction_save (void); |
| @@ -5496,6 +5498,7 @@ extern char *emacs_root_dir (void); | |||
| 5496 | #ifdef HAVE_TEXT_CONVERSION | 5498 | #ifdef HAVE_TEXT_CONVERSION |
| 5497 | /* Defined in textconv.c. */ | 5499 | /* Defined in textconv.c. */ |
| 5498 | extern void reset_frame_state (struct frame *); | 5500 | extern void reset_frame_state (struct frame *); |
| 5501 | extern void reset_frame_conversion (struct frame *); | ||
| 5499 | extern void report_selected_window_change (struct frame *); | 5502 | extern void report_selected_window_change (struct frame *); |
| 5500 | extern void report_point_change (struct frame *, struct window *, | 5503 | extern void report_point_change (struct frame *, struct window *, |
| 5501 | struct buffer *); | 5504 | struct buffer *); |
diff --git a/src/minibuf.c b/src/minibuf.c index 51816133fb2..1029fcdb1ba 100644 --- a/src/minibuf.c +++ b/src/minibuf.c | |||
| @@ -1367,6 +1367,20 @@ and some related functions, which use zero-indexing for POSITION. */) | |||
| 1367 | if (NILP (histpos)) | 1367 | if (NILP (histpos)) |
| 1368 | XSETFASTINT (histpos, 0); | 1368 | XSETFASTINT (histpos, 0); |
| 1369 | 1369 | ||
| 1370 | #ifdef HAVE_TEXT_CONVERSION | ||
| 1371 | /* If overriding-text-conversion-style is set, assume that it was | ||
| 1372 | changed prior to this call and force text conversion to be reset, | ||
| 1373 | since redisplay might conclude that the value was retained | ||
| 1374 | unmodified from a previous call to Fread_from_minibuffer as the | ||
| 1375 | selected window will not have changed. */ | ||
| 1376 | if (!EQ (Voverriding_text_conversion_style, Qlambda) | ||
| 1377 | /* Separate minibuffer frames are not material here, since they | ||
| 1378 | will already be selected if the situation that this is meant to | ||
| 1379 | prevent is possible. */ | ||
| 1380 | && FRAME_WINDOW_P (SELECTED_FRAME ())) | ||
| 1381 | reset_frame_conversion (SELECTED_FRAME ()); | ||
| 1382 | #endif /* HAVE_TEXT_CONVERSION */ | ||
| 1383 | |||
| 1370 | val = read_minibuf (keymap, initial_contents, prompt, | 1384 | val = read_minibuf (keymap, initial_contents, prompt, |
| 1371 | !NILP (read), | 1385 | !NILP (read), |
| 1372 | histvar, histpos, default_value, | 1386 | histvar, histpos, default_value, |
diff --git a/src/textconv.c b/src/textconv.c index 9625c884e16..8850f3cc6be 100644 --- a/src/textconv.c +++ b/src/textconv.c | |||
| @@ -195,6 +195,15 @@ textconv_query (struct frame *f, struct textconv_callback_struct *query, | |||
| 195 | : f->selected_window), Qt); | 195 | : f->selected_window), Qt); |
| 196 | w = XWINDOW (selected_window); | 196 | w = XWINDOW (selected_window); |
| 197 | 197 | ||
| 198 | /* Narrow to the field, if any. */ | ||
| 199 | if (!NILP (f->conversion.field)) | ||
| 200 | { | ||
| 201 | record_unwind_protect (save_restriction_restore, | ||
| 202 | save_restriction_save ()); | ||
| 203 | Fnarrow_to_region (XCAR (f->conversion.field), | ||
| 204 | XCAR (XCDR (f->conversion.field))); | ||
| 205 | } | ||
| 206 | |||
| 198 | /* Now find the appropriate text bounds for QUERY. First, move | 207 | /* Now find the appropriate text bounds for QUERY. First, move |
| 199 | point QUERY->position steps forward or backwards. */ | 208 | point QUERY->position steps forward or backwards. */ |
| 200 | 209 | ||
| @@ -488,6 +497,17 @@ record_buffer_change (ptrdiff_t beg, ptrdiff_t end, | |||
| 488 | Vtext_conversion_edits); | 497 | Vtext_conversion_edits); |
| 489 | } | 498 | } |
| 490 | 499 | ||
| 500 | /* Reset text conversion state of frame F, and resume text conversion. | ||
| 501 | Delete any overlays or markers inside. */ | ||
| 502 | |||
| 503 | void | ||
| 504 | reset_frame_conversion (struct frame *f) | ||
| 505 | { | ||
| 506 | reset_frame_state (f); | ||
| 507 | if (text_interface && FRAME_WINDOW_P (f) && FRAME_VISIBLE_P (f)) | ||
| 508 | text_interface->reset (f); | ||
| 509 | } | ||
| 510 | |||
| 491 | /* Reset text conversion state of frame F. Delete any overlays or | 511 | /* Reset text conversion state of frame F. Delete any overlays or |
| 492 | markers inside. */ | 512 | markers inside. */ |
| 493 | 513 | ||
| @@ -530,6 +550,15 @@ reset_frame_state (struct frame *f) | |||
| 530 | /* Clear batch edit state. */ | 550 | /* Clear batch edit state. */ |
| 531 | f->conversion.batch_edit_count = 0; | 551 | f->conversion.batch_edit_count = 0; |
| 532 | f->conversion.batch_edit_flags = 0; | 552 | f->conversion.batch_edit_flags = 0; |
| 553 | |||
| 554 | /* Clear active field. */ | ||
| 555 | if (!NILP (f->conversion.field)) | ||
| 556 | { | ||
| 557 | Fset_marker (XCAR (f->conversion.field), Qnil, Qnil); | ||
| 558 | Fset_marker (XCAR (XCDR (f->conversion.field)), Qnil, | ||
| 559 | Qnil); | ||
| 560 | } | ||
| 561 | f->conversion.field = Qnil; | ||
| 533 | } | 562 | } |
| 534 | 563 | ||
| 535 | /* Return whether or not there are pending edits from an input method | 564 | /* Return whether or not there are pending edits from an input method |
| @@ -1012,6 +1041,15 @@ really_delete_surrounding_text (struct frame *f, ptrdiff_t left, | |||
| 1012 | redisplay. */ | 1041 | redisplay. */ |
| 1013 | select_window (f->old_selected_window, Qt); | 1042 | select_window (f->old_selected_window, Qt); |
| 1014 | 1043 | ||
| 1044 | /* Narrow to the field, if any. */ | ||
| 1045 | if (!NILP (f->conversion.field)) | ||
| 1046 | { | ||
| 1047 | record_unwind_protect (save_restriction_restore, | ||
| 1048 | save_restriction_save ()); | ||
| 1049 | Fnarrow_to_region (XCAR (f->conversion.field), | ||
| 1050 | XCAR (XCDR (f->conversion.field))); | ||
| 1051 | } | ||
| 1052 | |||
| 1015 | /* Figure out where to start deleting from. */ | 1053 | /* Figure out where to start deleting from. */ |
| 1016 | 1054 | ||
| 1017 | a = get_mark (); | 1055 | a = get_mark (); |
| @@ -1078,6 +1116,115 @@ really_delete_surrounding_text (struct frame *f, ptrdiff_t left, | |||
| 1078 | unbind_to (count, Qnil); | 1116 | unbind_to (count, Qnil); |
| 1079 | } | 1117 | } |
| 1080 | 1118 | ||
| 1119 | /* Save the confines of the field surrounding point in w into F's text | ||
| 1120 | conversion state. If NOTIFY_COMPOSE, notify the input method of | ||
| 1121 | changes to the composition region if they arise in this process. */ | ||
| 1122 | |||
| 1123 | static void | ||
| 1124 | locate_and_save_position_in_field (struct frame *f, struct window *w, | ||
| 1125 | bool notify_compose) | ||
| 1126 | { | ||
| 1127 | Lisp_Object pos, window, c1, c2; | ||
| 1128 | specpdl_ref count; | ||
| 1129 | ptrdiff_t beg, end, cstart, cend, newstart, newend; | ||
| 1130 | |||
| 1131 | /* Set the current buffer to W's. */ | ||
| 1132 | count = SPECPDL_INDEX (); | ||
| 1133 | record_unwind_protect (restore_selected_window, selected_window); | ||
| 1134 | XSETWINDOW (window, w); | ||
| 1135 | select_window (window, Qt); | ||
| 1136 | |||
| 1137 | /* Search for a field around the current editing position; this should | ||
| 1138 | also serve to confine text conversion to the visible region. */ | ||
| 1139 | XSETFASTINT (pos, min (max (w->ephemeral_last_point, BEGV), ZV)); | ||
| 1140 | find_field (pos, Qnil, Qnil, &beg, Qnil, &end); | ||
| 1141 | |||
| 1142 | /* If beg is 1 and end is ZV, disable the active field entirely. */ | ||
| 1143 | if (beg == 1 && end == ZV) | ||
| 1144 | { | ||
| 1145 | f->conversion.field = Qnil; | ||
| 1146 | goto exit; | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | /* Don't cons if a pair already exists. */ | ||
| 1150 | if (!NILP (f->conversion.field)) | ||
| 1151 | { | ||
| 1152 | c1 = f->conversion.field; | ||
| 1153 | c2 = XCDR (c1); | ||
| 1154 | Fset_marker (XCAR (c1), make_fixed_natnum (beg), Qnil); | ||
| 1155 | Fset_marker (XCAR (c2), make_fixed_natnum (end), Qnil); | ||
| 1156 | XSETCDR (c2, window); | ||
| 1157 | } | ||
| 1158 | else | ||
| 1159 | { | ||
| 1160 | c1 = build_marker (current_buffer, beg, CHAR_TO_BYTE (beg)); | ||
| 1161 | c2 = build_marker (current_buffer, end, CHAR_TO_BYTE (end)); | ||
| 1162 | Fset_marker_insertion_type (c2, Qt); | ||
| 1163 | f->conversion.field = Fcons (c1, Fcons (c2, window)); | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | /* If the composition region is active and oversteps the active field, | ||
| 1167 | restrict it to the same. */ | ||
| 1168 | |||
| 1169 | if (!NILP (f->conversion.compose_region_start)) | ||
| 1170 | { | ||
| 1171 | cstart = marker_position (f->conversion.compose_region_start); | ||
| 1172 | cend = marker_position (f->conversion.compose_region_end); | ||
| 1173 | |||
| 1174 | if (cend < beg || cstart > end) | ||
| 1175 | { | ||
| 1176 | /* Remove the composition region in whole. */ | ||
| 1177 | /* Make the composition region markers point elsewhere. */ | ||
| 1178 | |||
| 1179 | if (!NILP (f->conversion.compose_region_start)) | ||
| 1180 | { | ||
| 1181 | Fset_marker (f->conversion.compose_region_start, Qnil, Qnil); | ||
| 1182 | Fset_marker (f->conversion.compose_region_end, Qnil, Qnil); | ||
| 1183 | f->conversion.compose_region_start = Qnil; | ||
| 1184 | f->conversion.compose_region_end = Qnil; | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | /* Delete the composition region overlay. */ | ||
| 1188 | |||
| 1189 | if (!NILP (f->conversion.compose_region_overlay)) | ||
| 1190 | Fdelete_overlay (f->conversion.compose_region_overlay); | ||
| 1191 | |||
| 1192 | TEXTCONV_DEBUG ("removing composing region outside active field"); | ||
| 1193 | } | ||
| 1194 | else | ||
| 1195 | { | ||
| 1196 | newstart = max (beg, min (cstart, end)); | ||
| 1197 | newend = max (beg, min (cend, end)); | ||
| 1198 | |||
| 1199 | if (newstart != cstart || newend != cend) | ||
| 1200 | { | ||
| 1201 | TEXTCONV_DEBUG ("confined composing region to %td, %td", | ||
| 1202 | newstart, newend); | ||
| 1203 | Fset_marker (f->conversion.compose_region_end, | ||
| 1204 | make_fixed_natnum (newstart), Qnil); | ||
| 1205 | Fset_marker (f->conversion.compose_region_end, | ||
| 1206 | make_fixed_natnum (newend), Qnil); | ||
| 1207 | } | ||
| 1208 | else | ||
| 1209 | notify_compose = false; | ||
| 1210 | } | ||
| 1211 | } | ||
| 1212 | else | ||
| 1213 | notify_compose = false; | ||
| 1214 | |||
| 1215 | if (notify_compose | ||
| 1216 | && text_interface->compose_region_changed) | ||
| 1217 | { | ||
| 1218 | if (f->conversion.batch_edit_count > 0) | ||
| 1219 | f->conversion.batch_edit_flags |= PENDING_COMPOSE_CHANGE; | ||
| 1220 | else | ||
| 1221 | text_interface->compose_region_changed (f); | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | exit: | ||
| 1225 | unbind_to (count, Qnil); | ||
| 1226 | } | ||
| 1227 | |||
| 1081 | /* Update the interface with frame F's new point and mark. If a batch | 1228 | /* Update the interface with frame F's new point and mark. If a batch |
| 1082 | edit is in progress, schedule the update for when it finishes | 1229 | edit is in progress, schedule the update for when it finishes |
| 1083 | instead. */ | 1230 | instead. */ |
| @@ -1085,6 +1232,8 @@ really_delete_surrounding_text (struct frame *f, ptrdiff_t left, | |||
| 1085 | static void | 1232 | static void |
| 1086 | really_request_point_update (struct frame *f) | 1233 | really_request_point_update (struct frame *f) |
| 1087 | { | 1234 | { |
| 1235 | struct window *w; | ||
| 1236 | |||
| 1088 | /* If F's old selected window is no longer live, fail. */ | 1237 | /* If F's old selected window is no longer live, fail. */ |
| 1089 | 1238 | ||
| 1090 | if (!WINDOW_LIVE_P (f->old_selected_window)) | 1239 | if (!WINDOW_LIVE_P (f->old_selected_window)) |
| @@ -1093,9 +1242,11 @@ really_request_point_update (struct frame *f) | |||
| 1093 | if (f->conversion.batch_edit_count > 0) | 1242 | if (f->conversion.batch_edit_count > 0) |
| 1094 | f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; | 1243 | f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; |
| 1095 | else if (text_interface && text_interface->point_changed) | 1244 | else if (text_interface && text_interface->point_changed) |
| 1096 | text_interface->point_changed (f, | 1245 | { |
| 1097 | XWINDOW (f->old_selected_window), | 1246 | w = XWINDOW (f->old_selected_window); |
| 1098 | current_buffer); | 1247 | locate_and_save_position_in_field (f, w, false); |
| 1248 | text_interface->point_changed (f, w, current_buffer); | ||
| 1249 | } | ||
| 1099 | } | 1250 | } |
| 1100 | 1251 | ||
| 1101 | /* Set point in frame F's selected window to POSITION. If MARK is not | 1252 | /* Set point in frame F's selected window to POSITION. If MARK is not |
| @@ -1130,9 +1281,11 @@ really_set_point_and_mark (struct frame *f, ptrdiff_t point, | |||
| 1130 | if (f->conversion.batch_edit_count > 0) | 1281 | if (f->conversion.batch_edit_count > 0) |
| 1131 | f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; | 1282 | f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; |
| 1132 | else if (text_interface && text_interface->point_changed) | 1283 | else if (text_interface && text_interface->point_changed) |
| 1133 | text_interface->point_changed (f, | 1284 | { |
| 1134 | XWINDOW (f->old_selected_window), | 1285 | w = XWINDOW (f->old_selected_window); |
| 1135 | current_buffer); | 1286 | locate_and_save_position_in_field (f, w, false); |
| 1287 | text_interface->point_changed (f, w, current_buffer); | ||
| 1288 | } | ||
| 1136 | } | 1289 | } |
| 1137 | else | 1290 | else |
| 1138 | /* Set the point. */ | 1291 | /* Set the point. */ |
| @@ -1331,7 +1484,10 @@ complete_edit_check (void *ptr) | |||
| 1331 | if (f->conversion.batch_edit_count > 0) | 1484 | if (f->conversion.batch_edit_count > 0) |
| 1332 | f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; | 1485 | f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; |
| 1333 | else | 1486 | else |
| 1334 | text_interface->point_changed (f, context->w, NULL); | 1487 | { |
| 1488 | locate_and_save_position_in_field (f, context->w, false); | ||
| 1489 | text_interface->point_changed (f, context->w, NULL); | ||
| 1490 | } | ||
| 1335 | } | 1491 | } |
| 1336 | } | 1492 | } |
| 1337 | } | 1493 | } |
| @@ -1400,7 +1556,10 @@ handle_pending_conversion_events_1 (struct frame *f, | |||
| 1400 | break; | 1556 | break; |
| 1401 | 1557 | ||
| 1402 | if (f->conversion.batch_edit_flags & PENDING_POINT_CHANGE) | 1558 | if (f->conversion.batch_edit_flags & PENDING_POINT_CHANGE) |
| 1403 | text_interface->point_changed (f, w, buffer); | 1559 | { |
| 1560 | locate_and_save_position_in_field (f, w, false); | ||
| 1561 | text_interface->point_changed (f, w, buffer); | ||
| 1562 | } | ||
| 1404 | 1563 | ||
| 1405 | if (f->conversion.batch_edit_flags & PENDING_COMPOSE_CHANGE) | 1564 | if (f->conversion.batch_edit_flags & PENDING_COMPOSE_CHANGE) |
| 1406 | text_interface->compose_region_changed (f); | 1565 | text_interface->compose_region_changed (f); |
| @@ -1529,7 +1688,10 @@ handle_pending_conversion_events (void) | |||
| 1529 | if (f->conversion.batch_edit_count > 0) | 1688 | if (f->conversion.batch_edit_count > 0) |
| 1530 | f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; | 1689 | f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; |
| 1531 | else | 1690 | else |
| 1532 | text_interface->point_changed (f, NULL, NULL); | 1691 | { |
| 1692 | locate_and_save_position_in_field (f, w, false); | ||
| 1693 | text_interface->point_changed (f, NULL, NULL); | ||
| 1694 | } | ||
| 1533 | } | 1695 | } |
| 1534 | 1696 | ||
| 1535 | last_point = w->ephemeral_last_point; | 1697 | last_point = w->ephemeral_last_point; |
| @@ -1564,6 +1726,39 @@ handle_pending_conversion_events (void) | |||
| 1564 | unbind_to (count, Qnil); | 1726 | unbind_to (count, Qnil); |
| 1565 | } | 1727 | } |
| 1566 | 1728 | ||
| 1729 | /* Return the confines of the field to which editing operations on frame | ||
| 1730 | F should be constrained in *BEG and *END. Should no field be active, | ||
| 1731 | set *END to MOST_POSITIVE_FIXNUM. */ | ||
| 1732 | |||
| 1733 | void | ||
| 1734 | get_conversion_field (struct frame *f, ptrdiff_t *beg, ptrdiff_t *end) | ||
| 1735 | { | ||
| 1736 | Lisp_Object c1, c2; | ||
| 1737 | struct window *w; | ||
| 1738 | |||
| 1739 | if (!NILP (f->conversion.field)) | ||
| 1740 | { | ||
| 1741 | c1 = f->conversion.field; | ||
| 1742 | c2 = XCDR (c1); | ||
| 1743 | |||
| 1744 | if (!EQ (XCDR (c2), f->old_selected_window)) | ||
| 1745 | { | ||
| 1746 | /* Update this outdated field location. */ | ||
| 1747 | w = XWINDOW (f->old_selected_window); | ||
| 1748 | locate_and_save_position_in_field (f, w, true); | ||
| 1749 | get_conversion_field (f, beg, end); | ||
| 1750 | return; | ||
| 1751 | } | ||
| 1752 | |||
| 1753 | *beg = marker_position (XCAR (c1)); | ||
| 1754 | *end = marker_position (XCAR (c2)); | ||
| 1755 | return; | ||
| 1756 | } | ||
| 1757 | |||
| 1758 | *beg = 1; | ||
| 1759 | *end = MOST_POSITIVE_FIXNUM; | ||
| 1760 | } | ||
| 1761 | |||
| 1567 | /* Start a ``batch edit'' in frame F. During a batch edit, | 1762 | /* Start a ``batch edit'' in frame F. During a batch edit, |
| 1568 | point_changed will not be called until the batch edit ends. | 1763 | point_changed will not be called until the batch edit ends. |
| 1569 | 1764 | ||
| @@ -1694,7 +1889,8 @@ set_composing_text (struct frame *f, Lisp_Object object, | |||
| 1694 | } | 1889 | } |
| 1695 | 1890 | ||
| 1696 | /* Make the region between START and END the currently active | 1891 | /* Make the region between START and END the currently active |
| 1697 | ``composing region'' on frame F. | 1892 | ``composing region'' on frame F. Which of START and END is the |
| 1893 | larger value is not significant. | ||
| 1698 | 1894 | ||
| 1699 | The ``composing region'' is a region of text in the buffer that is | 1895 | The ``composing region'' is a region of text in the buffer that is |
| 1700 | about to undergo editing by the input method. */ | 1896 | about to undergo editing by the input method. */ |
| @@ -1704,14 +1900,22 @@ set_composing_region (struct frame *f, ptrdiff_t start, | |||
| 1704 | ptrdiff_t end, unsigned long counter) | 1900 | ptrdiff_t end, unsigned long counter) |
| 1705 | { | 1901 | { |
| 1706 | struct text_conversion_action *action, **last; | 1902 | struct text_conversion_action *action, **last; |
| 1903 | ptrdiff_t field_start, field_end, temp; | ||
| 1904 | |||
| 1905 | if (start > end) | ||
| 1906 | { | ||
| 1907 | temp = end; | ||
| 1908 | end = start; | ||
| 1909 | start = temp; | ||
| 1910 | } | ||
| 1707 | 1911 | ||
| 1708 | start = min (start, MOST_POSITIVE_FIXNUM); | 1912 | get_conversion_field (f, &field_start, &field_end); |
| 1709 | end = min (end, MOST_POSITIVE_FIXNUM); | 1913 | start = min (start + field_start - 1, MOST_POSITIVE_FIXNUM); |
| 1914 | end = max (start, min (end + field_start - 1, field_end)); | ||
| 1710 | 1915 | ||
| 1711 | action = xmalloc (sizeof *action); | 1916 | action = xmalloc (sizeof *action); |
| 1712 | action->operation = TEXTCONV_SET_COMPOSING_REGION; | 1917 | action->operation = TEXTCONV_SET_COMPOSING_REGION; |
| 1713 | action->data = Fcons (make_fixnum (start), | 1918 | action->data = Fcons (make_fixnum (start), make_fixnum (end)); |
| 1714 | make_fixnum (end)); | ||
| 1715 | action->next = NULL; | 1919 | action->next = NULL; |
| 1716 | action->counter = counter; | 1920 | action->counter = counter; |
| 1717 | for (last = &f->conversion.actions; *last; last = &(*last)->next) | 1921 | for (last = &f->conversion.actions; *last; last = &(*last)->next) |
| @@ -1730,8 +1934,13 @@ textconv_set_point_and_mark (struct frame *f, ptrdiff_t point, | |||
| 1730 | ptrdiff_t mark, unsigned long counter) | 1934 | ptrdiff_t mark, unsigned long counter) |
| 1731 | { | 1935 | { |
| 1732 | struct text_conversion_action *action, **last; | 1936 | struct text_conversion_action *action, **last; |
| 1937 | ptrdiff_t field_start, field_end; | ||
| 1733 | 1938 | ||
| 1734 | point = min (point, MOST_POSITIVE_FIXNUM); | 1939 | get_conversion_field (f, &field_start, &field_end); |
| 1940 | point = min (max (point + field_start - 1, field_start), | ||
| 1941 | field_end); | ||
| 1942 | mark = min (max (mark + field_start - 1, field_start), | ||
| 1943 | field_end); | ||
| 1735 | 1944 | ||
| 1736 | action = xmalloc (sizeof *action); | 1945 | action = xmalloc (sizeof *action); |
| 1737 | action->operation = TEXTCONV_SET_POINT_AND_MARK; | 1946 | action->operation = TEXTCONV_SET_POINT_AND_MARK; |
| @@ -1809,10 +2018,11 @@ textconv_barrier (struct frame *f, unsigned long counter) | |||
| 1809 | input_pending = true; | 2018 | input_pending = true; |
| 1810 | } | 2019 | } |
| 1811 | 2020 | ||
| 1812 | /* Remove the composing region. Replace the text between START and | 2021 | /* Remove the composing region. Replace the text between START and END |
| 1813 | END within F's selected window with TEXT; deactivate the mark if it | 2022 | (whose order, as in `set_composing_region', is not significant) |
| 1814 | is active. Subsequently, set point to POSITION relative to TEXT, | 2023 | within F's selected window with TEXT; deactivate the mark if it is |
| 1815 | much as `commit_text' would. */ | 2024 | active. Subsequently, set point to POSITION relative to TEXT, as |
| 2025 | `commit_text' would. */ | ||
| 1816 | 2026 | ||
| 1817 | void | 2027 | void |
| 1818 | replace_text (struct frame *f, ptrdiff_t start, ptrdiff_t end, | 2028 | replace_text (struct frame *f, ptrdiff_t start, ptrdiff_t end, |
| @@ -1820,6 +2030,18 @@ replace_text (struct frame *f, ptrdiff_t start, ptrdiff_t end, | |||
| 1820 | unsigned long counter) | 2030 | unsigned long counter) |
| 1821 | { | 2031 | { |
| 1822 | struct text_conversion_action *action, **last; | 2032 | struct text_conversion_action *action, **last; |
| 2033 | ptrdiff_t field_start, field_end, temp; | ||
| 2034 | |||
| 2035 | if (start > end) | ||
| 2036 | { | ||
| 2037 | temp = end; | ||
| 2038 | end = start; | ||
| 2039 | start = temp; | ||
| 2040 | } | ||
| 2041 | |||
| 2042 | get_conversion_field (f, &field_start, &field_end); | ||
| 2043 | start = min (start + field_start - 1, MOST_POSITIVE_FIXNUM); | ||
| 2044 | end = max (start, min (end + field_start - 1, field_end)); | ||
| 1823 | 2045 | ||
| 1824 | action = xmalloc (sizeof *action); | 2046 | action = xmalloc (sizeof *action); |
| 1825 | action->operation = TEXTCONV_REPLACE_TEXT; | 2047 | action->operation = TEXTCONV_REPLACE_TEXT; |
| @@ -1858,6 +2080,7 @@ get_extracted_text (struct frame *f, ptrdiff_t n, | |||
| 1858 | specpdl_ref count; | 2080 | specpdl_ref count; |
| 1859 | ptrdiff_t start, end, start_byte, end_byte, mark; | 2081 | ptrdiff_t start, end, start_byte, end_byte, mark; |
| 1860 | char *buffer; | 2082 | char *buffer; |
| 2083 | ptrdiff_t field_start, field_end; | ||
| 1861 | 2084 | ||
| 1862 | if (!WINDOW_LIVE_P (f->old_selected_window)) | 2085 | if (!WINDOW_LIVE_P (f->old_selected_window)) |
| 1863 | return NULL; | 2086 | return NULL; |
| @@ -1907,6 +2130,15 @@ get_extracted_text (struct frame *f, ptrdiff_t n, | |||
| 1907 | goto finish; | 2130 | goto finish; |
| 1908 | } | 2131 | } |
| 1909 | 2132 | ||
| 2133 | /* Narrow to the field, if any. */ | ||
| 2134 | if (!NILP (f->conversion.field)) | ||
| 2135 | { | ||
| 2136 | record_unwind_protect (save_restriction_restore, | ||
| 2137 | save_restriction_save ()); | ||
| 2138 | Fnarrow_to_region (XCAR (f->conversion.field), | ||
| 2139 | XCAR (XCDR (f->conversion.field))); | ||
| 2140 | } | ||
| 2141 | |||
| 1910 | start = max (start, BEGV); | 2142 | start = max (start, BEGV); |
| 1911 | end = min (end, ZV); | 2143 | end = min (end, ZV); |
| 1912 | 2144 | ||
| @@ -1935,7 +2167,8 @@ get_extracted_text (struct frame *f, ptrdiff_t n, | |||
| 1935 | } | 2167 | } |
| 1936 | 2168 | ||
| 1937 | /* Return the offsets. */ | 2169 | /* Return the offsets. */ |
| 1938 | *start_return = start; | 2170 | get_conversion_field (f, &field_start, &field_end); |
| 2171 | *start_return = max (1, start - field_start + 1); | ||
| 1939 | *start_offset = min (mark - start, PT - start); | 2172 | *start_offset = min (mark - start, PT - start); |
| 1940 | *end_offset = max (mark - start, PT - start); | 2173 | *end_offset = max (mark - start, PT - start); |
| 1941 | *length = end - start; | 2174 | *length = end - start; |
| @@ -1968,6 +2201,7 @@ get_surrounding_text (struct frame *f, ptrdiff_t left, | |||
| 1968 | { | 2201 | { |
| 1969 | specpdl_ref count; | 2202 | specpdl_ref count; |
| 1970 | ptrdiff_t start, end, start_byte, end_byte, mark, temp; | 2203 | ptrdiff_t start, end, start_byte, end_byte, mark, temp; |
| 2204 | ptrdiff_t field_start, field_end; | ||
| 1971 | char *buffer; | 2205 | char *buffer; |
| 1972 | 2206 | ||
| 1973 | if (!WINDOW_LIVE_P (f->old_selected_window)) | 2207 | if (!WINDOW_LIVE_P (f->old_selected_window)) |
| @@ -2012,6 +2246,15 @@ get_surrounding_text (struct frame *f, ptrdiff_t left, | |||
| 2012 | || ckd_add (&end, end, right)) | 2246 | || ckd_add (&end, end, right)) |
| 2013 | goto finish; | 2247 | goto finish; |
| 2014 | 2248 | ||
| 2249 | /* Narrow to the field, if any. */ | ||
| 2250 | if (!NILP (f->conversion.field)) | ||
| 2251 | { | ||
| 2252 | record_unwind_protect (save_restriction_restore, | ||
| 2253 | save_restriction_save ()); | ||
| 2254 | Fnarrow_to_region (XCAR (f->conversion.field), | ||
| 2255 | XCAR (XCDR (f->conversion.field))); | ||
| 2256 | } | ||
| 2257 | |||
| 2015 | start = max (start, BEGV); | 2258 | start = max (start, BEGV); |
| 2016 | end = min (end, ZV); | 2259 | end = min (end, ZV); |
| 2017 | 2260 | ||
| @@ -2038,7 +2281,8 @@ get_surrounding_text (struct frame *f, ptrdiff_t left, | |||
| 2038 | /* Return the offsets. Unlike `get_extracted_text', this need not | 2281 | /* Return the offsets. Unlike `get_extracted_text', this need not |
| 2039 | sort mark and point. */ | 2282 | sort mark and point. */ |
| 2040 | 2283 | ||
| 2041 | *offset = start; | 2284 | get_conversion_field (f, &field_start, &field_end); |
| 2285 | *offset = max (1, start - field_start + 1); | ||
| 2042 | *start_return = mark - start; | 2286 | *start_return = mark - start; |
| 2043 | *end_return = PT - start; | 2287 | *end_return = PT - start; |
| 2044 | *length = end - start; | 2288 | *length = end - start; |
| @@ -2110,7 +2354,10 @@ report_point_change (struct frame *f, struct window *window, | |||
| 2110 | if (f->conversion.batch_edit_count > 0) | 2354 | if (f->conversion.batch_edit_count > 0) |
| 2111 | f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; | 2355 | f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; |
| 2112 | else | 2356 | else |
| 2113 | text_interface->point_changed (f, window, buffer); | 2357 | { |
| 2358 | locate_and_save_position_in_field (f, window, false); | ||
| 2359 | text_interface->point_changed (f, window, buffer); | ||
| 2360 | } | ||
| 2114 | } | 2361 | } |
| 2115 | 2362 | ||
| 2116 | /* Temporarily disable text conversion. Must be paired with a | 2363 | /* Temporarily disable text conversion. Must be paired with a |
| @@ -2348,8 +2595,9 @@ as indenting or automatically filling text, should not take place. | |||
| 2348 | Otherwise, it is either a string containing text that was inserted, | 2595 | Otherwise, it is either a string containing text that was inserted, |
| 2349 | text deleted before point, or nil if text was deleted after point. | 2596 | text deleted before point, or nil if text was deleted after point. |
| 2350 | 2597 | ||
| 2351 | The list contents are ordered in the reverse order of editing, i.e. | 2598 | The list contents are arranged in the reverse of the order of editing, |
| 2352 | the latest edit first, so you must iterate through the list in reverse. */); | 2599 | i.e. latest edit first, so you must iterate through the list in |
| 2600 | reverse. */); | ||
| 2353 | Vtext_conversion_edits = Qnil; | 2601 | Vtext_conversion_edits = Qnil; |
| 2354 | 2602 | ||
| 2355 | DEFVAR_LISP ("overriding-text-conversion-style", | 2603 | DEFVAR_LISP ("overriding-text-conversion-style", |
diff --git a/src/textconv.h b/src/textconv.h index 61f13ebcb43..e87ff5cd1f8 100644 --- a/src/textconv.h +++ b/src/textconv.h | |||
| @@ -155,6 +155,7 @@ extern char *get_surrounding_text (struct frame *, ptrdiff_t, | |||
| 155 | extern bool conversion_disabled_p (void); | 155 | extern bool conversion_disabled_p (void); |
| 156 | extern void check_postponed_buffers (void); | 156 | extern void check_postponed_buffers (void); |
| 157 | 157 | ||
| 158 | extern void get_conversion_field (struct frame *, ptrdiff_t *, ptrdiff_t *); | ||
| 158 | extern void register_textconv_interface (struct textconv_interface *); | 159 | extern void register_textconv_interface (struct textconv_interface *); |
| 159 | 160 | ||
| 160 | #endif /* _TEXTCONV_H_ */ | 161 | #endif /* _TEXTCONV_H_ */ |