aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2024-04-21 21:51:09 +0800
committerPo Lu2024-04-29 12:34:39 +0800
commit430088c9ccec5fe9be57d267f45acdc87aa3b28e (patch)
treea953f845c4176e4a18a542c1e321f80ad34ab4af /src
parentee2e0031d8cc32bb7837ea97ce07ef3b25463223 (diff)
downloademacs-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.c1
-rw-r--r--src/androidterm.c39
-rw-r--r--src/editfns.c2
-rw-r--r--src/frame.c1
-rw-r--r--src/frame.h4
-rw-r--r--src/lisp.h3
-rw-r--r--src/minibuf.c14
-rw-r--r--src/textconv.c296
-rw-r--r--src/textconv.h1
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
373static void 373void
374find_field (Lisp_Object pos, Lisp_Object merge_at_boundary, 374find_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. */
4935extern void insert1 (Lisp_Object); 4935extern void insert1 (Lisp_Object);
4936extern void find_field (Lisp_Object, Lisp_Object, Lisp_Object,
4937 ptrdiff_t *, Lisp_Object, ptrdiff_t *);
4936extern void save_excursion_save (union specbinding *); 4938extern void save_excursion_save (union specbinding *);
4937extern void save_excursion_restore (Lisp_Object, Lisp_Object); 4939extern void save_excursion_restore (Lisp_Object, Lisp_Object);
4938extern Lisp_Object save_restriction_save (void); 4940extern 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. */
5498extern void reset_frame_state (struct frame *); 5500extern void reset_frame_state (struct frame *);
5501extern void reset_frame_conversion (struct frame *);
5499extern void report_selected_window_change (struct frame *); 5502extern void report_selected_window_change (struct frame *);
5500extern void report_point_change (struct frame *, struct window *, 5503extern 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
503void
504reset_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
1123static void
1124locate_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,
1085static void 1232static void
1086really_request_point_update (struct frame *f) 1233really_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
1733void
1734get_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
1817void 2027void
1818replace_text (struct frame *f, ptrdiff_t start, ptrdiff_t end, 2028replace_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.
2348Otherwise, it is either a string containing text that was inserted, 2595Otherwise, it is either a string containing text that was inserted,
2349text deleted before point, or nil if text was deleted after point. 2596text deleted before point, or nil if text was deleted after point.
2350 2597
2351The list contents are ordered in the reverse order of editing, i.e. 2598The list contents are arranged in the reverse of the order of editing,
2352the latest edit first, so you must iterate through the list in reverse. */); 2599i.e. latest edit first, so you must iterate through the list in
2600reverse. */);
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,
155extern bool conversion_disabled_p (void); 155extern bool conversion_disabled_p (void);
156extern void check_postponed_buffers (void); 156extern void check_postponed_buffers (void);
157 157
158extern void get_conversion_field (struct frame *, ptrdiff_t *, ptrdiff_t *);
158extern void register_textconv_interface (struct textconv_interface *); 159extern void register_textconv_interface (struct textconv_interface *);
159 160
160#endif /* _TEXTCONV_H_ */ 161#endif /* _TEXTCONV_H_ */