From a61f9cb77ced0607e4607bc5d82ae06165e6138d Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 18 Feb 2023 23:09:30 +0800 Subject: [PATCH] Update Android port * doc/emacs/input.texi (On-Screen Keyboards): Document `touch-screen-always-display'. * doc/lispref/commands.texi (Misc Events): Improve documentation of text conversion events. * java/org/gnu/emacs/EmacsDialog.java (toAlertDialog, display1): Reorder buttons to make more sense. * lisp/elec-pair.el (electric-pair-analyze-conversion): New function. * lisp/simple.el (analyze-text-conversion): Improve integration with electric pair modes. * lisp/term.el (term-mode): Always display the onscreen keyboard. * lisp/touch-screen.el (touch-screen-display-keyboard) (touch-screen-handle-point-up): Respect new options. * src/textconv.c (really_set_composing_text): Stop widenining unnecessarily. (really_delete_surrounding_text): Really delete surrounding text. Give text conversion analyzers the buffer text. (syms_of_textconv): Update doc string. --- doc/emacs/input.texi | 6 +++ doc/lispref/commands.texi | 7 +-- java/org/gnu/emacs/EmacsDialog.java | 10 ++-- lisp/elec-pair.el | 14 ++++++ lisp/simple.el | 76 ++++++++++++++++++++--------- lisp/term.el | 3 ++ lisp/touch-screen.el | 16 +++++- src/textconv.c | 43 +++++++++------- 8 files changed, 124 insertions(+), 51 deletions(-) diff --git a/doc/emacs/input.texi b/doc/emacs/input.texi index 87ed1f4f8a9..37167f5a9e0 100644 --- a/doc/emacs/input.texi +++ b/doc/emacs/input.texi @@ -94,6 +94,12 @@ If it is, then Emacs looks up whether or not the text under the point is read-only; if not, it activates the on-screen keyboard, assuming that the user is about to enter text in to the current buffer. +@vindex touch-screen-always-display + The user option @code{touch-screen-display-keyboard} forces Emacs to +always display the on screen keyboard; it may also be bound buffer +locally, meaning to always display the keyboard when the buffer is +selected. + Emacs also provides a set of functions to show or hide the on-screen keyboard. For more details, @pxref{On-Screen Keyboards,,, elisp, The Emacs Lisp Reference Manual}. diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index d12f0f54405..495e48bad3f 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi @@ -2227,9 +2227,10 @@ form: 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. +containing any text which was inserted, or any text before point +which was deleted, @code{t}, meaning that the edit is a +temporary edit made by the input method, and @code{nil}, meaning +that some text was deleted after point. @vindex text-conversion-style Whether or not this event is sent depends on the value of the diff --git a/java/org/gnu/emacs/EmacsDialog.java b/java/org/gnu/emacs/EmacsDialog.java index bc0333e99b9..9f9124ce99c 100644 --- a/java/org/gnu/emacs/EmacsDialog.java +++ b/java/org/gnu/emacs/EmacsDialog.java @@ -166,14 +166,14 @@ public class EmacsDialog implements DialogInterface.OnDismissListener if (size >= 2) { button = buttons.get (1); - dialog.setButton (DialogInterface.BUTTON_NEUTRAL, + dialog.setButton (DialogInterface.BUTTON_NEGATIVE, button.name, button); } if (size >= 3) { button = buttons.get (2); - dialog.setButton (DialogInterface.BUTTON_NEGATIVE, + dialog.setButton (DialogInterface.BUTTON_NEUTRAL, button.name, button); } } @@ -274,10 +274,8 @@ public class EmacsDialog implements DialogInterface.OnDismissListener if (size >= 2) { button = buttons.get (1); - dialog.setButton (DialogInterface.BUTTON_NEUTRAL, - button.name, button); buttonView - = dialog.getButton (DialogInterface.BUTTON_NEUTRAL); + = dialog.getButton (DialogInterface.BUTTON_NEGATIVE); buttonView.setEnabled (button.enabled); } @@ -285,7 +283,7 @@ public class EmacsDialog implements DialogInterface.OnDismissListener { button = buttons.get (2); buttonView - = dialog.getButton (DialogInterface.BUTTON_NEGATIVE); + = dialog.getButton (DialogInterface.BUTTON_NEUTRAL); buttonView.setEnabled (button.enabled); } } diff --git a/lisp/elec-pair.el b/lisp/elec-pair.el index b894965eae4..a7fd8e4a70e 100644 --- a/lisp/elec-pair.el +++ b/lisp/elec-pair.el @@ -162,6 +162,20 @@ Before attempting a skip, if `electric-pair-skip-whitespace' is non-nil, this function is called. It move point to a new buffer position, presumably skipping only whitespace in between.") +(defun electric-pair-analyze-conversion (string) + "Notice that STRING has been deleted by an input method. +If the last character of STRING is an electric pair character, +and the character after point is too, then delete that other +character." + (let* ((prev (aref string (1- (length string)))) + (next (char-after)) + (syntax-info (electric-pair-syntax-info prev)) + (syntax (car syntax-info)) + (pair (cadr syntax-info))) + (when (and next pair (memq syntax '(?\( ?\" ?\$)) + (eq pair next)) + (delete-char 1)))) + (defun electric-pair--skip-whitespace () "Skip whitespace forward, not crossing comment or string boundaries." (let ((saved (point)) diff --git a/lisp/simple.el b/lisp/simple.el index f8af54fc4e7..c290468928b 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -10877,6 +10877,10 @@ If the buffer doesn't exist, create it first." ;; Actually in textconv.c. (defvar text-conversion-edits) +;; Actually in elec-pair.el. +(defvar electric-pair-preserve-balance) +(declare-function electric-pair-analyze-conversion "elec-pair.el") + (defun analyze-text-conversion () "Analyze the results of the previous text conversion event. @@ -10890,35 +10894,61 @@ For each insertion: line breaking of the previous line when `auto-fill-mode' is enabled. + - Look for the deletion of a single electric pair character, + and delete the adjascent pair if + `electric-pair-delete-adjacent-pairs'. + - Run `post-self-insert-functions' for the last character of any inserted text so that modes such as `electric-pair-mode' can work." (interactive) - (dolist (edit text-conversion-edits) + ;; The list must be processed in reverse. + (dolist (edit (reverse text-conversion-edits)) ;; Filter out ephemeral edits and deletions. - (when (and (not (eq (nth 1 edit) (nth 2 edit))) - (stringp (nth 3 edit))) + (when (and (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))))) - (goto-char (nth 2 edit)) - (let ((last-command-event end)) - (run-hooks 'post-self-insert-hook))))))) + (if (not (eq (nth 1 edit) (nth 2 edit))) + ;; Process this insertion. (nth 3 edit) is the text which + ;; was inserted. + (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)) + ;; FIXME: this leads to an error in + ;; `atomic-change-group', seemingly because + ;; buffer-undo-list is being modified or + ;; prematurely truncated. Turn it off for now. + (electric-pair-preserve-balance nil)) + (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))))) + (goto-char (nth 2 edit)) + (let ((last-command-event end)) + (run-hooks 'post-self-insert-hook))) + ;; Process this deletion before point. (nth 2 edit) is the + ;; text which was deleted. Input methods typically prefer + ;; to edit words instead of deleting characters off their + ;; ends, but they seem to always send proper requests for + ;; deletion for punctuation. + (when (and (boundp 'electric-pair-delete-adjacent-pairs) + (symbol-value 'electric-pair-delete-adjacent-pairs) + ;; Make sure elec-pair is loaded. + (fboundp 'electric-pair-analyze-conversion) + ;; Only do this if only a single edit happened. + text-conversion-edits) + (save-excursion + (goto-char (nth 2 edit)) + (electric-pair-analyze-conversion (nth 3 edit))))))))) diff --git a/lisp/term.el b/lisp/term.el index 3e4907e8bfc..9f42fcdf851 100644 --- a/lisp/term.el +++ b/lisp/term.el @@ -1136,6 +1136,9 @@ Entry to this mode runs the hooks on `term-mode-hook'." (setq-local term-last-input-end (make-marker)) (setq-local term-last-input-match "") + ;; Always display the onscreen keyboard. + (setq-local touch-screen-display-keyboard t) + ;; These local variables are set to their local values: (make-local-variable 'term-saved-home-marker) (make-local-variable 'term-saved-cursor) diff --git a/lisp/touch-screen.el b/lisp/touch-screen.el index 01e56f1d499..3d542d78b1d 100644 --- a/lisp/touch-screen.el +++ b/lisp/touch-screen.el @@ -49,6 +49,14 @@ keyboard after a mouse command is executed in response to a "Timer used to track long-presses. This is always cleared upon any significant state change.") +(defcustom touch-screen-display-keyboard nil + "If non-nil, always display the on screen keyboard. +A buffer local value means to always display the on screen +keyboard when the buffer is selected." + :type 'boolean + :group 'mouse + :version "30.1") + (defcustom touch-screen-delay 0.7 "Delay in seconds before Emacs considers a touch to be a long-press." :type 'number @@ -417,8 +425,12 @@ is not read-only." (call-interactively command nil (vector event)) (when (memq command touch-screen-set-point-commands) - (if (not (or buffer-read-only - (get-text-property (point) 'read-only))) + (if (and (or (not buffer-read-only) + touch-screen-display-keyboard) + ;; Detect the splash screen and avoid + ;; displaying the on screen keyboard + ;; there. + (not (equal (buffer-name) "*GNU Emacs*"))) ;; Once the on-screen keyboard has been opened, ;; add `touch-screen-window-selection-changed' ;; as a window selection change function This diff --git a/src/textconv.c b/src/textconv.c index 50146820dce..1ca5f0488f8 100644 --- a/src/textconv.c +++ b/src/textconv.c @@ -702,11 +702,8 @@ really_set_composing_text (struct frame *f, ptrdiff_t position, } else { - /* Delete the text between the start of the composition region - and its end. TODO: avoid this widening. */ - record_unwind_protect (save_restriction_restore, - save_restriction_save ()); - Fwiden (); + /* Delete the text between the start of the composing region and + its end. */ start = marker_position (f->conversion.compose_region_start); end = marker_position (f->conversion.compose_region_end); del_range (start, end); @@ -844,6 +841,7 @@ really_delete_surrounding_text (struct frame *f, ptrdiff_t left, specpdl_ref count; ptrdiff_t start, end, a, b, a1, b1, lstart, rstart; struct window *w; + Lisp_Object text; /* If F's old selected window is no longer live, fail. */ @@ -888,21 +886,25 @@ really_delete_surrounding_text (struct frame *f, ptrdiff_t left, start = max (BEGV, lstart - left); end = min (ZV, rstart + right); - del_range (start, end); - record_buffer_change (start, start, Qnil); + text = del_range_1 (start, end, false, true); + record_buffer_change (start, start, text); } else { - start = max (BEGV, lstart - left); - end = lstart; - - del_range (start, end); - record_buffer_change (start, start, Qnil); + /* Don't record a deletion if the text which was deleted lies + after point. */ start = rstart; end = min (ZV, rstart + right); - del_range (start, end); - record_buffer_change (start, start, Qnil); + text = del_range_1 (start, end, false, true); + record_buffer_change (start, start, Qnil); + + /* Now delete what must be deleted on the left. */ + + start = max (BEGV, lstart - left); + end = lstart; + text = del_range_1 (start, end, false, true); + record_buffer_change (start, start, text); } /* if the mark is now equal to start, deactivate it. */ @@ -1701,7 +1703,8 @@ syms_of_textconv (void) DEFSYM (Qtext_conversion, "text-conversion"); DEFSYM (Qpush_mark, "push-mark"); DEFSYM (Qunderline, "underline"); - DEFSYM (Qoverriding_text_conversion_style, "overriding-text-conversion-style"); + DEFSYM (Qoverriding_text_conversion_style, + "overriding-text-conversion-style"); DEFVAR_LISP ("text-conversion-edits", Vtext_conversion_edits, doc: /* List of buffers that were last edited as a result of text conversion. @@ -1722,8 +1725,14 @@ changes to the text, so any actions that would otherwise be taken 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. */); +If a deletion occured before point, then BEG and END are the same, and +EPHEMERAL is the text which was deleted. + +If a deletion occured after point, then BEG and END are also the same, +but EPHEMERAL is nil. + +The list contents are ordered later edits first, so you must iterate +through the list in reverse. */); Vtext_conversion_edits = Qnil; DEFVAR_LISP ("overriding-text-conversion-style", -- 2.39.5