Update Android port
* doc/emacs/input.texi (On-Screen Keyboards): * doc/lispref/commands.texi (Misc Events): Improve documentation of text conversion stuff. * java/org/gnu/emacs/EmacsInputConnection.java (beginBatchEdit) (endBatchEdit, commitCompletion, commitText, deleteSurroundingText) (finishComposingText, getSelectedText, getTextAfterCursor) (EmacsInputConnection, setComposingRegion, performEditorAction) (getExtractedText): Condition debug code on DEBUG_IC. * java/org/gnu/emacs/EmacsService.java (EmacsService, updateIC): Likewise. * lisp/bindings.el (global-map): * lisp/electric.el (global-map): Make `text-conversion' `analyze-text-conversion'. * lisp/progmodes/prog-mode.el (prog-mode): Enable text conversion in input methods. * lisp/simple.el (analyze-text-conversion): New function. * lisp/textmodes/text-mode.el (text-conversion-style) (text-mode): Likewise. * src/androidterm.c (android_handle_ime_event): Handle set_point_and_mark. (android_sync_edit): Give Emacs 100 ms instead. (android_perform_conversion_query): Skip the active region, not the conversion region. (getSelectedText): Implement properly. (android_update_selection): Expose mark to input methods. (android_reset_conversion): Handle `text-conversion-style'. * src/buffer.c (init_buffer_once, syms_of_buffer): Add buffer local variable `text-conversion-style'. * src/buffer.h (struct buffer, bset_text_conversion_style): New fields. * src/emacs.c (android_emacs_init): Call syms_of_textconv. * src/frame.h (enum text_conversion_operation): Rename TEXTCONV_SET_POINT. * src/lisp.h: Export syms_of_textconv. * src/marker.c (set_marker_internal): Force redisplay when the mark is set and the buffer is visible on builds that use text conversion. Explain why. * src/textconv.c (copy_buffer): Fix copying past gap. (get_mark): New function. (textconv_query): Implement new flag. (sync_overlay): New function. Display conversion text in an overlay. (record_buffer_change, really_commit_text) (really_set_composing_text, really_set_composing_region) (really_delete_surrounding_text, really_set_point) (handle_pending_conversion_events_1, decrement_inside) (handle_pending_conversion_events, textconv_set_point) (get_extracted_text, register_textconv_interface): Various fixes and improvements. * src/textconv.h (struct textconv_interface): Update documentation. * src/window.h (GCALIGNED_STRUCT): New field `prev_mark'. * src/xdisp.c (mark_window_display_accurate_1): Handle prev_mark.
This commit is contained in:
parent
dd7066901f
commit
cf24b61985
20 changed files with 607 additions and 81 deletions
|
@ -121,6 +121,9 @@ screen, and send the appropriate key events to Emacs after completion.
|
||||||
However, on screen keyboard input methods directly perform edits to
|
However, on screen keyboard input methods directly perform edits to
|
||||||
the selected window of each frame; this is known as ``text
|
the selected window of each frame; this is known as ``text
|
||||||
conversion'', or ``string conversion'' under the X Window System.
|
conversion'', or ``string conversion'' under the X Window System.
|
||||||
|
Emacs enables these input methods whenever the buffer local value of
|
||||||
|
@code{text-conversion-style} is non-@code{nil}, normally inside
|
||||||
|
derivatives of @code{text-mode} and @code{prog-mode}.
|
||||||
|
|
||||||
Text conversion is performed asynchronously whenever Emacs receives
|
Text conversion is performed asynchronously whenever Emacs receives
|
||||||
a request to perform the conversion from the input method. After the
|
a request to perform the conversion from the input method. After the
|
||||||
|
|
|
@ -2205,9 +2205,51 @@ A few other event types represent occurrences within the system.
|
||||||
This kind of event is sent @strong{after} a system-wide input method
|
This kind of event is sent @strong{after} a system-wide input method
|
||||||
performs an edit to one or more buffers.
|
performs an edit to one or more buffers.
|
||||||
|
|
||||||
Once the event is sent, the input method may already have made changes
|
@vindex text-conversion-edits
|
||||||
to multiple frames. @c TODO: allow querying which frames to which
|
Once the event is sent, the input method may already have made
|
||||||
@c changes have been made.
|
changes to multiple buffers inside many different frames. To
|
||||||
|
determine which buffers have been changed, and what edits have
|
||||||
|
been made to them, use the variable
|
||||||
|
@code{text-conversion-edits}, which is set prior to each
|
||||||
|
@code{text-conversion} event being sent; it is a list of the
|
||||||
|
form:
|
||||||
|
|
||||||
|
@indentedblock
|
||||||
|
@w{@code{(@var{buffer} @var{beg} @var{end} @var{ephemeral})}}
|
||||||
|
@end indentedblock
|
||||||
|
|
||||||
|
Where @var{ephemeral} is the buffer which was modified,
|
||||||
|
@var{beg} and @var{end} are the positions of the edit at the
|
||||||
|
time it was completed, and @var{ephemeral} is either a string,
|
||||||
|
containing any text which was inserted, @code{t}, meaning that
|
||||||
|
the edit is a temporary edit made by the input method, and
|
||||||
|
@code{nil}, meaning that some text was deleted.
|
||||||
|
|
||||||
|
@vindex text-conversion-style
|
||||||
|
Whether or not this event is sent depends on the value of the
|
||||||
|
buffer-local variable @code{text-conversion-style}, which determines
|
||||||
|
how an input method that wishes to make edits to buffer contents will
|
||||||
|
behave.
|
||||||
|
|
||||||
|
This variable can have one three values:
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@item nil
|
||||||
|
This means that the input method will be disabled entirely, and key
|
||||||
|
events will be sent instead of text conversion events.
|
||||||
|
|
||||||
|
@item action
|
||||||
|
This means that the input method will be enabled, but @key{RET} will
|
||||||
|
be sent wherever the input method wanted to insert a new line.
|
||||||
|
|
||||||
|
@item t
|
||||||
|
This, or any other value, means that the input method will be enabled
|
||||||
|
and make edits terminated by @code{text-conversion} events.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Changes to the value of this variable will only take effect upon
|
||||||
|
the next redisplay after the buffer becomes the selected buffer
|
||||||
|
of a frame.
|
||||||
|
|
||||||
@cindex @code{delete-frame} event
|
@cindex @code{delete-frame} event
|
||||||
@item (delete-frame (@var{frame}))
|
@item (delete-frame (@var{frame}))
|
||||||
|
|
|
@ -55,7 +55,9 @@ public class EmacsInputConnection extends BaseInputConnection
|
||||||
public boolean
|
public boolean
|
||||||
beginBatchEdit ()
|
beginBatchEdit ()
|
||||||
{
|
{
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
Log.d (TAG, "beginBatchEdit");
|
Log.d (TAG, "beginBatchEdit");
|
||||||
|
|
||||||
EmacsNative.beginBatchEdit (windowHandle);
|
EmacsNative.beginBatchEdit (windowHandle);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +66,9 @@ public class EmacsInputConnection extends BaseInputConnection
|
||||||
public boolean
|
public boolean
|
||||||
endBatchEdit ()
|
endBatchEdit ()
|
||||||
{
|
{
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
Log.d (TAG, "endBatchEdit");
|
Log.d (TAG, "endBatchEdit");
|
||||||
|
|
||||||
EmacsNative.endBatchEdit (windowHandle);
|
EmacsNative.endBatchEdit (windowHandle);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -73,7 +77,9 @@ public class EmacsInputConnection extends BaseInputConnection
|
||||||
public boolean
|
public boolean
|
||||||
commitCompletion (CompletionInfo info)
|
commitCompletion (CompletionInfo info)
|
||||||
{
|
{
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
Log.d (TAG, "commitCompletion: " + info);
|
Log.d (TAG, "commitCompletion: " + info);
|
||||||
|
|
||||||
EmacsNative.commitCompletion (windowHandle,
|
EmacsNative.commitCompletion (windowHandle,
|
||||||
info.getText ().toString (),
|
info.getText ().toString (),
|
||||||
info.getPosition ());
|
info.getPosition ());
|
||||||
|
@ -84,7 +90,9 @@ public class EmacsInputConnection extends BaseInputConnection
|
||||||
public boolean
|
public boolean
|
||||||
commitText (CharSequence text, int newCursorPosition)
|
commitText (CharSequence text, int newCursorPosition)
|
||||||
{
|
{
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
Log.d (TAG, "commitText: " + text + " " + newCursorPosition);
|
Log.d (TAG, "commitText: " + text + " " + newCursorPosition);
|
||||||
|
|
||||||
EmacsNative.commitText (windowHandle, text.toString (),
|
EmacsNative.commitText (windowHandle, text.toString (),
|
||||||
newCursorPosition);
|
newCursorPosition);
|
||||||
return true;
|
return true;
|
||||||
|
@ -94,8 +102,10 @@ public class EmacsInputConnection extends BaseInputConnection
|
||||||
public boolean
|
public boolean
|
||||||
deleteSurroundingText (int leftLength, int rightLength)
|
deleteSurroundingText (int leftLength, int rightLength)
|
||||||
{
|
{
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
Log.d (TAG, ("deleteSurroundingText: "
|
Log.d (TAG, ("deleteSurroundingText: "
|
||||||
+ leftLength + " " + rightLength));
|
+ leftLength + " " + rightLength));
|
||||||
|
|
||||||
EmacsNative.deleteSurroundingText (windowHandle, leftLength,
|
EmacsNative.deleteSurroundingText (windowHandle, leftLength,
|
||||||
rightLength);
|
rightLength);
|
||||||
return true;
|
return true;
|
||||||
|
@ -105,6 +115,7 @@ public class EmacsInputConnection extends BaseInputConnection
|
||||||
public boolean
|
public boolean
|
||||||
finishComposingText ()
|
finishComposingText ()
|
||||||
{
|
{
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
Log.d (TAG, "finishComposingText");
|
Log.d (TAG, "finishComposingText");
|
||||||
|
|
||||||
EmacsNative.finishComposingText (windowHandle);
|
EmacsNative.finishComposingText (windowHandle);
|
||||||
|
@ -115,6 +126,7 @@ public class EmacsInputConnection extends BaseInputConnection
|
||||||
public String
|
public String
|
||||||
getSelectedText (int flags)
|
getSelectedText (int flags)
|
||||||
{
|
{
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
Log.d (TAG, "getSelectedText: " + flags);
|
Log.d (TAG, "getSelectedText: " + flags);
|
||||||
|
|
||||||
return EmacsNative.getSelectedText (windowHandle, flags);
|
return EmacsNative.getSelectedText (windowHandle, flags);
|
||||||
|
@ -124,26 +136,43 @@ public class EmacsInputConnection extends BaseInputConnection
|
||||||
public String
|
public String
|
||||||
getTextAfterCursor (int length, int flags)
|
getTextAfterCursor (int length, int flags)
|
||||||
{
|
{
|
||||||
|
String string;
|
||||||
|
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
Log.d (TAG, "getTextAfterCursor: " + length + " " + flags);
|
Log.d (TAG, "getTextAfterCursor: " + length + " " + flags);
|
||||||
|
|
||||||
return EmacsNative.getTextAfterCursor (windowHandle, length,
|
string = EmacsNative.getTextAfterCursor (windowHandle, length,
|
||||||
flags);
|
flags);
|
||||||
|
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
|
Log.d (TAG, " --> " + string);
|
||||||
|
|
||||||
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String
|
public String
|
||||||
getTextBeforeCursor (int length, int flags)
|
getTextBeforeCursor (int length, int flags)
|
||||||
{
|
{
|
||||||
|
String string;
|
||||||
|
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
Log.d (TAG, "getTextBeforeCursor: " + length + " " + flags);
|
Log.d (TAG, "getTextBeforeCursor: " + length + " " + flags);
|
||||||
|
|
||||||
return EmacsNative.getTextBeforeCursor (windowHandle, length,
|
string = EmacsNative.getTextBeforeCursor (windowHandle, length,
|
||||||
flags);
|
flags);
|
||||||
|
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
|
Log.d (TAG, " --> " + string);
|
||||||
|
|
||||||
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean
|
public boolean
|
||||||
setComposingText (CharSequence text, int newCursorPosition)
|
setComposingText (CharSequence text, int newCursorPosition)
|
||||||
{
|
{
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
Log.d (TAG, "setComposingText: " + newCursorPosition);
|
Log.d (TAG, "setComposingText: " + newCursorPosition);
|
||||||
|
|
||||||
EmacsNative.setComposingText (windowHandle, text.toString (),
|
EmacsNative.setComposingText (windowHandle, text.toString (),
|
||||||
|
@ -155,6 +184,7 @@ public class EmacsInputConnection extends BaseInputConnection
|
||||||
public boolean
|
public boolean
|
||||||
setComposingRegion (int start, int end)
|
setComposingRegion (int start, int end)
|
||||||
{
|
{
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
Log.d (TAG, "setComposingRegion: " + start + " " + end);
|
Log.d (TAG, "setComposingRegion: " + start + " " + end);
|
||||||
|
|
||||||
EmacsNative.setComposingRegion (windowHandle, start, end);
|
EmacsNative.setComposingRegion (windowHandle, start, end);
|
||||||
|
@ -165,6 +195,7 @@ public class EmacsInputConnection extends BaseInputConnection
|
||||||
public boolean
|
public boolean
|
||||||
performEditorAction (int editorAction)
|
performEditorAction (int editorAction)
|
||||||
{
|
{
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
Log.d (TAG, "performEditorAction: " + editorAction);
|
Log.d (TAG, "performEditorAction: " + editorAction);
|
||||||
|
|
||||||
EmacsNative.performEditorAction (windowHandle, editorAction);
|
EmacsNative.performEditorAction (windowHandle, editorAction);
|
||||||
|
@ -175,6 +206,7 @@ public class EmacsInputConnection extends BaseInputConnection
|
||||||
public ExtractedText
|
public ExtractedText
|
||||||
getExtractedText (ExtractedTextRequest request, int flags)
|
getExtractedText (ExtractedTextRequest request, int flags)
|
||||||
{
|
{
|
||||||
|
if (EmacsService.DEBUG_IC)
|
||||||
Log.d (TAG, "getExtractedText: " + request + " " + flags);
|
Log.d (TAG, "getExtractedText: " + request + " " + flags);
|
||||||
|
|
||||||
return EmacsNative.getExtractedText (windowHandle, request,
|
return EmacsNative.getExtractedText (windowHandle, request,
|
||||||
|
|
|
@ -88,6 +88,8 @@ public class EmacsService extends Service
|
||||||
/* Display metrics used by font backends. */
|
/* Display metrics used by font backends. */
|
||||||
public DisplayMetrics metrics;
|
public DisplayMetrics metrics;
|
||||||
|
|
||||||
|
public static final boolean DEBUG_IC = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int
|
public int
|
||||||
onStartCommand (Intent intent, int flags, int startId)
|
onStartCommand (Intent intent, int flags, int startId)
|
||||||
|
@ -612,6 +614,7 @@ invocation of app_process (through android-emacs) can
|
||||||
int newSelectionEnd, int composingRegionStart,
|
int newSelectionEnd, int composingRegionStart,
|
||||||
int composingRegionEnd)
|
int composingRegionEnd)
|
||||||
{
|
{
|
||||||
|
if (DEBUG_IC)
|
||||||
Log.d (TAG, ("updateIC: " + window + " " + newSelectionStart
|
Log.d (TAG, ("updateIC: " + window + " " + newSelectionStart
|
||||||
+ " " + newSelectionEnd + " "
|
+ " " + newSelectionEnd + " "
|
||||||
+ composingRegionStart + " "
|
+ composingRegionStart + " "
|
||||||
|
@ -626,6 +629,7 @@ invocation of app_process (through android-emacs) can
|
||||||
public void
|
public void
|
||||||
resetIC (EmacsWindow window, int icMode)
|
resetIC (EmacsWindow window, int icMode)
|
||||||
{
|
{
|
||||||
|
if (DEBUG_IC)
|
||||||
Log.d (TAG, "resetIC: " + window);
|
Log.d (TAG, "resetIC: " + window);
|
||||||
|
|
||||||
window.view.setICMode (icMode);
|
window.view.setICMode (icMode);
|
||||||
|
|
|
@ -1522,7 +1522,7 @@ if `inhibit-field-text-motion' is non-nil."
|
||||||
(define-key special-event-map [sigusr2] 'ignore)
|
(define-key special-event-map [sigusr2] 'ignore)
|
||||||
|
|
||||||
;; Text conversion
|
;; Text conversion
|
||||||
(define-key global-map [text-conversion] 'ignore)
|
(define-key global-map [text-conversion] 'analyze-text-conversion)
|
||||||
|
|
||||||
;; Don't look for autoload cookies in this file.
|
;; Don't look for autoload cookies in this file.
|
||||||
;; Local Variables:
|
;; Local Variables:
|
||||||
|
|
|
@ -294,6 +294,7 @@ or comment."
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(define-key global-map "\C-j" 'electric-newline-and-maybe-indent)
|
(define-key global-map "\C-j" 'electric-newline-and-maybe-indent)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun electric-newline-and-maybe-indent ()
|
(defun electric-newline-and-maybe-indent ()
|
||||||
"Insert a newline.
|
"Insert a newline.
|
||||||
|
|
|
@ -336,6 +336,8 @@ support it."
|
||||||
(setq-local require-final-newline mode-require-final-newline)
|
(setq-local require-final-newline mode-require-final-newline)
|
||||||
(setq-local parse-sexp-ignore-comments t)
|
(setq-local parse-sexp-ignore-comments t)
|
||||||
(add-hook 'context-menu-functions 'prog-context-menu 10 t)
|
(add-hook 'context-menu-functions 'prog-context-menu 10 t)
|
||||||
|
;; Enable text conversion in this buffer.
|
||||||
|
(setq-local text-conversion-style t)
|
||||||
;; Any programming language is always written left to right.
|
;; Any programming language is always written left to right.
|
||||||
(setq bidi-paragraph-direction 'left-to-right))
|
(setq bidi-paragraph-direction 'left-to-right))
|
||||||
|
|
||||||
|
|
|
@ -10864,6 +10864,58 @@ If the buffer doesn't exist, create it first."
|
||||||
"Change value in PLIST of PROP to VAL, comparing with `equal'."
|
"Change value in PLIST of PROP to VAL, comparing with `equal'."
|
||||||
(declare (obsolete plist-put "29.1"))
|
(declare (obsolete plist-put "29.1"))
|
||||||
(plist-put plist prop val #'equal))
|
(plist-put plist prop val #'equal))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;; Text conversion support. See textconv.c for more details about
|
||||||
|
;; what this is.
|
||||||
|
|
||||||
|
|
||||||
|
;; Actually in textconv.c.
|
||||||
|
(defvar text-conversion-edits)
|
||||||
|
|
||||||
|
(defun analyze-text-conversion ()
|
||||||
|
"Analyze the results of the previous text conversion event.
|
||||||
|
|
||||||
|
For each insertion:
|
||||||
|
|
||||||
|
- Look for the insertion of a string starting or ending with a
|
||||||
|
character inside `auto-fill-chars', and fill the text around
|
||||||
|
it if `auto-fill-mode' is enabled.
|
||||||
|
|
||||||
|
- Look for the insertion of a new line, and cause automatic
|
||||||
|
line breaking of the previous line when `auto-fill-mode' is
|
||||||
|
enabled.
|
||||||
|
|
||||||
|
- Look for the insertion of a new line, and indent this new
|
||||||
|
line if `electric-indent-mode' is enabled."
|
||||||
|
(interactive)
|
||||||
|
(dolist (edit text-conversion-edits)
|
||||||
|
;; Filter out ephemeral edits and deletions.
|
||||||
|
(when (and (not (eq (nth 1 edit) (nth 2 edit)))
|
||||||
|
(stringp (nth 3 edit)))
|
||||||
|
(with-current-buffer (car edit)
|
||||||
|
(let* ((inserted (nth 3 edit))
|
||||||
|
;; Get the first and last characters.
|
||||||
|
(start (aref inserted 0))
|
||||||
|
(end (aref inserted (1- (length inserted))))
|
||||||
|
;; Figure out whether or not to auto-fill.
|
||||||
|
(auto-fill-p (or (aref auto-fill-chars start)
|
||||||
|
(aref auto-fill-chars end)))
|
||||||
|
;; Figure out whether or not a newline was inserted.
|
||||||
|
(newline-p (string-search "\n" inserted)))
|
||||||
|
(save-excursion
|
||||||
|
(if (and auto-fill-function newline-p)
|
||||||
|
(progn (goto-char (nth 2 edit))
|
||||||
|
(previous-logical-line)
|
||||||
|
(funcall auto-fill-function))
|
||||||
|
(when (and auto-fill-function auto-fill-p)
|
||||||
|
(progn (goto-char (nth 2 edit))
|
||||||
|
(funcall auto-fill-function)))))
|
||||||
|
(when (and electric-indent-mode newline-p)
|
||||||
|
(goto-char (nth 2 edit))
|
||||||
|
(indent-according-to-mode)))))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(provide 'simple)
|
(provide 'simple)
|
||||||
|
|
|
@ -41,6 +41,9 @@
|
||||||
"Non-nil if this buffer's major mode is a variant of Text mode.")
|
"Non-nil if this buffer's major mode is a variant of Text mode.")
|
||||||
(make-obsolete-variable 'text-mode-variant 'derived-mode-p "27.1")
|
(make-obsolete-variable 'text-mode-variant 'derived-mode-p "27.1")
|
||||||
|
|
||||||
|
;; Actually defined in textconv.c.
|
||||||
|
(defvar text-conversion-style)
|
||||||
|
|
||||||
(defvar text-mode-syntax-table
|
(defvar text-mode-syntax-table
|
||||||
(let ((st (make-syntax-table)))
|
(let ((st (make-syntax-table)))
|
||||||
(modify-syntax-entry ?\" ". " st)
|
(modify-syntax-entry ?\" ". " st)
|
||||||
|
@ -125,6 +128,9 @@ You can thus get the full benefit of adaptive filling
|
||||||
Turning on Text mode runs the normal hook `text-mode-hook'."
|
Turning on Text mode runs the normal hook `text-mode-hook'."
|
||||||
(setq-local text-mode-variant t)
|
(setq-local text-mode-variant t)
|
||||||
(setq-local require-final-newline mode-require-final-newline)
|
(setq-local require-final-newline mode-require-final-newline)
|
||||||
|
|
||||||
|
;; Enable text conversion in this buffer.
|
||||||
|
(setq-local text-conversion-style t)
|
||||||
(add-hook 'context-menu-functions 'text-mode-context-menu 10 t))
|
(add-hook 'context-menu-functions 'text-mode-context-menu 10 t))
|
||||||
|
|
||||||
(define-derived-mode paragraph-indent-text-mode text-mode "Parindent"
|
(define-derived-mode paragraph-indent-text-mode text-mode "Parindent"
|
||||||
|
|
|
@ -621,7 +621,8 @@ android_handle_ime_event (union android_event *event, struct frame *f)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ANDROID_IME_SET_POINT:
|
case ANDROID_IME_SET_POINT:
|
||||||
textconv_set_point (f, event->ime.position,
|
textconv_set_point_and_mark (f, event->ime.start,
|
||||||
|
event->ime.end,
|
||||||
event->ime.counter);
|
event->ime.counter);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -4305,7 +4306,7 @@ static sem_t edit_sem;
|
||||||
|
|
||||||
Every time one of the text retrieval functions is called and an
|
Every time one of the text retrieval functions is called and an
|
||||||
editing request is made, Emacs gives the main thread approximately
|
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. */
|
sync with the buffer contents. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -4319,7 +4320,7 @@ android_sync_edit (void)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
start = current_timespec ();
|
start = current_timespec ();
|
||||||
end = timespec_add (start, make_timespec (0, 50000000));
|
end = timespec_add (start, make_timespec (0, 100000000));
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -4550,8 +4551,7 @@ android_perform_conversion_query (void *data)
|
||||||
if (!f)
|
if (!f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
textconv_query (f, &context->query,
|
textconv_query (f, &context->query, TEXTCONV_SKIP_ACTIVE_REGION);
|
||||||
TEXTCONV_SKIP_CONVERSION_REGION);
|
|
||||||
|
|
||||||
/* context->query.text will have been set even if textconv_query
|
/* context->query.text will have been set even if textconv_query
|
||||||
returns 1. */
|
returns 1. */
|
||||||
|
@ -4648,13 +4648,6 @@ android_text_to_string (JNIEnv *env, char *buffer, ptrdiff_t n,
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
|
||||||
NATIVE_NAME (getSelectedText) (JNIEnv *env, jobject object,
|
|
||||||
jshort window)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jstring JNICALL
|
||||||
NATIVE_NAME (getTextAfterCursor) (JNIEnv *env, jobject object, jshort window,
|
NATIVE_NAME (getTextAfterCursor) (JNIEnv *env, jobject object, jshort window,
|
||||||
jint length, jint flags)
|
jint length, jint flags)
|
||||||
|
@ -4805,8 +4798,8 @@ NATIVE_NAME (setSelection) (JNIEnv *env, jobject object, jshort window,
|
||||||
event.ime.serial = ++event_serial;
|
event.ime.serial = ++event_serial;
|
||||||
event.ime.window = window;
|
event.ime.window = window;
|
||||||
event.ime.operation = ANDROID_IME_SET_POINT;
|
event.ime.operation = ANDROID_IME_SET_POINT;
|
||||||
event.ime.start = 0;
|
event.ime.start = start;
|
||||||
event.ime.end = 0;
|
event.ime.end = end;
|
||||||
event.ime.length = 0;
|
event.ime.length = 0;
|
||||||
event.ime.position = start;
|
event.ime.position = start;
|
||||||
event.ime.text = NULL;
|
event.ime.text = NULL;
|
||||||
|
@ -5068,6 +5061,34 @@ NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject ignored_object,
|
||||||
return 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__
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
#else
|
#else
|
||||||
|
@ -5083,7 +5104,8 @@ NATIVE_NAME (getExtractedText) (JNIEnv *env, jobject ignored_object,
|
||||||
static void
|
static void
|
||||||
android_update_selection (struct frame *f, struct window *w)
|
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))
|
if (MARKERP (f->conversion.compose_region_start))
|
||||||
{
|
{
|
||||||
|
@ -5103,12 +5125,20 @@ android_update_selection (struct frame *f, struct window *w)
|
||||||
if (!w)
|
if (!w)
|
||||||
w = XWINDOW (f->selected_window);
|
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));
|
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. */
|
/* Send the update. Android doesn't have a concept of ``point'' and
|
||||||
android_update_ic (FRAME_ANDROID_WINDOW (f), point, point,
|
``mark''; instead, it only has a selection, where the start of
|
||||||
start, end);
|
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
|
/* 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
|
static void
|
||||||
android_reset_conversion (struct frame *f)
|
android_reset_conversion (struct frame *f)
|
||||||
{
|
{
|
||||||
|
enum android_ic_mode mode;
|
||||||
|
struct window *w;
|
||||||
|
struct buffer *buffer;
|
||||||
|
|
||||||
/* Reset the input method.
|
/* Reset the input method.
|
||||||
|
|
||||||
Pick an appropriate ``input mode'' based on whether or not the
|
Pick an appropriate ``input mode'' based on whether or not the
|
||||||
minibuffer window is selected; this controls whether or not
|
minibuffer window is selected; this controls whether or not
|
||||||
``RET'' inserts a newline or sends an actual key event. */
|
``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),
|
android_reset_ic (FRAME_ANDROID_WINDOW (f),
|
||||||
(EQ (f->selected_window,
|
(EQ (f->selected_window,
|
||||||
f->minibuffer_window)
|
f->minibuffer_window)
|
||||||
? ANDROID_IC_MODE_ACTION
|
? ANDROID_IC_MODE_ACTION
|
||||||
: ANDROID_IC_MODE_TEXT));
|
: mode));
|
||||||
|
|
||||||
/* Move its selection to the specified position. */
|
/* Move its selection to the specified position. */
|
||||||
android_update_selection (f, NULL);
|
android_update_selection (f, NULL);
|
||||||
|
|
20
src/buffer.c
20
src/buffer.c
|
@ -4710,6 +4710,7 @@ init_buffer_once (void)
|
||||||
#ifdef HAVE_TREE_SITTER
|
#ifdef HAVE_TREE_SITTER
|
||||||
XSETFASTINT (BVAR (&buffer_local_flags, ts_parser_list), idx); ++idx;
|
XSETFASTINT (BVAR (&buffer_local_flags, ts_parser_list), idx); ++idx;
|
||||||
#endif
|
#endif
|
||||||
|
XSETFASTINT (BVAR (&buffer_local_flags, text_conversion_style), idx); ++idx;
|
||||||
XSETFASTINT (BVAR (&buffer_local_flags, cursor_in_non_selected_windows), 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
|
/* buffer_local_flags contains no pointers, so it's safe to treat it
|
||||||
|
@ -4780,6 +4781,9 @@ init_buffer_once (void)
|
||||||
bset_extra_line_spacing (&buffer_defaults, Qnil);
|
bset_extra_line_spacing (&buffer_defaults, Qnil);
|
||||||
#ifdef HAVE_TREE_SITTER
|
#ifdef HAVE_TREE_SITTER
|
||||||
bset_ts_parser_list (&buffer_defaults, Qnil);
|
bset_ts_parser_list (&buffer_defaults, Qnil);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_TEXT_CONVERSION
|
||||||
|
bset_text_conversion_style (&buffer_defaults, Qnil);
|
||||||
#endif
|
#endif
|
||||||
bset_cursor_in_non_selected_windows (&buffer_defaults, Qt);
|
bset_cursor_in_non_selected_windows (&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.
|
You can also specify the cursor type as in the `cursor-type' variable.
|
||||||
Use Custom to set this variable and update the display. */);
|
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,
|
DEFVAR_LISP ("kill-buffer-query-functions", Vkill_buffer_query_functions,
|
||||||
doc: /* List of functions called with no args to query before killing a buffer.
|
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.
|
The buffer being killed will be current while the functions are running.
|
||||||
|
|
11
src/buffer.h
11
src/buffer.h
|
@ -566,6 +566,11 @@ struct buffer
|
||||||
/* A list of tree-sitter parsers for this buffer. */
|
/* A list of tree-sitter parsers for this buffer. */
|
||||||
Lisp_Object ts_parser_list_;
|
Lisp_Object ts_parser_list_;
|
||||||
#endif
|
#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.
|
/* Cursor type to display in non-selected windows.
|
||||||
t means to use hollow box cursor.
|
t means to use hollow box cursor.
|
||||||
See `cursor-type' for other values. */
|
See `cursor-type' for other values. */
|
||||||
|
@ -842,6 +847,12 @@ bset_width_table (struct buffer *b, Lisp_Object val)
|
||||||
b->width_table_ = 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
|
/* BUFFER_CEILING_OF (resp. BUFFER_FLOOR_OF), when applied to n, return
|
||||||
the max (resp. min) p such that
|
the max (resp. min) p such that
|
||||||
|
|
||||||
|
|
|
@ -2000,6 +2000,9 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
|
||||||
#ifdef HAVE_WINDOW_SYSTEM
|
#ifdef HAVE_WINDOW_SYSTEM
|
||||||
init_fringe_once (); /* Swap bitmaps if necessary. */
|
init_fringe_once (); /* Swap bitmaps if necessary. */
|
||||||
#endif /* HAVE_WINDOW_SYSTEM */
|
#endif /* HAVE_WINDOW_SYSTEM */
|
||||||
|
#ifdef HAVE_TEXT_CONVERSION
|
||||||
|
syms_of_textconv ();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
init_alloc ();
|
init_alloc ();
|
||||||
|
|
|
@ -86,7 +86,7 @@ enum text_conversion_operation
|
||||||
TEXTCONV_FINISH_COMPOSING_TEXT,
|
TEXTCONV_FINISH_COMPOSING_TEXT,
|
||||||
TEXTCONV_SET_COMPOSING_TEXT,
|
TEXTCONV_SET_COMPOSING_TEXT,
|
||||||
TEXTCONV_SET_COMPOSING_REGION,
|
TEXTCONV_SET_COMPOSING_REGION,
|
||||||
TEXTCONV_SET_POINT,
|
TEXTCONV_SET_POINT_AND_MARK,
|
||||||
TEXTCONV_DELETE_SURROUNDING_TEXT,
|
TEXTCONV_DELETE_SURROUNDING_TEXT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5234,6 +5234,7 @@ extern void reset_frame_state (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 *);
|
||||||
|
extern void syms_of_textconv (void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_NATIVE_COMP
|
#ifdef HAVE_NATIVE_COMP
|
||||||
|
|
26
src/marker.c
26
src/marker.c
|
@ -23,6 +23,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
#include "lisp.h"
|
#include "lisp.h"
|
||||||
#include "character.h"
|
#include "character.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
/* Record one cached position found recently by
|
/* Record one cached position found recently by
|
||||||
buf_charpos_to_bytepos or buf_bytepos_to_charpos. */
|
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);
|
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;
|
return marker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
311
src/textconv.c
311
src/textconv.c
|
@ -89,13 +89,27 @@ copy_buffer (ptrdiff_t beg, ptrdiff_t beg_byte,
|
||||||
size = end0 - beg0;
|
size = end0 - beg0;
|
||||||
memcpy (buffer, BYTE_POS_ADDR (beg0), size);
|
memcpy (buffer, BYTE_POS_ADDR (beg0), size);
|
||||||
if (beg1 != -1)
|
if (beg1 != -1)
|
||||||
memcpy (buffer, BEG_ADDR + beg1, end1 - beg1);
|
memcpy (buffer + size, BEG_ADDR + beg1, end1 - beg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Conversion query. */
|
/* 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
|
/* Perform the text conversion operation specified in QUERY and return
|
||||||
the results.
|
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
|
If FLAGS & TEXTCONV_SKIP_CONVERSION_REGION, then first move PT past
|
||||||
the conversion region in the specified direction if it is inside.
|
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
|
Value is 0 if QUERY->operation was not TEXTCONV_SUBSTITUTION
|
||||||
or if deleting the text was successful, and 1 otherwise. */
|
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
|
/* If pos is outside the accessible part of the buffer or if it
|
||||||
overflows, move back to point or to the extremes of the
|
overflows, move back to point or to the extremes of the
|
||||||
accessible region. */
|
accessible region. */
|
||||||
|
@ -335,6 +385,55 @@ textconv_query (struct frame *f, struct textconv_callback_struct *query,
|
||||||
return 0;
|
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
|
/* Reset F's text conversion state. Delete any overlays or
|
||||||
markers inside. */
|
markers inside. */
|
||||||
|
|
||||||
|
@ -438,8 +537,10 @@ really_commit_text (struct frame *f, EMACS_INT position,
|
||||||
/* Replace its contents. */
|
/* Replace its contents. */
|
||||||
start = marker_position (f->conversion.compose_region_start);
|
start = marker_position (f->conversion.compose_region_start);
|
||||||
end = marker_position (f->conversion.compose_region_end);
|
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);
|
Finsert (1, &text);
|
||||||
|
record_buffer_change (start, PT, text);
|
||||||
|
|
||||||
/* Move to a the position specified in POSITION. */
|
/* Move to a the position specified in POSITION. */
|
||||||
|
|
||||||
|
@ -493,6 +594,7 @@ really_commit_text (struct frame *f, EMACS_INT position,
|
||||||
location. */
|
location. */
|
||||||
wanted = PT;
|
wanted = PT;
|
||||||
Finsert (1, &text);
|
Finsert (1, &text);
|
||||||
|
record_buffer_change (wanted, PT, text);
|
||||||
|
|
||||||
if (position < 0)
|
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);
|
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))
|
if (!MARKERP (f->conversion.compose_region_start))
|
||||||
{
|
{
|
||||||
f->conversion.compose_region_start = Fmake_marker ();
|
f->conversion.compose_region_start
|
||||||
f->conversion.compose_region_end = Fmake_marker ();
|
= build_marker (current_buffer, PT, PT_BYTE);
|
||||||
Fset_marker (f->conversion.compose_region_start,
|
f->conversion.compose_region_end
|
||||||
Fpoint (), Qnil);
|
= build_marker (current_buffer, PT, PT_BYTE);
|
||||||
Fset_marker (f->conversion.compose_region_end,
|
|
||||||
Fpoint (), Qnil);
|
|
||||||
Fset_marker_insertion_type (f->conversion.compose_region_end,
|
Fset_marker_insertion_type (f->conversion.compose_region_end,
|
||||||
Qt);
|
Qt);
|
||||||
|
|
||||||
|
@ -595,13 +698,19 @@ really_set_composing_text (struct frame *f, ptrdiff_t position,
|
||||||
Fwiden ();
|
Fwiden ();
|
||||||
start = marker_position (f->conversion.compose_region_start);
|
start = marker_position (f->conversion.compose_region_start);
|
||||||
end = marker_position (f->conversion.compose_region_end);
|
end = marker_position (f->conversion.compose_region_end);
|
||||||
safe_del_range (start, end);
|
del_range (start, end);
|
||||||
set_point (start);
|
set_point (start);
|
||||||
|
|
||||||
|
if (start != end)
|
||||||
|
record_buffer_change (start, start, Qnil);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert the new text. */
|
/* Insert the new text. */
|
||||||
Finsert (1, &text);
|
Finsert (1, &text);
|
||||||
|
|
||||||
|
if (start != PT)
|
||||||
|
record_buffer_change (start, PT, Qnil);
|
||||||
|
|
||||||
/* Now move point to an appropriate location. */
|
/* Now move point to an appropriate location. */
|
||||||
if (position < 0)
|
if (position < 0)
|
||||||
{
|
{
|
||||||
|
@ -632,6 +741,12 @@ really_set_composing_text (struct frame *f, ptrdiff_t position,
|
||||||
|
|
||||||
set_point (wanted);
|
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.
|
/* If PT hasn't changed, the conversion region definitely has.
|
||||||
Otherwise, redisplay will update the input method instead. */
|
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);
|
make_fixnum (start), Qnil);
|
||||||
Fset_marker (f->conversion.compose_region_end,
|
Fset_marker (f->conversion.compose_region_end,
|
||||||
make_fixnum (end), Qnil);
|
make_fixnum (end), Qnil);
|
||||||
|
sync_overlay (f);
|
||||||
|
|
||||||
unbind_to (count, Qnil);
|
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
|
static void
|
||||||
really_delete_surrounding_text (struct frame *f, ptrdiff_t left,
|
really_delete_surrounding_text (struct frame *f, ptrdiff_t left,
|
||||||
ptrdiff_t right)
|
ptrdiff_t right)
|
||||||
{
|
{
|
||||||
specpdl_ref count;
|
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. */
|
/* 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. */
|
redisplay. */
|
||||||
Fselect_window (f->old_selected_window, Qt);
|
Fselect_window (f->old_selected_window, Qt);
|
||||||
|
|
||||||
start = max (BEGV, PT - left);
|
/* Figure out where to start deleting from. */
|
||||||
end = min (ZV, PT + right);
|
|
||||||
|
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);
|
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
|
If it has not changed, signal an update through the text input
|
||||||
interface, which is necessary for the IME to acknowledge that the
|
interface, which is necessary for the IME to acknowledge that the
|
||||||
change has completed. */
|
change has completed. */
|
||||||
|
|
||||||
static void
|
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;
|
specpdl_ref count;
|
||||||
|
|
||||||
|
@ -763,6 +931,11 @@ really_set_point (struct frame *f, ptrdiff_t point)
|
||||||
/* Set the point. */
|
/* Set the point. */
|
||||||
Fgoto_char (make_fixnum (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);
|
unbind_to (count, Qnil);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -845,8 +1018,9 @@ handle_pending_conversion_events_1 (struct frame *f,
|
||||||
XFIXNUM (XCDR (data)));
|
XFIXNUM (XCDR (data)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TEXTCONV_SET_POINT:
|
case TEXTCONV_SET_POINT_AND_MARK:
|
||||||
really_set_point (f, XFIXNUM (data));
|
really_set_point_and_mark (f, XFIXNUM (XCAR (data)),
|
||||||
|
XFIXNUM (XCDR (data)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TEXTCONV_DELETE_SURROUNDING_TEXT:
|
case TEXTCONV_DELETE_SURROUNDING_TEXT:
|
||||||
|
@ -858,6 +1032,17 @@ handle_pending_conversion_events_1 (struct frame *f,
|
||||||
unbind_to (count, Qnil);
|
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.
|
/* Process any outstanding text conversion events.
|
||||||
This may run Lisp or signal. */
|
This may run Lisp or signal. */
|
||||||
|
|
||||||
|
@ -868,9 +1053,22 @@ handle_pending_conversion_events (void)
|
||||||
Lisp_Object tail, frame;
|
Lisp_Object tail, frame;
|
||||||
struct text_conversion_action *action, *next;
|
struct text_conversion_action *action, *next;
|
||||||
bool handled;
|
bool handled;
|
||||||
|
static int inside;
|
||||||
|
specpdl_ref count;
|
||||||
|
|
||||||
handled = false;
|
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)
|
FOR_EACH_FRAME (tail, frame)
|
||||||
{
|
{
|
||||||
f = XFRAME (frame);
|
f = XFRAME (frame);
|
||||||
|
@ -905,6 +1103,8 @@ handle_pending_conversion_events (void)
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unbind_to (count, Qnil);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start a ``batch edit'' in F. During a batch edit, point_changed
|
/* 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;
|
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'. */
|
COUNTER means the same as in `start_batch_edit'. */
|
||||||
|
|
||||||
void
|
void
|
||||||
textconv_set_point (struct frame *f, ptrdiff_t point,
|
textconv_set_point_and_mark (struct frame *f, ptrdiff_t point,
|
||||||
unsigned long counter)
|
ptrdiff_t mark, unsigned long counter)
|
||||||
{
|
{
|
||||||
struct text_conversion_action *action, **last;
|
struct text_conversion_action *action, **last;
|
||||||
|
|
||||||
|
@ -1071,8 +1271,9 @@ textconv_set_point (struct frame *f, ptrdiff_t point,
|
||||||
point = MOST_POSITIVE_FIXNUM;
|
point = MOST_POSITIVE_FIXNUM;
|
||||||
|
|
||||||
action = xmalloc (sizeof *action);
|
action = xmalloc (sizeof *action);
|
||||||
action->operation = TEXTCONV_SET_POINT;
|
action->operation = TEXTCONV_SET_POINT_AND_MARK;
|
||||||
action->data = make_fixnum (point);
|
action->data = Fcons (make_fixnum (point),
|
||||||
|
make_fixnum (mark));
|
||||||
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)
|
||||||
|
@ -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
|
/* Return N characters of text around point in F's old selected
|
||||||
window.
|
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
|
Set *N to the actual number of characters returned, *START_RETURN
|
||||||
to the position of the first character returned, *OFFSET to the
|
to the position of the first character returned, *OFFSET to the
|
||||||
offset of point within that text, *LENGTH to the actual number of
|
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
|
/* Temporarily switch to F's selected window at the time of the last
|
||||||
redisplay. */
|
redisplay. */
|
||||||
Fselect_window (f->old_selected_window, Qt);
|
Fselect_window (f->old_selected_window, Qt);
|
||||||
|
buffer = NULL;
|
||||||
|
|
||||||
/* Figure out the bounds of the text to return. */
|
/* Figure out the bounds of the text to return. */
|
||||||
|
if (n != -1)
|
||||||
|
{
|
||||||
start = PT - n / 2;
|
start = PT - n / 2;
|
||||||
end = PT + n - 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);
|
start = max (start, BEGV);
|
||||||
end = min (end, ZV);
|
end = min (end, ZV);
|
||||||
buffer = NULL;
|
|
||||||
|
|
||||||
/* Detect overflow. */
|
/* Detect overflow. */
|
||||||
|
|
||||||
|
@ -1218,3 +1447,37 @@ register_textconv_interface (struct textconv_interface *interface)
|
||||||
{
|
{
|
||||||
text_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;
|
||||||
|
}
|
||||||
|
|
|
@ -35,9 +35,10 @@ struct textconv_interface
|
||||||
unexpected buffer change occurs.) */
|
unexpected buffer change occurs.) */
|
||||||
void (*reset) (struct frame *);
|
void (*reset) (struct frame *);
|
||||||
|
|
||||||
/* Notice that point has moved in the specified frame's selected
|
/* Notice that point or mark has moved in the specified frame's
|
||||||
window's selected buffer. The second argument is the window
|
selected window's selected buffer. The second argument is the
|
||||||
whose point changed, and the third argument is the buffer. */
|
window whose point changed, and the third argument is the
|
||||||
|
buffer. */
|
||||||
void (*point_changed) (struct frame *, struct window *,
|
void (*point_changed) (struct frame *, struct window *,
|
||||||
struct buffer *);
|
struct buffer *);
|
||||||
|
|
||||||
|
@ -118,6 +119,7 @@ struct textconv_callback_struct
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TEXTCONV_SKIP_CONVERSION_REGION (1 << 0)
|
#define TEXTCONV_SKIP_CONVERSION_REGION (1 << 0)
|
||||||
|
#define TEXTCONV_SKIP_ACTIVE_REGION (1 << 1)
|
||||||
|
|
||||||
extern int textconv_query (struct frame *, struct textconv_callback_struct *,
|
extern int textconv_query (struct frame *, struct textconv_callback_struct *,
|
||||||
int);
|
int);
|
||||||
|
@ -132,7 +134,8 @@ extern void set_composing_text (struct frame *, Lisp_Object,
|
||||||
ptrdiff_t, unsigned long);
|
ptrdiff_t, unsigned long);
|
||||||
extern void set_composing_region (struct frame *, ptrdiff_t, ptrdiff_t,
|
extern void set_composing_region (struct frame *, ptrdiff_t, ptrdiff_t,
|
||||||
unsigned long);
|
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,
|
extern void delete_surrounding_text (struct frame *, ptrdiff_t,
|
||||||
ptrdiff_t, unsigned long);
|
ptrdiff_t, unsigned long);
|
||||||
extern char *get_extracted_text (struct frame *, ptrdiff_t, ptrdiff_t *,
|
extern char *get_extracted_text (struct frame *, ptrdiff_t, ptrdiff_t *,
|
||||||
|
|
|
@ -286,6 +286,10 @@ struct window
|
||||||
it should be positive. */
|
it should be positive. */
|
||||||
ptrdiff_t last_point;
|
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
|
/* 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. */
|
screen. If this field is zero, it means we don't have a base line. */
|
||||||
ptrdiff_t base_line_number;
|
ptrdiff_t base_line_number;
|
||||||
|
|
11
src/xdisp.c
11
src/xdisp.c
|
@ -17268,7 +17268,7 @@ mark_window_display_accurate_1 (struct window *w, bool accurate_p)
|
||||||
{
|
{
|
||||||
struct buffer *b = XBUFFER (w->contents);
|
struct buffer *b = XBUFFER (w->contents);
|
||||||
#ifdef HAVE_TEXT_CONVERSION
|
#ifdef HAVE_TEXT_CONVERSION
|
||||||
ptrdiff_t prev_point;
|
ptrdiff_t prev_point, prev_mark;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
w->last_modified = accurate_p ? BUF_MODIFF (b) : 0;
|
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
|
#ifdef HAVE_TEXT_CONVERSION
|
||||||
prev_point = w->last_point;
|
prev_point = w->last_point;
|
||||||
|
prev_mark = w->last_mark;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (w == XWINDOW (selected_window))
|
if (w == XWINDOW (selected_window))
|
||||||
|
@ -17308,6 +17309,11 @@ mark_window_display_accurate_1 (struct window *w, bool accurate_p)
|
||||||
else
|
else
|
||||||
w->last_point = marker_position (w->pointm);
|
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
|
#ifdef HAVE_TEXT_CONVERSION
|
||||||
/* Point motion is only propagated to the input method for use
|
/* Point motion is only propagated to the input method for use
|
||||||
in text conversion during a redisplay. While this can lead
|
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
|
during such a change, so the consequences are not that
|
||||||
severe. */
|
severe. */
|
||||||
|
|
||||||
if (prev_point != w->last_point
|
if ((prev_point != w->last_point
|
||||||
|
|| prev_mark != w->last_mark)
|
||||||
&& FRAME_WINDOW_P (WINDOW_XFRAME (w))
|
&& FRAME_WINDOW_P (WINDOW_XFRAME (w))
|
||||||
&& w == XWINDOW (WINDOW_XFRAME (w)->selected_window))
|
&& w == XWINDOW (WINDOW_XFRAME (w)->selected_window))
|
||||||
report_point_change (WINDOW_XFRAME (w), w, b);
|
report_point_change (WINDOW_XFRAME (w), w, b);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue