diff options
| author | Wolfgang Jenkner | 2013-01-10 10:01:35 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2013-01-10 10:01:35 -0500 |
| commit | 327a6ccaa01cdcd220e74df4f71acf0ad7e92f5f (patch) | |
| tree | ff27057bd411d31de8cc44960650ba210d7c1747 | |
| parent | ed9112575ebdf0fefec530d7b2687f83eea7bb8a (diff) | |
| download | emacs-327a6ccaa01cdcd220e74df4f71acf0ad7e92f5f.tar.gz emacs-327a6ccaa01cdcd220e74df4f71acf0ad7e92f5f.zip | |
* lisp/man.el: Handle different "man -k" behaviors. Use utf-8.
(Man-man-k-use-anchor): New var.
(Man-parse-man-k): New function.
(Man-completion-table): Use it.
(man): Flush the completion cache between uses.
* test/automated/man-tests.el: New file.
Fixes: debbugs:13160
| -rw-r--r-- | lisp/ChangeLog | 8 | ||||
| -rw-r--r-- | lisp/man.el | 79 | ||||
| -rw-r--r-- | test/ChangeLog | 4 | ||||
| -rw-r--r-- | test/automated/man-tests.el | 118 |
4 files changed, 196 insertions, 13 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 507550dbec0..f26c009bf2b 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,11 @@ | |||
| 1 | 2013-01-10 Wolfgang Jenkner <wjenkner@inode.at> | ||
| 2 | |||
| 3 | * man.el: Handle different "man -k" behaviors (bug#13160). Use utf-8. | ||
| 4 | (Man-man-k-use-anchor): New var. | ||
| 5 | (Man-parse-man-k): New function. | ||
| 6 | (Man-completion-table): Use it. | ||
| 7 | (man): Flush the completion cache between uses. | ||
| 8 | |||
| 1 | 2013-01-10 Michael Albinus <michael.albinus@gmx.de> | 9 | 2013-01-10 Michael Albinus <michael.albinus@gmx.de> |
| 2 | 10 | ||
| 3 | * autorevert.el: Add file watch support. | 11 | * autorevert.el: Add file watch support. |
diff --git a/lisp/man.el b/lisp/man.el index b6a6c179374..93a67128de4 100644 --- a/lisp/man.el +++ b/lisp/man.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; man.el --- browse UNIX manual pages -*- coding: iso-8859-1 -*- | 1 | ;;; man.el --- browse UNIX manual pages -*- coding: utf-8 -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 1993-1994, 1996-1997, 2001-2013 Free Software | 3 | ;; Copyright (C) 1993-1994, 1996-1997, 2001-2013 Free Software |
| 4 | ;; Foundation, Inc. | 4 | ;; Foundation, Inc. |
| @@ -276,7 +276,7 @@ Used in `bookmark-set' to get the default bookmark name." | |||
| 276 | :type 'hook | 276 | :type 'hook |
| 277 | :group 'man) | 277 | :group 'man) |
| 278 | 278 | ||
| 279 | (defvar Man-name-regexp "[-a-zA-Z0-9_+][-a-zA-Z0-9_.:+]*" | 279 | (defvar Man-name-regexp "[-a-zA-Z0-9_Â+][-a-zA-Z0-9_.:Â+]*" |
| 280 | "Regular expression describing the name of a manpage (without section).") | 280 | "Regular expression describing the name of a manpage (without section).") |
| 281 | 281 | ||
| 282 | (defvar Man-section-regexp "[0-9][a-zA-Z0-9+]*\\|[LNln]" | 282 | (defvar Man-section-regexp "[0-9][a-zA-Z0-9+]*\\|[LNln]" |
| @@ -780,6 +780,59 @@ POS defaults to `point'." | |||
| 780 | ;; but apparently that's not the case in all cases, so let's add a cache. | 780 | ;; but apparently that's not the case in all cases, so let's add a cache. |
| 781 | "Cache of completion table of the form (PREFIX . TABLE).") | 781 | "Cache of completion table of the form (PREFIX . TABLE).") |
| 782 | 782 | ||
| 783 | (defvar Man-man-k-use-anchor | ||
| 784 | ;; man-db or man-1.* | ||
| 785 | (memq system-type '(gnu gnu/linux gnu/kfreebsd)) | ||
| 786 | "If non-nil prepend ^ to the prefix passed to \"man -k\" for completion. | ||
| 787 | The value should be nil if \"man -k ^PREFIX\" may omit some man | ||
| 788 | pages whose names start with PREFIX. | ||
| 789 | |||
| 790 | Currently, the default value depends on `system-type' and is | ||
| 791 | non-nil where the standard man programs are known to behave | ||
| 792 | properly. Setting the value to nil always gives correct results | ||
| 793 | but computing the list of completions may take a bit longer.") | ||
| 794 | |||
| 795 | (defun Man-parse-man-k () | ||
| 796 | "Parse \"man -k\" output and return the list of page names. | ||
| 797 | |||
| 798 | The current buffer should contain the output of a command of the | ||
| 799 | form \"man -k keyword\", which is traditionally also available with | ||
| 800 | apropos(1). | ||
| 801 | |||
| 802 | While POSIX man(1p) is a bit vague about what to expect here, | ||
| 803 | this function tries to parse some commonly used formats, which | ||
| 804 | can be described in the following informal way, with square brackets | ||
| 805 | indicating optional parts and whitespace being interpreted | ||
| 806 | somewhat loosely. | ||
| 807 | |||
| 808 | foo[, bar [, ...]] [other stuff] (sec) - description | ||
| 809 | foo(sec)[, bar(sec) [, ...]] [other stuff] - description | ||
| 810 | |||
| 811 | For more details and some regression tests, please see | ||
| 812 | test/automated/man-tests.el in the emacs bzr repository." | ||
| 813 | (goto-char (point-min)) | ||
| 814 | ;; See man-tests for data about which systems use which format (hopefully we | ||
| 815 | ;; will be able to simplify the code if/when some of those formats aren't | ||
| 816 | ;; used any more). | ||
| 817 | (let (table) | ||
| 818 | (while (search-forward-regexp "^\\([^ \t,\n]+\\)\\(.*?\\)\ | ||
| 819 | \\(?:[ \t]\\(([^ \t,\n]+?)\\)\\)?\\(?:[ \t]+- ?\\(.*\\)\\)?$" nil t) | ||
| 820 | (let ((section (match-string 3)) | ||
| 821 | (description (match-string 4)) | ||
| 822 | (bound (match-end 2))) | ||
| 823 | (goto-char (match-end 1)) | ||
| 824 | (while | ||
| 825 | (progn | ||
| 826 | ;; The first regexp grouping may already match the section | ||
| 827 | ;; tacked on to the name, which is ok since for the formats we | ||
| 828 | ;; claim to support the third (non-shy) grouping does not | ||
| 829 | ;; match in this case, i.e., section is nil. | ||
| 830 | (push (propertize (concat (match-string 1) section) | ||
| 831 | 'help-echo description) | ||
| 832 | table) | ||
| 833 | (search-forward-regexp "\\=, *\\([^ \t,]+\\)" bound t))))) | ||
| 834 | (nreverse table))) | ||
| 835 | |||
| 783 | (defun Man-completion-table (string pred action) | 836 | (defun Man-completion-table (string pred action) |
| 784 | (cond | 837 | (cond |
| 785 | ;; This ends up returning t for pretty much any string, and hence leads to | 838 | ;; This ends up returning t for pretty much any string, and hence leads to |
| @@ -811,16 +864,15 @@ POS defaults to `point'." | |||
| 811 | ;; run differently in Man-getpage-in-background, an error | 864 | ;; run differently in Man-getpage-in-background, an error |
| 812 | ;; here may not necessarily mean that we'll also get an | 865 | ;; here may not necessarily mean that we'll also get an |
| 813 | ;; error later. | 866 | ;; error later. |
| 814 | (ignore-errors | 867 | (ignore-errors |
| 815 | (call-process manual-program nil '(t nil) nil | 868 | (call-process manual-program nil '(t nil) nil |
| 816 | "-k" (concat "^" prefix)))) | 869 | "-k" (concat (when (or Man-man-k-use-anchor |
| 817 | (goto-char (point-min)) | 870 | (string-equal prefix "")) |
| 818 | (while (re-search-forward "^\\([^ \t\n]+\\)\\(?: ?\\((.+?)\\)\\(?:[ \t]+- \\(.*\\)\\)?\\)?" nil t) | 871 | "^") |
| 819 | (push (propertize (concat (match-string 1) (match-string 2)) | 872 | prefix)))) |
| 820 | 'help-echo (match-string 3)) | 873 | (setq table (Man-parse-man-k))) |
| 821 | table))) | 874 | ;; Cache the table for later reuse. |
| 822 | ;; Cache the table for later reuse. | 875 | (setq Man-completion-cache (cons prefix table))) |
| 823 | (setq Man-completion-cache (cons prefix table))) | ||
| 824 | ;; The table may contain false positives since the match is made | 876 | ;; The table may contain false positives since the match is made |
| 825 | ;; by "man -k" not just on the manpage's name. | 877 | ;; by "man -k" not just on the manpage's name. |
| 826 | (if section | 878 | (if section |
| @@ -891,6 +943,7 @@ names or descriptions. The pattern argument is usually an | |||
| 891 | ;; ("man -k" is case-insensitive similarly, so the | 943 | ;; ("man -k" is case-insensitive similarly, so the |
| 892 | ;; table has everything available to complete) | 944 | ;; table has everything available to complete) |
| 893 | (completion-ignore-case t) | 945 | (completion-ignore-case t) |
| 946 | Man-completion-cache ;Don't cache across calls. | ||
| 894 | (input (completing-read | 947 | (input (completing-read |
| 895 | (format "Manual entry%s" | 948 | (format "Manual entry%s" |
| 896 | (if (string= default-entry "") | 949 | (if (string= default-entry "") |
| @@ -1395,7 +1448,7 @@ The following key bindings are currently in effect in the buffer: | |||
| 1395 | ;; Update len, in case a reference spans | 1448 | ;; Update len, in case a reference spans |
| 1396 | ;; more than two lines (paranoia). | 1449 | ;; more than two lines (paranoia). |
| 1397 | len (1- (length word)))) | 1450 | len (1- (length word)))) |
| 1398 | (if (memq (aref word len) '(?- ?)) | 1451 | (if (memq (aref word len) '(?- ?Â)) |
| 1399 | (setq hyphenated (substring word 0 len))) | 1452 | (setq hyphenated (substring word 0 len))) |
| 1400 | (and (string-match Man-reference-regexp word) | 1453 | (and (string-match Man-reference-regexp word) |
| 1401 | (not (member word Man--refpages)) | 1454 | (not (member word Man--refpages)) |
diff --git a/test/ChangeLog b/test/ChangeLog index c409e891d97..7b058c1d2bd 100644 --- a/test/ChangeLog +++ b/test/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2013-01-10 Wolfgang Jenkner <wjenkner@inode.at> | ||
| 2 | |||
| 3 | * automated/man-tests.el: New file. | ||
| 4 | |||
| 1 | 2013-01-09 Aaron S. Hawley <aaron.s.hawley@gmail.com> | 5 | 2013-01-09 Aaron S. Hawley <aaron.s.hawley@gmail.com> |
| 2 | 6 | ||
| 3 | * automated/undo-tests.el (undo-test0): Adjust error to code change. | 7 | * automated/undo-tests.el (undo-test0): Adjust error to code change. |
diff --git a/test/automated/man-tests.el b/test/automated/man-tests.el new file mode 100644 index 00000000000..8a2ec953002 --- /dev/null +++ b/test/automated/man-tests.el | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | ;;; man-tests.el --- Test suite for man. | ||
| 2 | |||
| 3 | ;; Copyright (C) 2013 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Wolfgang Jenkner <wjenkner@inode.at> | ||
| 6 | ;; Keywords: help, internal, unix | ||
| 7 | |||
| 8 | ;; This file is part of GNU Emacs. | ||
| 9 | |||
| 10 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 11 | ;; it under the terms of the GNU General Public License as published by | ||
| 12 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 13 | ;; (at your option) any later version. | ||
| 14 | |||
| 15 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | ;; GNU General Public License for more details. | ||
| 19 | |||
| 20 | ;; You should have received a copy of the GNU General Public License | ||
| 21 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | ||
| 22 | |||
| 23 | ;;; Code: | ||
| 24 | |||
| 25 | (require 'ert) | ||
| 26 | (require 'man) | ||
| 27 | |||
| 28 | (defconst man-tests-parse-man-k-tests | ||
| 29 | '(;; GNU/Linux: man-db-2.6.1 | ||
| 30 | ("\ | ||
| 31 | sin (3) - sine function | ||
| 32 | sinf (3) - sine function | ||
| 33 | sinl (3) - sine function" | ||
| 34 | . (#("sin(3)" 0 6 (help-echo "sine function")) #("sinf(3)" 0 7 (help-echo "sine function")) #("sinl(3)" 0 7 (help-echo "sine function")))) | ||
| 35 | ;; GNU/Linux: man-1.6g | ||
| 36 | ("\ | ||
| 37 | sin (3) - sine function | ||
| 38 | sinf [sin] (3) - sine function | ||
| 39 | sinl [sin] (3) - sine function" | ||
| 40 | . (#("sin(3)" 0 6 (help-echo "sine function")) #("sinf(3)" 0 7 (help-echo "sine function")) #("sinl(3)" 0 7 (help-echo "sine function")))) | ||
| 41 | ;; FreeBSD 9 | ||
| 42 | ("\ | ||
| 43 | sin(3), sinf(3), sinl(3) - sine functions" | ||
| 44 | . (#("sin(3)" 0 6 (help-echo "sine functions")) #("sinf(3)" 0 7 (help-echo "sine functions")) #("sinl(3)" 0 7 (help-echo "sine functions")))) | ||
| 45 | ;; SunOS, Solaris | ||
| 46 | ;; http://docs.oracle.com/cd/E19455-01/805-6331/usradm-7/index.html | ||
| 47 | ;; SunOS 4 | ||
| 48 | ("\ | ||
| 49 | tset, reset (1) - establish or restore terminal characteristics" | ||
| 50 | . (#("tset(1)" 0 7 (help-echo "establish or restore terminal characteristics")) #("reset(1)" 0 8 (help-echo "establish or restore terminal characteristics")))) | ||
| 51 | ;; SunOS 5.7, Solaris | ||
| 52 | ("\ | ||
| 53 | reset tset (1b) - establish or restore terminal characteristics | ||
| 54 | tset tset (1b) - establish or restore terminal characteristics" | ||
| 55 | . (#("reset(1b)" 0 8 (help-echo "establish or restore terminal characteristics")) #("tset(1b)" 0 7 (help-echo "establish or restore terminal characteristics")))) | ||
| 56 | ;; Minix 3 | ||
| 57 | ;; http://www.minix3.org/manpages/html5/whatis.html | ||
| 58 | ("\ | ||
| 59 | cawf, nroff (1) - C version of the nroff-like, Amazingly Workable (text) Formatter | ||
| 60 | whatis (5) - database of online manual pages" | ||
| 61 | . (#("cawf(1)" 0 7 (help-echo "C version of the nroff-like, Amazingly Workable (text) Formatter")) #("nroff(1)" 0 8 (help-echo "C version of the nroff-like, Amazingly Workable (text) Formatter")) #("whatis(5)" 0 9 (help-echo "database of online manual pages")))) | ||
| 62 | ;; HP-UX | ||
| 63 | ;; http://docstore.mik.ua/manuals/hp-ux/en/B2355-60130/man.1.html | ||
| 64 | ;; Assuming that the line break in the zgrep description was | ||
| 65 | ;; introduced by the man page formatting. | ||
| 66 | ("\ | ||
| 67 | grep, egrep, fgrep (1) - search a file for a pattern | ||
| 68 | zgrep(1) - search possibly compressed files for a regular expression" | ||
| 69 | . (#("grep(1)" 0 7 (help-echo "search a file for a pattern")) #("egrep(1)" 0 8 (help-echo "search a file for a pattern")) #("fgrep(1)" 0 8 (help-echo "search a file for a pattern")) #("zgrep(1)" 0 8 (help-echo "search possibly compressed files for a regular expression")))) | ||
| 70 | ;; AIX | ||
| 71 | ;; http://pic.dhe.ibm.com/infocenter/aix/v7r1/topic/com.ibm.aix.cmds/doc/aixcmds6/whatis.htm | ||
| 72 | ("\ | ||
| 73 | ls(1) -Displays the contents of a directory." | ||
| 74 | . (#("ls(1)" 0 5 (help-echo "Displays the contents of a directory.")))) | ||
| 75 | ;; https://www.ibm.com/developerworks/mydeveloperworks/blogs/cgaix/entry/catman_0703_102_usr_lbin_mkwhatis_the_error_number_is_1?lang=en | ||
| 76 | ("\ | ||
| 77 | loopmount(1) - Associate an image file to a loopback device." | ||
| 78 | . (#("loopmount(1)" 0 12 (help-echo "Associate an image file to a loopback device.")))) | ||
| 79 | ) | ||
| 80 | "List of tests for `Man-parse-man-k'. | ||
| 81 | Each element is a cons cell whose car is a string containing | ||
| 82 | man -k output. That should result in the table which is stored | ||
| 83 | in the cdr of the element.") | ||
| 84 | |||
| 85 | (defun man-tests-name-equal-p (name description string) | ||
| 86 | (and (equal name string) | ||
| 87 | (not (next-single-property-change 0 'help-echo string)) | ||
| 88 | (equal (get-text-property 0 'help-echo string) description))) | ||
| 89 | |||
| 90 | (defun man-tests-parse-man-k-test-case (test) | ||
| 91 | (let ((temp-buffer (get-buffer-create " *test-man*")) | ||
| 92 | (man-k-output (car test))) | ||
| 93 | (unwind-protect | ||
| 94 | (save-window-excursion | ||
| 95 | (with-current-buffer temp-buffer | ||
| 96 | (erase-buffer) | ||
| 97 | (insert man-k-output) | ||
| 98 | (let ((result (Man-parse-man-k)) | ||
| 99 | (checklist (cdr test))) | ||
| 100 | (while (and checklist result | ||
| 101 | (man-tests-name-equal-p | ||
| 102 | (car checklist) | ||
| 103 | (get-text-property 0 'help-echo | ||
| 104 | (car checklist)) | ||
| 105 | (pop result))) | ||
| 106 | (pop checklist)) | ||
| 107 | (and (null checklist) (null result))))) | ||
| 108 | (and (buffer-name temp-buffer) | ||
| 109 | (kill-buffer temp-buffer))))) | ||
| 110 | |||
| 111 | (ert-deftest man-tests () | ||
| 112 | "Test man." | ||
| 113 | (dolist (test man-tests-parse-man-k-tests) | ||
| 114 | (should (man-tests-parse-man-k-test-case test)))) | ||
| 115 | |||
| 116 | (provide 'man-tests) | ||
| 117 | |||
| 118 | ;;; man-tests.el ends here | ||