# HG changeset patch # User Eric S. Raymond # Date 735531655 0 # Node ID 1bd4cf98df684ae2a7323c700d8b89a3fc0fa1b9 # Parent 50d7841854b382ba011438fc10b926f45bedb2b9 (Info-find-node, Info-insert-subfile): Do the right thing if info files have been compressed or gzipped. This is saving me lots of disk space. diff -r 50d7841854b3 -r 1bd4cf98df68 lisp/info.el --- a/lisp/info.el Thu Apr 22 22:56:54 1993 +0000 +++ b/lisp/info.el Fri Apr 23 02:20:55 1993 +0000 @@ -67,6 +67,41 @@ "Marker pointing at beginning of current Info file's tag table. Marker points nowhere if file has no tag table.") +(defvar Info-index-alternatives nil + "List of possible matches for last Info-index command.") + +(defvar Info-suffix-list '( ("" . nil) + (".info" . nil) + (".Z" . "uncompress") + (".Y" . "unyabba") + (".z" . "gunzip") + (".info.Z" . "uncompress") + (".info.Y" . "unyabba") + (".z" . "gunzip")) + "List of file name suffixes and associated decoding commands. +Each entry should be (SUFFIX . STRING); the file is given to +the command as standard input. If STRING is nil, no decoding is done.") + +(defun info-insert-file-contents (filename &optional visit) + "Insert the contents of an info file in the current buffer. +Do the right thing if the file has been compressed or zipped." + (if (null (catch 'ok + (mapcar + (function + (lambda (x) + (let ((compressed (concat filename (car x)))) + (if (file-exists-p compressed) + (progn + (insert-file-contents compressed visit) + (if (cdr x) + (let ((buffer-read-only nil)) + (shell-command-on-region + (point-min) (point-max) (cdr x) t))) + (throw 'ok t)))))) + Info-suffix-list) + nil)) + (error "Can't find %s or any compressed version of it!" filename))) + ;;;###autoload (defun info (&optional file) "Enter Info, the documentation browser. @@ -118,15 +153,19 @@ (setq temp-downcase (expand-file-name (downcase filename) (car dirs))) ;; Try several variants of specified name. - ;; Try downcasing, appending `.info', or both. - (cond ((file-exists-p temp) - (setq found temp)) - ((file-exists-p temp-downcase) - (setq found temp-downcase)) - ((file-exists-p (concat temp ".info")) - (setq found (concat temp ".info"))) - ((file-exists-p (concat temp-downcase ".info")) - (setq found (concat temp-downcase ".info")))) + (catch 'foundit + (mapcar + (function + (lambda (x) + (if (file-exists-p (concat temp (car x))) + (progn + (setq found temp) + (throw 'foundit nil))) + (if (file-exists-p (concat temp-downcase (car x))) + (progn + (setq found temp-downcase) + (throw 'foundit nil))))) + Info-suffix-list)) (setq dirs (cdr dirs))))) (if found (setq filename found) @@ -151,11 +190,12 @@ (let ((buffer-read-only nil)) (setq Info-current-file nil Info-current-subfile nil + Info-index-alternatives nil buffer-file-name nil) (erase-buffer) (if (eq filename t) (Info-insert-dir) - (insert-file-contents filename t) + (info-insert-file-contents filename t) (setq default-directory (file-name-directory filename))) (set-buffer-modified-p nil) ;; See whether file has a tag table. Record the location if yes. @@ -381,7 +421,7 @@ (setq buffer-file-name nil) (widen) (erase-buffer) - (insert-file-contents lastfilename) + (info-insert-file-contents lastfilename) (set-buffer-modified-p nil) (setq Info-current-subfile lastfilename))) (goto-char (point-min)) @@ -870,6 +910,98 @@ (scroll-down)) ) +(defun Info-index (topic) + "Look up a string in the index for this file. +The index is defined as the first node in the top-level menu whose +name contains the word \"Index\", plus any immediately following +nodes whose names also contain the word \"Index\". +If there are no exact matches to the specified topic, this chooses +the first match which is a case-insensitive substring of a topic. +Use the `,' command to see the other matches. +Give a blank topic name to go to the Index node itself." + (interactive "sIndex topic: ") + (let ((orignode Info-current-node) + (rnode nil) + (pattern (format "\n\\* \\([^\n:]*%s[^\n:]*\\):[ \t]*\\([^.\n]*\\)\\.[ t]*\\([0-9]*\\)" + (regexp-quote topic))) + node) + (Info-goto-node "Top") + (or (search-forward "\n* menu:" nil t) + (error "No index")) + (or (re-search-forward "\n\\* \\(.*\\\\)" nil t) + (error "No index")) + (goto-char (match-beginning 1)) + (let ((Info-keeping-history nil)) + (Info-goto-node (Info-extract-menu-node-name))) + (or (equal topic "") + (let ((matches nil) + (exact nil) + (Info-keeping-history nil) + found) + (while + (progn + (goto-char (point-min)) + (while (re-search-forward pattern nil t) + (setq matches + (cons (list (buffer-substring (match-beginning 1) + (match-end 1)) + (buffer-substring (match-beginning 2) + (match-end 2)) + Info-current-node + (string-to-int (concat "0" + (buffer-substring + (match-beginning 3) + (match-end 3))))) + matches))) + (and (setq node (Info-extract-pointer "next" t)) + (string-match "\\" node))) + (Info-goto-node node)) + (or matches + (progn + (Info-last) + (error "No \"%s\" in index" topic))) + ;; Here it is a feature that assoc is case-sensitive. + (while (setq found (assoc topic matches)) + (setq exact (cons found exact) + matches (delq found matches))) + (setq Info-index-alternatives (nconc exact (nreverse matches))) + (Info-index-next 0))))) + +(defun Info-index-next (num) + "Go to the next matching index item from the last `i' command." + (interactive "p") + (or Info-index-alternatives + (error "No previous `i' command in this file")) + (while (< num 0) + (setq num (+ num (length Info-index-alternatives)))) + (while (> num 0) + (setq Info-index-alternatives + (nconc (cdr Info-index-alternatives) + (list (car Info-index-alternatives))) + num (1- num))) + (Info-goto-node (nth 1 (car Info-index-alternatives))) + (if (> (nth 3 (car Info-index-alternatives)) 0) + (forward-line (nth 3 (car Info-index-alternatives))) + (forward-line 3) ; don't search in headers + (let ((name (car (car Info-index-alternatives)))) + (if (or (re-search-forward (format + "\\(Function\\|Command\\): %s\\( \\|$\\)" + (regexp-quote name)) nil t) + (search-forward (format "`%s'" name) nil t) + (and (string-match "\\`.*\\( (.*)\\)\\'" name) + (search-forward + (format "`%s'" (substring name 0 (match-beginning 1))) + nil t)) + (search-forward name nil t)) + (beginning-of-line) + (goto-char (point-min))))) + (message "Found \"%s\" in %s. %s" + (car (car Info-index-alternatives)) + (nth 2 (car Info-index-alternatives)) + (if (cdr Info-index-alternatives) + "(Press `,' for more)" + "(Only match)"))) + (defun Info-undefined () "Make command be undefined in Info." (interactive) @@ -991,13 +1123,16 @@ (define-key Info-mode-map "f" 'Info-follow-reference) (define-key Info-mode-map "g" 'Info-goto-node) (define-key Info-mode-map "h" 'Info-help) + (define-key Info-mode-map "i" 'Info-index) (define-key Info-mode-map "l" 'Info-last) (define-key Info-mode-map "m" 'Info-menu) (define-key Info-mode-map "n" 'Info-next) (define-key Info-mode-map "p" 'Info-prev) (define-key Info-mode-map "q" 'Info-exit) (define-key Info-mode-map "s" 'Info-search) + (define-key Info-mode-map "t" 'Info-top) (define-key Info-mode-map "u" 'Info-up) + (define-key Info-mode-map "," 'Info-index-next) (define-key Info-mode-map "\177" 'Info-scroll-down) (define-key Info-mode-map [mouse-3] 'Info-follow-nearest-node) ) @@ -1023,6 +1158,8 @@ \\[Info-directory] Go to the Info directory node. \\[Info-follow-reference] Follow a cross reference. Reads name of reference. \\[Info-last] Move to the last node you were at. +\\[Info-index] Look up a topic in this file's Index and move to that node. +\\[Info-index-next] (comma) Move to the next match from a previous `i' command. Moving within a node: \\[scroll-up] Normally, scroll forward a full screen. If the end of the buffer is @@ -1056,6 +1193,7 @@ (make-local-variable 'Info-current-node) (make-local-variable 'Info-tag-table-marker) (make-local-variable 'Info-history) + (make-local-variable 'Info-index-alternatives) (Info-set-mode-line) (run-hooks 'Info-mode-hook))