summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/androidterm.c88
-rw-r--r--src/buffer.c20
-rw-r--r--src/buffer.h11
-rw-r--r--src/emacs.c3
-rw-r--r--src/frame.h2
-rw-r--r--src/lisp.h1
-rw-r--r--src/marker.c26
-rw-r--r--src/textconv.c315
-rw-r--r--src/textconv.h11
-rw-r--r--src/window.h4
-rw-r--r--src/xdisp.c11
11 files changed, 438 insertions, 54 deletions
diff --git a/src/androidterm.c b/src/androidterm.c
index 767b7d8240c..0c990d3d2d2 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -621,8 +621,9 @@ android_handle_ime_event (union android_event *event, struct frame *f)
break;
case ANDROID_IME_SET_POINT:
- textconv_set_point (f, event->ime.position,
- event->ime.counter);
+ textconv_set_point_and_mark (f, event->ime.start,
+ event->ime.end,
+ event->ime.counter);
break;
case ANDROID_IME_START_BATCH_EDIT:
@@ -4305,7 +4306,7 @@ static sem_t edit_sem;
Every time one of the text retrieval functions is called and an
editing request is made, Emacs gives the main thread approximately
- 50 ms to process it, in order to mostly keep the input method in
+ 100 ms to process it, in order to mostly keep the input method in
sync with the buffer contents. */
static void
@@ -4319,7 +4320,7 @@ android_sync_edit (void)
return;
start = current_timespec ();
- end = timespec_add (start, make_timespec (0, 50000000));
+ end = timespec_add (start, make_timespec (0, 100000000));
while (true)
{
@@ -4550,8 +4551,7 @@ android_perform_conversion_query (void *data)
if (!f)
return;
- textconv_query (f, &context->query,
- TEXTCONV_SKIP_CONVERSION_REGION);
+ textconv_query (f, &context->query, TEXTCONV_SKIP_ACTIVE_REGION);
/* context->query.text will have been set even if textconv_query
returns 1. */
@@ -4649,13 +4649,6 @@ android_text_to_string (JNIEnv *env, char *buffer, ptrdiff_t n,
}
JNIEXPORT jstring JNICALL
-NATIVE_NAME (getSelectedText) (JNIEnv *env, jobject object,
- jshort window)
-{
- return NULL;
-}
-
-JNIEXPORT jstring JNICALL
NATIVE_NAME (getTextAfterCursor) (JNIEnv *env, jobject object, jshort window,
jint length, jint flags)
{
@@ -4805,8 +4798,8 @@ NATIVE_NAME (setSelection) (JNIEnv *env, jobject object, jshort window,
event.ime.serial = ++event_serial;
event.ime.window = window;
event.ime.operation = ANDROID_IME_SET_POINT;
- event.ime.start = 0;
- event.ime.end = 0;
+ event.ime.start = start;
+ event.ime.end = end;
event.ime.length = 0;
event.ime.position = start;
event.ime.text = NULL;
@@ -5068,6 +5061,34 @@ NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject ignored_object,
return object;
}
+JNIEXPORT jstring JNICALL
+NATIVE_NAME (getSelectedText) (JNIEnv *env, jobject object,
+ jshort window)
+{
+ struct android_get_extracted_text_context context;
+ jstring string;
+
+ context.hint_max_chars = -1;
+ context.token = 0;
+ context.text = NULL;
+ context.window = window;
+
+ android_sync_edit ();
+ if (android_run_in_emacs_thread (android_get_extracted_text,
+ &context))
+ return NULL;
+
+ if (!context.text)
+ return NULL;
+
+ /* Encode the returned text. */
+ string = android_text_to_string (env, context.text, context.length,
+ context.bytes);
+ free (context.text);
+
+ return string;
+}
+
#ifdef __clang__
#pragma clang diagnostic pop
#else
@@ -5083,7 +5104,8 @@ NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject ignored_object,
static void
android_update_selection (struct frame *f, struct window *w)
{
- ptrdiff_t start, end, point;
+ ptrdiff_t start, end, point, mark;
+ struct buffer *b;
if (MARKERP (f->conversion.compose_region_start))
{
@@ -5103,12 +5125,20 @@ android_update_selection (struct frame *f, struct window *w)
if (!w)
w = XWINDOW (f->selected_window);
- /* Figure out where the point is. */
+ /* Figure out where the point and mark are. If the mark is not
+ active, then point is set to equal mark. */
+ b = XBUFFER (w->contents);
point = min (w->last_point, TYPE_MAXIMUM (jint));
+ mark = ((!NILP (BVAR (b, mark_active))
+ && w->last_mark != -1)
+ ? min (w->last_mark, TYPE_MAXIMUM (jint))
+ : point);
- /* Send the update. */
- android_update_ic (FRAME_ANDROID_WINDOW (f), point, point,
- start, end);
+ /* Send the update. Android doesn't have a concept of ``point'' and
+ ``mark''; instead, it only has a selection, where the start of
+ the selection is less than or equal to the end. */
+ android_update_ic (FRAME_ANDROID_WINDOW (f), min (point, mark),
+ max (point, mark), start, end);
}
/* Notice that the input method connection to F should be reset as a
@@ -5117,16 +5147,32 @@ android_update_selection (struct frame *f, struct window *w)
static void
android_reset_conversion (struct frame *f)
{
+ enum android_ic_mode mode;
+ struct window *w;
+ struct buffer *buffer;
+
/* Reset the input method.
Pick an appropriate ``input mode'' based on whether or not the
minibuffer window is selected; this controls whether or not
``RET'' inserts a newline or sends an actual key event. */
+
+ w = XWINDOW (f->selected_window);
+ buffer = XBUFFER (WINDOW_BUFFER (w));
+
+ if (NILP (BVAR (buffer, text_conversion_style)))
+ mode = ANDROID_IC_MODE_NULL;
+ else if (EQ (BVAR (buffer, text_conversion_style),
+ Qaction))
+ mode = ANDROID_IC_MODE_ACTION;
+ else
+ mode = ANDROID_IC_MODE_TEXT;
+
android_reset_ic (FRAME_ANDROID_WINDOW (f),
(EQ (f->selected_window,
f->minibuffer_window)
? ANDROID_IC_MODE_ACTION
- : ANDROID_IC_MODE_TEXT));
+ : mode));
/* Move its selection to the specified position. */
android_update_selection (f, NULL);
diff --git a/src/buffer.c b/src/buffer.c
index 38648519ba0..af4aa583c96 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -4710,6 +4710,7 @@ init_buffer_once (void)
#ifdef HAVE_TREE_SITTER
XSETFASTINT (BVAR (&buffer_local_flags, ts_parser_list), idx); ++idx;
#endif
+ XSETFASTINT (BVAR (&buffer_local_flags, text_conversion_style), idx); ++idx;
XSETFASTINT (BVAR (&buffer_local_flags, cursor_in_non_selected_windows), idx); ++idx;
/* buffer_local_flags contains no pointers, so it's safe to treat it
@@ -4781,6 +4782,9 @@ init_buffer_once (void)
#ifdef HAVE_TREE_SITTER
bset_ts_parser_list (&buffer_defaults, Qnil);
#endif
+#ifdef HAVE_TEXT_CONVERSION
+ bset_text_conversion_style (&buffer_defaults, Qnil);
+#endif
bset_cursor_in_non_selected_windows (&buffer_defaults, Qt);
bset_enable_multibyte_characters (&buffer_defaults, Qt);
@@ -5852,6 +5856,22 @@ If t, displays a cursor related to the usual cursor type
You can also specify the cursor type as in the `cursor-type' variable.
Use Custom to set this variable and update the display. */);
+ /* While this is defined here, each *term.c module must implement
+ the logic itself. */
+
+ DEFVAR_PER_BUFFER ("text-conversion-style", &BVAR (current_buffer,
+ text_conversion_style),
+ Qnil,
+ "How the on screen keyboard's input method should insert in this buffer.\n\
+When nil, the input method will be disabled and an ordinary keyboard\n\
+will be displayed in its place.\n\
+When the symbol `action', the input method will insert text directly, but\n\
+will send `return' key events instead of inserting new line characters.\n\
+Any other value means that the input method will insert text directly.\n\
+\n\
+This variable does not take immediate effect when set; rather, it takes\n\
+effect upon the next redisplay after the selected window or buffer changes.");
+
DEFVAR_LISP ("kill-buffer-query-functions", Vkill_buffer_query_functions,
doc: /* List of functions called with no args to query before killing a buffer.
The buffer being killed will be current while the functions are running.
diff --git a/src/buffer.h b/src/buffer.h
index e700297a264..e71ffe28045 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -566,6 +566,11 @@ struct buffer
/* A list of tree-sitter parsers for this buffer. */
Lisp_Object ts_parser_list_;
#endif
+
+ /* What type of text conversion the input method should apply to
+ this buffer. */
+ Lisp_Object text_conversion_style_;
+
/* Cursor type to display in non-selected windows.
t means to use hollow box cursor.
See `cursor-type' for other values. */
@@ -842,6 +847,12 @@ bset_width_table (struct buffer *b, Lisp_Object val)
b->width_table_ = val;
}
+INLINE void
+bset_text_conversion_style (struct buffer *b, Lisp_Object val)
+{
+ b->text_conversion_style_ = val;
+}
+
/* BUFFER_CEILING_OF (resp. BUFFER_FLOOR_OF), when applied to n, return
the max (resp. min) p such that
diff --git a/src/emacs.c b/src/emacs.c
index d7de3c85bbe..2f953510a3d 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -2000,6 +2000,9 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
#ifdef HAVE_WINDOW_SYSTEM
init_fringe_once (); /* Swap bitmaps if necessary. */
#endif /* HAVE_WINDOW_SYSTEM */
+#ifdef HAVE_TEXT_CONVERSION
+ syms_of_textconv ();
+#endif
}
init_alloc ();
diff --git a/src/frame.h b/src/frame.h
index 27484936ff1..ca4cca17d74 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -86,7 +86,7 @@ enum text_conversion_operation
TEXTCONV_FINISH_COMPOSING_TEXT,
TEXTCONV_SET_COMPOSING_TEXT,
TEXTCONV_SET_COMPOSING_REGION,
- TEXTCONV_SET_POINT,
+ TEXTCONV_SET_POINT_AND_MARK,
TEXTCONV_DELETE_SURROUNDING_TEXT,
};
diff --git a/src/lisp.h b/src/lisp.h
index 2dc51d32481..a39ca8cc541 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -5234,6 +5234,7 @@ extern void reset_frame_state (struct frame *);
extern void report_selected_window_change (struct frame *);
extern void report_point_change (struct frame *, struct window *,
struct buffer *);
+extern void syms_of_textconv (void);
#endif
#ifdef HAVE_NATIVE_COMP
diff --git a/src/marker.c b/src/marker.c
index e42c49a5434..7b15cd62f1e 100644
--- a/src/marker.c
+++ b/src/marker.c
@@ -23,6 +23,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "lisp.h"
#include "character.h"
#include "buffer.h"
+#include "window.h"
/* Record one cached position found recently by
buf_charpos_to_bytepos or buf_bytepos_to_charpos. */
@@ -566,6 +567,31 @@ set_marker_internal (Lisp_Object marker, Lisp_Object position,
attach_marker (m, b, charpos, bytepos);
}
+
+#ifdef HAVE_TEXT_CONVERSION
+
+ /* If B is the buffer's mark and there is a window displaying B, and
+ text conversion is enabled while the mark is active, redisplay
+ the buffer.
+
+ propagate_window_redisplay will propagate this redisplay to the
+ window, which will eventually reach
+ mark_window_display_accurate_1. At that point,
+ report_point_change will be told to update the mark as seen by
+ the input method.
+
+ This is done all the way in (the seemingly irrelevant) redisplay
+ because the selection reported to the input method is actually what
+ is visible on screen, namely w->last_point. */
+
+ if (m->buffer
+ && EQ (marker, BVAR (m->buffer, mark))
+ && !NILP (BVAR (m->buffer, mark_active))
+ && buffer_window_count (m->buffer))
+ bset_redisplay (m->buffer);
+
+#endif
+
return marker;
}
diff --git a/src/textconv.c b/src/textconv.c
index a39748457d3..835d03f3037 100644
--- a/src/textconv.c
+++ b/src/textconv.c
@@ -89,13 +89,27 @@ copy_buffer (ptrdiff_t beg, ptrdiff_t beg_byte,
size = end0 - beg0;
memcpy (buffer, BYTE_POS_ADDR (beg0), size);
if (beg1 != -1)
- memcpy (buffer, BEG_ADDR + beg1, end1 - beg1);
+ memcpy (buffer + size, BEG_ADDR + beg1, end1 - beg1);
}
/* Conversion query. */
+/* Return the position of the active mark, or -1 if there is no mark
+ or it is not active. */
+
+static ptrdiff_t
+get_mark (void)
+{
+ if (!NILP (BVAR (current_buffer, mark_active))
+ && XMARKER (BVAR (current_buffer, mark))->buffer)
+ return marker_position (BVAR (current_buffer,
+ mark));
+
+ return -1;
+}
+
/* Perform the text conversion operation specified in QUERY and return
the results.
@@ -109,6 +123,9 @@ copy_buffer (ptrdiff_t beg, ptrdiff_t beg_byte,
If FLAGS & TEXTCONV_SKIP_CONVERSION_REGION, then first move PT past
the conversion region in the specified direction if it is inside.
+ If FLAGS & TEXTCONV_SKIP_ACTIVE_REGION, then also move PT past the
+ region if the mark is active.
+
Value is 0 if QUERY->operation was not TEXTCONV_SUBSTITUTION
or if deleting the text was successful, and 1 otherwise. */
@@ -169,6 +186,39 @@ textconv_query (struct frame *f, struct textconv_callback_struct *query,
}
}
+ /* Likewise for the region if the mark is active. */
+
+ if (flags & TEXTCONV_SKIP_ACTIVE_REGION)
+ {
+ temp = get_mark ();
+
+ if (temp == -1)
+ goto escape;
+
+ start = min (temp, PT);
+ end = max (temp, PT);
+
+ if (pos >= start && pos < end)
+ {
+ switch (query->direction)
+ {
+ case TEXTCONV_FORWARD_CHAR:
+ case TEXTCONV_FORWARD_WORD:
+ case TEXTCONV_CARET_DOWN:
+ case TEXTCONV_NEXT_LINE:
+ case TEXTCONV_LINE_START:
+ pos = end;
+ break;
+
+ default:
+ pos = max (BEGV, start);
+ break;
+ }
+ }
+ }
+
+ escape:
+
/* If pos is outside the accessible part of the buffer or if it
overflows, move back to point or to the extremes of the
accessible region. */
@@ -335,6 +385,55 @@ textconv_query (struct frame *f, struct textconv_callback_struct *query,
return 0;
}
+/* Update the overlay displaying the conversion area on F after a
+ change to the conversion region. */
+
+static void
+sync_overlay (struct frame *f)
+{
+ if (MARKERP (f->conversion.compose_region_start))
+ {
+ if (NILP (f->conversion.compose_region_overlay))
+ {
+ f->conversion.compose_region_overlay
+ = Fmake_overlay (f->conversion.compose_region_start,
+ f->conversion.compose_region_end, Qnil,
+ Qt, Qnil);
+ Foverlay_put (f->conversion.compose_region_overlay,
+ Qface, Qunderline);
+ }
+
+ Fmove_overlay (f->conversion.compose_region_overlay,
+ f->conversion.compose_region_start,
+ f->conversion.compose_region_end, Qnil);
+ }
+ else if (!NILP (f->conversion.compose_region_overlay))
+ {
+ Fdelete_overlay (f->conversion.compose_region_overlay);
+ f->conversion.compose_region_overlay = Qnil;
+ }
+}
+
+/* Record a change to the current buffer as a result of an
+ asynchronous text conversion operation on F.
+
+ Consult the doc string of `text-conversion-edits' for the meaning
+ of BEG, END, and EPHEMERAL. */
+
+static void
+record_buffer_change (ptrdiff_t beg, ptrdiff_t end,
+ Lisp_Object ephemeral)
+{
+ Lisp_Object buffer;
+
+ XSETBUFFER (buffer, current_buffer);
+
+ Vtext_conversion_edits
+ = Fcons (list4 (buffer, make_fixnum (beg),
+ make_fixnum (end), ephemeral),
+ Vtext_conversion_edits);
+}
+
/* Reset F's text conversion state. Delete any overlays or
markers inside. */
@@ -438,8 +537,10 @@ really_commit_text (struct frame *f, EMACS_INT position,
/* Replace its contents. */
start = marker_position (f->conversion.compose_region_start);
end = marker_position (f->conversion.compose_region_end);
- safe_del_range (start, end);
+ del_range (start, end);
+ record_buffer_change (start, start, Qnil);
Finsert (1, &text);
+ record_buffer_change (start, PT, text);
/* Move to a the position specified in POSITION. */
@@ -493,6 +594,7 @@ really_commit_text (struct frame *f, EMACS_INT position,
location. */
wanted = PT;
Finsert (1, &text);
+ record_buffer_change (wanted, PT, text);
if (position < 0)
{
@@ -520,6 +622,8 @@ really_commit_text (struct frame *f, EMACS_INT position,
}
}
+ /* This should deactivate the mark. */
+ call0 (Qdeactivate_mark);
unbind_to (count, Qnil);
}
@@ -575,12 +679,11 @@ really_set_composing_text (struct frame *f, ptrdiff_t position,
if (!MARKERP (f->conversion.compose_region_start))
{
- f->conversion.compose_region_start = Fmake_marker ();
- f->conversion.compose_region_end = Fmake_marker ();
- Fset_marker (f->conversion.compose_region_start,
- Fpoint (), Qnil);
- Fset_marker (f->conversion.compose_region_end,
- Fpoint (), Qnil);
+ f->conversion.compose_region_start
+ = build_marker (current_buffer, PT, PT_BYTE);
+ f->conversion.compose_region_end
+ = build_marker (current_buffer, PT, PT_BYTE);
+
Fset_marker_insertion_type (f->conversion.compose_region_end,
Qt);
@@ -595,13 +698,19 @@ really_set_composing_text (struct frame *f, ptrdiff_t position,
Fwiden ();
start = marker_position (f->conversion.compose_region_start);
end = marker_position (f->conversion.compose_region_end);
- safe_del_range (start, end);
+ del_range (start, end);
set_point (start);
+
+ if (start != end)
+ record_buffer_change (start, start, Qnil);
}
/* Insert the new text. */
Finsert (1, &text);
+ if (start != PT)
+ record_buffer_change (start, PT, Qnil);
+
/* Now move point to an appropriate location. */
if (position < 0)
{
@@ -632,6 +741,12 @@ really_set_composing_text (struct frame *f, ptrdiff_t position,
set_point (wanted);
+ /* This should deactivate the mark. */
+ call0 (Qdeactivate_mark);
+
+ /* Move the composition overlay. */
+ sync_overlay (f);
+
/* If PT hasn't changed, the conversion region definitely has.
Otherwise, redisplay will update the input method instead. */
@@ -693,18 +808,21 @@ really_set_composing_region (struct frame *f, ptrdiff_t start,
make_fixnum (start), Qnil);
Fset_marker (f->conversion.compose_region_end,
make_fixnum (end), Qnil);
+ sync_overlay (f);
unbind_to (count, Qnil);
}
-/* Delete LEFT and RIGHT chars around point. */
+/* Delete LEFT and RIGHT chars around point or the active mark,
+ whichever is larger, avoiding the composing region if
+ necessary. */
static void
really_delete_surrounding_text (struct frame *f, ptrdiff_t left,
ptrdiff_t right)
{
specpdl_ref count;
- ptrdiff_t start, end;
+ ptrdiff_t start, end, a, b, a1, b1, lstart, rstart;
/* If F's old selected window is no longer live, fail. */
@@ -719,21 +837,71 @@ really_delete_surrounding_text (struct frame *f, ptrdiff_t left,
redisplay. */
Fselect_window (f->old_selected_window, Qt);
- start = max (BEGV, PT - left);
- end = min (ZV, PT + right);
+ /* Figure out where to start deleting from. */
+
+ a = get_mark ();
+
+ if (a != -1 && a != PT)
+ lstart = rstart = max (a, PT);
+ else
+ lstart = rstart = PT;
+
+ /* Avoid the composing text. This behavior is identical to how
+ Android's BaseInputConnection actually implements avoiding the
+ composing span. */
+
+ if (MARKERP (f->conversion.compose_region_start))
+ {
+ a = marker_position (f->conversion.compose_region_start);
+ b = marker_position (f->conversion.compose_region_end);
+
+ a1 = min (a, b);
+ b1 = max (a, b);
+
+ lstart = min (lstart, min (PT, a1));
+ rstart = max (rstart, max (PT, b1));
+ }
+
+ if (lstart == rstart)
+ {
+ start = max (BEGV, lstart - left);
+ end = min (ZV, rstart + right);
+
+ del_range (start, end);
+ record_buffer_change (start, start, Qnil);
+ }
+ else
+ {
+ start = max (BEGV, lstart - left);
+ end = lstart;
+
+ del_range (start, end);
+ record_buffer_change (start, start, Qnil);
+
+ start = rstart;
+ end = min (ZV, rstart + right);
+ del_range (start, end);
+ record_buffer_change (start, start, Qnil);
+ }
+
+ /* if the mark is now equal to start, deactivate it. */
+
+ if (get_mark () == PT)
+ call0 (Qdeactivate_mark);
- safe_del_range (start, end);
unbind_to (count, Qnil);
}
-/* Set point in F to POSITION.
+/* Set point in F to POSITION. If MARK is not POSITION, activate the
+ mark and set MARK to that as well.
If it has not changed, signal an update through the text input
interface, which is necessary for the IME to acknowledge that the
change has completed. */
static void
-really_set_point (struct frame *f, ptrdiff_t point)
+really_set_point_and_mark (struct frame *f, ptrdiff_t point,
+ ptrdiff_t mark)
{
specpdl_ref count;
@@ -763,6 +931,11 @@ really_set_point (struct frame *f, ptrdiff_t point)
/* Set the point. */
Fgoto_char (make_fixnum (point));
+ if (mark == point && BVAR (current_buffer, mark_active))
+ call0 (Qdeactivate_mark);
+ else
+ call1 (Qpush_mark, make_fixnum (mark));
+
unbind_to (count, Qnil);
}
@@ -845,8 +1018,9 @@ handle_pending_conversion_events_1 (struct frame *f,
XFIXNUM (XCDR (data)));
break;
- case TEXTCONV_SET_POINT:
- really_set_point (f, XFIXNUM (data));
+ case TEXTCONV_SET_POINT_AND_MARK:
+ really_set_point_and_mark (f, XFIXNUM (XCAR (data)),
+ XFIXNUM (XCDR (data)));
break;
case TEXTCONV_DELETE_SURROUNDING_TEXT:
@@ -858,6 +1032,17 @@ handle_pending_conversion_events_1 (struct frame *f,
unbind_to (count, Qnil);
}
+/* Decrement the variable pointed to by *PTR. */
+
+static void
+decrement_inside (void *ptr)
+{
+ int *i;
+
+ i = ptr;
+ (*i)--;
+}
+
/* Process any outstanding text conversion events.
This may run Lisp or signal. */
@@ -868,9 +1053,22 @@ handle_pending_conversion_events (void)
Lisp_Object tail, frame;
struct text_conversion_action *action, *next;
bool handled;
+ static int inside;
+ specpdl_ref count;
handled = false;
+ /* Reset Vtext_conversion_edits. Do not do this if called
+ reentrantly. */
+
+ if (!inside)
+ Vtext_conversion_edits = Qnil;
+
+ inside++;
+
+ count = SPECPDL_INDEX ();
+ record_unwind_protect_ptr (decrement_inside, &inside);
+
FOR_EACH_FRAME (tail, frame)
{
f = XFRAME (frame);
@@ -905,6 +1103,8 @@ handle_pending_conversion_events (void)
handled = true;
}
}
+
+ unbind_to (count, Qnil);
}
/* Start a ``batch edit'' in F. During a batch edit, point_changed
@@ -1057,13 +1257,13 @@ set_composing_region (struct frame *f, ptrdiff_t start,
input_pending = true;
}
-/* Move point in F's selected buffer to POINT.
+/* Move point in F's selected buffer to POINT and maybe push MARK.
COUNTER means the same as in `start_batch_edit'. */
void
-textconv_set_point (struct frame *f, ptrdiff_t point,
- unsigned long counter)
+textconv_set_point_and_mark (struct frame *f, ptrdiff_t point,
+ ptrdiff_t mark, unsigned long counter)
{
struct text_conversion_action *action, **last;
@@ -1071,8 +1271,9 @@ textconv_set_point (struct frame *f, ptrdiff_t point,
point = MOST_POSITIVE_FIXNUM;
action = xmalloc (sizeof *action);
- action->operation = TEXTCONV_SET_POINT;
- action->data = make_fixnum (point);
+ action->operation = TEXTCONV_SET_POINT_AND_MARK;
+ action->data = Fcons (make_fixnum (point),
+ make_fixnum (mark));
action->next = NULL;
action->counter = counter;
for (last = &f->conversion.actions; *last; last = &(*last)->next)
@@ -1105,6 +1306,9 @@ delete_surrounding_text (struct frame *f, ptrdiff_t left,
/* Return N characters of text around point in F's old selected
window.
+ If N is -1, return the text between point and mark instead, given
+ that the mark is active.
+
Set *N to the actual number of characters returned, *START_RETURN
to the position of the first character returned, *OFFSET to the
offset of point within that text, *LENGTH to the actual number of
@@ -1137,13 +1341,38 @@ get_extracted_text (struct frame *f, ptrdiff_t n,
/* Temporarily switch to F's selected window at the time of the last
redisplay. */
Fselect_window (f->old_selected_window, Qt);
+ buffer = NULL;
/* Figure out the bounds of the text to return. */
- start = PT - n / 2;
- end = PT + n - n / 2;
+ if (n != -1)
+ {
+ start = PT - n / 2;
+ end = PT + n - n / 2;
+ }
+ else
+ {
+ if (!NILP (BVAR (current_buffer, mark_active))
+ && XMARKER (BVAR (current_buffer, mark))->buffer)
+ {
+ start = marker_position (BVAR (current_buffer, mark));
+ end = PT;
+
+ /* Sort start and end. start_byte is used to hold a
+ temporary value. */
+
+ if (start > end)
+ {
+ start_byte = end;
+ end = start;
+ start = start_byte;
+ }
+ }
+ else
+ goto finish;
+ }
+
start = max (start, BEGV);
end = min (end, ZV);
- buffer = NULL;
/* Detect overflow. */
@@ -1218,3 +1447,37 @@ register_textconv_interface (struct textconv_interface *interface)
{
text_interface = interface;
}
+
+
+
+void
+syms_of_textconv (void)
+{
+ DEFSYM (Qaction, "action");
+ DEFSYM (Qtext_conversion, "text-conversion");
+ DEFSYM (Qpush_mark, "push-mark");
+ DEFSYM (Qunderline, "underline");
+
+ DEFVAR_LISP ("text-conversion-edits", Vtext_conversion_edits,
+ doc: /* List of buffers that were last edited as a result of text conversion.
+
+This list can be used while handling a `text-conversion' event to
+determine the changes which have taken place.
+
+Each element of the list describes a single edit in a buffer, of the
+form:
+
+ (BUFFER BEG END EPHEMERAL)
+
+If an insertion or a change occured, then BEG and END are buffer
+positions denote the bounds of the text that was changed or inserted.
+If EPHEMERAL is t, then the input method will shortly make more
+changes to the text, so any actions that would otherwise be taken
+(such as indenting or automatically filling text) should not take
+place; otherwise, it is a string describing the text which was
+inserted.
+
+If a deletion occured, then BEG and END are the same, and EPHEMERAL is
+nil. */);
+ Vtext_conversion_edits = Qnil;
+}
diff --git a/src/textconv.h b/src/textconv.h
index ce003847637..034c663521a 100644
--- a/src/textconv.h
+++ b/src/textconv.h
@@ -35,9 +35,10 @@ struct textconv_interface
unexpected buffer change occurs.) */
void (*reset) (struct frame *);
- /* Notice that point has moved in the specified frame's selected
- window's selected buffer. The second argument is the window
- whose point changed, and the third argument is the buffer. */
+ /* Notice that point or mark has moved in the specified frame's
+ selected window's selected buffer. The second argument is the
+ window whose point changed, and the third argument is the
+ buffer. */
void (*point_changed) (struct frame *, struct window *,
struct buffer *);
@@ -118,6 +119,7 @@ struct textconv_callback_struct
};
#define TEXTCONV_SKIP_CONVERSION_REGION (1 << 0)
+#define TEXTCONV_SKIP_ACTIVE_REGION (1 << 1)
extern int textconv_query (struct frame *, struct textconv_callback_struct *,
int);
@@ -132,7 +134,8 @@ extern void set_composing_text (struct frame *, Lisp_Object,
ptrdiff_t, unsigned long);
extern void set_composing_region (struct frame *, ptrdiff_t, ptrdiff_t,
unsigned long);
-extern void textconv_set_point (struct frame *, ptrdiff_t, unsigned long);
+extern void textconv_set_point_and_mark (struct frame *, ptrdiff_t,
+ ptrdiff_t, unsigned long);
extern void delete_surrounding_text (struct frame *, ptrdiff_t,
ptrdiff_t, unsigned long);
extern char *get_extracted_text (struct frame *, ptrdiff_t, ptrdiff_t *,
diff --git a/src/window.h b/src/window.h
index 32b5fe14f4f..463c7f89b9b 100644
--- a/src/window.h
+++ b/src/window.h
@@ -286,6 +286,10 @@ struct window
it should be positive. */
ptrdiff_t last_point;
+ /* Value of mark in the selected window at the time of the last
+ redisplay. */
+ ptrdiff_t last_mark;
+
/* Line number and position of a line somewhere above the top of the
screen. If this field is zero, it means we don't have a base line. */
ptrdiff_t base_line_number;
diff --git a/src/xdisp.c b/src/xdisp.c
index 4b91fcf31ca..525eaa64b3a 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -17268,7 +17268,7 @@ mark_window_display_accurate_1 (struct window *w, bool accurate_p)
{
struct buffer *b = XBUFFER (w->contents);
#ifdef HAVE_TEXT_CONVERSION
- ptrdiff_t prev_point;
+ ptrdiff_t prev_point, prev_mark;
#endif
w->last_modified = accurate_p ? BUF_MODIFF (b) : 0;
@@ -17301,6 +17301,7 @@ mark_window_display_accurate_1 (struct window *w, bool accurate_p)
#ifdef HAVE_TEXT_CONVERSION
prev_point = w->last_point;
+ prev_mark = w->last_mark;
#endif
if (w == XWINDOW (selected_window))
@@ -17308,6 +17309,11 @@ mark_window_display_accurate_1 (struct window *w, bool accurate_p)
else
w->last_point = marker_position (w->pointm);
+ if (XMARKER (BVAR (b, mark))->buffer == b)
+ w->last_mark = marker_position (BVAR (b, mark));
+ else
+ w->last_mark = -1;
+
#ifdef HAVE_TEXT_CONVERSION
/* Point motion is only propagated to the input method for use
in text conversion during a redisplay. While this can lead
@@ -17323,7 +17329,8 @@ mark_window_display_accurate_1 (struct window *w, bool accurate_p)
during such a change, so the consequences are not that
severe. */
- if (prev_point != w->last_point
+ if ((prev_point != w->last_point
+ || prev_mark != w->last_mark)
&& FRAME_WINDOW_P (WINDOW_XFRAME (w))
&& w == XWINDOW (WINDOW_XFRAME (w)->selected_window))
report_point_change (WINDOW_XFRAME (w), w, b);