📄 info.el
字号:
(forward-line 2) (looking-at "(Indirect)\n")) ;; It is indirect. Copy it to another buffer ;; and record that the tag table is in that buffer. (let ((buf (current-buffer)) (tagbuf (or Info-tag-table-buffer (generate-new-buffer " *info tag table*")))) (setq Info-tag-table-buffer tagbuf) (save-excursion (set-buffer tagbuf) (buffer-disable-undo (current-buffer)) (setq case-fold-search t) (erase-buffer) (insert-buffer-substring buf)) (set-marker Info-tag-table-marker (match-end 0) tagbuf)) (set-marker Info-tag-table-marker pos))) (set-marker Info-tag-table-marker nil)) (setq Info-current-file (if (eq filename t) "dir" filename)))) ;; Use string-equal, not equal, to ignore text props. (if (string-equal nodename "*") (progn (setq Info-current-node nodename) (Info-set-mode-line)) ;; Search file for a suitable node. (let ((guesspos (point-min)) (regexp (concat "Node: *" (regexp-quote nodename) " *[,\t\n\177]"))) ;; First get advice from tag table if file has one. ;; Also, if this is an indirect info file, ;; read the proper subfile into this buffer. (if (marker-position Info-tag-table-marker) (save-excursion (let ((m Info-tag-table-marker) found found-mode) (save-excursion (set-buffer (marker-buffer m)) (goto-char m) (beginning-of-line) ;so re-search will work. (setq found (re-search-forward regexp nil t)) (if found (setq guesspos (read (current-buffer)))) (setq found-mode major-mode)) (if found (progn ;; If this is an indirect file, determine ;; which file really holds this node and ;; read it in. (if (not (eq found-mode 'Info-mode)) ;; Note that the current buffer must be ;; the *info* buffer on entry to ;; Info-read-subfile. Thus the hackery ;; above. (setq guesspos (Info-read-subfile guesspos)))) (error "No such node: %s" nodename))))) (goto-char (max (point-min) (- guesspos 1000))) ;; Now search from our advised position (or from beg of buffer) ;; to find the actual node. (catch 'foo (while (search-forward "\n\^_" nil t) (forward-line 1) (let ((beg (point))) (forward-line 1) (if (re-search-backward regexp beg t) (throw 'foo t)))) (error "No such node: %s" nodename))) (Info-select-node))) ;; If we did not finish finding the specified node, ;; go back to the previous one. (or Info-current-node no-going-back (null Info-history) (let ((hist (car Info-history))) (setq Info-history (cdr Info-history)) (Info-find-node (nth 0 hist) (nth 1 hist) t) (goto-char (nth 2 hist))))) (goto-char (point-min)));; Cache the contents of the (virtual) dir file, once we have merged;; it for the first time, so we can save time subsequently.(defvar Info-dir-contents nil);; Cache for the directory we decided to use for the default-directory;; of the merged dir text.(defvar Info-dir-contents-directory nil);; Record the file attributes of all the files from which we;; constructed Info-dir-contents.(defvar Info-dir-file-attributes nil);; Construct the Info directory node by merging the files named `dir';; from various directories. Set the *info* buffer's;; default-directory to the first directory we actually get any text;; from.(defun Info-insert-dir () (if (and Info-dir-contents Info-dir-file-attributes ;; Verify that none of the files we used has changed ;; since we used it. (eval (cons 'and (mapcar '(lambda (elt) (let ((curr (file-attributes (car elt)))) ;; Don't compare the access time. (if curr (setcar (nthcdr 4 curr) 0)) (setcar (nthcdr 4 (cdr elt)) 0) (equal (cdr elt) curr))) Info-dir-file-attributes)))) (insert Info-dir-contents) (let ((dirs Info-directory-list) buffers buffer others nodes dirs-done) (setq Info-dir-file-attributes nil) ;; Search the directory list for the directory file. (while dirs (let ((truename (file-truename (expand-file-name (car dirs))))) (or (member truename dirs-done) (member (directory-file-name truename) dirs-done) ;; Try several variants of specified name. ;; Try upcasing, appending `.info', or both. (let* (file (attrs (or (progn (setq file (expand-file-name "dir" truename)) (file-attributes file)) (progn (setq file (expand-file-name "DIR" truename)) (file-attributes file)) (progn (setq file (expand-file-name "dir.info" truename)) (file-attributes file)) (progn (setq file (expand-file-name "DIR.INFO" truename)) (file-attributes file))))) (setq dirs-done (cons truename (cons (directory-file-name truename) dirs-done))) (if attrs (save-excursion (or buffers (message "Composing main Info directory...")) (set-buffer (generate-new-buffer "info dir")) (insert-file-contents file) (setq buffers (cons (current-buffer) buffers) Info-dir-file-attributes (cons (cons file attrs) Info-dir-file-attributes)))))) (or (cdr dirs) (setq Info-dir-contents-directory (file-name-as-directory (car dirs)))) (setq dirs (cdr dirs)))) (or buffers (error "Can't find the Info directory node")) ;; Distinguish the dir file that comes with Emacs from all the ;; others. Yes, that is really what this is supposed to do. ;; If it doesn't work, fix it. (setq buffer (car buffers) others (cdr buffers)) ;; Insert the entire original dir file as a start; note that we've ;; already saved its default directory to use as the default ;; directory for the whole concatenation. (insert-buffer buffer) ;; Look at each of the other buffers one by one. (while others (let ((other (car others))) ;; In each, find all the menus. (save-excursion (set-buffer other) (goto-char (point-min)) ;; Find each menu, and add an elt to NODES for it. (while (re-search-forward "^\\* Menu:" nil t) (let (beg nodename end) (forward-line 1) (setq beg (point)) (search-backward "\n\^_") (search-forward "Node: ") (setq nodename (Info-following-node-name)) (search-forward "\n\^_" nil 'move) (beginning-of-line) (setq end (point)) (setq nodes (cons (list nodename other beg end) nodes)))))) (setq others (cdr others))) ;; Add to the main menu a menu item for each other node. (re-search-forward "^\\* Menu:") (forward-line 1) (let ((menu-items '("top")) (nodes nodes) (case-fold-search t) (end (save-excursion (search-forward "\^_" nil t) (point)))) (while nodes (let ((nodename (car (car nodes)))) (save-excursion (or (member (downcase nodename) menu-items) (re-search-forward (concat "^\\* " (regexp-quote nodename) "::") end t) (progn (insert "* " nodename "::" "\n") (setq menu-items (cons nodename menu-items)))))) (setq nodes (cdr nodes)))) ;; Now take each node of each of the other buffers ;; and merge it into the main buffer. (while nodes (let ((nodename (car (car nodes)))) (goto-char (point-min)) ;; Find the like-named node in the main buffer. (if (re-search-forward (concat "\n\^_.*\n.*Node: " (regexp-quote nodename) "[,\n\t]") nil t) (progn (search-forward "\n\^_" nil 'move) (beginning-of-line) (insert "\n")) ;; If none exists, add one. (goto-char (point-max)) (insert "\^_\nFile: dir\tNode: " nodename "\n\n* Menu:\n\n")) ;; Merge the text from the other buffer's menu ;; into the menu in the like-named node in the main buffer. (apply 'insert-buffer-substring (cdr (car nodes)))) (setq nodes (cdr nodes))) ;; Kill all the buffers we just made. (while buffers (kill-buffer (car buffers)) (setq buffers (cdr buffers))) (message "Composing main Info directory...done")) (setq Info-dir-contents (buffer-string))) (setq default-directory Info-dir-contents-directory));; Note that on entry to this function the current-buffer must be the;; *info* buffer; not the info tags buffer.(defun Info-read-subfile (nodepos) ;; NODEPOS is either a position (in the Info file as a whole, ;; not relative to a subfile) or the name of a subfile. (let (lastfilepos lastfilename) (if (numberp nodepos) (save-excursion (set-buffer (marker-buffer Info-tag-table-marker)) (goto-char (point-min)) (search-forward "\n\^_") (forward-line 2) (catch 'foo (while (not (looking-at "\^_")) (if (not (eolp)) (let ((beg (point)) thisfilepos thisfilename) (search-forward ": ") (setq thisfilename (buffer-substring beg (- (point) 2))) (setq thisfilepos (read (current-buffer))) ;; read in version 19 stops at the end of number. ;; Advance to the next line. (forward-line 1) (if (> thisfilepos nodepos) (throw 'foo t)) (setq lastfilename thisfilename) (setq lastfilepos thisfilepos)) (forward-line 1))))) (setq lastfilename nodepos) (setq lastfilepos 0)) ;; Assume previous buffer is in Info-mode. ;; (set-buffer (get-buffer "*info*")) (or (equal Info-current-subfile lastfilename) (let ((buffer-read-only nil)) (setq buffer-file-name nil) (widen) (erase-buffer) (info-insert-file-contents lastfilename) (set-buffer-modified-p nil) (setq Info-current-subfile lastfilename))) (goto-char (point-min)) (search-forward "\n\^_") (if (numberp nodepos) (+ (- nodepos lastfilepos) (point)))));; Select the info node that point is in.(defun Info-select-node () (save-excursion ;; Find beginning of node. (search-backward "\n\^_") (forward-line 2) ;; Get nodename spelled as it is in the node. (re-search-forward "Node:[ \t]*") (setq Info-current-node (buffer-substring-no-properties (point) (progn (skip-chars-forward "^,\t\n") (point)))) (Info-set-mode-line) ;; Find the end of it, and narrow. (beginning-of-line) (let (active-expression) (narrow-to-region (point) (if (re-search-forward "\n[\^_\f]" nil t) (prog1 (1- (point)) (if (looking-at "[\n\^_\f]*execute: ") (progn (goto-char (match-end 0)) (setq active-expression (read (current-buffer)))))) (point-max))) (if Info-enable-active-nodes (eval active-expression)) (if Info-fontify (Info-fontify-node)) (run-hooks 'Info-selection-hook))))(defun Info-set-mode-line () (setq mode-line-buffer-identification (concat " Info: (" (if Info-current-file (file-name-nondirectory Info-current-file) "") ")" (or Info-current-node ""))));; Go to an info node specified with a filename-and-nodename string;; of the sort that is found in pointers in nodes.(defun Info-goto-node (nodename) "Go to info node named NAME. Give just NODENAME or (FILENAME)NODENAME." (interactive (list (Info-read-node-name "Goto node: "))) (let (filename) (string-match "\\s *\\((\\s *\\([^\t)]*\\)\\s *)\\s *\\|\\)\\(.*\\)" nodename) (setq filename (if (= (match-beginning 1) (match-end 1)) "" (substring nodename (match-beginning 2) (match-end 2))) nodename (substring nodename (match-beginning 3) (match-end 3))) (let ((trim (string-match "\\s *\\'" filename))) (if trim (setq filename (substring filename 0 trim)))) (let ((trim (string-match "\\s *\\'" nodename))) (if trim (setq nodename (substring nodename 0 trim)))) (if transient-mark-mode (deactivate-mark)) (Info-find-node (if (equal filename "") nil filename) (if (equal nodename "") "Top" nodename))));; This function is used as the "completion table" while reading a node name.;; It does completion using the alist in completion-table;; unless STRING starts with an open-paren.(defun Info-read-node-name-1 (string predicate code) (let ((no-completion (and (> (length string) 0) (eq (aref string 0) ?\()))) (cond ((eq code nil) (if no-completion string (try-completion string completion-table predicate))) ((eq code t) (if no-completion nil (all-completions string completion-table predicate))) ((eq code 'lambda) (if no-completion t (assoc string completion-table))))))(defun Info-read-node-name (prompt &optional default) (let* ((completion-ignore-case t) (completion-table (Info-build-node-completions)) (nodename (completing-read prompt 'Info-read-node-name-1 nil t))) (if (equal nodename "") (or default (Info-read-node-name prompt)) nodename)))(defun Info-build-node-completions () (or Info-current-file-completions (let ((compl nil)) (save-excursion
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -