aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorPaul Eggert2017-10-06 10:35:07 -0700
committerPaul Eggert2017-10-06 10:35:07 -0700
commit53da55b8cc45e76b836ebaadd23f46e92d25abce (patch)
tree107beb0cf1da6179656d035a42767345a7737639 /lisp
parent11f9cb522fed9aa6552f6315340ca7352661a1e8 (diff)
parent9226cf325421a168b42bd27abf5e171e877b48b9 (diff)
downloademacs-53da55b8cc45e76b836ebaadd23f46e92d25abce.tar.gz
emacs-53da55b8cc45e76b836ebaadd23f46e92d25abce.zip
Merge from origin/emacs-26
9226cf3254 Fix bug in recent styled_format change fa92f0c447 Cleanup emacs-lisp-mode's use of Flymake 0d0265bf50 Fix @include directive in Flymake doc 295457ae52 Move read-multiple-choice to its own library 560dd9b573 * src/process.c (syms_of_process): Remove duplicated call ...
Diffstat (limited to 'lisp')
-rw-r--r--lisp/emacs-lisp/rmc.el199
-rw-r--r--lisp/emacs-lisp/subr-x.el170
-rw-r--r--lisp/gnus/message.el2
-rw-r--r--lisp/net/nsm.el2
-rw-r--r--lisp/progmodes/elisp-mode.el120
5 files changed, 255 insertions, 238 deletions
diff --git a/lisp/emacs-lisp/rmc.el b/lisp/emacs-lisp/rmc.el
new file mode 100644
index 00000000000..417301cde06
--- /dev/null
+++ b/lisp/emacs-lisp/rmc.el
@@ -0,0 +1,199 @@
1;;; rmc.el --- read from a multiple choice question -*- lexical-binding: t -*-
2
3;; Copyright (C) 2017 Free Software Foundation, Inc.
4
5;; Maintainer: emacs-devel@gnu.org
6
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software: you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
11;; the Free Software Foundation, either version 3 of the License, or
12;; (at your option) any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
20;; along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22;;; Commentary:
23
24;;; Code:
25
26;;;###autoload
27(defun read-multiple-choice (prompt choices)
28 "Ask user a multiple choice question.
29PROMPT should be a string that will be displayed as the prompt.
30
31CHOICES is an alist where the first element in each entry is a
32character to be entered, the second element is a short name for
33the entry to be displayed while prompting (if there's room, it
34might be shortened), and the third, optional entry is a longer
35explanation that will be displayed in a help buffer if the user
36requests more help.
37
38This function translates user input into responses by consulting
39the bindings in `query-replace-map'; see the documentation of
40that variable for more information. In this case, the useful
41bindings are `recenter', `scroll-up', and `scroll-down'. If the
42user enters `recenter', `scroll-up', or `scroll-down' responses,
43perform the requested window recentering or scrolling and ask
44again.
45
46When `use-dialog-box' is t (the default), this function can pop
47up a dialog window to collect the user input. That functionality
48requires `display-popup-menus-p' to return t. Otherwise, a text
49dialog will be used.
50
51The return value is the matching entry from the CHOICES list.
52
53Usage example:
54
55\(read-multiple-choice \"Continue connecting?\"
56 \\='((?a \"always\")
57 (?s \"session only\")
58 (?n \"no\")))"
59 (let* ((altered-names nil)
60 (full-prompt
61 (format
62 "%s (%s): "
63 prompt
64 (mapconcat
65 (lambda (elem)
66 (let* ((name (cadr elem))
67 (pos (seq-position name (car elem)))
68 (altered-name
69 (cond
70 ;; Not in the name string.
71 ((not pos)
72 (format "[%c] %s" (car elem) name))
73 ;; The prompt character is in the name, so highlight
74 ;; it on graphical terminals...
75 ((display-supports-face-attributes-p
76 '(:underline t) (window-frame))
77 (setq name (copy-sequence name))
78 (put-text-property pos (1+ pos)
79 'face 'read-multiple-choice-face
80 name)
81 name)
82 ;; And put it in [bracket] on non-graphical terminals.
83 (t
84 (concat
85 (substring name 0 pos)
86 "["
87 (upcase (substring name pos (1+ pos)))
88 "]"
89 (substring name (1+ pos)))))))
90 (push (cons (car elem) altered-name)
91 altered-names)
92 altered-name))
93 (append choices '((?? "?")))
94 ", ")))
95 tchar buf wrong-char answer)
96 (save-window-excursion
97 (save-excursion
98 (while (not tchar)
99 (message "%s%s"
100 (if wrong-char
101 "Invalid choice. "
102 "")
103 full-prompt)
104 (setq tchar
105 (if (and (display-popup-menus-p)
106 last-input-event ; not during startup
107 (listp last-nonmenu-event)
108 use-dialog-box)
109 (x-popup-dialog
110 t
111 (cons prompt
112 (mapcar
113 (lambda (elem)
114 (cons (capitalize (cadr elem))
115 (car elem)))
116 choices)))
117 (condition-case nil
118 (let ((cursor-in-echo-area t))
119 (read-char))
120 (error nil))))
121 (setq answer (lookup-key query-replace-map (vector tchar) t))
122 (setq tchar
123 (cond
124 ((eq answer 'recenter)
125 (recenter) t)
126 ((eq answer 'scroll-up)
127 (ignore-errors (scroll-up-command)) t)
128 ((eq answer 'scroll-down)
129 (ignore-errors (scroll-down-command)) t)
130 ((eq answer 'scroll-other-window)
131 (ignore-errors (scroll-other-window)) t)
132 ((eq answer 'scroll-other-window-down)
133 (ignore-errors (scroll-other-window-down)) t)
134 (t tchar)))
135 (when (eq tchar t)
136 (setq wrong-char nil
137 tchar nil))
138 ;; The user has entered an invalid choice, so display the
139 ;; help messages.
140 (when (and (not (eq tchar nil))
141 (not (assq tchar choices)))
142 (setq wrong-char (not (memq tchar '(?? ?\C-h)))
143 tchar nil)
144 (when wrong-char
145 (ding))
146 (with-help-window (setq buf (get-buffer-create
147 "*Multiple Choice Help*"))
148 (with-current-buffer buf
149 (erase-buffer)
150 (pop-to-buffer buf)
151 (insert prompt "\n\n")
152 (let* ((columns (/ (window-width) 25))
153 (fill-column 21)
154 (times 0)
155 (start (point)))
156 (dolist (elem choices)
157 (goto-char start)
158 (unless (zerop times)
159 (if (zerop (mod times columns))
160 ;; Go to the next "line".
161 (goto-char (setq start (point-max)))
162 ;; Add padding.
163 (while (not (eobp))
164 (end-of-line)
165 (insert (make-string (max (- (* (mod times columns)
166 (+ fill-column 4))
167 (current-column))
168 0)
169 ?\s))
170 (forward-line 1))))
171 (setq times (1+ times))
172 (let ((text
173 (with-temp-buffer
174 (insert (format
175 "%c: %s\n"
176 (car elem)
177 (cdr (assq (car elem) altered-names))))
178 (fill-region (point-min) (point-max))
179 (when (nth 2 elem)
180 (let ((start (point)))
181 (insert (nth 2 elem))
182 (unless (bolp)
183 (insert "\n"))
184 (fill-region start (point-max))))
185 (buffer-string))))
186 (goto-char start)
187 (dolist (line (split-string text "\n"))
188 (end-of-line)
189 (if (bolp)
190 (insert line "\n")
191 (insert line))
192 (forward-line 1)))))))))))
193 (when (buffer-live-p buf)
194 (kill-buffer buf))
195 (assq tchar choices)))
196
197(provide 'rmc)
198
199;;; rmc.el ends here
diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 5189cc4a6e8..8ed29d8659d 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -245,176 +245,6 @@ TRIM-LEFT and TRIM-RIGHT default to \"[ \\t\\n\\r]+\"."
245 (substring string 0 (- (length string) (length suffix))) 245 (substring string 0 (- (length string) (length suffix)))
246 string)) 246 string))
247 247
248(defun read-multiple-choice (prompt choices)
249 "Ask user a multiple choice question.
250PROMPT should be a string that will be displayed as the prompt.
251
252CHOICES is an alist where the first element in each entry is a
253character to be entered, the second element is a short name for
254the entry to be displayed while prompting (if there's room, it
255might be shortened), and the third, optional entry is a longer
256explanation that will be displayed in a help buffer if the user
257requests more help.
258
259This function translates user input into responses by consulting
260the bindings in `query-replace-map'; see the documentation of
261that variable for more information. In this case, the useful
262bindings are `recenter', `scroll-up', and `scroll-down'. If the
263user enters `recenter', `scroll-up', or `scroll-down' responses,
264perform the requested window recentering or scrolling and ask
265again.
266
267When `use-dialog-box' is t (the default), this function can pop
268up a dialog window to collect the user input. That functionality
269requires `display-popup-menus-p' to return t. Otherwise, a text
270dialog will be used.
271
272The return value is the matching entry from the CHOICES list.
273
274Usage example:
275
276\(read-multiple-choice \"Continue connecting?\"
277 \\='((?a \"always\")
278 (?s \"session only\")
279 (?n \"no\")))"
280 (let* ((altered-names nil)
281 (full-prompt
282 (format
283 "%s (%s): "
284 prompt
285 (mapconcat
286 (lambda (elem)
287 (let* ((name (cadr elem))
288 (pos (seq-position name (car elem)))
289 (altered-name
290 (cond
291 ;; Not in the name string.
292 ((not pos)
293 (format "[%c] %s" (car elem) name))
294 ;; The prompt character is in the name, so highlight
295 ;; it on graphical terminals...
296 ((display-supports-face-attributes-p
297 '(:underline t) (window-frame))
298 (setq name (copy-sequence name))
299 (put-text-property pos (1+ pos)
300 'face 'read-multiple-choice-face
301 name)
302 name)
303 ;; And put it in [bracket] on non-graphical terminals.
304 (t
305 (concat
306 (substring name 0 pos)
307 "["
308 (upcase (substring name pos (1+ pos)))
309 "]"
310 (substring name (1+ pos)))))))
311 (push (cons (car elem) altered-name)
312 altered-names)
313 altered-name))
314 (append choices '((?? "?")))
315 ", ")))
316 tchar buf wrong-char answer)
317 (save-window-excursion
318 (save-excursion
319 (while (not tchar)
320 (message "%s%s"
321 (if wrong-char
322 "Invalid choice. "
323 "")
324 full-prompt)
325 (setq tchar
326 (if (and (display-popup-menus-p)
327 last-input-event ; not during startup
328 (listp last-nonmenu-event)
329 use-dialog-box)
330 (x-popup-dialog
331 t
332 (cons prompt
333 (mapcar
334 (lambda (elem)
335 (cons (capitalize (cadr elem))
336 (car elem)))
337 choices)))
338 (condition-case nil
339 (let ((cursor-in-echo-area t))
340 (read-char))
341 (error nil))))
342 (setq answer (lookup-key query-replace-map (vector tchar) t))
343 (setq tchar
344 (cond
345 ((eq answer 'recenter)
346 (recenter) t)
347 ((eq answer 'scroll-up)
348 (ignore-errors (scroll-up-command)) t)
349 ((eq answer 'scroll-down)
350 (ignore-errors (scroll-down-command)) t)
351 ((eq answer 'scroll-other-window)
352 (ignore-errors (scroll-other-window)) t)
353 ((eq answer 'scroll-other-window-down)
354 (ignore-errors (scroll-other-window-down)) t)
355 (t tchar)))
356 (when (eq tchar t)
357 (setq wrong-char nil
358 tchar nil))
359 ;; The user has entered an invalid choice, so display the
360 ;; help messages.
361 (when (and (not (eq tchar nil))
362 (not (assq tchar choices)))
363 (setq wrong-char (not (memq tchar '(?? ?\C-h)))
364 tchar nil)
365 (when wrong-char
366 (ding))
367 (with-help-window (setq buf (get-buffer-create
368 "*Multiple Choice Help*"))
369 (with-current-buffer buf
370 (erase-buffer)
371 (pop-to-buffer buf)
372 (insert prompt "\n\n")
373 (let* ((columns (/ (window-width) 25))
374 (fill-column 21)
375 (times 0)
376 (start (point)))
377 (dolist (elem choices)
378 (goto-char start)
379 (unless (zerop times)
380 (if (zerop (mod times columns))
381 ;; Go to the next "line".
382 (goto-char (setq start (point-max)))
383 ;; Add padding.
384 (while (not (eobp))
385 (end-of-line)
386 (insert (make-string (max (- (* (mod times columns)
387 (+ fill-column 4))
388 (current-column))
389 0)
390 ?\s))
391 (forward-line 1))))
392 (setq times (1+ times))
393 (let ((text
394 (with-temp-buffer
395 (insert (format
396 "%c: %s\n"
397 (car elem)
398 (cdr (assq (car elem) altered-names))))
399 (fill-region (point-min) (point-max))
400 (when (nth 2 elem)
401 (let ((start (point)))
402 (insert (nth 2 elem))
403 (unless (bolp)
404 (insert "\n"))
405 (fill-region start (point-max))))
406 (buffer-string))))
407 (goto-char start)
408 (dolist (line (split-string text "\n"))
409 (end-of-line)
410 (if (bolp)
411 (insert line "\n")
412 (insert line))
413 (forward-line 1)))))))))))
414 (when (buffer-live-p buf)
415 (kill-buffer buf))
416 (assq tchar choices)))
417
418(provide 'subr-x) 248(provide 'subr-x)
419 249
420;;; subr-x.el ends here 250;;; subr-x.el ends here
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index ed0b3cb44fc..7dc9dd7b13c 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -49,7 +49,7 @@
49(require 'mm-util) 49(require 'mm-util)
50(require 'rfc2047) 50(require 'rfc2047)
51(require 'puny) 51(require 'puny)
52(require 'subr-x) ; read-multiple-choice 52(require 'rmc) ; read-multiple-choice
53 53
54(autoload 'mailclient-send-it "mailclient") 54(autoload 'mailclient-send-it "mailclient")
55 55
diff --git a/lisp/net/nsm.el b/lisp/net/nsm.el
index e2053a09355..87fa9778b6d 100644
--- a/lisp/net/nsm.el
+++ b/lisp/net/nsm.el
@@ -25,7 +25,7 @@
25;;; Code: 25;;; Code:
26 26
27(require 'cl-lib) 27(require 'cl-lib)
28(require 'subr-x) ; read-multiple-choice 28(require 'rmc) ; read-multiple-choice
29 29
30(defvar nsm-permanent-host-settings nil) 30(defvar nsm-permanent-host-settings nil)
31(defvar nsm-temporary-host-settings nil) 31(defvar nsm-temporary-host-settings nil)
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 3690f673832..99a4841e318 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -1599,8 +1599,11 @@ ARGLIST is either a string, or a list of strings or symbols."
1599(defvar checkdoc-autofix-flag) 1599(defvar checkdoc-autofix-flag)
1600(defvar checkdoc-generate-compile-warnings-flag) 1600(defvar checkdoc-generate-compile-warnings-flag)
1601(defvar checkdoc-diagnostic-buffer) 1601(defvar checkdoc-diagnostic-buffer)
1602(defun elisp-flymake--checkdoc-1 () 1602
1603 "Do actual work for `elisp-flymake-checkdoc'." 1603;;;###autoload
1604(defun elisp-flymake-checkdoc (report-fn &rest _args)
1605 "A Flymake backend for `checkdoc'.
1606Calls REPORT-FN directly."
1604 (let (collected) 1607 (let (collected)
1605 (let* ((checkdoc-create-error-function 1608 (let* ((checkdoc-create-error-function
1606 (lambda (text start end &optional unfixable) 1609 (lambda (text start end &optional unfixable)
@@ -1608,63 +1611,52 @@ ARGLIST is either a string, or a list of strings or symbols."
1608 nil)) 1611 nil))
1609 (checkdoc-autofix-flag nil) 1612 (checkdoc-autofix-flag nil)
1610 (checkdoc-generate-compile-warnings-flag nil) 1613 (checkdoc-generate-compile-warnings-flag nil)
1611 (buf (generate-new-buffer " *checkdoc-temp*")) 1614 (checkdoc-diagnostic-buffer
1612 (checkdoc-diagnostic-buffer buf)) 1615 (generate-new-buffer " *checkdoc-temp*")))
1613 (unwind-protect 1616 (unwind-protect
1614 (save-excursion 1617 (save-excursion
1615 (checkdoc-current-buffer t)) 1618 (checkdoc-current-buffer t))
1616 (kill-buffer buf))) 1619 (kill-buffer checkdoc-diagnostic-buffer)))
1620 (funcall report-fn
1621 (cl-loop for (text start end _unfixable) in
1622 collected
1623 collect
1624 (flymake-make-diagnostic
1625 (current-buffer)
1626 start end :note text)))
1617 collected)) 1627 collected))
1618 1628
1619;;;###autoload
1620(defun elisp-flymake-checkdoc (report-fn &rest _args)
1621 "A Flymake backend for `checkdoc'.
1622Calls REPORT-FN directly."
1623 (unless (derived-mode-p 'emacs-lisp-mode)
1624 (error "Can only work on `emacs-lisp-mode' buffers"))
1625 (funcall report-fn
1626 (cl-loop for (text start end _unfixable) in
1627 (elisp-flymake--checkdoc-1)
1628 collect
1629 (flymake-make-diagnostic
1630 (current-buffer)
1631 start end :note text))))
1632
1633(defun elisp-flymake--byte-compile-done (report-fn 1629(defun elisp-flymake--byte-compile-done (report-fn
1634 origin-buffer 1630 source-buffer
1635 output-buffer 1631 output-buffer)
1636 temp-file) 1632 (with-current-buffer
1637 (unwind-protect 1633 source-buffer
1638 (with-current-buffer 1634 (save-excursion
1639 origin-buffer 1635 (save-restriction
1640 (save-excursion 1636 (widen)
1641 (save-restriction 1637 (funcall
1642 (widen) 1638 report-fn
1643 (funcall 1639 (cl-loop with data =
1644 report-fn 1640 (with-current-buffer output-buffer
1645 (cl-loop with data = 1641 (goto-char (point-min))
1646 (with-current-buffer output-buffer 1642 (search-forward ":elisp-flymake-output-start")
1647 (goto-char (point-min)) 1643 (read (point-marker)))
1648 (search-forward ":elisp-flymake-output-start") 1644 for (string pos _fill level) in data
1649 (read (point-marker))) 1645 do (goto-char pos)
1650 for (string pos _fill level) in data 1646 for beg = (if (< (point) (point-max))
1651 do (goto-char pos) 1647 (point)
1652 for beg = (if (< (point) (point-max)) 1648 (line-beginning-position))
1653 (point) 1649 for end = (min
1654 (line-beginning-position)) 1650 (line-end-position)
1655 for end = (min 1651 (or (cdr
1656 (line-end-position) 1652 (bounds-of-thing-at-point 'sexp))
1657 (or (cdr 1653 (point-max)))
1658 (bounds-of-thing-at-point 'sexp)) 1654 collect (flymake-make-diagnostic
1659 (point-max))) 1655 (current-buffer)
1660 collect (flymake-make-diagnostic 1656 (if (= beg end) (1- beg) beg)
1661 (current-buffer) 1657 end
1662 (if (= beg end) (1- beg) beg) 1658 level
1663 end 1659 string)))))))
1664 level
1665 string))))))
1666 (kill-buffer output-buffer)
1667 (ignore-errors (delete-file temp-file))))
1668 1660
1669(defvar-local elisp-flymake--byte-compile-process nil 1661(defvar-local elisp-flymake--byte-compile-process nil
1670 "Buffer-local process started for byte-compiling the buffer.") 1662 "Buffer-local process started for byte-compiling the buffer.")
@@ -1674,16 +1666,11 @@ Calls REPORT-FN directly."
1674 "A Flymake backend for elisp byte compilation. 1666 "A Flymake backend for elisp byte compilation.
1675Spawn an Emacs process that byte-compiles a file representing the 1667Spawn an Emacs process that byte-compiles a file representing the
1676current buffer state and calls REPORT-FN when done." 1668current buffer state and calls REPORT-FN when done."
1677 (interactive (list (lambda (stuff)
1678 (message "aha %s" stuff))))
1679 (unless (derived-mode-p 'emacs-lisp-mode)
1680 (error "Can only work on `emacs-lisp-mode' buffers"))
1681 (when elisp-flymake--byte-compile-process 1669 (when elisp-flymake--byte-compile-process
1682 (process-put elisp-flymake--byte-compile-process 'elisp-flymake--obsolete t)
1683 (when (process-live-p elisp-flymake--byte-compile-process) 1670 (when (process-live-p elisp-flymake--byte-compile-process)
1684 (kill-process elisp-flymake--byte-compile-process))) 1671 (kill-process elisp-flymake--byte-compile-process)))
1685 (let ((temp-file (make-temp-file "elisp-flymake-byte-compile")) 1672 (let ((temp-file (make-temp-file "elisp-flymake-byte-compile"))
1686 (origin-buffer (current-buffer))) 1673 (source-buffer (current-buffer)))
1687 (save-restriction 1674 (save-restriction
1688 (widen) 1675 (widen)
1689 (write-region (point-min) (point-max) temp-file nil 'nomessage)) 1676 (write-region (point-min) (point-max) temp-file nil 'nomessage))
@@ -1703,21 +1690,22 @@ current buffer state and calls REPORT-FN when done."
1703 :connection-type 'pipe 1690 :connection-type 'pipe
1704 :sentinel 1691 :sentinel
1705 (lambda (proc _event) 1692 (lambda (proc _event)
1706 (unless (process-live-p proc) 1693 (when (eq (process-status proc) 'exit)
1707 (unwind-protect 1694 (unwind-protect
1708 (cond 1695 (cond
1696 ((not (eq proc elisp-flymake--byte-compile-process))
1697 (flymake-log :warning "byte-compile process %s obsolete" proc))
1709 ((zerop (process-exit-status proc)) 1698 ((zerop (process-exit-status proc))
1710 (elisp-flymake--byte-compile-done report-fn 1699 (elisp-flymake--byte-compile-done report-fn
1711 origin-buffer 1700 source-buffer
1712 output-buffer 1701 output-buffer))
1713 temp-file))
1714 ((process-get proc 'elisp-flymake--obsolete)
1715 (flymake-log :warning "byte-compile process %s obsolete" proc))
1716 (t 1702 (t
1717 (funcall report-fn 1703 (funcall report-fn
1718 :panic 1704 :panic
1719 :explanation 1705 :explanation
1720 (format "byte-compile process %s died" proc))))))))) 1706 (format "byte-compile process %s died" proc))))
1707 (ignore-errors (delete-file temp-file))
1708 (kill-buffer output-buffer))))))
1721 :stderr null-device 1709 :stderr null-device
1722 :noquery t))) 1710 :noquery t)))
1723 1711