aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorAndrea Corallo2020-05-24 10:20:23 +0100
committerAndrea Corallo2020-05-24 10:20:23 +0100
commit9daffe9cfe82d3b1e1e9fa8929dbb40cfed60f0f (patch)
treec9e78cbb4e151dc3c3996a65cf1eedab19248fb4 /lisp
parentf5dceed09a8234548d5b3acb76d443569533cab9 (diff)
parente021c2dc2279e0fd3a5331f9ea661e4d39c2e840 (diff)
downloademacs-9daffe9cfe82d3b1e1e9fa8929dbb40cfed60f0f.tar.gz
emacs-9daffe9cfe82d3b1e1e9fa8929dbb40cfed60f0f.zip
Merge remote-tracking branch 'savannah/master' into HEAD
Diffstat (limited to 'lisp')
-rw-r--r--lisp/calculator.el10
-rw-r--r--lisp/cedet/ede.el7
-rw-r--r--lisp/doc-view.el4
-rw-r--r--lisp/emacs-lisp/package.el28
-rw-r--r--lisp/emacs-lisp/syntax.el35
-rw-r--r--lisp/gnus/gnus-art.el14
-rw-r--r--lisp/gnus/gnus-registry.el36
-rw-r--r--lisp/ido.el19
-rw-r--r--lisp/json.el576
-rw-r--r--lisp/jsonrpc.el50
-rw-r--r--lisp/language/tibet-util.el14
-rw-r--r--lisp/mouse.el2
-rw-r--r--lisp/net/eww.el30
-rw-r--r--lisp/net/shr.el84
-rw-r--r--lisp/net/tramp-archive.el7
-rw-r--r--lisp/net/tramp-rclone.el13
-rw-r--r--lisp/net/webjump.el5
-rw-r--r--lisp/obsolete/levents.el292
-rw-r--r--lisp/org/org-agenda.el5
-rw-r--r--lisp/password-cache.el3
-rw-r--r--lisp/progmodes/cc-langs.el10
-rw-r--r--lisp/progmodes/cc-mode.el2
-rw-r--r--lisp/progmodes/project.el153
-rw-r--r--lisp/progmodes/python.el21
-rw-r--r--lisp/progmodes/which-func.el97
-rw-r--r--lisp/progmodes/xref.el4
-rw-r--r--lisp/subr.el6
-rw-r--r--lisp/vc/vc-dir.el36
-rw-r--r--lisp/vc/vc-git.el4
-rw-r--r--lisp/vc/vc-hooks.el2
-rw-r--r--lisp/version.el4
-rw-r--r--lisp/xml.el13
32 files changed, 738 insertions, 848 deletions
diff --git a/lisp/calculator.el b/lisp/calculator.el
index 7e0b2fcc6a3..cd92f992689 100644
--- a/lisp/calculator.el
+++ b/lisp/calculator.el
@@ -858,12 +858,10 @@ The result should not exceed the screen width."
858 "Convert the given STR to a number, according to the value of 858 "Convert the given STR to a number, according to the value of
859`calculator-input-radix'." 859`calculator-input-radix'."
860 (if calculator-input-radix 860 (if calculator-input-radix
861 (string-to-number str (cadr (assq calculator-input-radix 861 (string-to-number str (cadr (assq calculator-input-radix
862 '((bin 2) (oct 8) (hex 16))))) 862 '((bin 2) (oct 8) (hex 16)))))
863 (let* ((str (replace-regexp-in-string 863 ;; Allow entry of "1.e3".
864 "\\.\\([^0-9].*\\)?$" ".0\\1" str)) 864 (let ((str (replace-regexp-in-string (rx "." (any "eE")) "e" str)))
865 (str (replace-regexp-in-string
866 "[eE][+-]?\\([^0-9].*\\)?$" "e0\\1" str)))
867 (float (string-to-number str))))) 865 (float (string-to-number str)))))
868 866
869(defun calculator-push-curnum () 867(defun calculator-push-curnum ()
diff --git a/lisp/cedet/ede.el b/lisp/cedet/ede.el
index 8c336117c92..41252815734 100644
--- a/lisp/cedet/ede.el
+++ b/lisp/cedet/ede.el
@@ -1515,8 +1515,11 @@ It does not apply the value to buffers."
1515 (when project-dir 1515 (when project-dir
1516 (ede-directory-get-open-project project-dir 'ROOT)))) 1516 (ede-directory-get-open-project project-dir 'ROOT))))
1517 1517
1518(cl-defmethod project-roots ((project ede-project)) 1518(cl-defmethod project-root ((project ede-project))
1519 (list (ede-project-root-directory project))) 1519 (ede-project-root-directory project))
1520
1521;;; FIXME: Could someone look into implementing `project-ignores' for
1522;;; EDE and/or a faster `project-files'?
1520 1523
1521(add-hook 'project-find-functions #'project-try-ede) 1524(add-hook 'project-find-functions #'project-try-ede)
1522 1525
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index 3cac2629a9c..de342f1519e 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -2050,8 +2050,8 @@ See the command `doc-view-mode' for more information on this mode."
2050 (when (memq (selected-frame) (alist-get 'frames attrs)) 2050 (when (memq (selected-frame) (alist-get 'frames attrs))
2051 (let ((geom (alist-get 'geometry attrs))) 2051 (let ((geom (alist-get 'geometry attrs)))
2052 (when geom 2052 (when geom
2053 (setq monitor-top (nth 0 geom)) 2053 (setq monitor-left (nth 0 geom))
2054 (setq monitor-left (nth 1 geom)) 2054 (setq monitor-top (nth 1 geom))
2055 (setq monitor-width (nth 2 geom)) 2055 (setq monitor-width (nth 2 geom))
2056 (setq monitor-height (nth 3 geom)))))) 2056 (setq monitor-height (nth 3 geom))))))
2057 (let ((frame (make-frame 2057 (let ((frame (make-frame
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 95659840ad5..808e4f34fc5 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -397,6 +397,26 @@ synchronously."
397 :type 'boolean 397 :type 'boolean
398 :version "25.1") 398 :version "25.1")
399 399
400(defcustom package-name-column-width 30
401 "Column width for the Package name in the package menu."
402 :type 'number
403 :version "28.1")
404
405(defcustom package-version-column-width 14
406 "Column width for the Package version in the package menu."
407 :type 'number
408 :version "28.1")
409
410(defcustom package-status-column-width 12
411 "Column width for the Package status in the package menu."
412 :type 'number
413 :version "28.1")
414
415(defcustom package-archive-column-width 8
416 "Column width for the Package status in the package menu."
417 :type 'number
418 :version "28.1")
419
400 420
401;;; `package-desc' object definition 421;;; `package-desc' object definition
402;; This is the struct used internally to represent packages. 422;; This is the struct used internally to represent packages.
@@ -2750,11 +2770,11 @@ Letters do not insert themselves; instead, they are commands.
2750 (package-menu--transaction-status 2770 (package-menu--transaction-status
2751 package-menu--transaction-status))) 2771 package-menu--transaction-status)))
2752 (setq tabulated-list-format 2772 (setq tabulated-list-format
2753 `[("Package" 18 package-menu--name-predicate) 2773 `[("Package" ,package-name-column-width package-menu--name-predicate)
2754 ("Version" 13 package-menu--version-predicate) 2774 ("Version" ,package-version-column-width package-menu--version-predicate)
2755 ("Status" 10 package-menu--status-predicate) 2775 ("Status" ,package-status-column-width package-menu--status-predicate)
2756 ,@(if (cdr package-archives) 2776 ,@(if (cdr package-archives)
2757 '(("Archive" 10 package-menu--archive-predicate))) 2777 `(("Archive" ,package-archive-column-width package-menu--archive-predicate)))
2758 ("Description" 0 package-menu--description-predicate)]) 2778 ("Description" 0 package-menu--description-predicate)])
2759 (setq tabulated-list-padding 2) 2779 (setq tabulated-list-padding 2)
2760 (setq tabulated-list-sort-key (cons "Status" nil)) 2780 (setq tabulated-list-sort-key (cons "Status" nil))
diff --git a/lisp/emacs-lisp/syntax.el b/lisp/emacs-lisp/syntax.el
index 46dc8d9ade8..ce495af95bc 100644
--- a/lisp/emacs-lisp/syntax.el
+++ b/lisp/emacs-lisp/syntax.el
@@ -139,14 +139,28 @@ delimiter or an Escaped or Char-quoted character."))
139 (point-max)))) 139 (point-max))))
140 (cons beg end)) 140 (cons beg end))
141 141
142(defun syntax-propertize--shift-groups (re n) 142(defun syntax-propertize--shift-groups-and-backrefs (re n)
143 (replace-regexp-in-string 143 (let ((new-re (replace-regexp-in-string
144 "\\\\(\\?\\([0-9]+\\):" 144 "\\\\(\\?\\([0-9]+\\):"
145 (lambda (s) 145 (lambda (s)
146 (replace-match 146 (replace-match
147 (number-to-string (+ n (string-to-number (match-string 1 s)))) 147 (number-to-string
148 t t s 1)) 148 (+ n (string-to-number (match-string 1 s))))
149 re t t)) 149 t t s 1))
150 re t t))
151 (pos 0))
152 (while (string-match "\\\\\\([0-9]+\\)" new-re pos)
153 (setq pos (+ 1 (match-beginning 1)))
154 (when (save-match-data
155 ;; With \N, the \ must be in a subregexp context, i.e.,
156 ;; not in a character class or in a \{\} repetition.
157 (subregexp-context-p new-re (match-beginning 0)))
158 (let ((shifted (+ n (string-to-number (match-string 1 new-re)))))
159 (when (> shifted 9)
160 (error "There may be at most nine back-references"))
161 (setq new-re (replace-match (number-to-string shifted)
162 t t new-re 1)))))
163 new-re))
150 164
151(defmacro syntax-propertize-precompile-rules (&rest rules) 165(defmacro syntax-propertize-precompile-rules (&rest rules)
152 "Return a precompiled form of RULES to pass to `syntax-propertize-rules'. 166 "Return a precompiled form of RULES to pass to `syntax-propertize-rules'.
@@ -190,7 +204,8 @@ for subsequent HIGHLIGHTs.
190Also SYNTAX is free to move point, in which case RULES may not be applied to 204Also SYNTAX is free to move point, in which case RULES may not be applied to
191some parts of the text or may be applied several times to other parts. 205some parts of the text or may be applied several times to other parts.
192 206
193Note: back-references in REGEXPs do not work." 207Note: There may be at most nine back-references in the REGEXPs of
208all RULES in total."
194 (declare (debug (&rest &or symbolp ;FIXME: edebug this eval step. 209 (declare (debug (&rest &or symbolp ;FIXME: edebug this eval step.
195 (form &rest 210 (form &rest
196 (numberp 211 (numberp
@@ -219,7 +234,7 @@ Note: back-references in REGEXPs do not work."
219 ;; tell when *this* match 0 has succeeded. 234 ;; tell when *this* match 0 has succeeded.
220 (cl-incf offset) 235 (cl-incf offset)
221 (setq re (concat "\\(" re "\\)"))) 236 (setq re (concat "\\(" re "\\)")))
222 (setq re (syntax-propertize--shift-groups re offset)) 237 (setq re (syntax-propertize--shift-groups-and-backrefs re offset))
223 (let ((code '()) 238 (let ((code '())
224 (condition 239 (condition
225 (cond 240 (cond
diff --git a/lisp/gnus/gnus-art.el b/lisp/gnus/gnus-art.el
index 6b9610d3121..614651afff9 100644
--- a/lisp/gnus/gnus-art.el
+++ b/lisp/gnus/gnus-art.el
@@ -5833,6 +5833,7 @@ all parts."
5833 "" "...")) 5833 "" "..."))
5834 (gnus-tmp-length (with-current-buffer (mm-handle-buffer handle) 5834 (gnus-tmp-length (with-current-buffer (mm-handle-buffer handle)
5835 (buffer-size))) 5835 (buffer-size)))
5836 (help-echo "mouse-2: toggle the MIME part; down-mouse-3: more options")
5836 gnus-tmp-type-long b e) 5837 gnus-tmp-type-long b e)
5837 (when (string-match ".*/" gnus-tmp-name) 5838 (when (string-match ".*/" gnus-tmp-name)
5838 (setq gnus-tmp-name (replace-match "" t t gnus-tmp-name))) 5839 (setq gnus-tmp-name (replace-match "" t t gnus-tmp-name)))
@@ -5841,6 +5842,16 @@ all parts."
5841 (concat "; " gnus-tmp-name)))) 5842 (concat "; " gnus-tmp-name))))
5842 (unless (equal gnus-tmp-description "") 5843 (unless (equal gnus-tmp-description "")
5843 (setq gnus-tmp-type-long (concat " --- " gnus-tmp-type-long))) 5844 (setq gnus-tmp-type-long (concat " --- " gnus-tmp-type-long)))
5845 (when (zerop gnus-tmp-length)
5846 (setq gnus-tmp-type-long
5847 (concat
5848 gnus-tmp-type-long
5849 (substitute-command-keys
5850 (concat "\\<gnus-summary-mode-map> (not downloaded, "
5851 "\\[gnus-summary-show-complete-article] to fetch.)"))))
5852 (setq help-echo
5853 (concat "Type \\[gnus-summary-show-complete-article] "
5854 "to download complete article. " help-echo)))
5844 (setq b (point)) 5855 (setq b (point))
5845 (gnus-eval-format 5856 (gnus-eval-format
5846 gnus-mime-button-line-format gnus-mime-button-line-format-alist 5857 gnus-mime-button-line-format gnus-mime-button-line-format-alist
@@ -5859,8 +5870,7 @@ all parts."
5859 'keymap gnus-mime-button-map 5870 'keymap gnus-mime-button-map
5860 'face gnus-article-button-face 5871 'face gnus-article-button-face
5861 'follow-link t 5872 'follow-link t
5862 'help-echo 5873 'help-echo help-echo)))
5863 "mouse-2: toggle the MIME part; down-mouse-3: more options")))
5864 5874
5865(defvar gnus-displaying-mime nil) 5875(defvar gnus-displaying-mime nil)
5866 5876
diff --git a/lisp/gnus/gnus-registry.el b/lisp/gnus/gnus-registry.el
index 480ed80ef81..f306889a7fc 100644
--- a/lisp/gnus/gnus-registry.el
+++ b/lisp/gnus/gnus-registry.el
@@ -485,23 +485,25 @@ This is not required after changing `gnus-registry-cache-file'."
485 (when from 485 (when from
486 (setq entry (cons (delete from (assoc 'group entry)) 486 (setq entry (cons (delete from (assoc 'group entry))
487 (assq-delete-all 'group entry)))) 487 (assq-delete-all 'group entry))))
488 488 ;; Only keep the entry if the message is going to a new group, or
489 (dolist (kv `((group ,to) 489 ;; it's still in some previous group.
490 (sender ,sender) 490 (when (or to (alist-get 'group entry))
491 (recipient ,@recipients) 491 (dolist (kv `((group ,to)
492 (subject ,subject))) 492 (sender ,sender)
493 (when (cadr kv) 493 (recipient ,@recipients)
494 (let ((new (or (assq (car kv) entry) 494 (subject ,subject)))
495 (list (car kv))))) 495 (when (cadr kv)
496 (dolist (toadd (cdr kv)) 496 (let ((new (or (assq (car kv) entry)
497 (unless (member toadd new) 497 (list (car kv)))))
498 (setq new (append new (list toadd))))) 498 (dolist (toadd (cdr kv))
499 (setq entry (cons new 499 (unless (member toadd new)
500 (assq-delete-all (car kv) entry)))))) 500 (setq new (append new (list toadd)))))
501 (gnus-message 10 "Gnus registry: new entry for %s is %S" 501 (setq entry (cons new
502 id 502 (assq-delete-all (car kv) entry))))))
503 entry) 503 (gnus-message 10 "Gnus registry: new entry for %s is %S"
504 (gnus-registry-insert db id entry))) 504 id
505 entry)
506 (gnus-registry-insert db id entry))))
505 507
506;; Function for nn{mail|imap}-split-fancy: look up all references in 508;; Function for nn{mail|imap}-split-fancy: look up all references in
507;; the cache and if a match is found, return that group. 509;; the cache and if a match is found, return that group.
diff --git a/lisp/ido.el b/lisp/ido.el
index 81883402add..ad71d468cb4 100644
--- a/lisp/ido.el
+++ b/lisp/ido.el
@@ -499,11 +499,14 @@ This means that \\[ido-complete] must always be followed by \\[ido-exit-minibuff
499even when there is only one unique completion." 499even when there is only one unique completion."
500 :type 'boolean) 500 :type 'boolean)
501 501
502(defcustom ido-cannot-complete-command 'ido-completion-help 502(defcustom ido-cannot-complete-command #'ido-completion-auto-help
503 "Command run when `ido-complete' can't complete any more. 503 "Command run when `ido-complete' can't complete any more.
504The most useful values are `ido-completion-help', which pops up a 504The most useful values are `ido-completion-help', which pops up a
505window with completion alternatives, or `ido-next-match' or 505window with completion alternatives; `ido-completion-auto-help',
506`ido-prev-match', which cycle the buffer list." 506which does the same but respects the value of
507`completion-auto-help'; and `ido-next-match' or `ido-prev-match',
508which cycle the buffer list."
509 :version "28.1"
507 :type 'function) 510 :type 'function)
508 511
509 512
@@ -1546,7 +1549,7 @@ This function also adds a hook to the minibuffer."
1546 ((> (prefix-numeric-value arg) 0) 'both) 1549 ((> (prefix-numeric-value arg) 0) 'both)
1547 (t nil))) 1550 (t nil)))
1548 1551
1549 (ido-everywhere (if ido-everywhere 1 -1)) 1552 (ido-everywhere (if (and ido-mode ido-everywhere) 1 -1))
1550 1553
1551 (when ido-mode 1554 (when ido-mode
1552 (ido-common-initialization) 1555 (ido-common-initialization)
@@ -3926,6 +3929,14 @@ If `ido-change-word-sub' cannot be found in WORD, return nil."
3926 (when (bobp) 3929 (when (bobp)
3927 (next-completion 1))))) 3930 (next-completion 1)))))
3928 3931
3932(defun ido-completion-auto-help ()
3933 "Call `ido-completion-help' if `completion-auto-help' is non-nil."
3934 (interactive)
3935 ;; Note: `completion-auto-help' could also be `lazy', but this value
3936 ;; is irrelevant to ido, which is fundamentally eager, so it is
3937 ;; treated the same as t.
3938 (when completion-auto-help
3939 (ido-completion-help)))
3929 3940
3930(defun ido-completion-help () 3941(defun ido-completion-help ()
3931 "Show possible completions in the `ido-completion-buffer'." 3942 "Show possible completions in the `ido-completion-buffer'."
diff --git a/lisp/json.el b/lisp/json.el
index 6f3b791ed17..9002e868537 100644
--- a/lisp/json.el
+++ b/lisp/json.el
@@ -3,7 +3,7 @@
3;; Copyright (C) 2006-2020 Free Software Foundation, Inc. 3;; Copyright (C) 2006-2020 Free Software Foundation, Inc.
4 4
5;; Author: Theresa O'Connor <ted@oconnor.cx> 5;; Author: Theresa O'Connor <ted@oconnor.cx>
6;; Version: 1.4 6;; Version: 1.5
7;; Keywords: convenience 7;; Keywords: convenience
8 8
9;; This file is part of GNU Emacs. 9;; This file is part of GNU Emacs.
@@ -29,11 +29,11 @@
29;; Learn all about JSON here: <URL:http://json.org/>. 29;; Learn all about JSON here: <URL:http://json.org/>.
30 30
31;; The user-serviceable entry points for the parser are the functions 31;; The user-serviceable entry points for the parser are the functions
32;; `json-read' and `json-read-from-string'. The encoder has a single 32;; `json-read' and `json-read-from-string'. The encoder has a single
33;; entry point, `json-encode'. 33;; entry point, `json-encode'.
34 34
35;; Since there are several natural representations of key-value pair 35;; Since there are several natural representations of key-value pair
36;; mappings in elisp (alist, plist, hash-table), `json-read' allows you 36;; mappings in Elisp (alist, plist, hash-table), `json-read' allows you
37;; to specify which you'd prefer (see `json-object-type' and 37;; to specify which you'd prefer (see `json-object-type' and
38;; `json-array-type'). 38;; `json-array-type').
39 39
@@ -55,6 +55,7 @@
55;;; Code: 55;;; Code:
56 56
57(require 'map) 57(require 'map)
58(require 'seq)
58(require 'subr-x) 59(require 'subr-x)
59 60
60;; Parameters 61;; Parameters
@@ -113,8 +114,10 @@ Used only when `json-encoding-pretty-print' is non-nil.")
113 "If non-nil, then the output of `json-encode' will be pretty-printed.") 114 "If non-nil, then the output of `json-encode' will be pretty-printed.")
114 115
115(defvar json-encoding-lisp-style-closings nil 116(defvar json-encoding-lisp-style-closings nil
116 "If non-nil, ] and } closings will be formatted lisp-style, 117 "If non-nil, delimiters ] and } will be formatted Lisp-style.
117without indentation.") 118This means they will be placed on the same line as the last
119element of the respective array or object, without indentation.
120Used only when `json-encoding-pretty-print' is non-nil.")
118 121
119(defvar json-encoding-object-sort-predicate nil 122(defvar json-encoding-object-sort-predicate nil
120 "Sorting predicate for JSON object keys during encoding. 123 "Sorting predicate for JSON object keys during encoding.
@@ -124,88 +127,81 @@ instance, setting this to `string<' will have JSON object keys
124ordered alphabetically.") 127ordered alphabetically.")
125 128
126(defvar json-pre-element-read-function nil 129(defvar json-pre-element-read-function nil
127 "Function called (if non-nil) by `json-read-array' and 130 "If non-nil, a function to call before reading a JSON array or object.
128`json-read-object' right before reading a JSON array or object, 131It is called by `json-read-array' and `json-read-object',
129respectively. The function is called with one argument, which is 132respectively, with one argument, which is the current JSON key.")
130the current JSON key.")
131 133
132(defvar json-post-element-read-function nil 134(defvar json-post-element-read-function nil
133 "Function called (if non-nil) by `json-read-array' and 135 "If non-nil, a function to call after reading a JSON array or object.
134`json-read-object' right after reading a JSON array or object, 136It is called by `json-read-array' and `json-read-object',
135respectively.") 137respectively, with no arguments.")
136 138
137 139
138 140
139;;; Utilities 141;;; Utilities
140 142
141(defun json-join (strings separator) 143(define-obsolete-function-alias 'json-join #'string-join "28.1")
142 "Join STRINGS with SEPARATOR."
143 (mapconcat 'identity strings separator))
144 144
145(defun json-alist-p (list) 145(defun json-alist-p (list)
146 "Non-null if and only if LIST is an alist with simple keys." 146 "Non-nil if and only if LIST is an alist with simple keys."
147 (while (consp list) 147 (declare (pure t) (side-effect-free error-free))
148 (setq list (if (and (consp (car list)) 148 (while (and (consp (car-safe list))
149 (atom (caar list))) 149 (atom (caar list))
150 (cdr list) 150 (setq list (cdr list))))
151 'not-alist)))
152 (null list)) 151 (null list))
153 152
154(defun json-plist-p (list) 153(defun json-plist-p (list)
155 "Non-null if and only if LIST is a plist with keyword keys." 154 "Non-nil if and only if LIST is a plist with keyword keys."
156 (while (consp list) 155 (declare (pure t) (side-effect-free error-free))
157 (setq list (if (and (keywordp (car list)) 156 (while (and (keywordp (car-safe list))
158 (consp (cdr list))) 157 (consp (cdr list))
159 (cddr list) 158 (setq list (cddr list))))
160 'not-plist)))
161 (null list)) 159 (null list))
162 160
163(defun json--plist-reverse (plist) 161(defun json--plist-nreverse (plist)
164 "Return a copy of PLIST in reverse order. 162 "Return PLIST in reverse order.
165Unlike `reverse', this keeps the property-value pairs intact." 163Unlike `nreverse', this keeps the ordering of each property
166 (let (res) 164relative to its value intact. Like `nreverse', this function may
167 (while plist 165destructively modify PLIST to produce the result."
168 (let ((prop (pop plist)) 166 (let (prev (next (cddr plist)))
169 (val (pop plist))) 167 (while next
170 (push val res) 168 (setcdr (cdr plist) prev)
171 (push prop res))) 169 (setq prev plist plist next next (cddr next))
172 res)) 170 (setcdr (cdr plist) prev)))
173 171 plist)
174(defun json--plist-to-alist (plist) 172
175 "Return an alist of the property-value pairs in PLIST." 173(defmacro json--with-indentation (&rest body)
176 (let (res) 174 "Evaluate BODY with the correct indentation for JSON encoding.
177 (while plist 175This macro binds `json--encoding-current-indentation' according
178 (let ((prop (pop plist)) 176to `json-encoding-pretty-print' around BODY."
179 (val (pop plist))) 177 (declare (debug t) (indent 0))
180 (push (cons prop val) res)))
181 (nreverse res)))
182
183(defmacro json--with-indentation (body)
184 `(let ((json--encoding-current-indentation 178 `(let ((json--encoding-current-indentation
185 (if json-encoding-pretty-print 179 (if json-encoding-pretty-print
186 (concat json--encoding-current-indentation 180 (concat json--encoding-current-indentation
187 json-encoding-default-indentation) 181 json-encoding-default-indentation)
188 ""))) 182 "")))
189 ,body)) 183 ,@body))
190 184
191;; Reader utilities 185;; Reader utilities
192 186
193(define-inline json-advance (&optional n) 187(define-inline json-advance (&optional n)
194 "Advance N characters forward." 188 "Advance N characters forward, or 1 character if N is nil.
189On reaching the end of the accessible region of the buffer, stop
190and signal an error."
195 (inline-quote (forward-char ,n))) 191 (inline-quote (forward-char ,n)))
196 192
197(define-inline json-peek () 193(define-inline json-peek ()
198 "Return the character at point." 194 "Return the character at point.
195At the end of the accessible region of the buffer, return 0."
199 (inline-quote (following-char))) 196 (inline-quote (following-char)))
200 197
201(define-inline json-pop () 198(define-inline json-pop ()
202 "Advance past the character at point, returning it." 199 "Advance past the character at point, returning it.
200Signal `json-end-of-file' if called at the end of the buffer."
203 (inline-quote 201 (inline-quote
204 (let ((char (json-peek))) 202 (prog1 (or (char-after)
205 (if (zerop char) 203 (signal 'json-end-of-file ()))
206 (signal 'json-end-of-file nil) 204 (json-advance))))
207 (json-advance)
208 char))))
209 205
210(define-inline json-skip-whitespace () 206(define-inline json-skip-whitespace ()
211 "Skip past the whitespace at point." 207 "Skip past the whitespace at point."
@@ -213,7 +209,7 @@ Unlike `reverse', this keeps the property-value pairs intact."
213 ;; https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf 209 ;; https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
214 ;; or https://tools.ietf.org/html/rfc7159#section-2 for the 210 ;; or https://tools.ietf.org/html/rfc7159#section-2 for the
215 ;; definition of whitespace in JSON. 211 ;; definition of whitespace in JSON.
216 (inline-quote (skip-chars-forward "\t\r\n "))) 212 (inline-quote (skip-chars-forward "\t\n\r ")))
217 213
218 214
219 215
@@ -236,8 +232,8 @@ Unlike `reverse', this keeps the property-value pairs intact."
236;;; Paths 232;;; Paths
237 233
238(defvar json--path '() 234(defvar json--path '()
239 "Used internally by `json-path-to-position' to keep track of 235 "Keeps track of the path during recursive calls to `json-read'.
240the path during recursive calls to `json-read'.") 236Used internally by `json-path-to-position'.")
241 237
242(defun json--record-path (key) 238(defun json--record-path (key)
243 "Record the KEY to the current JSON path. 239 "Record the KEY to the current JSON path.
@@ -248,7 +244,7 @@ Used internally by `json-path-to-position'."
248 "Check if the last parsed JSON structure passed POSITION. 244 "Check if the last parsed JSON structure passed POSITION.
249Used internally by `json-path-to-position'." 245Used internally by `json-path-to-position'."
250 (let ((start (caar json--path))) 246 (let ((start (caar json--path)))
251 (when (< start position (+ (point) 1)) 247 (when (< start position (1+ (point)))
252 (throw :json-path (list :path (nreverse (mapcar #'cdr json--path)) 248 (throw :json-path (list :path (nreverse (mapcar #'cdr json--path))
253 :match-start start 249 :match-start start
254 :match-end (point))))) 250 :match-end (point)))))
@@ -266,13 +262,13 @@ properties:
266:path -- A list of strings and numbers forming the path to 262:path -- A list of strings and numbers forming the path to
267 the JSON element at the given position. Strings 263 the JSON element at the given position. Strings
268 denote object names, while numbers denote array 264 denote object names, while numbers denote array
269 indexes. 265 indices.
270 266
271:match-start -- Position where the matched JSON element begins. 267:match-start -- Position where the matched JSON element begins.
272 268
273:match-end -- Position where the matched JSON element ends. 269:match-end -- Position where the matched JSON element ends.
274 270
275This can for instance be useful to determine the path to a JSON 271This can, for instance, be useful to determine the path to a JSON
276element in a deeply nested structure." 272element in a deeply nested structure."
277 (save-excursion 273 (save-excursion
278 (unless string 274 (unless string
@@ -280,7 +276,7 @@ element in a deeply nested structure."
280 (let* ((json--path '()) 276 (let* ((json--path '())
281 (json-pre-element-read-function #'json--record-path) 277 (json-pre-element-read-function #'json--record-path)
282 (json-post-element-read-function 278 (json-post-element-read-function
283 (apply-partially #'json--check-position position)) 279 (lambda () (json--check-position position)))
284 (path (catch :json-path 280 (path (catch :json-path
285 (if string 281 (if string
286 (json-read-from-string string) 282 (json-read-from-string string)
@@ -290,38 +286,33 @@ element in a deeply nested structure."
290 286
291;;; Keywords 287;;; Keywords
292 288
293(defvar json-keywords '("true" "false" "null") 289(defconst json-keywords '("true" "false" "null")
294 "List of JSON keywords.") 290 "List of JSON keywords.")
291(make-obsolete-variable 'json-keywords "it is no longer used." "28.1")
295 292
296;; Keyword parsing 293;; Keyword parsing
297 294
295;; Characters that can follow a JSON value.
296(rx-define json--post-value (| (in "\t\n\r ,]}") eos))
297
298(defun json-read-keyword (keyword) 298(defun json-read-keyword (keyword)
299 "Read a JSON keyword at point. 299 "Read the expected JSON KEYWORD at point."
300KEYWORD is the keyword expected." 300 (prog1 (cond ((equal keyword "true") t)
301 (unless (member keyword json-keywords) 301 ((equal keyword "false") json-false)
302 (signal 'json-unknown-keyword (list keyword))) 302 ((equal keyword "null") json-null)
303 (mapc (lambda (char) 303 (t (signal 'json-unknown-keyword (list keyword))))
304 (when (/= char (json-peek)) 304 (or (looking-at-p keyword)
305 (signal 'json-unknown-keyword 305 (signal 'json-unknown-keyword (list (thing-at-point 'word))))
306 (list (save-excursion 306 (json-advance (length keyword))
307 (backward-word-strictly 1) 307 (or (looking-at-p (rx json--post-value))
308 (thing-at-point 'word))))) 308 (signal 'json-unknown-keyword (list (thing-at-point 'word))))
309 (json-advance)) 309 (json-skip-whitespace)))
310 keyword)
311 (json-skip-whitespace)
312 (unless (looking-at "\\([],}]\\|$\\)")
313 (signal 'json-unknown-keyword
314 (list (save-excursion
315 (backward-word-strictly 1)
316 (thing-at-point 'word)))))
317 (cond ((string-equal keyword "true") t)
318 ((string-equal keyword "false") json-false)
319 ((string-equal keyword "null") json-null)))
320 310
321;; Keyword encoding 311;; Keyword encoding
322 312
323(defun json-encode-keyword (keyword) 313(defun json-encode-keyword (keyword)
324 "Encode KEYWORD as a JSON value." 314 "Encode KEYWORD as a JSON value."
315 (declare (side-effect-free t))
325 (cond ((eq keyword t) "true") 316 (cond ((eq keyword t) "true")
326 ((eq keyword json-false) "false") 317 ((eq keyword json-false) "false")
327 ((eq keyword json-null) "null"))) 318 ((eq keyword json-null) "null")))
@@ -330,37 +321,31 @@ KEYWORD is the keyword expected."
330 321
331;; Number parsing 322;; Number parsing
332 323
333(defun json-read-number (&optional sign) 324(rx-define json--number
334 "Read the JSON number following point. 325 (: (? ?-) ; Sign.
335The optional SIGN argument is for internal use. 326 (| (: (in "1-9") (* digit)) ?0) ; Integer.
336 327 (? ?. (+ digit)) ; Fraction.
337N.B.: Only numbers which can fit in Emacs Lisp's native number 328 (? (in "Ee") (? (in ?+ ?-)) (+ digit)))) ; Exponent.
338representation will be parsed correctly." 329
339 ;; If SIGN is non-nil, the number is explicitly signed. 330(defun json-read-number (&optional _sign)
340 (let ((number-regexp 331 "Read the JSON number following point."
341 "\\([0-9]+\\)?\\(\\.[0-9]+\\)?\\([Ee][+-]?[0-9]+\\)?")) 332 (declare (advertised-calling-convention () "28.1"))
342 (cond ((and (null sign) (= (json-peek) ?-)) 333 (or (looking-at (rx json--number))
343 (json-advance) 334 (signal 'json-number-format (list (point))))
344 (- (json-read-number t))) 335 (goto-char (match-end 0))
345 ((and (null sign) (= (json-peek) ?+)) 336 (prog1 (string-to-number (match-string 0))
346 (json-advance) 337 (or (looking-at-p (rx json--post-value))
347 (json-read-number t)) 338 (signal 'json-number-format (list (point))))
348 ((and (looking-at number-regexp) 339 (json-skip-whitespace)))
349 (or (match-beginning 1)
350 (match-beginning 2)))
351 (goto-char (match-end 0))
352 (string-to-number (match-string 0)))
353 (t (signal 'json-number-format (list (point)))))))
354 340
355;; Number encoding 341;; Number encoding
356 342
357(defun json-encode-number (number) 343(defalias 'json-encode-number #'number-to-string
358 "Return a JSON representation of NUMBER." 344 "Return a JSON representation of NUMBER.")
359 (format "%s" number))
360 345
361;;; Strings 346;;; Strings
362 347
363(defvar json-special-chars 348(defconst json-special-chars
364 '((?\" . ?\") 349 '((?\" . ?\")
365 (?\\ . ?\\) 350 (?\\ . ?\\)
366 (?b . ?\b) 351 (?b . ?\b)
@@ -368,7 +353,7 @@ representation will be parsed correctly."
368 (?n . ?\n) 353 (?n . ?\n)
369 (?r . ?\r) 354 (?r . ?\r)
370 (?t . ?\t)) 355 (?t . ?\t))
371 "Characters which are escaped in JSON, with their elisp counterparts.") 356 "Characters which are escaped in JSON, with their Elisp counterparts.")
372 357
373;; String parsing 358;; String parsing
374 359
@@ -378,48 +363,47 @@ representation will be parsed correctly."
378 363
379(defun json-read-escaped-char () 364(defun json-read-escaped-char ()
380 "Read the JSON string escaped character at point." 365 "Read the JSON string escaped character at point."
381 ;; Skip over the '\' 366 ;; Skip over the '\'.
382 (json-advance) 367 (json-advance)
383 (let* ((char (json-pop)) 368 (let ((char (json-pop)))
384 (special (assq char json-special-chars)))
385 (cond 369 (cond
386 (special (cdr special)) 370 ((cdr (assq char json-special-chars)))
387 ((not (eq char ?u)) char) 371 ((/= char ?u) char)
388 ;; Special-case UTF-16 surrogate pairs, 372 ;; Special-case UTF-16 surrogate pairs,
389 ;; cf. <https://tools.ietf.org/html/rfc7159#section-7>. Note that 373 ;; cf. <https://tools.ietf.org/html/rfc7159#section-7>. Note that
390 ;; this clause overlaps with the next one and therefore has to 374 ;; this clause overlaps with the next one and therefore has to
391 ;; come first. 375 ;; come first.
392 ((looking-at 376 ((looking-at
393 (rx (group (any "Dd") (any "89ABab") (= 2 (any xdigit))) 377 (rx (group (any "Dd") (any "89ABab") (= 2 xdigit))
394 "\\u" (group (any "Dd") (any "C-Fc-f") (= 2 (any xdigit))))) 378 "\\u" (group (any "Dd") (any "C-Fc-f") (= 2 xdigit))))
395 (json-advance 10) 379 (json-advance 10)
396 (json--decode-utf-16-surrogates 380 (json--decode-utf-16-surrogates
397 (string-to-number (match-string 1) 16) 381 (string-to-number (match-string 1) 16)
398 (string-to-number (match-string 2) 16))) 382 (string-to-number (match-string 2) 16)))
399 ((looking-at (rx (= 4 xdigit))) 383 ((looking-at (rx (= 4 xdigit)))
400 (let ((hex (match-string 0))) 384 (json-advance 4)
401 (json-advance 4) 385 (string-to-number (match-string 0) 16))
402 (string-to-number hex 16)))
403 (t 386 (t
404 (signal 'json-string-escape (list (point))))))) 387 (signal 'json-string-escape (list (point)))))))
405 388
406(defun json-read-string () 389(defun json-read-string ()
407 "Read the JSON string at point." 390 "Read the JSON string at point."
408 (unless (= (json-peek) ?\") 391 ;; Skip over the '"'.
409 (signal 'json-string-format (list "doesn't start with `\"'!")))
410 ;; Skip over the '"'
411 (json-advance) 392 (json-advance)
412 (let ((characters '()) 393 (let ((characters '())
413 (char (json-peek))) 394 (char (json-peek)))
414 (while (not (= char ?\")) 395 (while (/= char ?\")
415 (when (< char 32) 396 (when (< char 32)
416 (signal 'json-string-format (list (prin1-char char)))) 397 (if (zerop char)
398 (signal 'json-end-of-file ())
399 (signal 'json-string-format (list char))))
417 (push (if (= char ?\\) 400 (push (if (= char ?\\)
418 (json-read-escaped-char) 401 (json-read-escaped-char)
419 (json-pop)) 402 (json-advance)
403 char)
420 characters) 404 characters)
421 (setq char (json-peek))) 405 (setq char (json-peek)))
422 ;; Skip over the '"' 406 ;; Skip over the '"'.
423 (json-advance) 407 (json-advance)
424 (if characters 408 (if characters
425 (concat (nreverse characters)) 409 (concat (nreverse characters))
@@ -427,29 +411,47 @@ representation will be parsed correctly."
427 411
428;; String encoding 412;; String encoding
429 413
414;; Escape only quotation mark, backslash, and the control
415;; characters U+0000 to U+001F (RFC 4627, ECMA-404).
416(rx-define json--escape (in ?\" ?\\ cntrl))
417
418(defvar json--long-string-threshold 200
419 "Length above which strings are considered long for JSON encoding.
420It is generally faster to manipulate such strings in a buffer
421rather than directly.")
422
423(defvar json--string-buffer nil
424 "Buffer used for encoding Lisp strings as JSON.
425Initialized lazily by `json-encode-string'.")
426
430(defun json-encode-string (string) 427(defun json-encode-string (string)
431 "Return a JSON representation of STRING." 428 "Return a JSON representation of STRING."
432 ;; Reimplement the meat of `replace-regexp-in-string', for 429 ;; Try to avoid buffer overhead in trivial cases, while also
433 ;; performance (bug#20154). 430 ;; avoiding searching pathological strings for escape characters.
434 (let ((l (length string)) 431 ;; Since `string-match-p' doesn't take a LIMIT argument, we use
435 (start 0) 432 ;; string length as our heuristic. See also bug#20154.
436 res mb) 433 (if (and (< (length string) json--long-string-threshold)
437 ;; Only escape quotation mark, backslash and the control 434 (not (string-match-p (rx json--escape) string)))
438 ;; characters U+0000 to U+001F (RFC 4627, ECMA-404). 435 (concat "\"" string "\"")
439 (while (setq mb (string-match "[\"\\[:cntrl:]]" string start)) 436 (with-current-buffer
440 (let* ((c (aref string mb)) 437 (or json--string-buffer
441 (special (rassq c json-special-chars))) 438 (with-current-buffer (generate-new-buffer " *json-string*")
442 (push (substring string start mb) res) 439 ;; This seems to afford decent performance gains.
443 (push (if special 440 (setq-local inhibit-modification-hooks t)
444 ;; Special JSON character (\n, \r, etc.). 441 (setq json--string-buffer (current-buffer))))
445 (string ?\\ (car special)) 442 (insert ?\" string)
446 ;; Fallback: UCS code point in \uNNNN form. 443 (goto-char (1+ (point-min)))
447 (format "\\u%04x" c)) 444 (while (re-search-forward (rx json--escape) nil 'move)
448 res) 445 (let ((char (preceding-char)))
449 (setq start (1+ mb)))) 446 (delete-char -1)
450 (push (substring string start l) res) 447 (insert ?\\ (or
451 (push "\"" res) 448 ;; Special JSON character (\n, \r, etc.).
452 (apply #'concat "\"" (nreverse res)))) 449 (car (rassq char json-special-chars))
450 ;; Fallback: UCS code point in \uNNNN form.
451 (format "u%04x" char)))))
452 (insert ?\")
453 ;; Empty buffer for next invocation.
454 (delete-and-extract-region (point-min) (point-max)))))
453 455
454(defun json-encode-key (object) 456(defun json-encode-key (object)
455 "Return a JSON representation of OBJECT. 457 "Return a JSON representation of OBJECT.
@@ -460,15 +462,13 @@ this signals `json-key-format'."
460 (signal 'json-key-format (list object))) 462 (signal 'json-key-format (list object)))
461 encoded)) 463 encoded))
462 464
463;;; JSON Objects 465;;; Objects
464 466
465(defun json-new-object () 467(defun json-new-object ()
466 "Create a new Elisp object corresponding to a JSON object. 468 "Create a new Elisp object corresponding to an empty JSON object.
467Please see the documentation of `json-object-type'." 469Please see the documentation of `json-object-type'."
468 (cond ((eq json-object-type 'hash-table) 470 (and (eq json-object-type 'hash-table)
469 (make-hash-table :test 'equal)) 471 (make-hash-table :test #'equal)))
470 (t
471 ())))
472 472
473(defun json-add-to-object (object key value) 473(defun json-add-to-object (object key value)
474 "Add a new KEY -> VALUE association to OBJECT. 474 "Add a new KEY -> VALUE association to OBJECT.
@@ -476,10 +476,10 @@ Returns the updated object, which you should save, e.g.:
476 (setq obj (json-add-to-object obj \"foo\" \"bar\")) 476 (setq obj (json-add-to-object obj \"foo\" \"bar\"))
477Please see the documentation of `json-object-type' and `json-key-type'." 477Please see the documentation of `json-object-type' and `json-key-type'."
478 (let ((json-key-type 478 (let ((json-key-type
479 (or json-key-type 479 (cond (json-key-type)
480 (cdr (assq json-object-type '((hash-table . string) 480 ((eq json-object-type 'hash-table) 'string)
481 (alist . symbol) 481 ((eq json-object-type 'alist) 'symbol)
482 (plist . keyword))))))) 482 ((eq json-object-type 'plist) 'keyword))))
483 (setq key 483 (setq key
484 (cond ((eq json-key-type 'string) 484 (cond ((eq json-key-type 'string)
485 key) 485 key)
@@ -499,13 +499,13 @@ Please see the documentation of `json-object-type' and `json-key-type'."
499 499
500(defun json-read-object () 500(defun json-read-object ()
501 "Read the JSON object at point." 501 "Read the JSON object at point."
502 ;; Skip over the "{" 502 ;; Skip over the '{'.
503 (json-advance) 503 (json-advance)
504 (json-skip-whitespace) 504 (json-skip-whitespace)
505 ;; read key/value pairs until "}" 505 ;; Read key/value pairs until '}'.
506 (let ((elements (json-new-object)) 506 (let ((elements (json-new-object))
507 key value) 507 key value)
508 (while (not (= (json-peek) ?})) 508 (while (/= (json-peek) ?\})
509 (json-skip-whitespace) 509 (json-skip-whitespace)
510 (setq key (json-read-string)) 510 (setq key (json-read-string))
511 (json-skip-whitespace) 511 (json-skip-whitespace)
@@ -520,94 +520,94 @@ Please see the documentation of `json-object-type' and `json-key-type'."
520 (funcall json-post-element-read-function)) 520 (funcall json-post-element-read-function))
521 (setq elements (json-add-to-object elements key value)) 521 (setq elements (json-add-to-object elements key value))
522 (json-skip-whitespace) 522 (json-skip-whitespace)
523 (when (/= (json-peek) ?}) 523 (when (/= (json-peek) ?\})
524 (if (= (json-peek) ?,) 524 (if (= (json-peek) ?,)
525 (json-advance) 525 (json-advance)
526 (signal 'json-object-format (list "," (json-peek)))))) 526 (signal 'json-object-format (list "," (json-peek))))))
527 ;; Skip over the "}" 527 ;; Skip over the '}'.
528 (json-advance) 528 (json-advance)
529 (pcase json-object-type 529 (pcase json-object-type
530 ('alist (nreverse elements)) 530 ('alist (nreverse elements))
531 ('plist (json--plist-reverse elements)) 531 ('plist (json--plist-nreverse elements))
532 (_ elements)))) 532 (_ elements))))
533 533
534;; Hash table encoding 534;; Hash table encoding
535 535
536(defun json-encode-hash-table (hash-table) 536(defun json-encode-hash-table (hash-table)
537 "Return a JSON representation of HASH-TABLE." 537 "Return a JSON representation of HASH-TABLE."
538 (if json-encoding-object-sort-predicate 538 (cond ((hash-table-empty-p hash-table) "{}")
539 (json-encode-alist (map-into hash-table 'list)) 539 (json-encoding-object-sort-predicate
540 (format "{%s%s}" 540 (json--encode-alist (map-pairs hash-table) t))
541 (json-join 541 (t
542 (let (r) 542 (let ((kv-sep (if json-encoding-pretty-print ": " ":"))
543 (json--with-indentation 543 result)
544 (maphash 544 (json--with-indentation
545 (lambda (k v) 545 (maphash
546 (push (format 546 (lambda (k v)
547 (if json-encoding-pretty-print 547 (push (concat json--encoding-current-indentation
548 "%s%s: %s" 548 (json-encode-key k)
549 "%s%s:%s") 549 kv-sep
550 json--encoding-current-indentation 550 (json-encode v))
551 (json-encode-key k) 551 result))
552 (json-encode v)) 552 hash-table))
553 r)) 553 (concat "{"
554 hash-table)) 554 (string-join (nreverse result) json-encoding-separator)
555 r) 555 (and json-encoding-pretty-print
556 json-encoding-separator) 556 (not json-encoding-lisp-style-closings)
557 (if (or (not json-encoding-pretty-print) 557 json--encoding-current-indentation)
558 json-encoding-lisp-style-closings) 558 "}")))))
559 ""
560 json--encoding-current-indentation))))
561 559
562;; List encoding (including alists and plists) 560;; List encoding (including alists and plists)
563 561
564(defun json-encode-alist (alist) 562(defun json--encode-alist (alist &optional destructive)
565 "Return a JSON representation of ALIST." 563 "Return a JSON representation of ALIST.
564DESTRUCTIVE non-nil means it is safe to modify ALIST by
565side-effects."
566 (when json-encoding-object-sort-predicate 566 (when json-encoding-object-sort-predicate
567 (setq alist 567 (setq alist (sort (if destructive alist (copy-sequence alist))
568 (sort alist (lambda (a b) 568 (lambda (a b)
569 (funcall json-encoding-object-sort-predicate 569 (funcall json-encoding-object-sort-predicate
570 (car a) (car b)))))) 570 (car a) (car b))))))
571 (format "{%s%s}" 571 (concat "{"
572 (json-join 572 (let ((kv-sep (if json-encoding-pretty-print ": " ":")))
573 (json--with-indentation 573 (json--with-indentation
574 (mapcar (lambda (cons) 574 (mapconcat (lambda (cons)
575 (format (if json-encoding-pretty-print 575 (concat json--encoding-current-indentation
576 "%s%s: %s" 576 (json-encode-key (car cons))
577 "%s%s:%s") 577 kv-sep
578 json--encoding-current-indentation 578 (json-encode (cdr cons))))
579 (json-encode-key (car cons)) 579 alist
580 (json-encode (cdr cons)))) 580 json-encoding-separator)))
581 alist)) 581 (and json-encoding-pretty-print
582 json-encoding-separator) 582 (not json-encoding-lisp-style-closings)
583 (if (or (not json-encoding-pretty-print) 583 json--encoding-current-indentation)
584 json-encoding-lisp-style-closings) 584 "}"))
585 "" 585
586 json--encoding-current-indentation))) 586(defun json-encode-alist (alist)
587 "Return a JSON representation of ALIST."
588 (if alist (json--encode-alist alist) "{}"))
587 589
588(defun json-encode-plist (plist) 590(defun json-encode-plist (plist)
589 "Return a JSON representation of PLIST." 591 "Return a JSON representation of PLIST."
590 (if json-encoding-object-sort-predicate 592 (cond ((null plist) "{}")
591 (json-encode-alist (json--plist-to-alist plist)) 593 (json-encoding-object-sort-predicate
592 (let (result) 594 (json--encode-alist (map-pairs plist) t))
593 (json--with-indentation 595 (t
594 (while plist 596 (let ((kv-sep (if json-encoding-pretty-print ": " ":"))
595 (push (concat
596 json--encoding-current-indentation
597 (json-encode-key (car plist))
598 (if json-encoding-pretty-print
599 ": "
600 ":")
601 (json-encode (cadr plist)))
602 result) 597 result)
603 (setq plist (cddr plist)))) 598 (json--with-indentation
604 (concat "{" 599 (while plist
605 (json-join (nreverse result) json-encoding-separator) 600 (push (concat json--encoding-current-indentation
606 (if (and json-encoding-pretty-print 601 (json-encode-key (pop plist))
607 (not json-encoding-lisp-style-closings)) 602 kv-sep
608 json--encoding-current-indentation 603 (json-encode (pop plist)))
609 "") 604 result)))
610 "}")))) 605 (concat "{"
606 (string-join (nreverse result) json-encoding-separator)
607 (and json-encoding-pretty-print
608 (not json-encoding-lisp-style-closings)
609 json--encoding-current-indentation)
610 "}")))))
611 611
612(defun json-encode-list (list) 612(defun json-encode-list (list)
613 "Return a JSON representation of LIST. 613 "Return a JSON representation of LIST.
@@ -625,15 +625,17 @@ become JSON objects."
625 625
626(defun json-read-array () 626(defun json-read-array ()
627 "Read the JSON array at point." 627 "Read the JSON array at point."
628 ;; Skip over the "[" 628 ;; Skip over the '['.
629 (json-advance) 629 (json-advance)
630 (json-skip-whitespace) 630 (json-skip-whitespace)
631 ;; read values until "]" 631 ;; Read values until ']'.
632 (let (elements) 632 (let (elements
633 (while (not (= (json-peek) ?\])) 633 (len 0))
634 (while (/= (json-peek) ?\])
634 (json-skip-whitespace) 635 (json-skip-whitespace)
635 (when json-pre-element-read-function 636 (when json-pre-element-read-function
636 (funcall json-pre-element-read-function (length elements))) 637 (funcall json-pre-element-read-function len)
638 (setq len (1+ len)))
637 (push (json-read) elements) 639 (push (json-read) elements)
638 (when json-post-element-read-function 640 (when json-post-element-read-function
639 (funcall json-post-element-read-function)) 641 (funcall json-post-element-read-function))
@@ -641,8 +643,8 @@ become JSON objects."
641 (when (/= (json-peek) ?\]) 643 (when (/= (json-peek) ?\])
642 (if (= (json-peek) ?,) 644 (if (= (json-peek) ?,)
643 (json-advance) 645 (json-advance)
644 (signal 'json-array-format (list ?, (json-peek)))))) 646 (signal 'json-array-format (list "," (json-peek))))))
645 ;; Skip over the "]" 647 ;; Skip over the ']'.
646 (json-advance) 648 (json-advance)
647 (pcase json-array-type 649 (pcase json-array-type
648 ('vector (nreverse (vconcat elements))) 650 ('vector (nreverse (vconcat elements)))
@@ -653,42 +655,43 @@ become JSON objects."
653(defun json-encode-array (array) 655(defun json-encode-array (array)
654 "Return a JSON representation of ARRAY." 656 "Return a JSON representation of ARRAY."
655 (if (and json-encoding-pretty-print 657 (if (and json-encoding-pretty-print
656 (> (length array) 0)) 658 (not (seq-empty-p array)))
657 (concat 659 (concat
660 "["
658 (json--with-indentation 661 (json--with-indentation
659 (concat (format "[%s" json--encoding-current-indentation) 662 (concat json--encoding-current-indentation
660 (json-join (mapcar 'json-encode array) 663 (mapconcat #'json-encode array
661 (format "%s%s" 664 (concat json-encoding-separator
662 json-encoding-separator
663 json--encoding-current-indentation)))) 665 json--encoding-current-indentation))))
664 (format "%s]" 666 (unless json-encoding-lisp-style-closings
665 (if json-encoding-lisp-style-closings 667 json--encoding-current-indentation)
666 "" 668 "]")
667 json--encoding-current-indentation)))
668 (concat "[" 669 (concat "["
669 (mapconcat 'json-encode array json-encoding-separator) 670 (mapconcat #'json-encode array json-encoding-separator)
670 "]"))) 671 "]")))
671 672
672 673
673 674
674;;; JSON reader. 675;;; Reader
675 676
676(defmacro json-readtable-dispatch (char) 677(defmacro json-readtable-dispatch (char)
677 "Dispatch reader function for CHAR." 678 "Dispatch reader function for CHAR at point.
678 (declare (debug (symbolp))) 679If CHAR is nil, signal `json-end-of-file'."
679 (let ((table 680 (declare (debug t))
680 '((?t json-read-keyword "true") 681 (macroexp-let2 nil char char
681 (?f json-read-keyword "false") 682 `(cond ,@(map-apply
682 (?n json-read-keyword "null") 683 (lambda (key expr)
683 (?{ json-read-object) 684 `((eq ,char ,key) ,expr))
684 (?\[ json-read-array) 685 `((?\" ,#'json-read-string)
685 (?\" json-read-string))) 686 (?\[ ,#'json-read-array)
686 res) 687 (?\{ ,#'json-read-object)
687 (dolist (c '(?- ?+ ?. ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9)) 688 (?n ,#'json-read-keyword "null")
688 (push (list c 'json-read-number) table)) 689 (?f ,#'json-read-keyword "false")
689 (pcase-dolist (`(,c . ,rest) table) 690 (?t ,#'json-read-keyword "true")
690 (push `((eq ,char ,c) (,@rest)) res)) 691 ,@(mapcar (lambda (c) (list c #'json-read-number))
691 `(cond ,@res (t (signal 'json-readtable-error (list ,char)))))) 692 '(?- ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))))
693 (,char (signal 'json-readtable-error (list ,char)))
694 (t (signal 'json-end-of-file ())))))
692 695
693(defun json-read () 696(defun json-read ()
694 "Parse and return the JSON object following point. 697 "Parse and return the JSON object following point.
@@ -706,10 +709,7 @@ you will get the following structure returned:
706 ((c . :json-false))]) 709 ((c . :json-false))])
707 (b . \"foo\"))" 710 (b . \"foo\"))"
708 (json-skip-whitespace) 711 (json-skip-whitespace)
709 (let ((char (json-peek))) 712 (json-readtable-dispatch (char-after)))
710 (if (zerop char)
711 (signal 'json-end-of-file nil)
712 (json-readtable-dispatch char))))
713 713
714;; Syntactic sugar for the reader 714;; Syntactic sugar for the reader
715 715
@@ -724,12 +724,11 @@ you will get the following structure returned:
724 "Read the first JSON object contained in FILE and return it." 724 "Read the first JSON object contained in FILE and return it."
725 (with-temp-buffer 725 (with-temp-buffer
726 (insert-file-contents file) 726 (insert-file-contents file)
727 (goto-char (point-min))
728 (json-read))) 727 (json-read)))
729 728
730 729
731 730
732;;; JSON encoder 731;;; Encoder
733 732
734(defun json-encode (object) 733(defun json-encode (object)
735 "Return a JSON representation of OBJECT as a string. 734 "Return a JSON representation of OBJECT as a string.
@@ -737,20 +736,21 @@ you will get the following structure returned:
737OBJECT should have a structure like one returned by `json-read'. 736OBJECT should have a structure like one returned by `json-read'.
738If an error is detected during encoding, an error based on 737If an error is detected during encoding, an error based on
739`json-error' is signaled." 738`json-error' is signaled."
740 (cond ((memq object (list t json-null json-false)) 739 (cond ((eq object t) (json-encode-keyword object))
741 (json-encode-keyword object)) 740 ((eq object json-null) (json-encode-keyword object))
742 ((stringp object) (json-encode-string object)) 741 ((eq object json-false) (json-encode-keyword object))
743 ((keywordp object) (json-encode-string 742 ((stringp object) (json-encode-string object))
744 (substring (symbol-name object) 1))) 743 ((keywordp object) (json-encode-string
745 ((listp object) (json-encode-list object)) 744 (substring (symbol-name object) 1)))
746 ((symbolp object) (json-encode-string 745 ((listp object) (json-encode-list object))
747 (symbol-name object))) 746 ((symbolp object) (json-encode-string
748 ((numberp object) (json-encode-number object)) 747 (symbol-name object)))
749 ((arrayp object) (json-encode-array object)) 748 ((numberp object) (json-encode-number object))
750 ((hash-table-p object) (json-encode-hash-table object)) 749 ((arrayp object) (json-encode-array object))
751 (t (signal 'json-error (list object))))) 750 ((hash-table-p object) (json-encode-hash-table object))
752 751 (t (signal 'json-error (list object)))))
753;; Pretty printing & minimizing 752
753;;; Pretty printing & minimizing
754 754
755(defun json-pretty-print-buffer (&optional minimize) 755(defun json-pretty-print-buffer (&optional minimize)
756 "Pretty-print current buffer. 756 "Pretty-print current buffer.
@@ -769,9 +769,9 @@ MAX-SECS.")
769With prefix argument MINIMIZE, minimize it instead." 769With prefix argument MINIMIZE, minimize it instead."
770 (interactive "r\nP") 770 (interactive "r\nP")
771 (let ((json-encoding-pretty-print (null minimize)) 771 (let ((json-encoding-pretty-print (null minimize))
772 ;; Distinguish an empty objects from 'null' 772 ;; Distinguish an empty object from 'null'.
773 (json-null :json-null) 773 (json-null :json-null)
774 ;; Ensure that ordering is maintained 774 ;; Ensure that ordering is maintained.
775 (json-object-type 'alist) 775 (json-object-type 'alist)
776 (orig-buf (current-buffer)) 776 (orig-buf (current-buffer))
777 error) 777 error)
@@ -800,9 +800,7 @@ With prefix argument MINIMIZE, minimize it instead."
800 ;; them. 800 ;; them.
801 (let ((space (buffer-substring 801 (let ((space (buffer-substring
802 (point) 802 (point)
803 (+ (point) 803 (+ (point) (skip-chars-forward " \t\n"))))
804 (skip-chars-forward
805 " \t\n" (point-max)))))
806 (json (json-read))) 804 (json (json-read)))
807 (setq pos (point)) ; End of last good json-read. 805 (setq pos (point)) ; End of last good json-read.
808 (set-buffer tmp-buf) 806 (set-buffer tmp-buf)
@@ -832,14 +830,14 @@ With prefix argument MINIMIZE, minimize it instead."
832 "Pretty-print current buffer with object keys ordered. 830 "Pretty-print current buffer with object keys ordered.
833With prefix argument MINIMIZE, minimize it instead." 831With prefix argument MINIMIZE, minimize it instead."
834 (interactive "P") 832 (interactive "P")
835 (let ((json-encoding-object-sort-predicate 'string<)) 833 (let ((json-encoding-object-sort-predicate #'string<))
836 (json-pretty-print-buffer minimize))) 834 (json-pretty-print-buffer minimize)))
837 835
838(defun json-pretty-print-ordered (begin end &optional minimize) 836(defun json-pretty-print-ordered (begin end &optional minimize)
839 "Pretty-print the region with object keys ordered. 837 "Pretty-print the region with object keys ordered.
840With prefix argument MINIMIZE, minimize it instead." 838With prefix argument MINIMIZE, minimize it instead."
841 (interactive "r\nP") 839 (interactive "r\nP")
842 (let ((json-encoding-object-sort-predicate 'string<)) 840 (let ((json-encoding-object-sort-predicate #'string<))
843 (json-pretty-print begin end minimize))) 841 (json-pretty-print begin end minimize)))
844 842
845(provide 'json) 843(provide 'json)
diff --git a/lisp/jsonrpc.el b/lisp/jsonrpc.el
index 293dfaa7483..42e7701af18 100644
--- a/lisp/jsonrpc.el
+++ b/lisp/jsonrpc.el
@@ -37,7 +37,6 @@
37;;; Code: 37;;; Code:
38 38
39(require 'cl-lib) 39(require 'cl-lib)
40(require 'json)
41(require 'eieio) 40(require 'eieio)
42(eval-when-compile (require 'subr-x)) 41(eval-when-compile (require 'subr-x))
43(require 'warnings) 42(require 'warnings)
@@ -470,26 +469,35 @@ With optional CLEANUP, kill any associated buffers."
470;;; 469;;;
471(define-error 'jsonrpc-error "jsonrpc-error") 470(define-error 'jsonrpc-error "jsonrpc-error")
472 471
473(defun jsonrpc--json-read () 472(defalias 'jsonrpc--json-read
474 "Read JSON object in buffer, move point to end of buffer." 473 (if (fboundp 'json-parse-buffer)
475 ;; TODO: I guess we can make these macros if/when jsonrpc.el 474 (lambda ()
476 ;; goes into Emacs core. 475 (json-parse-buffer :object-type 'plist
477 (cond ((fboundp 'json-parse-buffer) (json-parse-buffer 476 :null-object nil
478 :object-type 'plist 477 :false-object :json-false))
479 :null-object nil 478 (require 'json)
480 :false-object :json-false)) 479 (defvar json-object-type)
481 (t (let ((json-object-type 'plist)) 480 (declare-function json-read "json" ())
482 (json-read))))) 481 (lambda ()
483 482 (let ((json-object-type 'plist))
484(defun jsonrpc--json-encode (object) 483 (json-read))))
485 "Encode OBJECT into a JSON string." 484 "Read JSON object in buffer, move point to end of buffer.")
486 (cond ((fboundp 'json-serialize) (json-serialize 485
487 object 486(defalias 'jsonrpc--json-encode
488 :false-object :json-false 487 (if (fboundp 'json-serialize)
489 :null-object nil)) 488 (lambda (object)
490 (t (let ((json-false :json-false) 489 (json-serialize object
491 (json-null nil)) 490 :false-object :json-false
492 (json-encode object))))) 491 :null-object nil))
492 (require 'json)
493 (defvar json-false)
494 (defvar json-null)
495 (declare-function json-encode "json" (object))
496 (lambda (object)
497 (let ((json-false :json-false)
498 (json-null nil))
499 (json-encode object))))
500 "Encode OBJECT into a JSON string.")
493 501
494(cl-defun jsonrpc--reply 502(cl-defun jsonrpc--reply
495 (connection id &key (result nil result-supplied-p) (error nil error-supplied-p)) 503 (connection id &key (result nil result-supplied-p) (error nil error-supplied-p))
diff --git a/lisp/language/tibet-util.el b/lisp/language/tibet-util.el
index 29fff9175b7..8684cdb1338 100644
--- a/lisp/language/tibet-util.el
+++ b/lisp/language/tibet-util.el
@@ -43,13 +43,17 @@
43 ("་" . "་") 43 ("་" . "་")
44 ("༔" . "༔") 44 ("༔" . "༔")
45 ;; Yes these are dirty. But ... 45 ;; Yes these are dirty. But ...
46 ("༎ ༎" . ,(compose-string "༎ ༎" 0 3 [?༎ (Br . Bl) ? (Br . Bl) ?༎])) 46 ("༎ ༎" . ,(compose-string (copy-sequence "༎ ༎")
47 0 3 [?༎ (Br . Bl) ? (Br . Bl) ?༎]))
47 ("༄༅༅" . ,(compose-string 48 ("༄༅༅" . ,(compose-string
48 "࿁࿂࿂࿂" 0 4 49 (copy-sequence "࿁࿂࿂࿂") 0 4
49 [?࿁ (Br . Bl) ?࿂ (Br . Bl) ?࿂ (Br . Bl) ?࿂])) 50 [?࿁ (Br . Bl) ?࿂ (Br . Bl) ?࿂ (Br . Bl) ?࿂]))
50 ("༄༅" . ,(compose-string "࿁࿂࿂" 0 3 [?࿁ (Br . Bl) ?࿂ (Br . Bl) ?࿂])) 51 ("༄༅" . ,(compose-string (copy-sequence "࿁࿂࿂")
51 ("༆" . ,(compose-string "࿁࿂༙" 0 3 [?࿁ (Br . Bl) ?࿂ (br . tr) ?༙])) 52 0 3 [?࿁ (Br . Bl) ?࿂ (Br . Bl) ?࿂]))
52 ("༄" . ,(compose-string "࿁࿂" 0 2 [?࿁ (Br . Bl) ?࿂])))) 53 ("༆" . ,(compose-string (copy-sequence "࿁࿂༙")
54 0 3 [?࿁ (Br . Bl) ?࿂ (br . tr) ?༙]))
55 ("༄" . ,(compose-string (copy-sequence "࿁࿂")
56 0 2 [?࿁ (Br . Bl) ?࿂]))))
53 57
54;;;###autoload 58;;;###autoload
55(defun tibetan-char-p (ch) 59(defun tibetan-char-p (ch)
diff --git a/lisp/mouse.el b/lisp/mouse.el
index f045e5bdce2..640f10af4e1 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -2580,7 +2580,7 @@ in a tooltip."
2580 :type '(choice 2580 :type '(choice
2581 (const :tag "Do not show tooltips" nil) 2581 (const :tag "Do not show tooltips" nil)
2582 (const :tag "Show all text" t) 2582 (const :tag "Show all text" t)
2583 (integer :tag "Show characters (max)" 256)) 2583 (integer :tag "Max number of characters to show" 256))
2584 :version "26.1") 2584 :version "26.1")
2585 2585
2586(defcustom mouse-drag-and-drop-region-show-cursor t 2586(defcustom mouse-drag-and-drop-region-show-cursor t
diff --git a/lisp/net/eww.el b/lisp/net/eww.el
index a6c1abdbb19..2a70560ca7b 100644
--- a/lisp/net/eww.el
+++ b/lisp/net/eww.el
@@ -307,10 +307,10 @@ the default EWW buffer."
307 (insert (format "Loading %s..." url)) 307 (insert (format "Loading %s..." url))
308 (goto-char (point-min))) 308 (goto-char (point-min)))
309 (let ((url-mime-accept-string eww-accept-content-types)) 309 (let ((url-mime-accept-string eww-accept-content-types))
310 (url-retrieve url 'eww-render 310 (url-retrieve url #'eww-render
311 (list url nil (current-buffer))))) 311 (list url nil (current-buffer)))))
312 312
313(put 'eww 'browse-url-browser-kind 'internal) 313(function-put 'eww 'browse-url-browser-kind 'internal)
314 314
315(defun eww--dwim-expand-url (url) 315(defun eww--dwim-expand-url (url)
316 (setq url (string-trim url)) 316 (setq url (string-trim url))
@@ -375,8 +375,8 @@ engine used."
375 (let ((region-string (buffer-substring (region-beginning) (region-end)))) 375 (let ((region-string (buffer-substring (region-beginning) (region-end))))
376 (if (not (string-match-p "\\`[ \n\t\r\v\f]*\\'" region-string)) 376 (if (not (string-match-p "\\`[ \n\t\r\v\f]*\\'" region-string))
377 (eww region-string) 377 (eww region-string)
378 (call-interactively 'eww))) 378 (call-interactively #'eww)))
379 (call-interactively 'eww))) 379 (call-interactively #'eww)))
380 380
381(defun eww-open-in-new-buffer () 381(defun eww-open-in-new-buffer ()
382 "Fetch link at point in a new EWW buffer." 382 "Fetch link at point in a new EWW buffer."
@@ -1013,7 +1013,7 @@ just re-display the HTML already fetched."
1013 (eww-display-html 'utf-8 url (plist-get eww-data :dom) 1013 (eww-display-html 'utf-8 url (plist-get eww-data :dom)
1014 (point) (current-buffer))) 1014 (point) (current-buffer)))
1015 (let ((url-mime-accept-string eww-accept-content-types)) 1015 (let ((url-mime-accept-string eww-accept-content-types))
1016 (url-retrieve url 'eww-render 1016 (url-retrieve url #'eww-render
1017 (list url (point) (current-buffer) encode)))))) 1017 (list url (point) (current-buffer) encode))))))
1018 1018
1019;; Form support. 1019;; Form support.
@@ -1576,8 +1576,10 @@ If EXTERNAL is double prefix, browse in new buffer."
1576 (cond 1576 (cond
1577 ((not url) 1577 ((not url)
1578 (message "No link under point")) 1578 (message "No link under point"))
1579 ((string-match "^mailto:" url) 1579 ((string-match-p "\\`mailto:" url)
1580 (browse-url-mail url)) 1580 ;; This respects the user options `browse-url-handlers'
1581 ;; and `browse-url-mailto-function'.
1582 (browse-url url))
1581 ((and (consp external) (<= (car external) 4)) 1583 ((and (consp external) (<= (car external) 4))
1582 (funcall browse-url-secondary-browser-function url) 1584 (funcall browse-url-secondary-browser-function url)
1583 (shr--blink-link)) 1585 (shr--blink-link))
@@ -1615,7 +1617,7 @@ Use link at point if there is one, else the current page's URL."
1615 (eww-current-url)))) 1617 (eww-current-url))))
1616 (if (not url) 1618 (if (not url)
1617 (message "No URL under point") 1619 (message "No URL under point")
1618 (url-retrieve url 'eww-download-callback (list url))))) 1620 (url-retrieve url #'eww-download-callback (list url)))))
1619 1621
1620(defun eww-download-callback (status url) 1622(defun eww-download-callback (status url)
1621 (unless (plist-get status :error) 1623 (unless (plist-get status :error)
@@ -2128,12 +2130,12 @@ entries (if any) will be removed from the list.
2128Only the properties listed in `eww-desktop-data-save' are included. 2130Only the properties listed in `eww-desktop-data-save' are included.
2129Generally, the list should not include the (usually overly large) 2131Generally, the list should not include the (usually overly large)
2130:dom, :source and :text properties." 2132:dom, :source and :text properties."
2131 (let ((history (mapcar 'eww-desktop-data-1 2133 (let ((history (mapcar #'eww-desktop-data-1
2132 (cons eww-data eww-history)))) 2134 (cons eww-data eww-history))))
2133 (list :history (if eww-desktop-remove-duplicates 2135 (list :history (if eww-desktop-remove-duplicates
2134 (cl-remove-duplicates 2136 (cl-remove-duplicates
2135 history :test 'eww-desktop-history-duplicate) 2137 history :test #'eww-desktop-history-duplicate)
2136 history)))) 2138 history))))
2137 2139
2138(defun eww-restore-desktop (file-name buffer-name misc-data) 2140(defun eww-restore-desktop (file-name buffer-name misc-data)
2139 "Restore an eww buffer from its desktop file record. 2141 "Restore an eww buffer from its desktop file record.
diff --git a/lisp/net/shr.el b/lisp/net/shr.el
index 1f80ab74db5..03260c9e70a 100644
--- a/lisp/net/shr.el
+++ b/lisp/net/shr.el
@@ -135,7 +135,7 @@ same domain as the main data."
135This is used for cid: URLs, and the function is called with the 135This is used for cid: URLs, and the function is called with the
136cid: URL as the argument.") 136cid: URL as the argument.")
137 137
138(defvar shr-put-image-function 'shr-put-image 138(defvar shr-put-image-function #'shr-put-image
139 "Function called to put image and alt string.") 139 "Function called to put image and alt string.")
140 140
141(defface shr-strike-through '((t :strike-through t)) 141(defface shr-strike-through '((t :strike-through t))
@@ -365,25 +365,20 @@ If the URL is already at the front of the kill ring act like
365 (shr-copy-url url))) 365 (shr-copy-url url)))
366 366
367(defun shr--current-link-region () 367(defun shr--current-link-region ()
368 (let ((current (get-text-property (point) 'shr-url)) 368 "Return the start and end positions of the URL at point, if any.
369 start) 369Value is a pair of positions (START . END) if there is a non-nil
370 (save-excursion 370`shr-url' text property at point; otherwise nil."
371 ;; Go to the beginning. 371 (when (get-text-property (point) 'shr-url)
372 (while (and (not (bobp)) 372 (let* ((end (or (next-single-property-change (point) 'shr-url)
373 (equal (get-text-property (point) 'shr-url) current)) 373 (point-max)))
374 (forward-char -1)) 374 (beg (or (previous-single-property-change end 'shr-url)
375 (unless (equal (get-text-property (point) 'shr-url) current) 375 (point-min))))
376 (forward-char 1)) 376 (cons beg end))))
377 (setq start (point))
378 ;; Go to the end.
379 (while (and (not (eobp))
380 (equal (get-text-property (point) 'shr-url) current))
381 (forward-char 1))
382 (list start (point)))))
383 377
384(defun shr--blink-link () 378(defun shr--blink-link ()
385 (let* ((region (shr--current-link-region)) 379 "Briefly fontify URL at point with the face `shr-selected-link'."
386 (overlay (make-overlay (car region) (cadr region)))) 380 (when-let* ((region (shr--current-link-region))
381 (overlay (make-overlay (car region) (cdr region))))
387 (overlay-put overlay 'face 'shr-selected-link) 382 (overlay-put overlay 'face 'shr-selected-link)
388 (run-at-time 1 nil (lambda () 383 (run-at-time 1 nil (lambda ()
389 (delete-overlay overlay))))) 384 (delete-overlay overlay)))))
@@ -437,7 +432,7 @@ the URL of the image to the kill buffer instead."
437 (if (not url) 432 (if (not url)
438 (message "No image under point") 433 (message "No image under point")
439 (message "Inserting %s..." url) 434 (message "Inserting %s..." url)
440 (url-retrieve url 'shr-image-fetched 435 (url-retrieve url #'shr-image-fetched
441 (list (current-buffer) (1- (point)) (point-marker)) 436 (list (current-buffer) (1- (point)) (point-marker))
442 t)))) 437 t))))
443 438
@@ -463,7 +458,7 @@ size, and full-buffer size."
463 (when (> (- (point) start) 2) 458 (when (> (- (point) start) 2)
464 (delete-region start (1- (point))))) 459 (delete-region start (1- (point)))))
465 (message "Inserting %s..." url) 460 (message "Inserting %s..." url)
466 (url-retrieve url 'shr-image-fetched 461 (url-retrieve url #'shr-image-fetched
467 (list (current-buffer) (1- (point)) (point-marker) 462 (list (current-buffer) (1- (point)) (point-marker)
468 (list (cons 'size 463 (list (cons 'size
469 (cond ((or (eq size 'default) 464 (cond ((or (eq size 'default)
@@ -493,7 +488,7 @@ size, and full-buffer size."
493 ((fboundp function) 488 ((fboundp function)
494 (apply function dom args)) 489 (apply function dom args))
495 (t 490 (t
496 (apply 'shr-generic dom args))))) 491 (apply #'shr-generic dom args)))))
497 492
498(defun shr-descend (dom) 493(defun shr-descend (dom)
499 (let ((function 494 (let ((function
@@ -730,9 +725,10 @@ size, and full-buffer size."
730 (let ((gap-start (point)) 725 (let ((gap-start (point))
731 (face (get-text-property (point) 'face))) 726 (face (get-text-property (point) 'face)))
732 ;; Extend the background to the end of the line. 727 ;; Extend the background to the end of the line.
733 (if face 728 (insert ?\n)
734 (insert (propertize "\n" 'face (shr-face-background face))) 729 (when face
735 (insert "\n")) 730 (put-text-property (1- (point)) (point)
731 'face (shr-face-background face)))
736 (shr-indent) 732 (shr-indent)
737 (when (and (> (1- gap-start) (point-min)) 733 (when (and (> (1- gap-start) (point-min))
738 (get-text-property (point) 'shr-url) 734 (get-text-property (point) 'shr-url)
@@ -935,12 +931,11 @@ size, and full-buffer size."
935 931
936(defun shr-indent () 932(defun shr-indent ()
937 (when (> shr-indentation 0) 933 (when (> shr-indentation 0)
938 (insert 934 (if (not shr-use-fonts)
939 (if (not shr-use-fonts) 935 (insert-char ?\s shr-indentation)
940 (make-string shr-indentation ?\s) 936 (insert ?\s)
941 (propertize " " 937 (put-text-property (1- (point)) (point)
942 'display 938 'display `(space :width (,shr-indentation))))))
943 `(space :width (,shr-indentation)))))))
944 939
945(defun shr-fontize-dom (dom &rest types) 940(defun shr-fontize-dom (dom &rest types)
946 (let ((start (point))) 941 (let ((start (point)))
@@ -987,16 +982,11 @@ the mouse click event."
987 (cond 982 (cond
988 ((not url) 983 ((not url)
989 (message "No link under point")) 984 (message "No link under point"))
990 ((string-match "^mailto:" url) 985 (external
991 (browse-url-mail url)) 986 (funcall browse-url-secondary-browser-function url)
987 (shr--blink-link))
992 (t 988 (t
993 (if external 989 (browse-url url (xor new-window browse-url-new-window-flag))))))
994 (progn
995 (funcall browse-url-secondary-browser-function url)
996 (shr--blink-link))
997 (browse-url url (if new-window
998 (not browse-url-new-window-flag)
999 browse-url-new-window-flag)))))))
1000 990
1001(defun shr-save-contents (directory) 991(defun shr-save-contents (directory)
1002 "Save the contents from URL in a file." 992 "Save the contents from URL in a file."
@@ -1005,7 +995,7 @@ the mouse click event."
1005 (if (not url) 995 (if (not url)
1006 (message "No link under point") 996 (message "No link under point")
1007 (url-retrieve (shr-encode-url url) 997 (url-retrieve (shr-encode-url url)
1008 'shr-store-contents (list url directory))))) 998 #'shr-store-contents (list url directory)))))
1009 999
1010(defun shr-store-contents (status url directory) 1000(defun shr-store-contents (status url directory)
1011 (unless (plist-get status :error) 1001 (unless (plist-get status :error)
@@ -1156,7 +1146,6 @@ width/height instead."
1156 1146
1157;; url-cache-extract autoloads url-cache. 1147;; url-cache-extract autoloads url-cache.
1158(declare-function url-cache-create-filename "url-cache" (url)) 1148(declare-function url-cache-create-filename "url-cache" (url))
1159(autoload 'browse-url-mail "browse-url")
1160 1149
1161(defun shr-get-image-data (url) 1150(defun shr-get-image-data (url)
1162 "Get image data for URL. 1151 "Get image data for URL.
@@ -1230,7 +1219,7 @@ START, and END. Note that START and END should be markers."
1230 (funcall shr-put-image-function 1219 (funcall shr-put-image-function
1231 image (buffer-substring start end)) 1220 image (buffer-substring start end))
1232 (delete-region (point) end)))) 1221 (delete-region (point) end))))
1233 (url-retrieve url 'shr-image-fetched 1222 (url-retrieve url #'shr-image-fetched
1234 (list (current-buffer) start end) 1223 (list (current-buffer) start end)
1235 t t))))) 1224 t t)))))
1236 1225
@@ -1679,7 +1668,7 @@ The preference is a float determined from `shr-prefer-media-type'."
1679 (or alt ""))) 1668 (or alt "")))
1680 (insert " ") 1669 (insert " ")
1681 (url-queue-retrieve 1670 (url-queue-retrieve
1682 (shr-encode-url url) 'shr-image-fetched 1671 (shr-encode-url url) #'shr-image-fetched
1683 (list (current-buffer) start (set-marker (make-marker) (point)) 1672 (list (current-buffer) start (set-marker (make-marker) (point))
1684 (list :width width :height height)) 1673 (list :width width :height height))
1685 t 1674 t
@@ -2006,12 +1995,11 @@ BASE is the URL of the HTML being rendered."
2006 (cond 1995 (cond
2007 ((null tbodies) 1996 ((null tbodies)
2008 dom) 1997 dom)
2009 ((= (length tbodies) 1) 1998 ((null (cdr tbodies))
2010 (car tbodies)) 1999 (car tbodies))
2011 (t 2000 (t
2012 ;; Table with multiple tbodies. Convert into a single tbody. 2001 ;; Table with multiple tbodies. Convert into a single tbody.
2013 `(tbody nil ,@(cl-reduce 'append 2002 `(tbody nil ,@(mapcan #'dom-non-text-children tbodies))))))
2014 (mapcar 'dom-non-text-children tbodies)))))))
2015 2003
2016(defun shr--fix-tbody (tbody) 2004(defun shr--fix-tbody (tbody)
2017 (nconc (list 'tbody (dom-attributes tbody)) 2005 (nconc (list 'tbody (dom-attributes tbody))
@@ -2311,8 +2299,8 @@ flags that control whether to collect or render objects."
2311 (dolist (column row) 2299 (dolist (column row)
2312 (aset natural-widths i (max (aref natural-widths i) column)) 2300 (aset natural-widths i (max (aref natural-widths i) column))
2313 (setq i (1+ i))))) 2301 (setq i (1+ i)))))
2314 (let ((extra (- (apply '+ (append suggested-widths nil)) 2302 (let ((extra (- (apply #'+ (append suggested-widths nil))
2315 (apply '+ (append widths nil)) 2303 (apply #'+ (append widths nil))
2316 (* shr-table-separator-pixel-width (1+ (length widths))))) 2304 (* shr-table-separator-pixel-width (1+ (length widths)))))
2317 (expanded-columns 0)) 2305 (expanded-columns 0))
2318 ;; We have extra, unused space, so divide this space amongst the 2306 ;; We have extra, unused space, so divide this space amongst the
diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el
index 95cbfb8c22a..24ee6fa51f3 100644
--- a/lisp/net/tramp-archive.el
+++ b/lisp/net/tramp-archive.el
@@ -109,7 +109,7 @@
109 109
110(eval-when-compile (require 'cl-lib)) 110(eval-when-compile (require 'cl-lib))
111;; Sometimes, compilation fails with "Variable binding depth exceeds 111;; Sometimes, compilation fails with "Variable binding depth exceeds
112;; max-specpdl-size". 112;; max-specpdl-size". Shall be fixed in Emacs 27.
113(eval-and-compile 113(eval-and-compile
114 (let ((max-specpdl-size (* 2 max-specpdl-size))) (require 'tramp-gvfs))) 114 (let ((max-specpdl-size (* 2 max-specpdl-size))) (require 'tramp-gvfs)))
115 115
@@ -318,7 +318,10 @@ arguments to pass to the OPERATION."
318 318
319 (let* ((filename (apply #'tramp-archive-file-name-for-operation 319 (let* ((filename (apply #'tramp-archive-file-name-for-operation
320 operation args)) 320 operation args))
321 (archive (tramp-archive-file-name-archive filename))) 321 (archive (tramp-archive-file-name-archive filename))
322 ;; Sometimes, it fails with "Variable binding depth exceeds
323 ;; max-specpdl-size". Shall be fixed in Emacs 27.
324 (max-specpdl-size (* 2 max-specpdl-size)))
322 325
323 ;; `filename' could be a quoted file name. Or the file 326 ;; `filename' could be a quoted file name. Or the file
324 ;; archive could be a directory, see Bug#30293. 327 ;; archive could be a directory, see Bug#30293.
diff --git a/lisp/net/tramp-rclone.el b/lisp/net/tramp-rclone.el
index 445098a5bca..08bba33afed 100644
--- a/lisp/net/tramp-rclone.el
+++ b/lisp/net/tramp-rclone.el
@@ -477,7 +477,18 @@ file names."
477 (with-tramp-connection-property 477 (with-tramp-connection-property
478 (tramp-get-connection-process vec) "rclone-pid" 478 (tramp-get-connection-process vec) "rclone-pid"
479 (catch 'pid 479 (catch 'pid
480 (dolist (pid (list-system-processes)) ;; "pidof rclone" ? 480 (dolist
481 (pid
482 ;; Until Emacs 25, `process-attributes' could
483 ;; crash Emacs for some processes. So we use
484 ;; "pidof", which might not work everywhere.
485 (if (<= emacs-major-version 25)
486 (let ((default-directory temporary-file-directory))
487 (mapcar
488 #'string-to-number
489 (split-string
490 (shell-command-to-string "pidof rclone"))))
491 (list-system-processes)))
481 (and (string-match-p 492 (and (string-match-p
482 (regexp-quote 493 (regexp-quote
483 (format "rclone mount %s:" (tramp-file-name-host vec))) 494 (format "rclone mount %s:" (tramp-file-name-host vec)))
diff --git a/lisp/net/webjump.el b/lisp/net/webjump.el
index 6edd03c39cc..8bb156199c5 100644
--- a/lisp/net/webjump.el
+++ b/lisp/net/webjump.el
@@ -1,4 +1,4 @@
1;;; webjump.el --- programmable Web hotlist 1;;; webjump.el --- programmable Web hotlist -*- lexical-binding: t; -*-
2 2
3;; Copyright (C) 1996-1997, 2001-2020 Free Software Foundation, Inc. 3;; Copyright (C) 1996-1997, 2001-2020 Free Software Foundation, Inc.
4 4
@@ -323,8 +323,7 @@ Please submit bug reports and other feedback to the author, Neil W. Van Dyke
323 323
324(defun webjump-read-url-choice (what urls &optional default) 324(defun webjump-read-url-choice (what urls &optional default)
325 ;; Note: Convert this to use `webjump-read-choice' someday. 325 ;; Note: Convert this to use `webjump-read-choice' someday.
326 (let* ((completions (mapcar (function (lambda (n) (cons n n))) 326 (let* ((completions (mapcar (lambda (n) (cons n n)) urls))
327 urls))
328 (input (completing-read (concat what 327 (input (completing-read (concat what
329 ;;(if default " (RET for default)" "") 328 ;;(if default " (RET for default)" "")
330 ": ") 329 ": ")
diff --git a/lisp/obsolete/levents.el b/lisp/obsolete/levents.el
deleted file mode 100644
index 2ae1ca48d16..00000000000
--- a/lisp/obsolete/levents.el
+++ /dev/null
@@ -1,292 +0,0 @@
1;;; levents.el --- emulate the Lucid event data type and associated functions
2
3;; Copyright (C) 1993, 2001-2020 Free Software Foundation, Inc.
4
5;; Maintainer: emacs-devel@gnu.org
6;; Keywords: emulations
7;; Obsolete-since: 23.2
8
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software: you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
23
24;;; Commentary:
25
26;; Things we cannot emulate in Lisp:
27;; It is not possible to emulate current-mouse-event as a variable,
28;; though it is not hard to obtain the data from (this-command-keys).
29
30;; We do not have a variable unread-command-event;
31;; instead, we have the more general unread-command-events.
32
33;; Our read-key-sequence and read-char are not precisely
34;; compatible with those in Lucid Emacs, but they should work ok.
35
36;;; Code:
37
38(defun next-command-event (event)
39 (error "You must rewrite to use `read-command-event' instead of `next-command-event'"))
40
41(defun next-event (event)
42 (error "You must rewrite to use `read-event' instead of `next-event'"))
43
44(defun dispatch-event (event)
45 (error "`dispatch-event' not supported"))
46
47;; Make events of type eval, menu and timeout
48;; execute properly.
49
50(define-key global-map [menu] 'execute-eval-event)
51(define-key global-map [timeout] 'execute-eval-event)
52(define-key global-map [eval] 'execute-eval-event)
53
54(defun execute-eval-event (event)
55 (interactive "e")
56 (funcall (nth 1 event) (nth 2 event)))
57
58(put 'eval 'event-symbol-elements '(eval))
59(put 'menu 'event-symbol-elements '(eval))
60(put 'timeout 'event-symbol-elements '(eval))
61
62(defun allocate-event ()
63 "Return an empty event structure.
64In this emulation, it returns nil."
65 nil)
66
67(defun button-press-event-p (obj)
68 "True if the argument is a mouse-button-press event object."
69 (and (consp obj) (symbolp (car obj))
70 (memq 'down (get (car obj) 'event-symbol-elements))))
71
72(defun button-release-event-p (obj)
73 "True if the argument is a mouse-button-release event object."
74 (and (consp obj) (symbolp (car obj))
75 (or (memq 'click (get (car obj) 'event-symbol-elements))
76 (memq 'drag (get (car obj) 'event-symbol-elements)))))
77
78(defun button-event-p (obj)
79 "True if the argument is a mouse-button press or release event object."
80 (and (consp obj) (symbolp (car obj))
81 (or (memq 'click (get (car obj) 'event-symbol-elements))
82 (memq 'down (get (car obj) 'event-symbol-elements))
83 (memq 'drag (get (car obj) 'event-symbol-elements)))))
84
85(defun mouse-event-p (obj)
86 "True if the argument is a mouse-button press or release event object."
87 (and (consp obj) (symbolp (car obj))
88 (or (eq (car obj) 'mouse-movement)
89 (memq 'click (get (car obj) 'event-symbol-elements))
90 (memq 'down (get (car obj) 'event-symbol-elements))
91 (memq 'drag (get (car obj) 'event-symbol-elements)))))
92
93(defun character-to-event (ch &optional event)
94 "Converts a numeric ASCII value to an event structure, replete with
95bucky bits. The character is the first argument, and the event to fill
96in is the second. This function contains knowledge about what the codes
97mean -- for example, the number 9 is converted to the character Tab,
98not the distinct character Control-I.
99
100Beware that character-to-event and event-to-character are not strictly
101inverse functions, since events contain much more information than the
102ASCII character set can encode."
103 ch)
104
105(defun copy-event (event1 &optional event2)
106 "Make a copy of the given event object.
107In this emulation, `copy-event' just returns its argument."
108 event1)
109
110(defun deallocate-event (event)
111 "Allow the given event structure to be reused.
112In actual Lucid Emacs, you MUST NOT use this event object after
113calling this function with it. You will lose. It is not necessary to
114call this function, as event objects are garbage- collected like all
115other objects; however, it may be more efficient to explicitly
116deallocate events when you are sure that this is safe.
117
118This emulation does not actually deallocate or reuse events
119except via garbage collection and `cons'."
120 nil)
121
122(defun enqueue-eval-event: (function object)
123 "Add an eval event to the back of the queue.
124It will be the next event read after all pending events."
125 (setq unread-command-events
126 (nconc unread-command-events
127 (list (list 'eval function object)))))
128
129(defun eval-event-p (obj)
130 "True if the argument is an eval or menu event object."
131 (eq (car-safe obj) 'eval))
132
133(defun event-button (event)
134 "Return the button-number of the given mouse-button-press event."
135 (let ((sym (car (get (car event) 'event-symbol-elements))))
136 (cdr (assq sym '((mouse-1 . 1) (mouse-2 . 2) (mouse-3 . 3)
137 (mouse-4 . 4) (mouse-5 . 5))))))
138
139(defun event-function (event)
140 "Return the callback function of the given timeout, menu, or eval event."
141 (nth 1 event))
142
143(defun event-key (event)
144 "Return the KeySym of the given key-press event.
145The value is an ASCII printing character (not upper case) or a symbol."
146 (if (symbolp event)
147 (car (get event 'event-symbol-elements))
148 (let ((base (logand event (1- (ash 1 18)))))
149 (downcase (if (< base 32) (logior base 64) base)))))
150
151(defun event-object (event)
152 "Return the function argument of the given timeout, menu, or eval event."
153 (nth 2 event))
154
155(defun event-point (event)
156 "Return the character position of the given mouse-related event.
157If the event did not occur over a window, or did
158not occur over text, then this returns nil. Otherwise, it returns an index
159into the buffer visible in the event's window."
160 (posn-point (event-end event)))
161
162;; Return position of start of line LINE in WINDOW.
163;; If LINE is nil, return the last position
164;; visible in WINDOW.
165(defun event-closest-point-1 (window &optional line)
166 (let* ((total (- (window-height window)
167 (if (window-minibuffer-p window)
168 0 1)))
169 (distance (or line total)))
170 (save-excursion
171 (goto-char (window-start window))
172 (if (= (vertical-motion distance) distance)
173 (if (not line)
174 (forward-char -1)))
175 (point))))
176
177(defun event-closest-point (event &optional start-window)
178 "Return the nearest position to where EVENT ended its motion.
179This is computed for the window where EVENT's motion started,
180or for window WINDOW if that is specified."
181 (or start-window (setq start-window (posn-window (event-start event))))
182 (if (eq start-window (posn-window (event-end event)))
183 (if (eq (event-point event) 'vertical-line)
184 (event-closest-point-1 start-window
185 (cdr (posn-col-row (event-end event))))
186 (if (eq (event-point event) 'mode-line)
187 (event-closest-point-1 start-window)
188 (event-point event)))
189 ;; EVENT ended in some other window.
190 (let* ((end-w (posn-window (event-end event)))
191 (end-w-top)
192 (w-top (nth 1 (window-edges start-window))))
193 (setq end-w-top
194 (if (windowp end-w)
195 (nth 1 (window-edges end-w))
196 (/ (cdr (posn-x-y (event-end event)))
197 (frame-char-height end-w))))
198 (if (>= end-w-top w-top)
199 (event-closest-point-1 start-window)
200 (window-start start-window)))))
201
202(defun event-process (event)
203 "Return the process of the given process-output event."
204 (nth 1 event))
205
206(defun event-timestamp (event)
207 "Return the timestamp of the given event object.
208In Lucid Emacs, this works for any kind of event.
209In this emulation, it returns nil for non-mouse-related events."
210 (and (listp event)
211 (posn-timestamp (event-end event))))
212
213(defun event-to-character (event &optional lenient)
214 "Return the closest ASCII approximation to the given event object.
215If the event isn't a keypress, this returns nil.
216If the second argument is non-nil, then this is lenient in its
217translation; it will ignore modifier keys other than control and meta,
218and will ignore the shift modifier on those characters which have no
219shifted ASCII equivalent (Control-Shift-A for example, will be mapped to
220the same ASCII code as Control-A.) If the second arg is nil, then nil
221will be returned for events which have no direct ASCII equivalent."
222 (if (symbolp event)
223 (and lenient
224 (cdr (assq event '((backspace . 8) (delete . 127) (tab . 9)
225 (return . 10) (enter . 10)))))
226 ;; Our interpretation is, ASCII means anything a number can represent.
227 (if (integerp event)
228 event nil)))
229
230(defun event-window (event)
231 "Return the window of the given mouse-related event object."
232 (posn-window (event-end event)))
233
234(defun event-x (event)
235 "Return the X position in characters of the given mouse-related event."
236 (/ (car (posn-col-row (event-end event)))
237 (frame-char-width (window-frame (event-window event)))))
238
239(defun event-x-pixel (event)
240 "Return the X position in pixels of the given mouse-related event."
241 (car (posn-col-row (event-end event))))
242
243(defun event-y (event)
244 "Return the Y position in characters of the given mouse-related event."
245 (/ (cdr (posn-col-row (event-end event)))
246 (frame-char-height (window-frame (event-window event)))))
247
248(defun event-y-pixel (event)
249 "Return the Y position in pixels of the given mouse-related event."
250 (cdr (posn-col-row (event-end event))))
251
252(defun key-press-event-p (obj)
253 "True if the argument is a keyboard event object."
254 (or (integerp obj)
255 (and (symbolp obj)
256 (get obj 'event-symbol-elements))))
257
258(defun menu-event-p (obj)
259 "True if the argument is a menu event object."
260 (eq (car-safe obj) 'menu))
261
262(defun motion-event-p (obj)
263 "True if the argument is a mouse-motion event object."
264 (eq (car-safe obj) 'mouse-movement))
265
266(defun read-command-event ()
267 "Return the next keyboard or mouse event; execute other events.
268This is similar to the function `next-command-event' of Lucid Emacs,
269but different in that it returns the event rather than filling in
270an existing event object."
271 (let (event)
272 (while (progn
273 (setq event (read-event))
274 (not (or (key-press-event-p event)
275 (button-press-event-p event)
276 (button-release-event-p event)
277 (menu-event-p event))))
278 (let ((type (car-safe event)))
279 (cond ((eq type 'eval)
280 (funcall (nth 1 event) (nth 2 event)))
281 ((eq type 'switch-frame)
282 (select-frame (nth 1 event))))))
283 event))
284
285(defun process-event-p (obj)
286 "True if the argument is a process-output event object.
287GNU Emacs 19 does not currently generate process-output events."
288 (eq (car-safe obj) 'process))
289
290(provide 'levents)
291
292;;; levents.el ends here
diff --git a/lisp/org/org-agenda.el b/lisp/org/org-agenda.el
index 5fe140d00ef..689d134627e 100644
--- a/lisp/org/org-agenda.el
+++ b/lisp/org/org-agenda.el
@@ -2995,7 +2995,8 @@ Agenda views are separated by `org-agenda-block-separator'."
2995 (erase-buffer) 2995 (erase-buffer)
2996 (insert (eval-when-compile 2996 (insert (eval-when-compile
2997 (let ((header 2997 (let ((header
2998 "Press key for an agenda command: 2998 (copy-sequence
2999 "Press key for an agenda command:
2999-------------------------------- < Buffer, subtree/region restriction 3000-------------------------------- < Buffer, subtree/region restriction
3000a Agenda for current week or day > Remove restriction 3001a Agenda for current week or day > Remove restriction
3001t List of all TODO entries e Export agenda views 3002t List of all TODO entries e Export agenda views
@@ -3004,7 +3005,7 @@ s Search for keywords M Like m, but only TODO entries
3004/ Multi-occur S Like s, but only TODO entries 3005/ Multi-occur S Like s, but only TODO entries
3005? Find :FLAGGED: entries C Configure custom agenda commands 3006? Find :FLAGGED: entries C Configure custom agenda commands
3006* Toggle sticky agenda views # List stuck projects (!=configure) 3007* Toggle sticky agenda views # List stuck projects (!=configure)
3007") 3008"))
3008 (start 0)) 3009 (start 0))
3009 (while (string-match 3010 (while (string-match
3010 "\\(^\\| \\|(\\)\\(\\S-\\)\\( \\|=\\)" 3011 "\\(^\\| \\|(\\)\\(\\S-\\)\\( \\|=\\)"
diff --git a/lisp/password-cache.el b/lisp/password-cache.el
index 86d802f283c..f5007579a8a 100644
--- a/lisp/password-cache.el
+++ b/lisp/password-cache.el
@@ -31,7 +31,8 @@
31;; ;; Minibuffer prompt for password. 31;; ;; Minibuffer prompt for password.
32;; => "foo" 32;; => "foo"
33;; 33;;
34;; (password-cache-add "test" (copy-sequence "foo")) 34;; (password-cache-add "test" (read-passwd "Password? "))
35;; ;; Minibuffer prompt from read-passwd, which returns "foo".
35;; => nil 36;; => nil
36 37
37;; (password-read "Password? " "test") 38;; (password-read "Password? " "test")
diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el
index 1e72352f719..17ffea59ff0 100644
--- a/lisp/progmodes/cc-langs.el
+++ b/lisp/progmodes/cc-langs.el
@@ -3412,8 +3412,14 @@ regexp should match \"(\" if parentheses are valid in declarators.
3412The end of the first submatch is taken as the end of the operator. 3412The end of the first submatch is taken as the end of the operator.
3413Identifier syntax is in effect when this is matched (see 3413Identifier syntax is in effect when this is matched (see
3414`c-identifier-syntax-table')." 3414`c-identifier-syntax-table')."
3415 t (if (c-lang-const c-type-modifier-kwds) 3415 t (if (or (c-lang-const c-type-modifier-kwds) (c-lang-const c-modifier-kwds))
3416 (concat (regexp-opt (c-lang-const c-type-modifier-kwds) t) "\\>") 3416 (concat
3417 (regexp-opt (c--delete-duplicates
3418 (append (c-lang-const c-type-modifier-kwds)
3419 (c-lang-const c-modifier-kwds))
3420 :test 'string-equal)
3421 t)
3422 "\\>")
3417 ;; Default to a regexp that never matches. 3423 ;; Default to a regexp that never matches.
3418 regexp-unmatchable) 3424 regexp-unmatchable)
3419 ;; Check that there's no "=" afterwards to avoid matching tokens 3425 ;; Check that there's no "=" afterwards to avoid matching tokens
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index d822788bee2..b3b2374805d 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -795,7 +795,7 @@ compatible with old code; callers should always specify it."
795 (set (make-local-variable 'outline-level) 'c-outline-level) 795 (set (make-local-variable 'outline-level) 'c-outline-level)
796 (set (make-local-variable 'add-log-current-defun-function) 796 (set (make-local-variable 'add-log-current-defun-function)
797 (lambda () 797 (lambda ()
798 (or (c-cpp-define-name) (c-defun-name)))) 798 (or (c-cpp-define-name) (car (c-defun-name-and-limits nil)))))
799 (let ((rfn (assq mode c-require-final-newline))) 799 (let ((rfn (assq mode c-require-final-newline)))
800 (when rfn 800 (when rfn
801 (if (boundp 'mode-require-final-newline) 801 (if (boundp 'mode-require-final-newline)
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 198f040fb29..c72e9d94b1c 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1,7 +1,7 @@
1;;; project.el --- Operations on the current project -*- lexical-binding: t; -*- 1;;; project.el --- Operations on the current project -*- lexical-binding: t; -*-
2 2
3;; Copyright (C) 2015-2020 Free Software Foundation, Inc. 3;; Copyright (C) 2015-2020 Free Software Foundation, Inc.
4;; Version: 0.1.3 4;; Version: 0.2.0
5;; Package-Requires: ((emacs "26.3")) 5;; Package-Requires: ((emacs "26.3"))
6 6
7;; This is a GNU ELPA :core package. Avoid using functionality that 7;; This is a GNU ELPA :core package. Avoid using functionality that
@@ -40,7 +40,7 @@
40;; Infrastructure: 40;; Infrastructure:
41;; 41;;
42;; Function `project-current', to determine the current project 42;; Function `project-current', to determine the current project
43;; instance, and 5 (at the moment) generic functions that act on it. 43;; instance, and 4 (at the moment) generic functions that act on it.
44;; This list is to be extended in future versions. 44;; This list is to be extended in future versions.
45;; 45;;
46;; Utils: 46;; Utils:
@@ -122,14 +122,25 @@ is not a part of a detectable project either, return a
122(defun project--find-in-directory (dir) 122(defun project--find-in-directory (dir)
123 (run-hook-with-args-until-success 'project-find-functions dir)) 123 (run-hook-with-args-until-success 'project-find-functions dir))
124 124
125(cl-defgeneric project-roots (project) 125(cl-defgeneric project-root (project)
126 "Return the list of directory roots of the current project. 126 "Return root directory of the current project.
127
128It usually contains the main build file, dependencies
129configuration file, etc. Though neither is mandatory.
127 130
128Most often it's just one directory which contains the project 131The directory name must be absolute."
129build file and everything else in the project. But in more 132 (car (project-roots project)))
130advanced configurations, a project can span multiple directories.
131 133
132The directory names should be absolute.") 134(cl-defgeneric project-roots (project)
135 "Return the list containing the current project root.
136
137The function is obsolete, all projects have one main root anyway,
138and the rest should be possible to express through
139`project-external-roots'."
140 ;; FIXME: Can we specify project's version here?
141 ;; FIXME: Could we make this affect cl-defmethod calls too?
142 (declare (obsolete project-root "0.3.0"))
143 (list (project-root project)))
133 144
134;; FIXME: Add MODE argument, like in `ede-source-paths'? 145;; FIXME: Add MODE argument, like in `ede-source-paths'?
135(cl-defgeneric project-external-roots (_project) 146(cl-defgeneric project-external-roots (_project)
@@ -138,18 +149,14 @@ The directory names should be absolute.")
138It's the list of directories outside of the project that are 149It's the list of directories outside of the project that are
139still related to it. If the project deals with source code then, 150still related to it. If the project deals with source code then,
140depending on the languages used, this list should include the 151depending on the languages used, this list should include the
141headers search path, load path, class path, and so on. 152headers search path, load path, class path, and so on."
142
143The rule of thumb for whether to include a directory here, and
144not in `project-roots', is whether its contents are meant to be
145edited together with the rest of the project."
146 nil) 153 nil)
147 154
148(cl-defgeneric project-ignores (_project _dir) 155(cl-defgeneric project-ignores (_project _dir)
149 "Return the list of glob patterns to ignore inside DIR. 156 "Return the list of glob patterns to ignore inside DIR.
150Patterns can match both regular files and directories. 157Patterns can match both regular files and directories.
151To root an entry, start it with `./'. To match directories only, 158To root an entry, start it with `./'. To match directories only,
152end it with `/'. DIR must be one of `project-roots' or 159end it with `/'. DIR must be either `project-root' or one of
153`project-external-roots'." 160`project-external-roots'."
154 ;; TODO: Document and support regexp ignores as used by Hg. 161 ;; TODO: Document and support regexp ignores as used by Hg.
155 ;; TODO: Support whitelist entries. 162 ;; TODO: Support whitelist entries.
@@ -170,13 +177,13 @@ end it with `/'. DIR must be one of `project-roots' or
170 (t 177 (t
171 (complete-with-action action all-files string pred))))) 178 (complete-with-action action all-files string pred)))))
172 179
173(cl-defmethod project-roots ((project (head transient))) 180(cl-defmethod project-root ((project (head transient)))
174 (list (cdr project))) 181 (cdr project))
175 182
176(cl-defgeneric project-files (project &optional dirs) 183(cl-defgeneric project-files (project &optional dirs)
177 "Return a list of files in directories DIRS in PROJECT. 184 "Return a list of files in directories DIRS in PROJECT.
178DIRS is a list of absolute directories; it should be some 185DIRS is a list of absolute directories; it should be some
179subset of the project roots and external roots. 186subset of the project root and external roots.
180 187
181The default implementation uses `find-program'. PROJECT is used 188The default implementation uses `find-program'. PROJECT is used
182to find the list of ignores for each directory." 189to find the list of ignores for each directory."
@@ -184,7 +191,8 @@ to find the list of ignores for each directory."
184 (lambda (dir) 191 (lambda (dir)
185 (project--files-in-directory dir 192 (project--files-in-directory dir
186 (project--dir-ignores project dir))) 193 (project--dir-ignores project dir)))
187 (or dirs (project-roots project)))) 194 (or dirs
195 (list (project-root project)))))
188 196
189(defun project--files-in-directory (dir ignores &optional files) 197(defun project--files-in-directory (dir ignores &optional files)
190 (require 'find-dired) 198 (require 'find-dired)
@@ -223,7 +231,7 @@ to find the list of ignores for each directory."
223 local-files)))) 231 local-files))))
224 232
225(defgroup project-vc nil 233(defgroup project-vc nil
226 "Project implementation using the VC package." 234 "Project implementation based on the VC package."
227 :version "25.1" 235 :version "25.1"
228 :group 'tools) 236 :group 'tools)
229 237
@@ -232,6 +240,15 @@ to find the list of ignores for each directory."
232 :type '(repeat string) 240 :type '(repeat string)
233 :safe 'listp) 241 :safe 'listp)
234 242
243(defcustom project-vc-merge-submodules t
244 "Non-nil to consider submodules part of the parent project.
245
246After changing this variable (using Customize or .dir-locals.el)
247you might have to restart Emacs to see the effect."
248 :type 'boolean
249 :package-version '(project . "0.2.0")
250 :safe 'booleanp)
251
235;; FIXME: Using the current approach, major modes are supposed to set 252;; FIXME: Using the current approach, major modes are supposed to set
236;; this variable to a buffer-local value. So we don't have access to 253;; this variable to a buffer-local value. So we don't have access to
237;; the "external roots" of language A from buffers of language B, which 254;; the "external roots" of language A from buffers of language B, which
@@ -273,38 +290,48 @@ backend implementation of `project-external-roots'.")
273 (pcase backend 290 (pcase backend
274 ('Git 291 ('Git
275 ;; Don't stop at submodule boundary. 292 ;; Don't stop at submodule boundary.
276 ;; Note: It's not necessarily clear-cut what should be
277 ;; considered a "submodule" in the sense that some users
278 ;; may setup things equivalent to "git-submodule"s using
279 ;; "git worktree" instead (for example).
280 ;; FIXME: Also it may be the case that some users would consider
281 ;; a submodule as its own project. So there's a good chance
282 ;; we will need to let the user tell us what is their intention.
283 (or (vc-file-getprop dir 'project-git-root) 293 (or (vc-file-getprop dir 'project-git-root)
284 (let* ((root (vc-call-backend backend 'root dir)) 294 (let ((root (vc-call-backend backend 'root dir)))
285 (gitfile (expand-file-name ".git" root)))
286 (vc-file-setprop 295 (vc-file-setprop
287 dir 'project-git-root 296 dir 'project-git-root
288 (cond 297 (if (and
289 ((file-directory-p gitfile) 298 ;; FIXME: Invalidate the cache when the value
290 root) 299 ;; of this variable changes.
291 ((with-temp-buffer 300 project-vc-merge-submodules
292 (insert-file-contents gitfile) 301 (project--submodule-p root))
293 (goto-char (point-min)) 302 (let* ((parent (file-name-directory
294 ;; Kind of a hack to distinguish a submodule from 303 (directory-file-name root))))
295 ;; other cases of .git files pointing elsewhere. 304 (vc-call-backend backend 'root parent))
296 (looking-at "gitdir: [./]+/\\.git/modules/")) 305 root)))))
297 (let* ((parent (file-name-directory
298 (directory-file-name root))))
299 (vc-call-backend backend 'root parent)))
300 (t root)))
301 )))
302 ('nil nil) 306 ('nil nil)
303 (_ (ignore-errors (vc-call-backend backend 'root dir)))))) 307 (_ (ignore-errors (vc-call-backend backend 'root dir))))))
304 (and root (cons 'vc root)))) 308 (and root (cons 'vc root))))
305 309
306(cl-defmethod project-roots ((project (head vc))) 310(defun project--submodule-p (root)
307 (list (cdr project))) 311 ;; XXX: We only support Git submodules for now.
312 ;;
313 ;; For submodules, at least, we expect the users to prefer them to
314 ;; be considered part of the parent project. For those who don't,
315 ;; there is the custom var now.
316 ;;
317 ;; Some users may also set up things equivalent to Git submodules
318 ;; using "git worktree" (for example). However, we expect that most
319 ;; of them would prefer to treat those as separate projects anyway.
320 (let* ((gitfile (expand-file-name ".git" root)))
321 (cond
322 ((file-directory-p gitfile)
323 nil)
324 ((with-temp-buffer
325 (insert-file-contents gitfile)
326 (goto-char (point-min))
327 ;; Kind of a hack to distinguish a submodule from
328 ;; other cases of .git files pointing elsewhere.
329 (looking-at "gitdir: [./]+/\\.git/modules/"))
330 t)
331 (t nil))))
332
333(cl-defmethod project-root ((project (head vc)))
334 (cdr project))
308 335
309(cl-defmethod project-external-roots ((project (head vc))) 336(cl-defmethod project-external-roots ((project (head vc)))
310 (project-subtract-directories 337 (project-subtract-directories
@@ -312,7 +339,7 @@ backend implementation of `project-external-roots'.")
312 (mapcar 339 (mapcar
313 #'file-name-as-directory 340 #'file-name-as-directory
314 (funcall project-vc-external-roots-function))) 341 (funcall project-vc-external-roots-function)))
315 (project-roots project))) 342 (list (project-root project))))
316 343
317(cl-defmethod project-files ((project (head vc)) &optional dirs) 344(cl-defmethod project-files ((project (head vc)) &optional dirs)
318 (cl-mapcan 345 (cl-mapcan
@@ -330,7 +357,8 @@ backend implementation of `project-external-roots'.")
330 (project--files-in-directory 357 (project--files-in-directory
331 dir 358 dir
332 (project--dir-ignores project dir))))) 359 (project--dir-ignores project dir)))))
333 (or dirs (project-roots project)))) 360 (or dirs
361 (list (project-root project)))))
334 362
335(declare-function vc-git--program-version "vc-git") 363(declare-function vc-git--program-version "vc-git")
336(declare-function vc-git--run-command-string "vc-git") 364(declare-function vc-git--run-command-string "vc-git")
@@ -372,7 +400,9 @@ backend implementation of `project-external-roots'.")
372 submodules))) 400 submodules)))
373 (setq files 401 (setq files
374 (apply #'nconc files sub-files))) 402 (apply #'nconc files sub-files)))
375 files)) 403 ;; 'git ls-files' returns duplicate entries for merge conflicts.
404 ;; XXX: Better solutions welcome, but this seems cheap enough.
405 (delete-consecutive-dups files)))
376 (`Hg 406 (`Hg
377 (let ((default-directory (expand-file-name (file-name-as-directory dir))) 407 (let ((default-directory (expand-file-name (file-name-as-directory dir)))
378 args) 408 args)
@@ -471,7 +501,7 @@ requires quoting, e.g. `\\[quoted-insert]<space>'."
471 (let* ((pr (project-current t)) 501 (let* ((pr (project-current t))
472 (files 502 (files
473 (if (not current-prefix-arg) 503 (if (not current-prefix-arg)
474 (project-files pr (project-roots pr)) 504 (project-files pr)
475 (let ((dir (read-directory-name "Base directory: " 505 (let ((dir (read-directory-name "Base directory: "
476 nil default-directory t))) 506 nil default-directory t)))
477 (project--files-in-directory dir 507 (project--files-in-directory dir
@@ -482,9 +512,8 @@ requires quoting, e.g. `\\[quoted-insert]<space>'."
482 nil))) 512 nil)))
483 513
484(defun project--dir-ignores (project dir) 514(defun project--dir-ignores (project dir)
485 (let* ((roots (project-roots project)) 515 (let ((root (project-root project)))
486 (root (cl-find dir roots :test #'file-in-directory-p))) 516 (if (not (file-in-directory-p dir root))
487 (if (not root)
488 (project-ignores nil nil) ;The defaults. 517 (project-ignores nil nil) ;The defaults.
489 (let ((ignores (project-ignores project root))) 518 (let ((ignores (project-ignores project root)))
490 (if (file-equal-p root dir) 519 (if (file-equal-p root dir)
@@ -502,8 +531,8 @@ pattern to search for."
502 (require 'xref) 531 (require 'xref)
503 (let* ((pr (project-current t)) 532 (let* ((pr (project-current t))
504 (files 533 (files
505 (project-files pr (append 534 (project-files pr (cons
506 (project-roots pr) 535 (project-root pr)
507 (project-external-roots pr))))) 536 (project-external-roots pr)))))
508 (xref--show-xrefs 537 (xref--show-xrefs
509 (apply-partially #'project--find-regexp-in-files regexp files) 538 (apply-partially #'project--find-regexp-in-files regexp files)
@@ -541,23 +570,23 @@ pattern to search for."
541 570
542;;;###autoload 571;;;###autoload
543(defun project-find-file () 572(defun project-find-file ()
544 "Visit a file (with completion) in the current project's roots. 573 "Visit a file (with completion) in the current project.
545The completion default is the filename at point, if one is 574The completion default is the filename at point, if one is
546recognized." 575recognized."
547 (interactive) 576 (interactive)
548 (let* ((pr (project-current t)) 577 (let* ((pr (project-current t))
549 (dirs (project-roots pr))) 578 (dirs (list (project-root pr))))
550 (project-find-file-in (thing-at-point 'filename) dirs pr))) 579 (project-find-file-in (thing-at-point 'filename) dirs pr)))
551 580
552;;;###autoload 581;;;###autoload
553(defun project-or-external-find-file () 582(defun project-or-external-find-file ()
554 "Visit a file (with completion) in the current project's roots or external roots. 583 "Visit a file (with completion) in the current project or external roots.
555The completion default is the filename at point, if one is 584The completion default is the filename at point, if one is
556recognized." 585recognized."
557 (interactive) 586 (interactive)
558 (let* ((pr (project-current t)) 587 (let* ((pr (project-current t))
559 (dirs (append 588 (dirs (cons
560 (project-roots pr) 589 (project-root pr)
561 (project-external-roots pr)))) 590 (project-external-roots pr))))
562 (project-find-file-in (thing-at-point 'filename) dirs pr))) 591 (project-find-file-in (thing-at-point 'filename) dirs pr)))
563 592
@@ -660,5 +689,13 @@ loop using the command \\[fileloop-continue]."
660 from to (project-files (project-current t)) 'default) 689 from to (project-files (project-current t)) 'default)
661 (fileloop-continue)) 690 (fileloop-continue))
662 691
692;;;###autoload
693(defun project-compile ()
694 "Run `compile' in the project root."
695 (interactive)
696 (let* ((pr (project-current t))
697 (default-directory (project-root pr)))
698 (call-interactively 'compile)))
699
663(provide 'project) 700(provide 'project)
664;;; project.el ends here 701;;; project.el ends here
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 67383b34154..1ca9f019638 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -261,7 +261,6 @@
261(require 'ansi-color) 261(require 'ansi-color)
262(require 'cl-lib) 262(require 'cl-lib)
263(require 'comint) 263(require 'comint)
264(require 'json)
265(require 'tramp-sh) 264(require 'tramp-sh)
266 265
267;; Avoid compiler warnings 266;; Avoid compiler warnings
@@ -2276,6 +2275,18 @@ Do not set this variable directly, instead use
2276Do not set this variable directly, instead use 2275Do not set this variable directly, instead use
2277`python-shell-prompt-set-calculated-regexps'.") 2276`python-shell-prompt-set-calculated-regexps'.")
2278 2277
2278(defalias 'python--parse-json-array
2279 (if (fboundp 'json-parse-string)
2280 (lambda (string)
2281 (json-parse-string string :array-type 'list))
2282 (require 'json)
2283 (defvar json-array-type)
2284 (declare-function json-read-from-string "json" (string))
2285 (lambda (string)
2286 (let ((json-array-type 'list))
2287 (json-read-from-string string))))
2288 "Parse the JSON array in STRING into a Lisp list.")
2289
2279(defun python-shell-prompt-detect () 2290(defun python-shell-prompt-detect ()
2280 "Detect prompts for the current `python-shell-interpreter'. 2291 "Detect prompts for the current `python-shell-interpreter'.
2281When prompts can be retrieved successfully from the 2292When prompts can be retrieved successfully from the
@@ -2324,11 +2335,11 @@ detection and just returns nil."
2324 (catch 'prompts 2335 (catch 'prompts
2325 (dolist (line (split-string output "\n" t)) 2336 (dolist (line (split-string output "\n" t))
2326 (let ((res 2337 (let ((res
2327 ;; Check if current line is a valid JSON array 2338 ;; Check if current line is a valid JSON array.
2328 (and (string= (substring line 0 2) "[\"") 2339 (and (string-prefix-p "[\"" line)
2329 (ignore-errors 2340 (ignore-errors
2330 ;; Return prompts as a list, not vector 2341 ;; Return prompts as a list.
2331 (append (json-read-from-string line) nil))))) 2342 (python--parse-json-array line)))))
2332 ;; The list must contain 3 strings, where the first 2343 ;; The list must contain 3 strings, where the first
2333 ;; is the input prompt, the second is the block 2344 ;; is the input prompt, the second is the block
2334 ;; prompt and the last one is the output prompt. The 2345 ;; prompt and the last one is the output prompt. The
diff --git a/lisp/progmodes/which-func.el b/lisp/progmodes/which-func.el
index 1cee552b0c0..266f40abbae 100644
--- a/lisp/progmodes/which-func.el
+++ b/lisp/progmodes/which-func.el
@@ -186,7 +186,7 @@ and you want to simplify them for the mode line
186 "Non-nil means display current function name in mode line. 186 "Non-nil means display current function name in mode line.
187This makes a difference only if `which-function-mode' is non-nil.") 187This makes a difference only if `which-function-mode' is non-nil.")
188 188
189(add-hook 'find-file-hook 'which-func-ff-hook t) 189(add-hook 'after-change-major-mode-hook 'which-func-ff-hook t)
190 190
191(defun which-func-try-to-enable () 191(defun which-func-try-to-enable ()
192 (unless (or (not which-function-mode) 192 (unless (or (not which-function-mode)
@@ -195,7 +195,7 @@ This makes a difference only if `which-function-mode' is non-nil.")
195 (member major-mode which-func-modes))))) 195 (member major-mode which-func-modes)))))
196 196
197(defun which-func-ff-hook () 197(defun which-func-ff-hook ()
198 "File find hook for Which Function mode. 198 "`after-change-major-mode-hook' for Which Function mode.
199It creates the Imenu index for the buffer, if necessary." 199It creates the Imenu index for the buffer, if necessary."
200 (which-func-try-to-enable) 200 (which-func-try-to-enable)
201 201
@@ -282,52 +282,55 @@ If no function name is found, return nil."
282 (when (null name) 282 (when (null name)
283 (setq name (add-log-current-defun))) 283 (setq name (add-log-current-defun)))
284 ;; If Imenu is loaded, try to make an index alist with it. 284 ;; If Imenu is loaded, try to make an index alist with it.
285 ;; If `add-log-current-defun' ran and gave nil, accept that.
285 (when (and (null name) 286 (when (and (null name)
286 (boundp 'imenu--index-alist) 287 (null add-log-current-defun-function))
287 (or (null imenu--index-alist) 288 (when (and (null name)
288 ;; Update if outdated 289 (boundp 'imenu--index-alist)
289 (/= (buffer-chars-modified-tick) imenu-menubar-modified-tick)) 290 (or (null imenu--index-alist)
290 (null which-function-imenu-failed)) 291 ;; Update if outdated
291 (ignore-errors (imenu--make-index-alist t)) 292 (/= (buffer-chars-modified-tick) imenu-menubar-modified-tick))
292 (unless imenu--index-alist 293 (null which-function-imenu-failed))
293 (set (make-local-variable 'which-function-imenu-failed) t))) 294 (ignore-errors (imenu--make-index-alist t))
294 ;; If we have an index alist, use it. 295 (unless imenu--index-alist
295 (when (and (null name) 296 (set (make-local-variable 'which-function-imenu-failed) t)))
296 (boundp 'imenu--index-alist) imenu--index-alist) 297 ;; If we have an index alist, use it.
297 (let ((alist imenu--index-alist) 298 (when (and (null name)
298 (minoffset (point-max)) 299 (boundp 'imenu--index-alist) imenu--index-alist)
299 offset pair mark imstack namestack) 300 (let ((alist imenu--index-alist)
300 ;; Elements of alist are either ("name" . marker), or 301 (minoffset (point-max))
301 ;; ("submenu" ("name" . marker) ... ). The list can be 302 offset pair mark imstack namestack)
302 ;; arbitrarily nested. 303 ;; Elements of alist are either ("name" . marker), or
303 (while (or alist imstack) 304 ;; ("submenu" ("name" . marker) ... ). The list can be
304 (if (null alist) 305 ;; arbitrarily nested.
305 (setq alist (car imstack) 306 (while (or alist imstack)
306 namestack (cdr namestack) 307 (if (null alist)
307 imstack (cdr imstack)) 308 (setq alist (car imstack)
308 309 namestack (cdr namestack)
309 (setq pair (car-safe alist) 310 imstack (cdr imstack))
310 alist (cdr-safe alist)) 311
311 312 (setq pair (car-safe alist)
312 (cond 313 alist (cdr-safe alist))
313 ((atom pair)) ; Skip anything not a cons. 314
314 315 (cond
315 ((imenu--subalist-p pair) 316 ((atom pair)) ; Skip anything not a cons.
316 (setq imstack (cons alist imstack) 317
317 namestack (cons (car pair) namestack) 318 ((imenu--subalist-p pair)
318 alist (cdr pair))) 319 (setq imstack (cons alist imstack)
319 320 namestack (cons (car pair) namestack)
320 ((or (number-or-marker-p (setq mark (cdr pair))) 321 alist (cdr pair)))
321 (and (overlayp mark) 322
322 (setq mark (overlay-start mark)))) 323 ((or (number-or-marker-p (setq mark (cdr pair)))
323 (when (and (>= (setq offset (- (point) mark)) 0) 324 (and (overlayp mark)
324 (< offset minoffset)) ; Find the closest item. 325 (setq mark (overlay-start mark))))
325 (setq minoffset offset 326 (when (and (>= (setq offset (- (point) mark)) 0)
326 name (if (null which-func-imenu-joiner-function) 327 (< offset minoffset)) ; Find the closest item.
327 (car pair) 328 (setq minoffset offset
328 (funcall 329 name (if (null which-func-imenu-joiner-function)
329 which-func-imenu-joiner-function 330 (car pair)
330 (reverse (cons (car pair) namestack)))))))))))) 331 (funcall
332 which-func-imenu-joiner-function
333 (reverse (cons (car pair) namestack)))))))))))))
331 ;; Filter the name if requested. 334 ;; Filter the name if requested.
332 (when name 335 (when name
333 (if which-func-cleanup-function 336 (if which-func-cleanup-function
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 7d1ee705b80..2477884f1ab 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -268,8 +268,8 @@ find a search tool; by default, this uses \"find | grep\" in the
268 (lambda (dir) 268 (lambda (dir)
269 (xref-references-in-directory identifier dir)) 269 (xref-references-in-directory identifier dir))
270 (let ((pr (project-current t))) 270 (let ((pr (project-current t)))
271 (append 271 (cons
272 (project-roots pr) 272 (project-root pr)
273 (project-external-roots pr))))) 273 (project-external-roots pr)))))
274 274
275(cl-defgeneric xref-backend-apropos (backend pattern) 275(cl-defgeneric xref-backend-apropos (backend pattern)
diff --git a/lisp/subr.el b/lisp/subr.el
index 971bce36b77..683e44123d7 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -4117,7 +4117,11 @@ MODES is as for `set-default-file-modes'."
4117;; now, but it generates slower code. 4117;; now, but it generates slower code.
4118(defmacro save-match-data (&rest body) 4118(defmacro save-match-data (&rest body)
4119 "Execute the BODY forms, restoring the global value of the match data. 4119 "Execute the BODY forms, restoring the global value of the match data.
4120The value returned is the value of the last form in BODY." 4120The value returned is the value of the last form in BODY.
4121NOTE: The convention in Elisp is that any function, except for a few
4122exceptions like car/assoc/+/goto-char, can clobber the match data,
4123so `save-match-data' should normally be used to save *your* match data
4124rather than your caller's match data."
4121 ;; It is better not to use backquote here, 4125 ;; It is better not to use backquote here,
4122 ;; because that makes a bootstrapping problem 4126 ;; because that makes a bootstrapping problem
4123 ;; if you need to recompile all the Lisp files using interpreted code. 4127 ;; if you need to recompile all the Lisp files using interpreted code.
diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el
index 0c9e656add4..a86c37c24ae 100644
--- a/lisp/vc/vc-dir.el
+++ b/lisp/vc/vc-dir.el
@@ -1106,6 +1106,7 @@ the *vc-dir* buffer.
1106 (set (make-local-variable 'vc-dir-backend) use-vc-backend) 1106 (set (make-local-variable 'vc-dir-backend) use-vc-backend)
1107 (set (make-local-variable 'desktop-save-buffer) 1107 (set (make-local-variable 'desktop-save-buffer)
1108 'vc-dir-desktop-buffer-misc-data) 1108 'vc-dir-desktop-buffer-misc-data)
1109 (setq-local bookmark-make-record-function #'vc-dir-bookmark-make-record)
1109 (setq buffer-read-only t) 1110 (setq buffer-read-only t)
1110 (when (boundp 'tool-bar-map) 1111 (when (boundp 'tool-bar-map)
1111 (set (make-local-variable 'tool-bar-map) vc-dir-tool-bar-map)) 1112 (set (make-local-variable 'tool-bar-map) vc-dir-tool-bar-map))
@@ -1466,6 +1467,41 @@ These are the commands available for use in the file status buffer:
1466 '(vc-dir-mode . vc-dir-restore-desktop-buffer)) 1467 '(vc-dir-mode . vc-dir-restore-desktop-buffer))
1467 1468
1468 1469
1470;;; Support for bookmark.el (adapted from what info.el does).
1471
1472(declare-function bookmark-make-record-default
1473 "bookmark" (&optional no-file no-context posn))
1474(declare-function bookmark-prop-get "bookmark" (bookmark prop))
1475(declare-function bookmark-default-handler "bookmark" (bmk))
1476(declare-function bookmark-get-bookmark-record "bookmark" (bmk))
1477
1478(defun vc-dir-bookmark-make-record ()
1479 "Make record used to bookmark a `vc-dir' buffer.
1480This implements the `bookmark-make-record-function' type for
1481`vc-dir' buffers."
1482 (let* ((bookmark-name
1483 (concat "(" (symbol-name vc-dir-backend) ") "
1484 (file-name-nondirectory
1485 (directory-file-name default-directory))))
1486 (defaults (list bookmark-name default-directory)))
1487 `(,bookmark-name
1488 ,@(bookmark-make-record-default 'no-file)
1489 (filename . ,default-directory)
1490 (handler . vc-dir-bookmark-jump)
1491 (defaults . ,defaults))))
1492
1493;;;###autoload
1494(defun vc-dir-bookmark-jump (bmk)
1495 "Provides the bookmark-jump behavior for a `vc-dir' buffer.
1496This implements the `handler' function interface for the record
1497type returned by `vc-dir-bookmark-make-record'."
1498 (let* ((file (bookmark-prop-get bmk 'filename))
1499 (buf (save-window-excursion
1500 (vc-dir file) (current-buffer))))
1501 (bookmark-default-handler
1502 `("" (buffer . ,buf) . ,(bookmark-get-bookmark-record bmk)))))
1503
1504
1469(provide 'vc-dir) 1505(provide 'vc-dir)
1470 1506
1471;;; vc-dir.el ends here 1507;;; vc-dir.el ends here
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 2caa287bce2..dcb52282656 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -72,6 +72,7 @@
72;; by git, so it's probably 72;; by git, so it's probably
73;; not a good idea. 73;; not a good idea.
74;; - merge-news (file) see `merge-file' 74;; - merge-news (file) see `merge-file'
75;; - mark-resolved (file) OK
75;; - steal-lock (file &optional revision) NOT NEEDED 76;; - steal-lock (file &optional revision) NOT NEEDED
76;; HISTORY FUNCTIONS 77;; HISTORY FUNCTIONS
77;; * print-log (files buffer &optional shortlog start-revision limit) OK 78;; * print-log (files buffer &optional shortlog start-revision limit) OK
@@ -1530,6 +1531,9 @@ This requires git 1.8.4 or later, for the \"-L\" option of \"git log\"."
1530(defun vc-git-rename-file (old new) 1531(defun vc-git-rename-file (old new)
1531 (vc-git-command nil 0 (list old new) "mv" "-f" "--")) 1532 (vc-git-command nil 0 (list old new) "mv" "-f" "--"))
1532 1533
1534(defun vc-git-mark-resolved (files)
1535 (vc-git-command nil 0 files "add"))
1536
1533(defvar vc-git-extra-menu-map 1537(defvar vc-git-extra-menu-map
1534 (let ((map (make-sparse-keymap))) 1538 (let ((map (make-sparse-keymap)))
1535 (define-key map [git-grep] 1539 (define-key map [git-grep]
diff --git a/lisp/vc/vc-hooks.el b/lisp/vc/vc-hooks.el
index 2ca9d3e620c..ce72a49b955 100644
--- a/lisp/vc/vc-hooks.el
+++ b/lisp/vc/vc-hooks.el
@@ -498,7 +498,7 @@ status of this file. Otherwise, the value returned is one of:
498 "Return the repository version from which FILE was checked out. 498 "Return the repository version from which FILE was checked out.
499If FILE is not registered, this function always returns nil." 499If FILE is not registered, this function always returns nil."
500 (or (vc-file-getprop file 'vc-working-revision) 500 (or (vc-file-getprop file 'vc-working-revision)
501 (progn 501 (let ((default-directory (file-name-directory file)))
502 (setq backend (or backend (vc-backend file))) 502 (setq backend (or backend (vc-backend file)))
503 (when backend 503 (when backend
504 (vc-file-setprop file 'vc-working-revision 504 (vc-file-setprop file 'vc-working-revision
diff --git a/lisp/version.el b/lisp/version.el
index 24da21c731c..b247232dcfd 100644
--- a/lisp/version.el
+++ b/lisp/version.el
@@ -163,8 +163,4 @@ correspond to the running Emacs.
163Optional argument DIR is a directory to use instead of `source-directory'." 163Optional argument DIR is a directory to use instead of `source-directory'."
164 (emacs-repository-branch-git (or dir source-directory))) 164 (emacs-repository-branch-git (or dir source-directory)))
165 165
166;; We put version info into the executable in the form that `ident' uses.
167(purecopy (concat "\n$Id: " (subst-char-in-string ?\n ?\s (emacs-version))
168 " $\n"))
169
170;;; version.el ends here 166;;; version.el ends here
diff --git a/lisp/xml.el b/lisp/xml.el
index dc774a202cf..767cf042846 100644
--- a/lisp/xml.el
+++ b/lisp/xml.el
@@ -1023,9 +1023,17 @@ entity references (e.g., replace each & with &amp;).
1023XML character data must not contain & or < characters, nor the > 1023XML character data must not contain & or < characters, nor the >
1024character under some circumstances. The XML spec does not impose 1024character under some circumstances. The XML spec does not impose
1025restriction on \" or \\=', but we just substitute for these too 1025restriction on \" or \\=', but we just substitute for these too
1026\(as is permitted by the spec)." 1026\(as is permitted by the spec).
1027
1028If STRING contains characters that are invalid in XML (as defined
1029by https://www.w3.org/TR/xml/#charsets), signal an error of type
1030`xml-invalid-character'."
1027 (with-temp-buffer 1031 (with-temp-buffer
1028 (insert string) 1032 (insert string)
1033 (goto-char (point-min))
1034 (when (re-search-forward
1035 "[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]")
1036 (signal 'xml-invalid-character (list (char-before) (match-beginning 0))))
1029 (dolist (substitution '(("&" . "&amp;") 1037 (dolist (substitution '(("&" . "&amp;")
1030 ("<" . "&lt;") 1038 ("<" . "&lt;")
1031 (">" . "&gt;") 1039 (">" . "&gt;")
@@ -1036,6 +1044,9 @@ restriction on \" or \\=', but we just substitute for these too
1036 (replace-match (cdr substitution) t t nil))) 1044 (replace-match (cdr substitution) t t nil)))
1037 (buffer-string))) 1045 (buffer-string)))
1038 1046
1047(define-error 'xml-invalid-character "Invalid XML character"
1048 'wrong-type-argument)
1049
1039(defun xml-debug-print-internal (xml indent-string) 1050(defun xml-debug-print-internal (xml indent-string)
1040 "Outputs the XML tree in the current buffer. 1051 "Outputs the XML tree in the current buffer.
1041The first line is indented with INDENT-STRING." 1052The first line is indented with INDENT-STRING."