1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-06 06:20:55 -08:00

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.
This commit is contained in:
Po Lu 2024-04-21 21:51:09 +08:00
parent ee2e0031d8
commit 430088c9cc
10 changed files with 324 additions and 38 deletions

View file

@ -5400,6 +5400,7 @@ if that value is non-nil."
(setq-local custom--invocation-options nil (setq-local custom--invocation-options nil
custom--hidden-state 'hidden) custom--hidden-state 'hidden)
(setq-local revert-buffer-function #'custom--revert-buffer) (setq-local revert-buffer-function #'custom--revert-buffer)
(setq-local text-conversion-style 'action)
(make-local-variable 'custom-options) (make-local-variable 'custom-options)
(make-local-variable 'custom-local-buffer) (make-local-variable 'custom-local-buffer)
(custom--initialize-widget-variables) (custom--initialize-widget-variables)

View file

@ -7050,6 +7050,7 @@ mark_frame (struct Lisp_Vector *ptr)
mark_object (f->conversion.compose_region_start); mark_object (f->conversion.compose_region_start);
mark_object (f->conversion.compose_region_end); mark_object (f->conversion.compose_region_end);
mark_object (f->conversion.compose_region_overlay); mark_object (f->conversion.compose_region_overlay);
mark_object (f->conversion.field);
for (tem = f->conversion.actions; tem; tem = tem->next) for (tem = f->conversion.actions; tem; tem = tem->next)
mark_object (tem->data); mark_object (tem->data);

View file

@ -6265,14 +6265,24 @@ android_update_selection (struct frame *f, struct window *w)
jobject extracted; jobject extracted;
jstring string; jstring string;
bool mark_active; bool mark_active;
ptrdiff_t field_start, field_end;
/* Offset these values by the start offset of the field. */
get_conversion_field (f, &field_start, &field_end);
if (MARKERP (f->conversion.compose_region_start)) if (MARKERP (f->conversion.compose_region_start))
{ {
eassert (MARKERP (f->conversion.compose_region_end)); eassert (MARKERP (f->conversion.compose_region_end));
/* Indexing in android starts from 0 instead of 1. */ /* Indexing in android starts from 0 instead of 1. */
start = marker_position (f->conversion.compose_region_start) - 1; start = marker_position (f->conversion.compose_region_start);
end = marker_position (f->conversion.compose_region_end) - 1; end = marker_position (f->conversion.compose_region_end);
/* Offset and detect underflow. */
start = max (start, field_start) - field_start - 1;
end = min (end, field_end) - field_start - 1;
if (end < 0 || start < 0)
end = start = -1;
} }
else else
start = -1, end = -1; start = -1, end = -1;
@ -6288,24 +6298,27 @@ android_update_selection (struct frame *f, struct window *w)
/* Figure out where the point and mark are. If the mark is not /* Figure out where the point and mark are. If the mark is not
active, then point is set to equal mark. */ active, then point is set to equal mark. */
b = XBUFFER (w->contents); b = XBUFFER (w->contents);
point = min (w->ephemeral_last_point, point = min (min (max (w->ephemeral_last_point,
field_start),
field_end) - field_start,
TYPE_MAXIMUM (jint)); TYPE_MAXIMUM (jint));
mark = ((!NILP (BVAR (b, mark_active)) mark = ((!NILP (BVAR (b, mark_active))
&& w->last_mark != -1) && w->last_mark != -1)
? min (w->last_mark, TYPE_MAXIMUM (jint)) ? min (min (max (w->last_mark, field_start),
field_end) - field_start,
TYPE_MAXIMUM (jint))
: point); : point);
/* Send the update. Android doesn't employ a concept of ``point'' /* Send the update. Android doesn't employ a concept of "point" and
and ``mark''; instead, it only has a selection, where the start "mark"; instead, it only has a selection, where the start of the
of the selection is less than or equal to the end, and the region selection is less than or equal to the end, and the region is
is ``active'' when those two values differ. Also, convert the "active" when those two values differ. The indices will have been
indices from 1-based Emacs indices to 0-based Android ones. */ converted from 1-based Emacs indices to 0-based Android ones. */
android_update_ic (FRAME_ANDROID_WINDOW (f), min (point, mark) - 1, android_update_ic (FRAME_ANDROID_WINDOW (f), min (point, mark),
max (point, mark) - 1, start, end); max (point, mark), start, end);
/* Update the extracted text as well, if the input method has asked /* Update the extracted text as well, if the input method has asked
for updates. 1 is for updates. 1 is InputConnection.GET_EXTRACTED_TEXT_MONITOR. */
InputConnection.GET_EXTRACTED_TEXT_MONITOR. */
if (FRAME_ANDROID_OUTPUT (f)->extracted_text_flags & 1) if (FRAME_ANDROID_OUTPUT (f)->extracted_text_flags & 1)
{ {

View file

@ -370,7 +370,7 @@ at POSITION. */)
Either BEG or END may be 0, in which case the corresponding value Either BEG or END may be 0, in which case the corresponding value
is not stored. */ is not stored. */
static void void
find_field (Lisp_Object pos, Lisp_Object merge_at_boundary, find_field (Lisp_Object pos, Lisp_Object merge_at_boundary,
Lisp_Object beg_limit, Lisp_Object beg_limit,
ptrdiff_t *beg, Lisp_Object end_limit, ptrdiff_t *end) ptrdiff_t *beg, Lisp_Object end_limit, ptrdiff_t *end)

View file

@ -1001,6 +1001,7 @@ make_frame (bool mini_p)
f->conversion.compose_region_start = Qnil; f->conversion.compose_region_start = Qnil;
f->conversion.compose_region_end = Qnil; f->conversion.compose_region_end = Qnil;
f->conversion.compose_region_overlay = Qnil; f->conversion.compose_region_overlay = Qnil;
f->conversion.field = Qnil;
f->conversion.batch_edit_count = 0; f->conversion.batch_edit_count = 0;
f->conversion.batch_edit_flags = 0; f->conversion.batch_edit_flags = 0;
f->conversion.actions = NULL; f->conversion.actions = NULL;

View file

@ -126,6 +126,10 @@ struct text_conversion_state
/* Overlay representing the composing region. */ /* Overlay representing the composing region. */
Lisp_Object compose_region_overlay; Lisp_Object compose_region_overlay;
/* Cons of (START END . WINDOW) holding the field to which text
conversion should be confined, or nil if no such field exists. */
Lisp_Object field;
/* The number of ongoing ``batch edits'' that are causing point /* The number of ongoing ``batch edits'' that are causing point
reporting to be delayed. */ reporting to be delayed. */
int batch_edit_count; int batch_edit_count;

View file

@ -4933,6 +4933,8 @@ extern void unmark_main_thread (void);
/* Defined in editfns.c. */ /* Defined in editfns.c. */
extern void insert1 (Lisp_Object); extern void insert1 (Lisp_Object);
extern void find_field (Lisp_Object, Lisp_Object, Lisp_Object,
ptrdiff_t *, Lisp_Object, ptrdiff_t *);
extern void save_excursion_save (union specbinding *); extern void save_excursion_save (union specbinding *);
extern void save_excursion_restore (Lisp_Object, Lisp_Object); extern void save_excursion_restore (Lisp_Object, Lisp_Object);
extern Lisp_Object save_restriction_save (void); extern Lisp_Object save_restriction_save (void);
@ -5496,6 +5498,7 @@ extern char *emacs_root_dir (void);
#ifdef HAVE_TEXT_CONVERSION #ifdef HAVE_TEXT_CONVERSION
/* Defined in textconv.c. */ /* Defined in textconv.c. */
extern void reset_frame_state (struct frame *); extern void reset_frame_state (struct frame *);
extern void reset_frame_conversion (struct frame *);
extern void report_selected_window_change (struct frame *); extern void report_selected_window_change (struct frame *);
extern void report_point_change (struct frame *, struct window *, extern void report_point_change (struct frame *, struct window *,
struct buffer *); struct buffer *);

View file

@ -1367,6 +1367,20 @@ and some related functions, which use zero-indexing for POSITION. */)
if (NILP (histpos)) if (NILP (histpos))
XSETFASTINT (histpos, 0); XSETFASTINT (histpos, 0);
#ifdef HAVE_TEXT_CONVERSION
/* If overriding-text-conversion-style is set, assume that it was
changed prior to this call and force text conversion to be reset,
since redisplay might conclude that the value was retained
unmodified from a previous call to Fread_from_minibuffer as the
selected window will not have changed. */
if (!EQ (Voverriding_text_conversion_style, Qlambda)
/* Separate minibuffer frames are not material here, since they
will already be selected if the situation that this is meant to
prevent is possible. */
&& FRAME_WINDOW_P (SELECTED_FRAME ()))
reset_frame_conversion (SELECTED_FRAME ());
#endif /* HAVE_TEXT_CONVERSION */
val = read_minibuf (keymap, initial_contents, prompt, val = read_minibuf (keymap, initial_contents, prompt,
!NILP (read), !NILP (read),
histvar, histpos, default_value, histvar, histpos, default_value,

View file

@ -195,6 +195,15 @@ textconv_query (struct frame *f, struct textconv_callback_struct *query,
: f->selected_window), Qt); : f->selected_window), Qt);
w = XWINDOW (selected_window); w = XWINDOW (selected_window);
/* Narrow to the field, if any. */
if (!NILP (f->conversion.field))
{
record_unwind_protect (save_restriction_restore,
save_restriction_save ());
Fnarrow_to_region (XCAR (f->conversion.field),
XCAR (XCDR (f->conversion.field)));
}
/* Now find the appropriate text bounds for QUERY. First, move /* Now find the appropriate text bounds for QUERY. First, move
point QUERY->position steps forward or backwards. */ point QUERY->position steps forward or backwards. */
@ -488,6 +497,17 @@ record_buffer_change (ptrdiff_t beg, ptrdiff_t end,
Vtext_conversion_edits); Vtext_conversion_edits);
} }
/* Reset text conversion state of frame F, and resume text conversion.
Delete any overlays or markers inside. */
void
reset_frame_conversion (struct frame *f)
{
reset_frame_state (f);
if (text_interface && FRAME_WINDOW_P (f) && FRAME_VISIBLE_P (f))
text_interface->reset (f);
}
/* Reset text conversion state of frame F. Delete any overlays or /* Reset text conversion state of frame F. Delete any overlays or
markers inside. */ markers inside. */
@ -530,6 +550,15 @@ reset_frame_state (struct frame *f)
/* Clear batch edit state. */ /* Clear batch edit state. */
f->conversion.batch_edit_count = 0; f->conversion.batch_edit_count = 0;
f->conversion.batch_edit_flags = 0; f->conversion.batch_edit_flags = 0;
/* Clear active field. */
if (!NILP (f->conversion.field))
{
Fset_marker (XCAR (f->conversion.field), Qnil, Qnil);
Fset_marker (XCAR (XCDR (f->conversion.field)), Qnil,
Qnil);
}
f->conversion.field = Qnil;
} }
/* Return whether or not there are pending edits from an input method /* 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,
redisplay. */ redisplay. */
select_window (f->old_selected_window, Qt); select_window (f->old_selected_window, Qt);
/* Narrow to the field, if any. */
if (!NILP (f->conversion.field))
{
record_unwind_protect (save_restriction_restore,
save_restriction_save ());
Fnarrow_to_region (XCAR (f->conversion.field),
XCAR (XCDR (f->conversion.field)));
}
/* Figure out where to start deleting from. */ /* Figure out where to start deleting from. */
a = get_mark (); a = get_mark ();
@ -1078,6 +1116,115 @@ really_delete_surrounding_text (struct frame *f, ptrdiff_t left,
unbind_to (count, Qnil); unbind_to (count, Qnil);
} }
/* Save the confines of the field surrounding point in w into F's text
conversion state. If NOTIFY_COMPOSE, notify the input method of
changes to the composition region if they arise in this process. */
static void
locate_and_save_position_in_field (struct frame *f, struct window *w,
bool notify_compose)
{
Lisp_Object pos, window, c1, c2;
specpdl_ref count;
ptrdiff_t beg, end, cstart, cend, newstart, newend;
/* Set the current buffer to W's. */
count = SPECPDL_INDEX ();
record_unwind_protect (restore_selected_window, selected_window);
XSETWINDOW (window, w);
select_window (window, Qt);
/* Search for a field around the current editing position; this should
also serve to confine text conversion to the visible region. */
XSETFASTINT (pos, min (max (w->ephemeral_last_point, BEGV), ZV));
find_field (pos, Qnil, Qnil, &beg, Qnil, &end);
/* If beg is 1 and end is ZV, disable the active field entirely. */
if (beg == 1 && end == ZV)
{
f->conversion.field = Qnil;
goto exit;
}
/* Don't cons if a pair already exists. */
if (!NILP (f->conversion.field))
{
c1 = f->conversion.field;
c2 = XCDR (c1);
Fset_marker (XCAR (c1), make_fixed_natnum (beg), Qnil);
Fset_marker (XCAR (c2), make_fixed_natnum (end), Qnil);
XSETCDR (c2, window);
}
else
{
c1 = build_marker (current_buffer, beg, CHAR_TO_BYTE (beg));
c2 = build_marker (current_buffer, end, CHAR_TO_BYTE (end));
Fset_marker_insertion_type (c2, Qt);
f->conversion.field = Fcons (c1, Fcons (c2, window));
}
/* If the composition region is active and oversteps the active field,
restrict it to the same. */
if (!NILP (f->conversion.compose_region_start))
{
cstart = marker_position (f->conversion.compose_region_start);
cend = marker_position (f->conversion.compose_region_end);
if (cend < beg || cstart > end)
{
/* Remove the composition region in whole. */
/* Make the composition region markers point elsewhere. */
if (!NILP (f->conversion.compose_region_start))
{
Fset_marker (f->conversion.compose_region_start, Qnil, Qnil);
Fset_marker (f->conversion.compose_region_end, Qnil, Qnil);
f->conversion.compose_region_start = Qnil;
f->conversion.compose_region_end = Qnil;
}
/* Delete the composition region overlay. */
if (!NILP (f->conversion.compose_region_overlay))
Fdelete_overlay (f->conversion.compose_region_overlay);
TEXTCONV_DEBUG ("removing composing region outside active field");
}
else
{
newstart = max (beg, min (cstart, end));
newend = max (beg, min (cend, end));
if (newstart != cstart || newend != cend)
{
TEXTCONV_DEBUG ("confined composing region to %td, %td",
newstart, newend);
Fset_marker (f->conversion.compose_region_end,
make_fixed_natnum (newstart), Qnil);
Fset_marker (f->conversion.compose_region_end,
make_fixed_natnum (newend), Qnil);
}
else
notify_compose = false;
}
}
else
notify_compose = false;
if (notify_compose
&& text_interface->compose_region_changed)
{
if (f->conversion.batch_edit_count > 0)
f->conversion.batch_edit_flags |= PENDING_COMPOSE_CHANGE;
else
text_interface->compose_region_changed (f);
}
exit:
unbind_to (count, Qnil);
}
/* Update the interface with frame F's new point and mark. If a batch /* Update the interface with frame F's new point and mark. If a batch
edit is in progress, schedule the update for when it finishes edit is in progress, schedule the update for when it finishes
instead. */ instead. */
@ -1085,6 +1232,8 @@ really_delete_surrounding_text (struct frame *f, ptrdiff_t left,
static void static void
really_request_point_update (struct frame *f) really_request_point_update (struct frame *f)
{ {
struct window *w;
/* If F's old selected window is no longer live, fail. */ /* If F's old selected window is no longer live, fail. */
if (!WINDOW_LIVE_P (f->old_selected_window)) if (!WINDOW_LIVE_P (f->old_selected_window))
@ -1093,9 +1242,11 @@ really_request_point_update (struct frame *f)
if (f->conversion.batch_edit_count > 0) if (f->conversion.batch_edit_count > 0)
f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
else if (text_interface && text_interface->point_changed) else if (text_interface && text_interface->point_changed)
text_interface->point_changed (f, {
XWINDOW (f->old_selected_window), w = XWINDOW (f->old_selected_window);
current_buffer); locate_and_save_position_in_field (f, w, false);
text_interface->point_changed (f, w, current_buffer);
}
} }
/* Set point in frame F's selected window to POSITION. If MARK is not /* 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,
if (f->conversion.batch_edit_count > 0) if (f->conversion.batch_edit_count > 0)
f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
else if (text_interface && text_interface->point_changed) else if (text_interface && text_interface->point_changed)
text_interface->point_changed (f, {
XWINDOW (f->old_selected_window), w = XWINDOW (f->old_selected_window);
current_buffer); locate_and_save_position_in_field (f, w, false);
text_interface->point_changed (f, w, current_buffer);
}
} }
else else
/* Set the point. */ /* Set the point. */
@ -1331,7 +1484,10 @@ complete_edit_check (void *ptr)
if (f->conversion.batch_edit_count > 0) if (f->conversion.batch_edit_count > 0)
f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
else else
text_interface->point_changed (f, context->w, NULL); {
locate_and_save_position_in_field (f, context->w, false);
text_interface->point_changed (f, context->w, NULL);
}
} }
} }
} }
@ -1400,7 +1556,10 @@ handle_pending_conversion_events_1 (struct frame *f,
break; break;
if (f->conversion.batch_edit_flags & PENDING_POINT_CHANGE) if (f->conversion.batch_edit_flags & PENDING_POINT_CHANGE)
text_interface->point_changed (f, w, buffer); {
locate_and_save_position_in_field (f, w, false);
text_interface->point_changed (f, w, buffer);
}
if (f->conversion.batch_edit_flags & PENDING_COMPOSE_CHANGE) if (f->conversion.batch_edit_flags & PENDING_COMPOSE_CHANGE)
text_interface->compose_region_changed (f); text_interface->compose_region_changed (f);
@ -1529,7 +1688,10 @@ handle_pending_conversion_events (void)
if (f->conversion.batch_edit_count > 0) if (f->conversion.batch_edit_count > 0)
f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
else else
text_interface->point_changed (f, NULL, NULL); {
locate_and_save_position_in_field (f, w, false);
text_interface->point_changed (f, NULL, NULL);
}
} }
last_point = w->ephemeral_last_point; last_point = w->ephemeral_last_point;
@ -1564,6 +1726,39 @@ handle_pending_conversion_events (void)
unbind_to (count, Qnil); unbind_to (count, Qnil);
} }
/* Return the confines of the field to which editing operations on frame
F should be constrained in *BEG and *END. Should no field be active,
set *END to MOST_POSITIVE_FIXNUM. */
void
get_conversion_field (struct frame *f, ptrdiff_t *beg, ptrdiff_t *end)
{
Lisp_Object c1, c2;
struct window *w;
if (!NILP (f->conversion.field))
{
c1 = f->conversion.field;
c2 = XCDR (c1);
if (!EQ (XCDR (c2), f->old_selected_window))
{
/* Update this outdated field location. */
w = XWINDOW (f->old_selected_window);
locate_and_save_position_in_field (f, w, true);
get_conversion_field (f, beg, end);
return;
}
*beg = marker_position (XCAR (c1));
*end = marker_position (XCAR (c2));
return;
}
*beg = 1;
*end = MOST_POSITIVE_FIXNUM;
}
/* Start a ``batch edit'' in frame F. During a batch edit, /* Start a ``batch edit'' in frame F. During a batch edit,
point_changed will not be called until the batch edit ends. point_changed will not be called until the batch edit ends.
@ -1694,7 +1889,8 @@ set_composing_text (struct frame *f, Lisp_Object object,
} }
/* Make the region between START and END the currently active /* Make the region between START and END the currently active
``composing region'' on frame F. ``composing region'' on frame F. Which of START and END is the
larger value is not significant.
The ``composing region'' is a region of text in the buffer that is The ``composing region'' is a region of text in the buffer that is
about to undergo editing by the input method. */ about to undergo editing by the input method. */
@ -1704,14 +1900,22 @@ set_composing_region (struct frame *f, ptrdiff_t start,
ptrdiff_t end, unsigned long counter) ptrdiff_t end, unsigned long counter)
{ {
struct text_conversion_action *action, **last; struct text_conversion_action *action, **last;
ptrdiff_t field_start, field_end, temp;
start = min (start, MOST_POSITIVE_FIXNUM); if (start > end)
end = min (end, MOST_POSITIVE_FIXNUM); {
temp = end;
end = start;
start = temp;
}
get_conversion_field (f, &field_start, &field_end);
start = min (start + field_start - 1, MOST_POSITIVE_FIXNUM);
end = max (start, min (end + field_start - 1, field_end));
action = xmalloc (sizeof *action); action = xmalloc (sizeof *action);
action->operation = TEXTCONV_SET_COMPOSING_REGION; action->operation = TEXTCONV_SET_COMPOSING_REGION;
action->data = Fcons (make_fixnum (start), action->data = Fcons (make_fixnum (start), make_fixnum (end));
make_fixnum (end));
action->next = NULL; action->next = NULL;
action->counter = counter; action->counter = counter;
for (last = &f->conversion.actions; *last; last = &(*last)->next) for (last = &f->conversion.actions; *last; last = &(*last)->next)
@ -1730,8 +1934,13 @@ textconv_set_point_and_mark (struct frame *f, ptrdiff_t point,
ptrdiff_t mark, unsigned long counter) ptrdiff_t mark, unsigned long counter)
{ {
struct text_conversion_action *action, **last; struct text_conversion_action *action, **last;
ptrdiff_t field_start, field_end;
point = min (point, MOST_POSITIVE_FIXNUM); get_conversion_field (f, &field_start, &field_end);
point = min (max (point + field_start - 1, field_start),
field_end);
mark = min (max (mark + field_start - 1, field_start),
field_end);
action = xmalloc (sizeof *action); action = xmalloc (sizeof *action);
action->operation = TEXTCONV_SET_POINT_AND_MARK; action->operation = TEXTCONV_SET_POINT_AND_MARK;
@ -1809,10 +2018,11 @@ textconv_barrier (struct frame *f, unsigned long counter)
input_pending = true; input_pending = true;
} }
/* Remove the composing region. Replace the text between START and /* Remove the composing region. Replace the text between START and END
END within F's selected window with TEXT; deactivate the mark if it (whose order, as in `set_composing_region', is not significant)
is active. Subsequently, set point to POSITION relative to TEXT, within F's selected window with TEXT; deactivate the mark if it is
much as `commit_text' would. */ active. Subsequently, set point to POSITION relative to TEXT, as
`commit_text' would. */
void void
replace_text (struct frame *f, ptrdiff_t start, ptrdiff_t end, 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,
unsigned long counter) unsigned long counter)
{ {
struct text_conversion_action *action, **last; struct text_conversion_action *action, **last;
ptrdiff_t field_start, field_end, temp;
if (start > end)
{
temp = end;
end = start;
start = temp;
}
get_conversion_field (f, &field_start, &field_end);
start = min (start + field_start - 1, MOST_POSITIVE_FIXNUM);
end = max (start, min (end + field_start - 1, field_end));
action = xmalloc (sizeof *action); action = xmalloc (sizeof *action);
action->operation = TEXTCONV_REPLACE_TEXT; action->operation = TEXTCONV_REPLACE_TEXT;
@ -1858,6 +2080,7 @@ get_extracted_text (struct frame *f, ptrdiff_t n,
specpdl_ref count; specpdl_ref count;
ptrdiff_t start, end, start_byte, end_byte, mark; ptrdiff_t start, end, start_byte, end_byte, mark;
char *buffer; char *buffer;
ptrdiff_t field_start, field_end;
if (!WINDOW_LIVE_P (f->old_selected_window)) if (!WINDOW_LIVE_P (f->old_selected_window))
return NULL; return NULL;
@ -1907,6 +2130,15 @@ get_extracted_text (struct frame *f, ptrdiff_t n,
goto finish; goto finish;
} }
/* Narrow to the field, if any. */
if (!NILP (f->conversion.field))
{
record_unwind_protect (save_restriction_restore,
save_restriction_save ());
Fnarrow_to_region (XCAR (f->conversion.field),
XCAR (XCDR (f->conversion.field)));
}
start = max (start, BEGV); start = max (start, BEGV);
end = min (end, ZV); end = min (end, ZV);
@ -1935,7 +2167,8 @@ get_extracted_text (struct frame *f, ptrdiff_t n,
} }
/* Return the offsets. */ /* Return the offsets. */
*start_return = start; get_conversion_field (f, &field_start, &field_end);
*start_return = max (1, start - field_start + 1);
*start_offset = min (mark - start, PT - start); *start_offset = min (mark - start, PT - start);
*end_offset = max (mark - start, PT - start); *end_offset = max (mark - start, PT - start);
*length = end - start; *length = end - start;
@ -1968,6 +2201,7 @@ get_surrounding_text (struct frame *f, ptrdiff_t left,
{ {
specpdl_ref count; specpdl_ref count;
ptrdiff_t start, end, start_byte, end_byte, mark, temp; ptrdiff_t start, end, start_byte, end_byte, mark, temp;
ptrdiff_t field_start, field_end;
char *buffer; char *buffer;
if (!WINDOW_LIVE_P (f->old_selected_window)) if (!WINDOW_LIVE_P (f->old_selected_window))
@ -2012,6 +2246,15 @@ get_surrounding_text (struct frame *f, ptrdiff_t left,
|| ckd_add (&end, end, right)) || ckd_add (&end, end, right))
goto finish; goto finish;
/* Narrow to the field, if any. */
if (!NILP (f->conversion.field))
{
record_unwind_protect (save_restriction_restore,
save_restriction_save ());
Fnarrow_to_region (XCAR (f->conversion.field),
XCAR (XCDR (f->conversion.field)));
}
start = max (start, BEGV); start = max (start, BEGV);
end = min (end, ZV); end = min (end, ZV);
@ -2038,7 +2281,8 @@ get_surrounding_text (struct frame *f, ptrdiff_t left,
/* Return the offsets. Unlike `get_extracted_text', this need not /* Return the offsets. Unlike `get_extracted_text', this need not
sort mark and point. */ sort mark and point. */
*offset = start; get_conversion_field (f, &field_start, &field_end);
*offset = max (1, start - field_start + 1);
*start_return = mark - start; *start_return = mark - start;
*end_return = PT - start; *end_return = PT - start;
*length = end - start; *length = end - start;
@ -2110,7 +2354,10 @@ report_point_change (struct frame *f, struct window *window,
if (f->conversion.batch_edit_count > 0) if (f->conversion.batch_edit_count > 0)
f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
else else
text_interface->point_changed (f, window, buffer); {
locate_and_save_position_in_field (f, window, false);
text_interface->point_changed (f, window, buffer);
}
} }
/* Temporarily disable text conversion. Must be paired with a /* Temporarily disable text conversion. Must be paired with a
@ -2348,8 +2595,9 @@ as indenting or automatically filling text, should not take place.
Otherwise, it is either a string containing text that was inserted, Otherwise, it is either a string containing text that was inserted,
text deleted before point, or nil if text was deleted after point. text deleted before point, or nil if text was deleted after point.
The list contents are ordered in the reverse order of editing, i.e. The list contents are arranged in the reverse of the order of editing,
the latest edit first, so you must iterate through the list in reverse. */); i.e. latest edit first, so you must iterate through the list in
reverse. */);
Vtext_conversion_edits = Qnil; Vtext_conversion_edits = Qnil;
DEFVAR_LISP ("overriding-text-conversion-style", DEFVAR_LISP ("overriding-text-conversion-style",

View file

@ -155,6 +155,7 @@ extern char *get_surrounding_text (struct frame *, ptrdiff_t,
extern bool conversion_disabled_p (void); extern bool conversion_disabled_p (void);
extern void check_postponed_buffers (void); extern void check_postponed_buffers (void);
extern void get_conversion_field (struct frame *, ptrdiff_t *, ptrdiff_t *);
extern void register_textconv_interface (struct textconv_interface *); extern void register_textconv_interface (struct textconv_interface *);
#endif /* _TEXTCONV_H_ */ #endif /* _TEXTCONV_H_ */