emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 6a0e1c4 3/5: Merge from origin/emacs-27


From: Glenn Morris
Subject: master 6a0e1c4 3/5: Merge from origin/emacs-27
Date: Wed, 4 Mar 2020 17:03:18 -0500 (EST)

branch: master
commit 6a0e1c41040059d1a463fbf69be52e898b30691a
Merge: b6c3921 a4e4510
Author: Glenn Morris <address@hidden>
Commit: Glenn Morris <address@hidden>

    Merge from origin/emacs-27
    
    a4e4510ccd Fix handling MS-Windows keyboard input above the BMP
    a38bebb0c1 * etc/NEWS: More complete description of rx 'not' changes.
    d373647e8f ; * doc/emacs/mini.texi (Yes or No Prompts): Fix last change.
    1ca6d15656 * doc/emacs/mini.texi (Yes or No Prompts): 'y-or-n-p' now ...
    fe1a447d52 Don't attempt to cache glyph metrics for FONT_INVALID_CODE
    b42b894d1d Fix fit-frame-to-buffer for multi-monitor setup
    366fd4fd07 (emacs-27) ; * etc/NEWS: Fix typo.
    49d3cd90bd rx: Improve 'or' compositionality (bug#37659)
    6b48aedb6b * lisp/tab-line.el: Fix auto-hscrolling (bug#39649)
    c5f255d681 (tag: emacs-27.0.90) ; Update lisp/ldefs-boot.el
    60c84ad992 ; * etc/TODO: Fix last change.
    5af9e5baad ; Add an entry to TODO
    d424195905 Fix rx charset generation
    9908b5a614 Merge branch 'emacs-27' of git.savannah.gnu.org:/srv/git/e...
    6dc2ebe00e Fix overquoting in mule.el
    5cca73dd82 * src/timefns.c (time_arith): Omit incorrect comment.
    d767c357ca Merge branch 'emacs-27' of git.savannah.gnu.org:/srv/git/e...
    4dec693f70 * lisp/vc/vc-cvs.el (vc-cvs-ignore): Copy-edit doc string
    ff729e3f97 ; bug#39779: Fix some typos in documentation.
    696ee02c3a checkdoc: Don't mistake "cf." for sentence end
    
    # Conflicts:
    #   etc/NEWS
---
 doc/emacs/mini.texi              | 47 ++++++++++-------------
 doc/lispref/frames.texi          |  2 +-
 doc/lispref/searching.texi       |  5 ++-
 doc/lispref/tips.texi            |  2 +-
 doc/lispref/variables.texi       |  2 +-
 doc/misc/gnus.texi               |  6 +--
 etc/DEBUG                        |  4 +-
 etc/NEWS.27                      | 11 +++++-
 etc/TODO                         | 71 ++++++++++++++++++++++++++++++++++
 lisp/emacs-lisp/checkdoc.el      |  2 +-
 lisp/emacs-lisp/rx.el            | 82 ++++++++++++++++++++++++++--------------
 lisp/gnus/gnus-art.el            |  6 +--
 lisp/gnus/spam-stat.el           |  2 +-
 lisp/international/mule.el       |  2 +-
 lisp/tab-line.el                 | 36 ++++++++++++------
 lisp/vc/vc-cvs.el                | 21 +++++-----
 lisp/window.el                   | 13 ++++---
 src/composite.c                  | 18 +++++++--
 src/font.c                       |  4 +-
 src/font.h                       |  2 +-
 src/timefns.c                    |  4 +-
 src/w32term.c                    | 42 +++++++++++++++++++-
 test/lisp/emacs-lisp/rx-tests.el | 24 ++++++++++--
 23 files changed, 292 insertions(+), 116 deletions(-)

diff --git a/doc/emacs/mini.texi b/doc/emacs/mini.texi
index 5d2a007..55e41e3 100644
--- a/doc/emacs/mini.texi
+++ b/doc/emacs/mini.texi
@@ -813,35 +813,23 @@ varieties.
 
 @cindex y or n prompt
   For the first type of yes-or-no query, the prompt ends with
-@samp{(y or n)}.  Such a query does not actually use the minibuffer;
-the prompt appears in the echo area, and you answer by typing either
-@samp{y} or @samp{n}, which immediately delivers the response.  For
-example, if you type @kbd{C-x C-w} (@kbd{write-file}) to save a
-buffer, and enter the name of an existing file, Emacs issues a prompt
-like this:
+@w{@samp{(y or n)}}.  You answer the query by typing a single key,
+either @samp{y} or @samp{n}, which immediately exits the minibuffer
+and delivers the response.  For example, if you type @kbd{C-x C-w}
+(@kbd{write-file}) to save a buffer, and enter the name of an existing
+file, Emacs issues a prompt like this:
 
 @smallexample
 File ‘foo.el’ exists; overwrite? (y or n)
 @end smallexample
 
-@noindent
-Because this query does not actually use the minibuffer, the usual
-minibuffer editing commands cannot be used.  However, you can perform
-some window scrolling operations while the query is active: @kbd{C-l}
-recenters the selected window; @kbd{C-v} (or @key{PageDown}, or
-@key{next}) scrolls forward; @kbd{M-v} (or @key{PageUp}, or
-@key{prior}) scrolls backward; @kbd{C-M-v} scrolls forward in the next
-window; and @kbd{C-M-S-v} scrolls backward in the next window.  Typing
-@kbd{C-g} dismisses the query, and quits the command that issued it
-(@pxref{Quitting}).
-
 @cindex yes or no prompt
-  The second type of yes-or-no query is typically employed if
-giving the wrong answer would have serious consequences; it uses the
-minibuffer, and features a prompt ending with @samp{(yes or no)}.  For
-example, if you invoke @kbd{C-x k} (@code{kill-buffer}) on a
-file-visiting buffer with unsaved changes, Emacs activates the
-minibuffer with a prompt like this:
+  The second type of yes-or-no query is typically employed if giving
+the wrong answer would have serious consequences; it thus features a
+longer prompt ending with @samp{(yes or no)}.  For example, if you
+invoke @kbd{C-x k} (@code{kill-buffer}) on a file-visiting buffer with
+unsaved changes, Emacs activates the minibuffer with a prompt like
+this:
 
 @smallexample
 Buffer foo.el modified; kill anyway? (yes or no)
@@ -849,7 +837,12 @@ Buffer foo.el modified; kill anyway? (yes or no)
 
 @noindent
 To answer, you must type @samp{yes} or @samp{no} into the minibuffer,
-followed by @key{RET}.  The minibuffer behaves as described in the
-previous sections; you can switch to another window with @kbd{C-x o},
-use the history commands @kbd{M-p} and @kbd{M-n}, etc.  Type @kbd{C-g}
-to quit the minibuffer and the querying command.
+followed by @key{RET}.
+
+With both types of yes-or-no query the minibuffer behaves as described
+in the previous sections; you can recenter the selected window with
+@kbd{C-l}, scroll that window (@kbd{C-v} or @kbd{PageDown} scrolls
+forward, @kbd{M-v} or @kbd{PageUp} scrolls backward), switch to
+another window with @kbd{C-x o}, use the history commands @kbd{M-p}
+and @kbd{M-n}, etc.  Type @kbd{C-g} to dismiss the query, and quit the
+minibuffer and the querying command (@pxref{Quitting}).
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index caa08ff..905e5c2 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -3264,7 +3264,7 @@ that deletion fails for whatever reason, the child frame 
is made a
 top-level frame.
 
   Whether a child frame can have a menu or tool bar is window-system or
-window manager dependent.  Most window-systems explicitly disallow menus
+window manager dependent.  Most window-systems explicitly disallow menu
 bars for child frames.  It seems advisable to disable both, menu and
 tool bars, via the frame's initial parameters settings.
 
diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi
index a4d5a27..1a090eb 100644
--- a/doc/lispref/searching.texi
+++ b/doc/lispref/searching.texi
@@ -1086,8 +1086,9 @@ Corresponding string regexp: @samp{@var{A}@var{B}@dots{}}
 @itemx @code{(| @var{rx}@dots{})}
 @cindex @code{|} in rx
 Match exactly one of the @var{rx}s.
-If all arguments are string literals, the longest possible match
-will always be used.  Otherwise, either the longest match or the
+If all arguments are strings, characters, or @code{or} forms
+so constrained, the longest possible match will always be used.
+Otherwise, either the longest match or the
 first (in left-to-right order) will be used.
 Without arguments, the expression will not match anything at all.@*
 Corresponding string regexp: @samp{@var{A}\|@var{B}\|@dots{}}.
diff --git a/doc/lispref/tips.texi b/doc/lispref/tips.texi
index 0610f80..1ca97e2 100644
--- a/doc/lispref/tips.texi
+++ b/doc/lispref/tips.texi
@@ -1076,7 +1076,7 @@ package is only activated if all its dependencies have 
been).
 Its format is a list of lists on a single line.  The @code{car} of
 each sub-list is the name of a package, as a symbol.  The @code{cadr}
 of each sub-list is the minimum acceptable version number, as a string
-that can be parse by @code{version-to-list}.  An entry that lacks a
+that can be parsed by @code{version-to-list}.  An entry that lacks a
 version (i.e., an entry which is just a symbol, or a sub-list of one
 element) is equivalent to entry with version "0".  For instance:
 
diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi
index 35eb4d5..33897bb 100644
--- a/doc/lispref/variables.texi
+++ b/doc/lispref/variables.texi
@@ -858,7 +858,7 @@ is a buffer if the buffer-local value of the variable is 
being
 changed, @code{nil} otherwise.
 @end defun
 
-@defun remove-variable-watch symbol watch-function
+@defun remove-variable-watcher symbol watch-function
 This function removes @var{watch-function} from @var{symbol}'s list of
 watchers.
 @end defun
diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi
index b5eb81b..424e15b 100644
--- a/doc/misc/gnus.texi
+++ b/doc/misc/gnus.texi
@@ -3181,7 +3181,7 @@ For example:
          (broken-reply-to . t))))
 @end lisp
 
-All clauses that matches the group name will be used, but the last
+All clauses that match the group name will be used, but the last
 setting ``wins''.  So if you have two clauses that both match the
 group name, and both set, say @code{display}, the last setting will
 override the first.
@@ -17874,7 +17874,7 @@ presence of 7 special headers.  These headers are of 
the form
 @code{X-Diary-<something>}, @code{<something>} being one of
 @code{Minute}, @code{Hour}, @code{Dom}, @code{Month}, @code{Year},
 @code{Time-Zone} and @code{Dow}.  @code{Dom} means ``Day of Month'', and
-@code{dow} means ``Day of Week''.  These headers actually behave like
+@code{Dow} means ``Day of Week''.  These headers actually behave like
 crontab specifications and define the event date(s):
 
 @itemize @bullet
@@ -30916,7 +30916,7 @@ description   = <string>
 
 Believe it or not, but some people who use Gnus haven't really used
 Emacs much before they embarked on their journey on the Gnus Love Boat.
-If you are one of those unfortunates whom ``@kbd{C-M-a}'', ``kill the
+If you are one of those unfortunates to whom ``@kbd{C-M-a}'', ``kill the
 region'', and ``set @code{gnus-flargblossen} to an alist where the key
 is a regexp that is used for matching on the group name'' are magical
 phrases with little or no meaning, then this appendix is for you.  If
diff --git a/etc/DEBUG b/etc/DEBUG
index a5e6418..7fb7e44 100644
--- a/etc/DEBUG
+++ b/etc/DEBUG
@@ -739,9 +739,9 @@ stepping, you will see where the loop starts and ends.  
Also, examine
 the data being used in the loop and try to determine why the loop does
 not exit when it should.
 
-On GNU and Unix systems, you can also trying sending Emacs SIGUSR2,
+On GNU and Unix systems, you can also try sending Emacs SIGUSR2,
 which, if 'debug-on-event' has its default value, will cause Emacs to
-attempt to break it out of its current loop and into the Lisp
+attempt to break out of its current loop and enter the Lisp
 debugger.  (See the node "Debugging" in the ELisp manual for the
 details about the Lisp debugger.)  This feature is useful when a
 C-level debugger is not conveniently available.
diff --git a/etc/NEWS.27 b/etc/NEWS.27
index e9dfd26..8d0e0b6 100644
--- a/etc/NEWS.27
+++ b/etc/NEWS.27
@@ -2323,7 +2323,16 @@ With 'or' and 'not', it can be used to compose 
character-matching
 expressions from simpler parts.
 
 +++
-*** 'not' argument can now be a character or single-char string.
+*** 'not' now accepts more argument types.
+The argument can now also be a character, a single-character string,
+an 'intersection' form, or an 'or' form whose arguments each match a
+single character.
+
++++
+*** Nested 'or' forms of strings guarantee a longest match.
+For example, '(or (or "IN" "OUT") (or "INPUT" "OUTPUT"))' now matches
+the whole string "INPUT" if present, not just "IN".  Previously, this
+was only guaranteed inside a single 'or' form of string literals.
 
 ** Frames
 
diff --git a/etc/TODO b/etc/TODO
index 0a06484..20262a7 100644
--- a/etc/TODO
+++ b/etc/TODO
@@ -244,6 +244,23 @@ populate composition-function-table with those rules.  See
 composite.el for examples of this, and also grep lisp/language/*.el
 for references to composition-function-table.
 
+One problem with character compositions that will need to be solved is
+that composition-function-table, the char-table which holds the
+composition rules, is a global variable, whereas use of ligatures is
+inherently specific to buffer-local stuff like the major mode and the
+script or language in use.  So there should be a buffer-local variable
+to augment/customize/override the global composition rules.
+
+Another problem is that ligatures are frequently composed of ASCII
+characters, and some of those ASCII characters are present in the mode
+line, for example "--".  Since displaying a ligature instead of 2
+separate '-' characters on a mode line is not right, there should be a
+way of preventing the ligation from happening.  One possibility is to
+have a ZWNJ character separate these ASCII characters; another
+possibility is to introduce a special text property that prevents
+character composition, and place that property on the relevant parts
+of the mode line.
+
 The prettify-symbols-mode should be deprecated once ligature support
 is in place.
 
@@ -267,6 +284,60 @@ should invoke the 'shape' method.  'hbfont_shape' should 
be extended
 to pass to 'hb_shape_full' the required array of features, as
 mentioned in the above HarfBuzz discussion.
 
+** Better support for displaying Emoji
+
+Emacs is capable of displaying Emoji and some of the Emoji sequences,
+provided that its fontsets are configured with a suitable font.  To
+make this easier out of the box, the following should be done:
+
+*** Populate composition-function-table with Emoji rules
+
+The Unicode Character Database (UCD) includes several data files that
+define the valid Emoji sequences.  These files should be imported into
+the Emacs tree, and should be converted by some script at Emacs build
+time to Lisp code that populates composition-function-table with the
+corresponding composition rules.
+
+*** Augment the default fontsets with Emoji-capable fonts
+
+The default fontsets set up by fontest.el should include known free
+fonts that provide good support for displaying Emoji sequences.  In
+addition, the rule that the default face's font is used for symbol and
+punctuation characters, disregarding the fontsets, should be modified
+to exempt Emoji from this rule (since Emoji characters belong to the
+'symbol' script in Emacs), so that use-default-font-for-symbols would
+not have to be tweaked to have Emoji display by default with a capable
+font.
+
+*** Consider changing the default display of Variation Selectors
+
+Emacs by default displays the Variation Selector (VS) codepoints not
+composed with base characters as hex codes in a box.  The Unicode FAQ
+says that if variation sequences cannot be supported, the VS
+characters should not be shown, leaving just the base character of the
+sequence visible.  This could be handled via glyphless-char-display,
+by changing the entries for VS codepoints to 'zero-width'.  Or we
+could display them as a thin 1-pixel space, as we do with format
+control characters, by using 'thin-space' there.
+
+*** Special face for displaying text presentation of Emoji
+
+Emoji-capable fonts support Emoji sequences with the U+FE0F VARIATION
+SELECTOR-16 (VS16) for emoji-style display, but usually don't support
+the U+FE0F VARIATION SELECTOR-15 (VS15) for text-style display.  There
+are other fonts which support the text-style sequences, but not
+emoji-style.  Since Emacs selects a font based on a single character,
+it cannot choose 2 different fonts for displaying both styles of the
+same base character.  To display both styles in the same buffer, one
+could use a special face, placing a 'face' text property on portions
+of the text.  This special face could specify a specific font known to
+support text-style Emoji sequences.  Emacs could have such a face
+built-in.
+
+See the discussion of bug#39799 for more details about this task.
+Another relevant resource is the Unicode Technical Standard #51
+"Unicode Emoji" (http://www.unicode.org/reports/tr51/).
+
 ** Extend text-properties and overlays
 *** Several text-property planes
 This would get us rid of font-lock-face property (and I'd be happy to
diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el
index ccdddb4..e15836e 100644
--- a/lisp/emacs-lisp/checkdoc.el
+++ b/lisp/emacs-lisp/checkdoc.el
@@ -2073,7 +2073,7 @@ If the offending word is in a piece of quoted text, then 
it is skipped."
                                     ;; piece of an abbreviation
                                     ;; FIXME etc
                                     (looking-at
-                                     
"\\([a-zA-Z]\\|[iI]\\.?e\\|[eE]\\.?g\\)\\."))
+                                     
"\\([a-zA-Z]\\|[iI]\\.?e\\|[eE]\\.?g\\|[cC]f\\)\\."))
                                 (error t))))
                   (if (checkdoc-autofix-ask-replace
                        b e
diff --git a/lisp/emacs-lisp/rx.el b/lisp/emacs-lisp/rx.el
index b4cab57..a0b2444 100644
--- a/lisp/emacs-lisp/rx.el
+++ b/lisp/emacs-lisp/rx.el
@@ -254,22 +254,39 @@ Left-fold the list L, starting with X, by the binary 
function F."
     (setq l (cdr l)))
   x)
 
+(defun rx--normalise-or-arg (form)
+  "Normalise the `or' argument FORM.
+Characters become strings, user-definitions and `eval' forms are expanded,
+and `or' forms are normalised recursively."
+  (cond ((characterp form)
+         (char-to-string form))
+        ((and (consp form) (memq (car form) '(or |)))
+         (cons (car form) (mapcar #'rx--normalise-or-arg (cdr form))))
+        ((and (consp form) (eq (car form) 'eval))
+         (rx--normalise-or-arg (rx--expand-eval (cdr form))))
+        (t
+         (let ((expanded (rx--expand-def form)))
+           (if expanded
+               (rx--normalise-or-arg expanded)
+             form)))))
+
+(defun rx--all-string-or-args (body)
+  "If BODY only consists of strings or such `or' forms, return all the strings.
+Otherwise throw `rx--nonstring'."
+  (mapcan (lambda (form)
+            (cond ((stringp form) (list form))
+                  ((and (consp form) (memq (car form) '(or |)))
+                   (rx--all-string-or-args (cdr form)))
+                  (t (throw 'rx--nonstring nil))))
+          body))
+
 (defun rx--translate-or (body)
   "Translate an or-pattern of zero or more rx items.
 Return (REGEXP . PRECEDENCE)."
   ;; FIXME: Possible improvements:
   ;;
-  ;; - Turn single characters to strings: (or ?a ?b) -> (or "a" "b"),
-  ;;   so that they can be candidates for regexp-opt.
-  ;;
-  ;; - Translate compile-time strings (`eval' forms), again for regexp-opt.
-  ;;
   ;; - Flatten sub-patterns first: (or (or A B) (or C D)) -> (or A B C D)
-  ;;   in order to improve effectiveness of regexp-opt.
-  ;;   This would also help composability.
-  ;;
-  ;; - Use associativity to run regexp-opt on contiguous subsets of arguments
-  ;;   if not all of them are strings.  Example:
+  ;;   Then call regexp-opt on runs of string arguments. Example:
   ;;   (or (+ digit) "CHARLIE" "CHAN" (+ blank))
   ;;   -> (or (+ digit) (or "CHARLIE" "CHAN") (+ blank))
   ;;
@@ -279,33 +296,32 @@ Return (REGEXP . PRECEDENCE)."
   ;;   so that (or "@" "%" digit (any "A-Z" space) (syntax word))
   ;;        -> (any "@" "%" digit "A-Z" space word)
   ;;        -> "[A-Z@%[:digit:][:space:][:word:]]"
-  ;;
-  ;; Problem: If a subpattern is carefully written to be
-  ;; optimizable by regexp-opt, how do we prevent the transforms
-  ;; above from destroying that property?
-  ;; Example: (or "a" (or "abc" "abd" "abe"))
   (cond
    ((null body)                    ; No items: a never-matching regexp.
     (rx--empty))
    ((null (cdr body))              ; Single item.
     (rx--translate (car body)))
-   ((rx--every #'stringp body)     ; All strings.
-    (cons (list (regexp-opt body nil))
-          t))
-   ((rx--every #'rx--charset-p body)  ; All charsets.
-    (rx--translate-union nil body))
    (t
-    (cons (append (car (rx--translate (car body)))
-                  (mapcan (lambda (item)
-                            (cons "\\|" (car (rx--translate item))))
-                          (cdr body)))
-          nil))))
+    (let* ((args (mapcar #'rx--normalise-or-arg body))
+           (all-strings (catch 'rx--nonstring (rx--all-string-or-args args))))
+      (cond
+       (all-strings                       ; Only strings.
+        (cons (list (regexp-opt all-strings nil))
+              t))
+       ((rx--every #'rx--charset-p args)  ; All charsets.
+        (rx--translate-union nil args))
+       (t
+        (cons (append (car (rx--translate (car args)))
+                      (mapcan (lambda (item)
+                                (cons "\\|" (car (rx--translate item))))
+                              (cdr args)))
+              nil)))))))
 
 (defun rx--charset-p (form)
   "Whether FORM looks like a charset, only consisting of character intervals
 and set operations."
   (or (and (consp form)
-           (or (and (memq (car form) '(any 'in 'char))
+           (or (and (memq (car form) '(any in char))
                     (rx--every (lambda (x) (not (symbolp x))) (cdr form)))
                (and (memq (car form) '(not or | intersection))
                     (rx--every #'rx--charset-p (cdr form)))))
@@ -450,6 +466,10 @@ classes."
            (not negated))
       (cons (list (regexp-quote (char-to-string (caar items))))
             t))
+     ;; Negated newline.
+     ((and (equal items '((?\n . ?\n)))
+           negated)
+      (rx--translate-symbol 'nonl))
      ;; At least one character or class, possibly negated.
      (t
       (cons
@@ -836,11 +856,15 @@ Return (REGEXP . PRECEDENCE)."
            (cons (list (list 'regexp-quote arg)) 'seq))
           (t (error "rx `literal' form with non-string argument")))))
 
-(defun rx--translate-eval (body)
-  "Translate the `eval' form.  Return (REGEXP . PRECEDENCE)."
+(defun rx--expand-eval (body)
+  "Expand `eval' arguments.  Return a new rx form."
   (unless (and body (null (cdr body)))
     (error "rx `eval' form takes exactly one argument"))
-  (rx--translate (eval (car body))))
+  (eval (car body)))
+
+(defun rx--translate-eval (body)
+  "Translate the `eval' form.  Return (REGEXP . PRECEDENCE)."
+  (rx--translate (rx--expand-eval body)))
 
 (defvar rx--regexp-atomic-regexp nil)
 
diff --git a/lisp/gnus/gnus-art.el b/lisp/gnus/gnus-art.el
index 754655d..6b9610d 100644
--- a/lisp/gnus/gnus-art.el
+++ b/lisp/gnus/gnus-art.el
@@ -7774,11 +7774,11 @@ also be Lisp expression evaluating to a string),
 BUTTON: is the number of the regexp grouping actually matching the button,
 FORM: is a Lisp expression which must eval to true for the button to
 be added,
-CALLBACK: is the function to call when the user push this button, and each
+CALLBACK: is the function to call when the user pushes this button, and each
 PAR: is a number of a regexp grouping whose text will be passed to CALLBACK.
 
-CALLBACK can also be a variable, in that case the value of that
-variable it the real callback function."
+CALLBACK can also be a variable, in which case the value of that
+variable is the real callback function."
   :group 'gnus-article-buttons
   :type '(repeat (list (choice regexp variable sexp)
                       (integer :tag "Button")
diff --git a/lisp/gnus/spam-stat.el b/lisp/gnus/spam-stat.el
index 8a4161e..2e03608 100644
--- a/lisp/gnus/spam-stat.el
+++ b/lisp/gnus/spam-stat.el
@@ -174,7 +174,7 @@ no effect when spam-stat is invoked through spam.el."
 
 (defcustom spam-stat-score-buffer-user-functions nil
   "List of additional scoring functions.
-Called  one by one on the buffer.
+Called one by one on the buffer.
 
 If all of these functions return non-nil answers, these numerical
 answers are added to the computed spam stat score on the buffer.  If
diff --git a/lisp/international/mule.el b/lisp/international/mule.el
index 6659479..86f3d2a 100644
--- a/lisp/international/mule.el
+++ b/lisp/international/mule.el
@@ -2601,7 +2601,7 @@ This function is intended to be added to 
`auto-coding-functions'."
                     (detect-coding-region (point-min) size t)))))
             ;; Pure ASCII always comes back as undecided.
             (if (memq detected
-                      '(utf-8 'utf-8-with-signature 'utf-8-hfs undecided))
+                      '(utf-8 utf-8-with-signature utf-8-hfs undecided))
                 'utf-8
               (warn "File contents detected as %s.
   Consider adding an encoding attribute to the xml declaration,
diff --git a/lisp/tab-line.el b/lisp/tab-line.el
index 8f1221a..902c312 100644
--- a/lisp/tab-line.el
+++ b/lisp/tab-line.el
@@ -446,17 +446,19 @@ variable `tab-line-tabs-function'."
            (setq hscroll nil)
            (set-window-parameter nil 'tab-line-hscroll hscroll))
        (list separator
-             (when (and (integerp hscroll) (not (zerop hscroll)))
+             (when (and (numberp hscroll) (not (zerop hscroll)))
                tab-line-left-button)
-             (when (if (integerp hscroll)
-                       (< (abs hscroll) (1- (length strings)))
+             (when (if (numberp hscroll)
+                       (< (truncate hscroll) (1- (length strings)))
                      (> (length strings) 1))
                tab-line-right-button)))
-     (if hscroll (nthcdr (abs hscroll) strings) strings)
+     (if hscroll (nthcdr (truncate hscroll) strings) strings)
      (when (eq tab-line-tabs-function #'tab-line-tabs-window-buffers)
        (list (concat separator (when tab-line-new-tab-choice
                                  tab-line-new-button)))))))
 
+(defvar tab-line-auto-hscroll)
+
 (defun tab-line-format ()
   "Template for displaying tab line for selected window."
   (let* ((tabs (funcall tab-line-tabs-function))
@@ -464,6 +466,13 @@ variable `tab-line-tabs-function'."
                           (window-buffer)
                           (window-parameter nil 'tab-line-hscroll)))
          (cache (window-parameter nil 'tab-line-cache)))
+    ;; Enable auto-hscroll again after it was disabled on manual scrolling.
+    ;; The moment to enable it is when the window-buffer was updated.
+    (when (and tab-line-auto-hscroll        ; if auto-hscroll was enabled
+               (integerp (nth 2 cache-key)) ; integer on manual scroll
+               cache                        ; window-buffer was updated
+               (not (equal (nth 1 (car cache)) (nth 1 cache-key))))
+      (set-window-parameter nil 'tab-line-hscroll (float (nth 2 cache-key))))
     (or (and cache (equal (car cache) cache-key) (cdr cache))
         (cdr (set-window-parameter
               nil 'tab-line-cache
@@ -478,24 +487,27 @@ the selected tab visible."
   :group 'tab-line
   :version "27.1")
 
+(defvar tab-line-auto-hscroll-buffer (generate-new-buffer " 
*tab-line-hscroll*"))
+
 (defun tab-line-auto-hscroll (strings hscroll)
-  (with-temp-buffer
+  (with-current-buffer tab-line-auto-hscroll-buffer
     (let ((truncate-partial-width-windows nil)
           (inhibit-modification-hooks t)
           show-arrows)
       (setq truncate-lines nil)
+      (erase-buffer)
       (apply 'insert strings)
       (goto-char (point-min))
       (add-face-text-property (point-min) (point-max) 'tab-line)
       ;; Continuation means tab-line doesn't fit completely,
       ;; thus scroll arrows are needed for scrolling.
       (setq show-arrows (> (vertical-motion 1) 0))
-      ;; Try to auto-scroll only when scrolling is needed,
+      ;; Try to auto-hscroll only when scrolling is needed,
       ;; but no manual scrolling was performed before.
       (when (and tab-line-auto-hscroll
                  show-arrows
                  ;; Do nothing when scrolled manually
-                 (not (and (integerp hscroll) (>= hscroll 0))))
+                 (not (integerp hscroll)))
         (let ((selected (seq-position strings 'selected
                                       (lambda (str prop)
                                         (get-pos-property 1 prop str)))))
@@ -503,7 +515,7 @@ the selected tab visible."
            ((null selected)
             ;; Do nothing if no tab is selected
             )
-           ((or (not (integerp hscroll)) (< selected (abs hscroll)))
+           ((or (not (numberp hscroll)) (< selected (truncate hscroll)))
             ;; Selected is scrolled to the left, or no scrolling yet
             (erase-buffer)
             (apply 'insert (reverse (seq-subseq strings 0 (1+ selected))))
@@ -520,14 +532,14 @@ the selected tab visible."
                                                     (lambda (str tab)
                                                       (eq (get-pos-property 1 
'tab str) tab))))))
                   (when new-hscroll
-                    (setq hscroll (- new-hscroll))
+                    (setq hscroll (float new-hscroll))
                     (set-window-parameter nil 'tab-line-hscroll hscroll)))
               (setq hscroll nil)
               (set-window-parameter nil 'tab-line-hscroll hscroll)))
            (t
             ;; Check if the selected tab is already visible
             (erase-buffer)
-            (apply 'insert (seq-subseq strings (abs hscroll) (1+ selected)))
+            (apply 'insert (seq-subseq strings (truncate hscroll) (1+ 
selected)))
             (goto-char (point-min))
             (add-face-text-property (point-min) (point-max) 'tab-line)
             (when (> (vertical-motion 1) 0)
@@ -547,7 +559,7 @@ the selected tab visible."
                                                     (lambda (str tab)
                                                       (eq (get-pos-property 1 
'tab str) tab))))))
                   (when new-hscroll
-                    (setq hscroll (- new-hscroll))
+                    (setq hscroll (float new-hscroll))
                     (set-window-parameter nil 'tab-line-hscroll 
hscroll)))))))))
       (list show-arrows hscroll))))
 
@@ -559,7 +571,7 @@ the selected tab visible."
                  (funcall tab-line-tabs-function))))
     (set-window-parameter
      window 'tab-line-hscroll
-     (max 0 (min (+ (if (integerp hscroll) (abs hscroll) 0) (or arg 1))
+     (max 0 (min (+ (if (numberp hscroll) (truncate hscroll) 0) (or arg 1))
                  (1- (length tabs)))))
     (when window
       (force-mode-line-update t))))
diff --git a/lisp/vc/vc-cvs.el b/lisp/vc/vc-cvs.el
index b6afda6..e8231ec 100644
--- a/lisp/vc/vc-cvs.el
+++ b/lisp/vc/vc-cvs.el
@@ -1222,23 +1222,24 @@ is non-nil."
 
 (defun vc-cvs-ignore (file &optional directory _remove)
   "Ignore FILE under CVS.
-FILE is either absolute or relative to DIRECTORY.  The basename
-of FILE is written unmodified into the ignore file and is
+FILE is either absolute or relative to DIRECTORY.  The non-directory
+part of FILE is written unmodified into the ignore file and is
 therefore evaluated by CVS as an ignore pattern which follows
 glob(7) syntax.  If the pattern should match any of the special
-characters ‘?*[\\\’ literally, they must be escaped with a
+characters `?*[\\' literally, they must be escaped with a
 backslash.
 
 CVS processes one ignore file for each subdirectory.  Patterns
 are separated by whitespace and only match files in the same
 directory.  Since FILE can be a relative filename with leading
-diretories, FILE is expanded against DIRECTORY to determine the
-correct absolute filename.  The directory name of this path is
-then used to determine the location of the ignore file.  The base
-name of this path is used as pattern for the ignore file.
-
-Since patterns are whitespace sparated, it is usually better to
-replace spaces in filenames with question marks ‘?’."
+directories, FILE is expanded against DIRECTORY to determine the
+correct absolute filename.  The directory part of the resulting name
+is then used to determine the location of the ignore file.  The
+non-directory part of the name is used as pattern for the ignore file.
+
+Since patterns are whitespace-separated, filenames containing spaces
+cannot be represented directly.  A work-around is to replace such
+spaces with question marks."
   (setq file (directory-file-name (expand-file-name file directory)))
   (vc-cvs-append-to-ignore (file-name-directory file) (file-name-nondirectory 
file)))
 
diff --git a/lisp/window.el b/lisp/window.el
index bd825c0..b1a0294 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -8806,8 +8806,7 @@ parameters of FRAME."
            (parent (frame-parent frame))
            (monitor-attributes
             (unless parent
-              (car (display-monitor-attributes-list
-                    (frame-parameter frame 'display)))))
+              (frame-monitor-attributes frame)))
            ;; FRAME'S parent or display sizes.  Used in connection
            ;; with margins.
            (geometry
@@ -8816,11 +8815,11 @@ parameters of FRAME."
            (parent-or-display-width
             (if parent
                 (frame-native-width parent)
-              (- (nth 2 geometry) (nth 0 geometry))))
+              (nth 2 geometry)))
            (parent-or-display-height
             (if parent
                 (frame-native-height parent)
-              (- (nth 3 geometry) (nth 1 geometry))))
+              (nth 3 geometry)))
            ;; FRAME's parent or workarea sizes.  Used when no margins
            ;; are specified.
            (parent-or-workarea
@@ -8882,13 +8881,15 @@ parameters of FRAME."
                                 (window--sanitize-margin
                                  (nth 2 margins) left-margin
                                  parent-or-display-width))
-                           (nth 2 parent-or-workarea)))
+                           (+ (nth 0 parent-or-workarea)
+                              (nth 2 parent-or-workarea))))
            (bottom-margin (if (nth 3 margins)
                               (- parent-or-display-height
                                  (window--sanitize-margin
                                   (nth 3 margins) top-margin
                                   parent-or-display-height))
-                            (nth 3 parent-or-workarea)))
+                            (+ (nth 1 parent-or-workarea)
+                               (nth 3 parent-or-workarea))))
            ;; Minimum and maximum sizes specified for FRAME.
            (sizes (or (frame-parameter frame 'fit-frame-to-buffer-sizes)
                       fit-frame-to-buffer-sizes))
diff --git a/src/composite.c b/src/composite.c
index 05365cf..84de334 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -818,6 +818,11 @@ fill_gstring_body (Lisp_Object gstring)
   Lisp_Object header = AREF (gstring, 0);
   ptrdiff_t len = LGSTRING_CHAR_LEN (gstring);
   ptrdiff_t i;
+  struct font *font = NULL;
+  unsigned int code;
+
+  if (FONT_OBJECT_P (font_object))
+    font = XFONT_OBJECT (font_object);
 
   for (i = 0; i < len; i++)
     {
@@ -832,10 +837,15 @@ fill_gstring_body (Lisp_Object gstring)
       LGLYPH_SET_FROM (g, i);
       LGLYPH_SET_TO (g, i);
       LGLYPH_SET_CHAR (g, c);
-      if (FONT_OBJECT_P (font_object))
-       {
-         font_fill_lglyph_metrics (g, font_object);
-       }
+
+      if (font != NULL)
+        code = font->driver->encode_char (font, LGLYPH_CHAR (g));
+      else
+        code = FONT_INVALID_CODE;
+      if (code != FONT_INVALID_CODE)
+        {
+         font_fill_lglyph_metrics (g, font, code);
+        }
       else
        {
          int width = XFIXNAT (CHAR_TABLE_REF (Vchar_width_table, c));
diff --git a/src/font.c b/src/font.c
index bb39aef..2a45630 100644
--- a/src/font.c
+++ b/src/font.c
@@ -4416,10 +4416,8 @@ DEFUN ("clear-font-cache", Fclear_font_cache, 
Sclear_font_cache, 0, 0, 0,
 
 
 void
-font_fill_lglyph_metrics (Lisp_Object glyph, Lisp_Object font_object)
+font_fill_lglyph_metrics (Lisp_Object glyph, struct font *font, unsigned int 
code)
 {
-  struct font *font = XFONT_OBJECT (font_object);
-  unsigned code = font->driver->encode_char (font, LGLYPH_CHAR (glyph));
   struct font_metrics metrics;
 
   LGLYPH_SET_CODE (glyph, code);
diff --git a/src/font.h b/src/font.h
index 0561e3c..8614e7f 100644
--- a/src/font.h
+++ b/src/font.h
@@ -886,7 +886,7 @@ extern Lisp_Object font_update_drivers (struct frame *f, 
Lisp_Object list);
 extern Lisp_Object font_range (ptrdiff_t, ptrdiff_t, ptrdiff_t *,
                               struct window *, struct face *,
                               Lisp_Object);
-extern void font_fill_lglyph_metrics (Lisp_Object, Lisp_Object);
+extern void font_fill_lglyph_metrics (Lisp_Object, struct font *, unsigned 
int);
 
 extern Lisp_Object font_put_extra (Lisp_Object font, Lisp_Object prop,
                                    Lisp_Object val);
diff --git a/src/timefns.c b/src/timefns.c
index 0aa8775..41db1e6 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -1039,9 +1039,7 @@ lispint_arith (Lisp_Object a, Lisp_Object b, bool 
subtract)
 }
 
 /* Given Lisp operands A and B, add their values, and return the
-   result as a Lisp timestamp that is in (TICKS . HZ) form if either A
-   or B are in that form or are floats, (HI LO US PS) form otherwise.
-   Subtract instead of adding if SUBTRACT.  */
+   result as a Lisp timestamp.  Subtract instead of adding if SUBTRACT.  */
 static Lisp_Object
 time_arith (Lisp_Object a, Lisp_Object b, bool subtract)
 {
diff --git a/src/w32term.c b/src/w32term.c
index 4eb5045..f515f56 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -4701,6 +4701,10 @@ static short temp_buffer[100];
 /* Temporarily store lead byte of DBCS input sequences.  */
 static char dbcs_lead = 0;
 
+/* Temporarily store pending UTF-16 high surrogate unit and the modifiers.  */
+static unsigned short utf16_high;
+static DWORD utf16_high_modifiers;
+
 /**
   mouse_or_wdesc_frame: When not dropping and the mouse was grabbed
   for DPYINFO, return the frame where the mouse was seen last.  If
@@ -4912,9 +4916,45 @@ w32_read_socket (struct terminal *terminal,
              XSETFRAME (inev.frame_or_window, f);
              inev.timestamp = msg.msg.time;
 
+             if (utf16_high
+                 && (msg.msg.message != WM_UNICHAR
+                     || UTF_16_HIGH_SURROGATE_P (msg.msg.wParam)))
+               {
+                 /* Flush the pending high surrogate if the low one
+                    isn't coming.  (This should never happen, but I
+                    have paranoia about this stuff.)  */
+                 struct input_event inev1;
+                 inev1.modifiers = utf16_high_modifiers;
+                 inev1.code = utf16_high;
+                 inev1.timestamp = inev.timestamp;
+                 inev1.arg = Qnil;
+                 kbd_buffer_store_event_hold (&inev1, hold_quit);
+                 utf16_high = 0;
+                 utf16_high_modifiers = 0;
+               }
+
               if (msg.msg.message == WM_UNICHAR)
                 {
-                  inev.code = msg.msg.wParam;
+                 /* Handle UTF-16 encoded codepoint above the BMP.
+                    This is needed to support Emoji input from input
+                    panel popped up by "Win+." shortcut.  */
+                 if (UTF_16_HIGH_SURROGATE_P (msg.msg.wParam))
+                   {
+                     utf16_high = msg.msg.wParam;
+                     utf16_high_modifiers = inev.modifiers;
+                     inev.kind = NO_EVENT;
+                     break;
+                   }
+                 else if (UTF_16_LOW_SURROGATE_P (msg.msg.wParam)
+                          && utf16_high)
+                   {
+                     inev.code = surrogates_to_codepoint (msg.msg.wParam,
+                                                          utf16_high);
+                     utf16_high = 0;
+                     utf16_high_modifiers = 0;
+                   }
+                 else
+                   inev.code = msg.msg.wParam;
                 }
               else if (msg.msg.wParam < 256)
                 {
diff --git a/test/lisp/emacs-lisp/rx-tests.el b/test/lisp/emacs-lisp/rx-tests.el
index a6c172a..4888e1d 100644
--- a/test/lisp/emacs-lisp/rx-tests.el
+++ b/test/lisp/emacs-lisp/rx-tests.el
@@ -42,13 +42,24 @@
 (ert-deftest rx-or ()
   (should (equal (rx (or "ab" (| "c" nonl) "de"))
                  "ab\\|c\\|.\\|de"))
-  (should (equal (rx (or "ab" "abc" "a"))
+  (should (equal (rx (or "ab" "abc" ?a))
                  "\\(?:a\\(?:bc?\\)?\\)"))
+  (should (equal (rx (or "ab" (| (or "abcd" "abcde")) (or "a" "abc")))
+                 "\\(?:a\\(?:b\\(?:c\\(?:de?\\)?\\)?\\)?\\)"))
+  (should (equal (rx (or "a" (eval (string ?a ?b))))
+                 "\\(?:ab?\\)"))
   (should (equal (rx (| nonl "a") (| "b" blank))
                  "\\(?:.\\|a\\)\\(?:b\\|[[:blank:]]\\)"))
   (should (equal (rx (|))
                  "\\`a\\`")))
 
+(ert-deftest rx-def-in-or ()
+  (rx-let ((a b)
+           (b (or "abc" c))
+           (c ?a))
+    (should (equal (rx (or a (| "ab" "abcde") "abcd"))
+                   "\\(?:a\\(?:b\\(?:c\\(?:de?\\)?\\)?\\)?\\)"))))
+
 (ert-deftest rx-char-any ()
   "Test character alternatives with `]' and `-' (Bug#25123)."
   (should (equal
@@ -130,7 +141,10 @@
   (should (equal (rx (any "") (not (any "")))
                  "\\`a\\`[^z-a]"))
   (should (equal (rx (any space ?a digit space))
-                 "[a[:space:][:digit:]]")))
+                 "[a[:space:][:digit:]]"))
+  (should (equal (rx (not "\n") (not ?\n) (not (any "\n")) (not-char ?\n)
+                     (| (not (in "a\n")) (not (char ?\n (?b . ?b)))))
+          ".....")))
 
 (ert-deftest rx-pcase ()
   (should (equal (pcase "a 1 2 3 1 1 b"
@@ -298,7 +312,11 @@
                          (not (any "a-k"))))
                  "[^abh-k]"))
   (should (equal (rx (or ?f (any "b-e") "a") (not (or ?x "y" (any "s-w"))))
-                 "[a-f][^s-y]")))
+                 "[a-f][^s-y]"))
+  (should (equal (rx (not (or (in "abc") (char "bcd"))))
+                 "[^a-d]"))
+  (should (equal (rx (or (not (in "abc")) (not (char "bcd"))))
+                 "[^bc]")))
 
 (ert-deftest rx-def-in-charset-or ()
   (rx-let ((a (any "badc"))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]