home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / octa21fb.zip / octave / lisp / octave-info.el next >
Lisp/Scheme  |  2000-01-15  |  46KB  |  1,209 lines

  1. ;;; octave-info.el --- octave-info package for Emacs.
  2.  
  3. ;; Modified for emx by Eberhard Mattes, Dec 1995
  4. ;; Modified for Octave by Klaus Gebhardt, Apr 1996 - Mar 1997
  5.  
  6. ;; Copyright (C) 1985, 1986, 1992, 1993, 1994 Free Software Foundation, Inc.
  7.  
  8. ;; Maintainer: FSF
  9. ;; Keywords: help
  10.  
  11. ;; This file is part of GNU Emacs.
  12.  
  13. ;; GNU Emacs is free software; you can redistribute it and/or modify
  14. ;; it under the terms of the GNU General Public License as published by
  15. ;; the Free Software Foundation; either version 2, or (at your option)
  16. ;; any later version.
  17.  
  18. ;; GNU Emacs is distributed in the hope that it will be useful,
  19. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21. ;; GNU General Public License for more details.
  22.  
  23. ;; You should have received a copy of the GNU General Public License
  24. ;; along with GNU Emacs; see the file COPYING.  If not, write to
  25. ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  26.  
  27. ;;; Commentary:
  28.  
  29. ;;; Note that nowadays we expect info files to be made using makeinfo.
  30.  
  31. ;;; Code:
  32.  
  33. (require 'info)
  34.  
  35. (defvar Octave-Info-index-strings nil
  36.   "List of the index strings.")
  37.  
  38. (defvar Octave-Info-history nil
  39.   "List of octave-info nodes user has visited.
  40. Each element of list is a list (FILENAME NODENAME BUFFERPOS).")
  41.  
  42. (defvar Octave-Info-enable-active-nodes t
  43.   "Non-nil allows Octave-Info to execute Lisp code associated with nodes.
  44. The Lisp code is executed when the node is selected.")
  45.  
  46. (defvar Octave-Info-fontify t
  47.   "*Non-nil enables highlighting and fonts in Octave-Info nodes.")
  48.  
  49. (defvar Octave-Info-fontify-maximum-menu-size 30000
  50.   "*Maximum size of menu to fontify if `Octave-Info-fontify' is non-nil.")
  51.  
  52. (defvar Octave-Info-current-file nil
  53.   "Octave-Info file that Octave-Info is now looking at, or nil.")
  54.  
  55. (defvar Octave-Info-current-subfile nil
  56.   "Octave-Info subfile that is actually in the *octave-info* buffer now,
  57. or nil if current octave-info file is not split into subfiles.")
  58.  
  59. (defvar Octave-Info-current-node nil
  60.   "Name of node that Octave-Info is now looking at, or nil.")
  61.  
  62. (defvar Octave-Info-tag-table-marker (make-marker)
  63.   "Marker pointing at beginning of current Octave-Info file's tag table.
  64. Marker points nowhere if file has no tag table.")
  65.  
  66. (defvar Octave-Info-current-file-completions nil
  67.   "Cached completion list for current Octave-Info file.")
  68.  
  69. (defvar Octave-Info-index-alternatives nil
  70.   "List of possible matches for last Octave-Info-index command.")
  71.  
  72. (defvar Octave-Info-running nil
  73.   "*Non-nil means Octave-Info has already been started.")
  74.  
  75. ;;;###autoload (add-hook 'same-window-buffer-names "*octave-info*")
  76.  
  77. ;;;###autoload
  78. (defun octave-info (index-strings)
  79.   "Enter Octave-Info, the documentation browser."
  80.   (if (or (not Octave-Info-running) t)
  81.       (progn
  82.     (setq Octave-Info-running t)
  83.     (Octave-Info-goto-node (format "(%s)" (car index-strings)))
  84.     (setq Octave-Info-index-strings (cdr index-strings))
  85.     (if (and (not (equal (car Octave-Info-index-strings) "(null)"))
  86.          (not (equal (car Octave-Info-index-strings) "")))
  87.         (Octave-Info-index (car Octave-Info-index-strings)))
  88.     (setq Octave-Info-index-strings (cdr Octave-Info-index-strings)))
  89.     (progn
  90.       (setq Octave-Info-index-strings (append Octave-Info-index-strings 
  91.                           index-strings)))))
  92.  
  93. (defun Octave-Info-error (fmt &optional string)
  94.   (setq Octave-Info-index-strings (cdr Octave-Info-index-strings))
  95.   (Octave-Info-exit)
  96.   (error fmt string))
  97.  
  98. (defun Octave-Info-find-node (filename nodename &optional no-going-back)
  99.   (if filename
  100.       (let (temp temp-downcase found)
  101.     (setq filename (substitute-in-file-name filename))
  102.     (if (string= (downcase (file-name-nondirectory filename)) "dir")
  103.         (setq found t)
  104.       (let ((dirs (if (string-match "^\\./" filename)
  105.               '("./")
  106.             (if (file-name-absolute-p filename)
  107.                 '(nil)
  108.               (if Info-additional-directory-list
  109.                   (append Info-directory-list
  110.                       Info-additional-directory-list)
  111.                 Info-directory-list)))))
  112.         (while (and dirs (not found))
  113.           (setq temp (expand-file-name filename (car dirs)))
  114.           (setq temp-downcase
  115.             (expand-file-name (downcase filename) (car dirs)))
  116.           (let ((suffix-list Info-suffix-list))
  117.         (while (and suffix-list (not found))
  118.           (cond ((file-exists-p
  119.               (info-insert-file-contents-1
  120.                temp (car (car suffix-list))))
  121.              (setq found temp))
  122.             ((file-exists-p
  123.               (info-insert-file-contents-1
  124.                temp-downcase (car (car suffix-list))))
  125.              (setq found temp-downcase)))
  126.           (setq suffix-list (cdr suffix-list))))
  127.           (setq dirs (cdr dirs)))))
  128.     (if found
  129.         (setq filename found)
  130.       (Octave-Info-error "Octave-Info file %s does not exist" filename))))
  131.   (if (and Octave-Info-current-file (not no-going-back))
  132.       (setq Octave-Info-history
  133.         (cons (list Octave-Info-current-file
  134.             Octave-Info-current-node (point))
  135.           Octave-Info-history)))
  136.   (switch-to-buffer "*octave-info*")
  137.   (buffer-disable-undo (current-buffer))
  138.   (or (eq major-mode 'Octave-Info-mode)
  139.       (Octave-Info-mode))
  140.   (widen)
  141.   (setq Octave-Info-current-node nil)
  142.   (unwind-protect
  143.       (progn
  144.     (or (null filename)
  145.         (equal Octave-Info-current-file filename)
  146.         (let ((buffer-read-only nil))
  147.           (setq Octave-Info-current-file nil
  148.             Octave-Info-current-subfile nil
  149.             Octave-Info-current-file-completions nil
  150.             Octave-Info-index-alternatives nil
  151.             buffer-file-name nil)
  152.           (erase-buffer)
  153.           (if (eq filename t)
  154.           (Octave-Info-insert-dir)
  155.         (info-insert-file-contents filename t)
  156.         (setq default-directory (file-name-directory filename)))
  157.           (set-buffer-modified-p nil)
  158.           (set-marker Octave-Info-tag-table-marker nil)
  159.           (goto-char (point-max))
  160.           (forward-line -8)
  161.           (or (string-equal nodename "*")
  162.           (not (search-forward "\^_\nEnd tag table\n" nil t))
  163.           (let (pos)
  164.             (search-backward "\nTag table:\n")
  165.             (setq pos (point))
  166.             (if (save-excursion
  167.               (forward-line 2)
  168.               (looking-at "(Indirect)\n"))
  169.             (save-excursion
  170.               (let ((buf (current-buffer)))
  171.                 (set-buffer
  172.                  (get-buffer-create " *octave-info tag table*"))
  173.                             (buffer-disable-undo (current-buffer))
  174.                 (setq case-fold-search t)
  175.                 (erase-buffer)
  176.                 (insert-buffer-substring buf)
  177.                 (set-marker Octave-Info-tag-table-marker
  178.                     (match-end 0))))
  179.               (set-marker Octave-Info-tag-table-marker pos))))
  180.           (setq Octave-Info-current-file
  181.             (if (eq filename t) "dir" filename))))
  182.     (if (string-equal nodename "*")
  183.         (progn (setq Octave-Info-current-node nodename)
  184.            (Octave-Info-set-mode-line))
  185.       (let ((guesspos (point-min))
  186.         (regexp (concat "Node: *"
  187.                 (regexp-quote nodename) " *[,\t\n\177]")))
  188.         (if (marker-position Octave-Info-tag-table-marker)
  189.         (save-excursion
  190.           (set-buffer (marker-buffer Octave-Info-tag-table-marker))
  191.           (goto-char Octave-Info-tag-table-marker)
  192.           (if (re-search-forward regexp nil t)
  193.               (progn
  194.             (setq guesspos (read (current-buffer)))
  195.             (if (not (eq (current-buffer)
  196.                      (get-buffer "*octave-info*")))
  197.                 (setq guesspos
  198.                   (Octave-Info-read-subfile guesspos))))
  199.             (Octave-Info-error "No such node: \"%s\"" nodename))))
  200.         (goto-char (max (point-min) (- guesspos 1000)))
  201.         (catch 'foo
  202.           (while (search-forward "\n\^_" nil t)
  203.         (forward-line 1)
  204.         (let ((beg (point)))
  205.           (forward-line 1)
  206.           (if (re-search-backward regexp beg t)
  207.               (throw 'foo t))))
  208.           (Octave-Info-error "No such node: %s" nodename)))
  209.       (Octave-Info-select-node)))
  210.     (or Octave-Info-current-node no-going-back (null Octave-Info-history)
  211.     (let ((hist (car Octave-Info-history)))
  212.       (setq Octave-Info-history (cdr Octave-Info-history))
  213.       (Octave-Info-find-node (nth 0 hist) (nth 1 hist) t)
  214.       (goto-char (nth 2 hist)))))
  215.   (goto-char (point-min)))
  216.  
  217. (defvar Octave-Info-dir-contents nil)
  218.  
  219. (defvar Octave-Info-dir-contents-directory nil)
  220.  
  221. (defvar Octave-Info-dir-file-attributes nil)
  222.  
  223. (defun Octave-Info-insert-dir ()
  224.   (if (and Octave-Info-dir-contents Octave-Info-dir-file-attributes
  225.        (eval (cons 'and
  226.                (mapcar '(lambda (elt)
  227.                   (let ((curr (file-attributes (car elt))))
  228.                     (if curr (setcar (nthcdr 4 curr) 0))
  229.                     (setcar (nthcdr 4 (cdr elt)) 0)
  230.                     (equal (cdr elt) curr)))
  231.                    Octave-Info-dir-file-attributes))))
  232.       (insert Octave-Info-dir-contents)
  233.     (let ((dirs Info-directory-list)
  234.       buffers buffer others nodes dirs-done)
  235.       (setq Octave-Info-dir-file-attributes nil)
  236.       (while dirs
  237.     (let ((truename (file-truename (expand-file-name (car dirs)))))
  238.       (or (member truename dirs-done)
  239.           (member (directory-file-name truename) dirs-done)
  240.           (let* (file
  241.              (attrs
  242.               (or
  243.                (progn
  244.              (setq file (expand-file-name "dir" truename))
  245.              (file-attributes file))
  246.                (progn
  247.              (setq file (expand-file-name "DIR" truename))
  248.              (file-attributes file))
  249.                (progn
  250.              (setq file (expand-file-name "dir.info" truename))
  251.              (file-attributes file))
  252.                (progn
  253.              (setq file (expand-file-name "DIR.INFO" truename))
  254.              (file-attributes file)))))
  255.         (setq dirs-done
  256.               (cons truename
  257.                 (cons (directory-file-name truename) dirs-done)))
  258.         (if attrs
  259.             (save-excursion
  260.               (or buffers
  261.               (message "Composing main Octave-Info directory..."))
  262.               (set-buffer (generate-new-buffer "octave-info dir"))
  263.               (insert-file-contents file)
  264.               (setq buffers (cons (current-buffer) buffers)
  265.                 Octave-Info-dir-file-attributes
  266.                 (cons (cons file attrs)
  267.                   Octave-Info-dir-file-attributes))))))
  268.       (setq dirs (cdr dirs))))
  269.       
  270.       (or buffers (Octave-Info-error "Can't find the octave-info directory node"))
  271.       (setq buffer (car buffers) others (cdr buffers))
  272.  
  273.       (insert-buffer buffer)
  274.       (setq Octave-Info-dir-contents-directory (save-excursion
  275.                          (set-buffer buffer)
  276.                          default-directory))
  277.       
  278.       (while others
  279.     (let ((other (car others)))
  280.       (save-excursion
  281.         (set-buffer other)
  282.         (goto-char (point-min))
  283.         (while (re-search-forward "^\\* Menu:" nil t)
  284.           (let (beg nodename end)
  285.         (forward-line 1)
  286.         (setq beg (point))
  287.         (search-backward "\n\^_")
  288.         (search-forward "Node: ")
  289.         (setq nodename (Info-following-node-name))
  290.         (search-forward "\n\^_" nil 'move)
  291.         (beginning-of-line)
  292.         (setq end (point))
  293.         (setq nodes (cons (list nodename other beg end) nodes))))))
  294.     (setq others (cdr others)))
  295.       (re-search-forward "^\\* Menu:")
  296.       (forward-line 1)
  297.       (let ((menu-items '("top"))
  298.         (nodes nodes)
  299.         (case-fold-search t)
  300.         (end (save-excursion (search-forward "\^_" nil t) (point))))
  301.     (while nodes
  302.       (let ((nodename (car (car nodes))))
  303.         (save-excursion
  304.           (or (member (downcase nodename) menu-items)
  305.           (re-search-forward (concat "^\\* "
  306.                          (regexp-quote nodename)
  307.                          "::")
  308.                      end t)
  309.           (progn
  310.             (insert "* " nodename "::" "\n")
  311.             (setq menu-items (cons nodename menu-items))))))
  312.       (setq nodes (cdr nodes))))
  313.       (while nodes
  314.     (let ((nodename (car (car nodes))))
  315.       (goto-char (point-min))
  316.       (if (re-search-forward (concat "\n\^_.*\n.*Node: "
  317.                      (regexp-quote nodename)
  318.                      "[,\n\t]")
  319.                  nil t)
  320.           (progn
  321.         (search-forward "\n\^_" nil 'move)
  322.         (beginning-of-line)
  323.         (insert "\n"))
  324.         (goto-char (point-max))
  325.         (insert "\^_\nFile: dir\tNode: " nodename "\n\n* Menu:\n\n"))
  326.       (apply 'insert-buffer-substring (cdr (car nodes))))
  327.     (setq nodes (cdr nodes)))
  328.       (while buffers
  329.     (kill-buffer (car buffers))
  330.     (setq buffers (cdr buffers)))
  331.       (message "Composing main Octave-Info directory...done"))
  332.     (setq Octave-Info-dir-contents (buffer-string)))
  333.   (setq default-directory Octave-Info-dir-contents-directory))
  334.  
  335. (defun Octave-Info-read-subfile (nodepos)
  336.   (set-buffer (marker-buffer Octave-Info-tag-table-marker))
  337.   (goto-char (point-min))
  338.   (search-forward "\n\^_")
  339.   (let (lastfilepos
  340.     lastfilename)
  341.     (forward-line 2)
  342.     (catch 'foo
  343.       (while (not (looking-at "\^_"))
  344.     (if (not (eolp))
  345.         (let ((beg (point))
  346.           thisfilepos thisfilename)
  347.           (search-forward ": ")
  348.           (setq thisfilename  (buffer-substring beg (- (point) 2)))
  349.           (setq thisfilepos (read (current-buffer)))
  350.           (forward-line 1)
  351.           (if (> thisfilepos nodepos) (throw 'foo t))
  352.           (setq lastfilename thisfilename)
  353.           (setq lastfilepos thisfilepos))
  354.       (forward-line 1))))
  355.     (set-buffer (get-buffer "*octave-info*"))
  356.     (or (equal Octave-Info-current-subfile lastfilename)
  357.     (let ((buffer-read-only nil))
  358.       (setq buffer-file-name nil)
  359.       (widen)
  360.       (erase-buffer)
  361.       (info-insert-file-contents lastfilename)
  362.       (set-buffer-modified-p nil)
  363.       (setq Octave-Info-current-subfile lastfilename)))
  364.     (goto-char (point-min))
  365.     (search-forward "\n\^_")
  366.     (+ (- nodepos lastfilepos) (point))))
  367.  
  368. (defun Octave-Info-select-node ()
  369.   (save-excursion
  370.     (search-backward "\n\^_")
  371.     (forward-line 2)
  372.     (re-search-forward "Node:[ \t]*")
  373.     (setq Octave-Info-current-node
  374.       (buffer-substring-no-properties (point)
  375.                       (progn
  376.                         (skip-chars-forward "^,\t\n")
  377.                         (point))))
  378.     (Octave-Info-set-mode-line)
  379.     (beginning-of-line)
  380.     (let (active-expression)
  381.       (narrow-to-region (point)
  382.             (if (re-search-forward "\n[\^_\f]" nil t)
  383.                 (prog1
  384.                 (1- (point))
  385.                   (if (looking-at "[\n\^_\f]*execute: ")
  386.                   (progn
  387.                     (goto-char (match-end 0))
  388.                     (setq active-expression
  389.                       (read (current-buffer))))))
  390.               (point-max)))
  391.       (if Octave-Info-enable-active-nodes (eval active-expression))
  392.       (if Octave-Info-fontify (Octave-Info-fontify-node))
  393.       (run-hooks 'Octave-Info-selection-hook))))
  394.  
  395. (defun Octave-Info-set-mode-line ()
  396.   (setq mode-line-buffer-identification
  397.     (concat
  398.      "Octave-Info:  ("
  399.      (if Octave-Info-current-file
  400.          (file-name-nondirectory Octave-Info-current-file) "") ")"
  401.          (or Octave-Info-current-node ""))))
  402.  
  403. (defun Octave-Info-goto-node (nodename)
  404.   "Go to octave-info node named NAME.  Give just NODENAME."
  405.   (interactive (list (Octave-Info-read-node-name "Goto node: ")))
  406.   (let (filename)
  407.     (string-match "\\s *\\((\\s *\\([^\t)]*\\)\\s *)\\s *\\|\\)\\(.*\\)"
  408.           nodename)
  409.     (setq filename (if (= (match-beginning 1) (match-end 1))
  410.                ""
  411.              (substring nodename (match-beginning 2) (match-end 2)))
  412.       nodename (substring nodename (match-beginning 3) (match-end 3)))
  413.     (let ((trim (string-match "\\s *\\'" filename)))
  414.       (if trim (setq filename (substring filename 0 trim))))
  415.     (let ((trim (string-match "\\s *\\'" nodename)))
  416.       (if trim (setq nodename (substring nodename 0 trim))))
  417.     (if transient-mark-mode (deactivate-mark))
  418.     (Octave-Info-find-node (if (equal filename "") nil filename)
  419.                (if (equal nodename "") "Top" nodename))))
  420.  
  421. (defun Octave-Info-read-node-name-1 (string predicate code)
  422.   (let ((no-completion (and (> (length string) 0) (eq (aref string 0) ?\())))
  423.     (cond ((eq code nil)
  424.        (if no-completion
  425.            string
  426.          (try-completion string completion-table predicate)))
  427.       ((eq code t)
  428.        (if no-completion
  429.            nil
  430.          (all-completions string completion-table predicate)))
  431.       ((eq code 'lambda)
  432.        (if no-completion
  433.            t
  434.          (assoc string completion-table))))))
  435.  
  436. (defun Octave-Info-read-node-name (prompt &optional default)
  437.   (let* ((completion-ignore-case t)
  438.      (completion-table (Octave-Info-build-node-completions))
  439.      (nodename (completing-read prompt 'Octave-Info-read-node-name-1)))
  440.     (if (equal nodename "")
  441.     (or default
  442.         (Octave-Info-read-node-name prompt))
  443.       nodename)))
  444.  
  445. (defun Octave-Info-build-node-completions ()
  446.   (or Octave-Info-current-file-completions
  447.       (let ((compl nil))
  448.     (save-excursion
  449.       (save-restriction
  450.         (if (marker-buffer Octave-Info-tag-table-marker)
  451.         (progn
  452.           (set-buffer (marker-buffer Octave-Info-tag-table-marker))
  453.           (widen)
  454.           (goto-char Octave-Info-tag-table-marker)
  455.           (while (re-search-forward "\nNode: \\(.*\\)\177" nil t)
  456.             (setq compl
  457.               (cons (list (buffer-substring (match-beginning 1)
  458.                             (match-end 1)))
  459.                 compl))))
  460.           (widen)
  461.           (goto-char (point-min))
  462.           (while (search-forward "\n\^_" nil t)
  463.         (forward-line 1)
  464.         (let ((beg (point)))
  465.           (forward-line 1)
  466.           (if (re-search-backward "Node: *\\([^,\n]*\\) *[,\n\t]"
  467.                       beg t)
  468.               (setq compl 
  469.                 (cons (list (buffer-substring (match-beginning 1)
  470.                               (match-end 1)))
  471.                   compl))))))))
  472.     (setq Octave-Info-current-file-completions compl))))
  473.  
  474. (defun Octave-Info-restore-point (hl)
  475.   "If this node has been visited, restore the point value when we left."
  476.   (while hl
  477.     (if (and (equal (nth 0 (car hl)) Octave-Info-current-file)
  478.          (string-equal (nth 1 (car hl)) Octave-Info-current-node))
  479.     (progn
  480.       (goto-char (nth 2 (car hl)))
  481.       (setq hl nil))
  482.       (setq hl (cdr hl)))))
  483.  
  484. (defvar Octave-Info-last-search nil)
  485.  
  486. (defun Octave-Info-search (regexp)
  487.   "Search for REGEXP, starting from point, and select node it's found in."
  488.   (interactive "sSearch (regexp): ")
  489.   (if transient-mark-mode (deactivate-mark))
  490.   (if (equal regexp "")
  491.       (setq regexp Octave-Info-last-search)
  492.     (setq Octave-Info-last-search regexp))
  493.   (let ((found ()) current
  494.     (onode Octave-Info-current-node)
  495.     (ofile Octave-Info-current-file)
  496.     (opoint (point))
  497.     (osubfile Octave-Info-current-subfile))
  498.     (save-excursion
  499.       (save-restriction
  500.     (widen)
  501.     (if (null Octave-Info-current-subfile)
  502.         (progn (re-search-forward regexp) (setq found (point)))
  503.       (condition-case err
  504.           (progn (re-search-forward regexp) (setq found (point)))
  505.         (search-failed nil)))))
  506.     (if (not found)
  507.     (unwind-protect
  508.         (let ((list ()))
  509.           (set-buffer (marker-buffer Octave-Info-tag-table-marker))
  510.           (goto-char (point-min))
  511.           (search-forward "\n\^_\nIndirect:")
  512.           (save-restriction
  513.         (narrow-to-region (point)
  514.                   (progn (search-forward "\n\^_")
  515.                      (1- (point))))
  516.         (goto-char (point-min))
  517.         (search-forward (concat "\n" osubfile ": "))
  518.         (beginning-of-line)
  519.         (while (not (eobp))
  520.           (re-search-forward "\\(^.*\\): [0-9]+$")
  521.           (goto-char (+ (match-end 1) 2))
  522.           (setq list (cons (cons (read (current-buffer))
  523.                      (buffer-substring (match-beginning 1)
  524.                                (match-end 1)))
  525.                    list))
  526.           (goto-char (1+ (match-end 0))))
  527.         (setq list (nreverse list)
  528.               current (car (car list))
  529.               list (cdr list)))
  530.           (while list
  531.         (message "Searching subfile %s..." (cdr (car list)))
  532.         (Octave-Info-read-subfile (car (car list)))
  533.         (setq list (cdr list))
  534.         (if (re-search-forward regexp nil t)
  535.             (setq found (point) list ())))
  536.           (if found
  537.           (message "")
  538.         (signal 'search-failed (list regexp))))
  539.       (if (not found)
  540.           (progn (Octave-Info-read-subfile opoint)
  541.              (goto-char opoint)
  542.              (Octave-Info-select-node)))))
  543.     (widen)
  544.     (goto-char found)
  545.     (Octave-Info-select-node)
  546.     (or (and (string-equal onode Octave-Info-current-node)
  547.          (equal ofile Octave-Info-current-file))
  548.     (setq Octave-Info-history (cons (list ofile onode opoint)
  549.                     Octave-Info-history)))))
  550.  
  551. (defun Octave-Info-next ()
  552.   "Go to the next node of this node."
  553.   (interactive)
  554.   (Octave-Info-goto-node (Info-extract-pointer "next")))
  555.  
  556. (defun Octave-Info-prev ()
  557.   "Go to the previous node of this node."
  558.   (interactive)
  559.   (Octave-Info-goto-node (Info-extract-pointer "prev[ious]*" "previous")))
  560.  
  561. (defun Octave-Info-up ()
  562.   "Go to the superior node of this node."
  563.   (interactive)
  564.   (Octave-Info-goto-node (Info-extract-pointer "up"))
  565.   (Octave-Info-restore-point Octave-Info-history))
  566.  
  567. (defun Octave-Info-last ()
  568.   "Go back to the last node visited."
  569.   (interactive)
  570.   (or Octave-Info-history
  571.       (Octave-Info-error "This is the first Octave-Info node you looked at"))
  572.   (let (filename nodename opoint)
  573.     (setq filename (car (car Octave-Info-history)))
  574.     (setq nodename (car (cdr (car Octave-Info-history))))
  575.     (setq opoint (car (cdr (cdr (car Octave-Info-history)))))
  576.     (setq Octave-Info-history (cdr Octave-Info-history))
  577.     (Octave-Info-find-node filename nodename)
  578.     (setq Octave-Info-history (cdr Octave-Info-history))
  579.     (goto-char opoint)))
  580.  
  581. (defun Octave-Info-directory ()
  582.   "Go to the Octave-Info directory node."
  583.   (interactive)
  584.   (Octave-Info-find-node "octave" "top"))
  585.  
  586. (defun Octave-Info-follow-reference (footnotename)
  587.   "Follow cross reference named NAME to the node it refers to.
  588. NAME may be an abbreviation of the reference name."
  589.   (interactive
  590.    (let ((completion-ignore-case t)
  591.      completions default alt-default (start-point (point)) str i bol eol)
  592.      (save-excursion
  593.        (end-of-line)
  594.        (setq eol (point))
  595.        (beginning-of-line)
  596.        (setq bol (point))
  597.        (goto-char (point-min))
  598.        (while (re-search-forward "\\*note[ \n\t]*\\([^:]*\\):" nil t)
  599.      (setq str (buffer-substring
  600.             (match-beginning 1)
  601.             (1- (point))))
  602.      ;; See if this one should be the default.
  603.      (and (null default)
  604.           (<= (match-beginning 0) start-point)
  605.           (<= start-point (point))
  606.           (setq default t))
  607.      ;; See if this one should be the alternate default.
  608.      (and (null alt-default)
  609.           (and (<= bol (match-beginning 0))
  610.            (<= (point) eol))
  611.           (setq alt-default t))
  612.      (setq i 0)
  613.      (while (setq i (string-match "[ \n\t]+" str i))
  614.        (setq str (concat (substring str 0 i) " "
  615.                  (substring str (match-end 0))))
  616.        (setq i (1+ i)))
  617.      ;; Record as a completion and perhaps as default.
  618.      (if (eq default t) (setq default str))
  619.      (if (eq alt-default t) (setq alt-default str))
  620.      (setq completions
  621.            (cons (cons str nil)
  622.              completions))))
  623.      ;; If no good default was found, try an alternate.
  624.      (or default
  625.      (setq default alt-default))
  626.      ;; If only one cross-reference found, then make it default.
  627.      (if (eq (length completions) 1)
  628.          (setq default (car (car completions))))
  629.      (if completions
  630.      (let ((input (completing-read (if default
  631.                        (concat "Follow reference named: ("
  632.                            default ") ")
  633.                      "Follow reference named: ")
  634.                        completions nil t)))
  635.        (list (if (equal input "")
  636.              default input)))
  637.        (Octave-Info-error "No cross-references in this node"))))
  638.   (let (target beg i (str (concat "\\*note " (regexp-quote footnotename))))
  639.     (while (setq i (string-match " " str i))
  640.       (setq str (concat (substring str 0 i) "[ \t\n]+" (substring str (1+ i))))
  641.       (setq i (+ i 6)))
  642.     (save-excursion
  643.       (goto-char (point-min))
  644.       (or (re-search-forward str nil t)
  645.       (Octave-Info-error "No cross-reference named %s" footnotename))
  646.       (goto-char (+ (match-beginning 0) 5))
  647.       (setq target
  648.         (Info-extract-menu-node-name "Bad format cross reference" t)))
  649.     (while (setq i (string-match "[ \t\n]+" target i))
  650.       (setq target (concat (substring target 0 i) " "
  651.                (substring target (match-end 0))))
  652.       (setq i (+ i 1)))
  653.     (Octave-Info-goto-node target)))
  654.  
  655. (defun Octave-Info-complete-menu-item (string predicate action)
  656.   (let ((case-fold-search t))
  657.     (cond ((eq action nil)
  658.        (let (completions
  659.          (pattern (concat "\n\\* \\("
  660.                   (regexp-quote string)
  661.                   "[^:\t\n]*\\):")))
  662.          (save-excursion
  663.            (set-buffer Octave-Info-complete-menu-buffer)
  664.            (goto-char (point-min))
  665.            (search-forward "\n* Menu:")
  666.            (while (re-search-forward pattern nil t)
  667.          (setq completions (cons (cons (format "%s"
  668.                                (buffer-substring
  669.                             (match-beginning 1)
  670.                             (match-end 1)))
  671.                            (match-beginning 1))
  672.                      completions))))
  673.          (try-completion string completions predicate)))
  674.       ((eq action t)
  675.        (let (completions
  676.          (pattern (concat "\n\\* \\("
  677.                   (regexp-quote string)
  678.                   "[^:\t\n]*\\):")))
  679.          (save-excursion
  680.            (set-buffer Octave-Info-complete-menu-buffer)
  681.            (goto-char (point-min))
  682.            (search-forward "\n* Menu:")
  683.            (while (re-search-forward pattern nil t)
  684.          (setq completions (cons (cons (format "%s"
  685.                                (buffer-substring
  686.                             (match-beginning 1)
  687.                             (match-end 1)))
  688.                            (match-beginning 1))
  689.                      completions))))
  690.          (all-completions string completions predicate)))
  691.       (t
  692.        (save-excursion
  693.          (set-buffer Octave-Info-complete-menu-buffer)
  694.          (goto-char (point-min))
  695.          (search-forward "\n* Menu:")
  696.          (re-search-forward (concat "\n\\* "
  697.                     (regexp-quote string)
  698.                     ":")
  699.                 nil t))))))
  700.  
  701. (defun Octave-Info-menu (menu-item)
  702.   "Go to node for menu item named (or abbreviated) NAME.
  703. Completion is allowed, and the menu item point is on is the default."
  704.   (interactive
  705.    (let ((completions '())
  706.      (default nil)
  707.      (p (point))
  708.      beg
  709.      (last nil))
  710.      (save-excursion
  711.        (goto-char (point-min))
  712.        (if (not (search-forward "\n* menu:" nil t))
  713.        (Octave-Info-error "No menu in this node"))
  714.        (setq beg (point))
  715.        (and (< (point) p)
  716.         (save-excursion
  717.           (goto-char p)
  718.           (end-of-line)
  719.           (re-search-backward "\n\\* \\([^:\t\n]*\\):" beg t)
  720.           (setq default (format "%s" (buffer-substring
  721.                       (match-beginning 1)
  722.                       (match-end 1)))))))
  723.      (let ((item nil))
  724.        (while (null item)
  725.      (setq item (let ((completion-ignore-case t)
  726.               (Octave-Info-complete-menu-buffer (current-buffer)))
  727.               (completing-read (if default
  728.                        (format "Menu item (default %s): "
  729.                            default)
  730.                      "Menu item: ")
  731.                        'Octave-Info-complete-menu-item nil t)))
  732.      (if (string= item "")
  733.          (if default
  734.          (setq item default)
  735.            (setq item nil))))
  736.        (list item))))
  737.   (Octave-Info-goto-node (Info-extract-menu-item menu-item)))
  738.  
  739. (defun Octave-Info-nth-menu-item ()
  740.   "Go to the node of the Nth menu item.
  741. N is the digit argument used to invoke this command."
  742.   (interactive)
  743.   (Octave-Info-goto-node
  744.    (Info-extract-menu-counting
  745.     (- (aref (this-command-keys) (1- (length (this-command-keys)))) ?0))))
  746.  
  747. (defun Octave-Info-top-node ()
  748.   "Go to the Top node of this file."
  749.   (interactive)
  750.   (Octave-Info-goto-node "Top"))
  751.  
  752. (defun Octave-Info-final-node ()
  753.   "Go to the final node in this file."
  754.   (interactive)
  755.   (Octave-Info-goto-node "Top")
  756.   (let (Octave-Info-history)
  757.     (Octave-Info-goto-node (Info-extract-menu-counting nil))
  758.     (while (Octave-Info-forward-node t t) nil)
  759.     (while (and (not (string-match "\\<index\\>" Octave-Info-current-node))
  760.         (save-excursion (search-forward "\n* Menu:" nil t)))
  761.       (Octave-Info-goto-node (Info-extract-menu-counting nil)))))
  762.  
  763. (defun Octave-Info-forward-node (&optional not-down no-error)
  764.   "Go forward one node, considering all nodes as forming one sequence."
  765.   (interactive)
  766.   (goto-char (point-min))
  767.   (forward-line 1)
  768.   (cond ((and (not not-down)
  769.               (save-excursion (search-forward "\n* menu:" nil t))
  770.           (not (string-match "\\<index\\>" Octave-Info-current-node)))
  771.      (Octave-Info-goto-node (Info-extract-menu-counting 1)) t)
  772.         ((save-excursion (search-backward "next:" nil t))
  773.          (Octave-Info-next) t)
  774.         ((and (save-excursion (search-backward "up:" nil t))
  775.           (not (string-equal (downcase (Info-extract-pointer "up"))
  776.                  "top")))
  777.          (let ((old-node Octave-Info-current-node))
  778.            (Octave-Info-up)
  779.            (let (Octave-Info-history success)
  780.              (unwind-protect
  781.                  (setq success (Octave-Info-forward-node t no-error))
  782.                (or success (Octave-Info-goto-node old-node))))))
  783.         (no-error nil)
  784.         (t (Octave-Info-error "No pointer forward from this node"))))
  785.  
  786. (defun Octave-Info-backward-node ()
  787.   "Go backward one node, considering all nodes as forming one sequence."
  788.   (interactive)
  789.   (let ((prevnode (Info-extract-pointer "prev[ious]*" t))
  790.     (upnode (Info-extract-pointer "up" t)))
  791.     (cond ((and upnode (string-match "(" upnode))
  792.        (Octave-Info-error "First node in file"))
  793.       ((and upnode (or (null prevnode)
  794.                (string-equal (downcase prevnode)
  795.                      (downcase upnode))))
  796.        (Octave-Info-up))
  797.       (prevnode
  798.        (Octave-Info-prev)
  799.        (let (Octave-Info-history)
  800.          (while (and (not (string-match "\\<index\\>"
  801.                         Octave-Info-current-node))
  802.              (save-excursion (search-forward "\n* Menu:" nil t)))
  803.            (Octave-Info-goto-node (Info-extract-menu-counting nil)))))
  804.       (t (Octave-Info-error "No pointer backward from this node")))))
  805.  
  806. (defun Octave-Info-exit ()
  807.   "Exit Octave-Info by selecting *octave* or some other buffer."
  808.   (interactive)
  809.   (if (equal Octave-Info-index-strings nil)
  810.       (progn
  811.     (split-window-vertically)
  812.     (delete-window)
  813.     (kill-buffer "*octave-info*")
  814.     (if (and (get-buffer "*octave*") (get-buffer-process "*octave*"))
  815.         (let ((octave-mode-cb (current-buffer)))
  816.           (switch-to-buffer-other-window "*octave*")
  817.           (delete-window (get-buffer-window octave-mode-cb)))
  818.       (switch-to-buffer (prog1 (other-buffer (current-buffer))
  819.                   (bury-buffer (current-buffer))))
  820.       (setq Octave-Info-running t)))
  821.     (progn
  822.       (Octave-Info-goto-node (format "(%s)" (car Octave-Info-index-strings)))
  823.       (setq Octave-Info-index-strings (cdr Octave-Info-index-strings))
  824.       (if (and (not (equal (car Octave-Info-index-strings) "(null)"))
  825.            (not (equal (car Octave-Info-index-strings) "")))
  826.       (Octave-Info-index (car Octave-Info-index-strings)))
  827.       (setq Octave-Info-index-strings (cdr Octave-Info-index-strings)))))
  828.  
  829. (defun Octave-Info-next-menu-item ()
  830.   (interactive)
  831.   (save-excursion
  832.     (forward-line -1)
  833.     (search-forward "\n* menu:" nil t)
  834.     (or (search-forward "\n* " nil t)
  835.     (Octave-Info-error "No more items in menu"))
  836.     (Octave-Info-goto-node (Info-extract-menu-node-name))))
  837.  
  838. (defun Octave-Info-last-menu-item ()
  839.   (interactive)
  840.   (save-excursion
  841.     (forward-line 1)
  842.     (let ((beg (save-excursion
  843.          (and (search-backward "\n* menu:" nil t) (point)))))
  844.       (or (and beg (search-backward "\n* " beg t))
  845.       (Octave-Info-error "No previous items in menu")))
  846.     (Octave-Info-goto-node (save-excursion (goto-char (match-end 0))
  847.                        (Info-extract-menu-node-name)))))
  848.  
  849. (defun Octave-Info-next-preorder ()
  850.   "Go to the next subnode or the next node, or go up a level."
  851.   (interactive)
  852.   (cond ((Info-no-error (Octave-Info-next-menu-item)))
  853.     ((Info-no-error (Octave-Info-next)))
  854.     ((Info-no-error (Octave-Info-up))
  855.      (goto-char (point-max)))
  856.     (t (Octave-Info-error "No more nodes"))))
  857.  
  858. (defun Octave-Info-last-preorder ()
  859.   "Go to the last node, popping up a level if there is none."
  860.   (interactive)
  861.   (cond ((Info-no-error
  862.       (Octave-Info-last-menu-item)
  863.       (goto-char (point-max)))
  864.      (recenter -1))
  865.     ((Info-no-error (Octave-Info-prev))
  866.      (goto-char (point-max))
  867.      (recenter -1))
  868.     ((Info-no-error (Octave-Info-up))
  869.      (goto-char (point-min))
  870.      (or (search-forward "\n* Menu:" nil t)
  871.          (goto-char (point-max))))
  872.     (t (Octave-Info-error "No previous nodes"))))
  873.  
  874. (defun Octave-Info-scroll-up ()
  875.   "Scroll one screenful forward in Octave-Info, considering all nodes as one 
  876. sequence. Once you scroll far enough in a node that its menu appears on the 
  877. screen, the next scroll moves into its first subnode.  When you scroll past
  878. the end of a node, that goes to the next node or back up to the parent node."
  879.   (interactive)
  880.   (if (or (< (window-start) (point-min))
  881.       (> (window-start) (point-max)))
  882.       (set-window-start (selected-window) (point)))
  883.   (let ((virtual-end (save-excursion
  884.                (goto-char (point-min))
  885.                (if (search-forward "\n* Menu:" nil t)
  886.                (point)
  887.              (point-max)))))
  888.     (if (or (< virtual-end (window-start))
  889.         (pos-visible-in-window-p virtual-end))
  890.     (Octave-Info-next-preorder)
  891.       (scroll-up))))
  892.  
  893. (defun Octave-Info-scroll-down ()
  894.   "Scroll one screenful back in Octave-Info, considering all nodes as one 
  895. sequence. Within the menu of a node, this goes to its last subnode.
  896. When you scroll past the beginning of a node, that goes to the
  897. previous node or back up to the parent node."
  898.   (interactive)
  899.   (if (or (< (window-start) (point-min))
  900.       (> (window-start) (point-max)))
  901.       (set-window-start (selected-window) (point)))
  902.   (let ((virtual-end (save-excursion
  903.                (goto-char (point-min))
  904.                (search-forward "\n* Menu:" nil t))))
  905.     (if (or virtual-end (pos-visible-in-window-p (point-min)))
  906.     (Octave-Info-last-preorder)
  907.       (scroll-down))))
  908.  
  909. (defun Octave-Info-next-reference ()
  910.   "Move cursor to the next cross-reference or menu item in the node."
  911.   (interactive)
  912.   (let ((pat "\\*note[ \n\t]*\\([^:]*\\):\\|^\\* .*:")
  913.     (old-pt (point)))
  914.     (or (eobp) (forward-char 1))
  915.     (or (re-search-forward pat nil t)
  916.     (progn
  917.       (goto-char (point-min))
  918.       (or (re-search-forward pat nil t)
  919.           (progn
  920.         (goto-char old-pt)
  921.         (Octave-Info-error "No cross references in this node")))))
  922.     (goto-char (match-beginning 0))
  923.     (if (looking-at "\\* Menu:")
  924.     (Octave-Info-next-reference))))
  925.  
  926. (defun Octave-Info-prev-reference ()
  927.   "Move cursor to the previous cross-reference or menu item in the node."
  928.   (interactive)
  929.   (let ((pat "\\*note[ \n\t]*\\([^:]*\\):\\|^\\* .*:")
  930.     (old-pt (point)))
  931.     (or (re-search-backward pat nil t)
  932.     (progn
  933.       (goto-char (point-max))
  934.       (or (re-search-backward pat nil t)
  935.           (progn
  936.         (goto-char old-pt)
  937.         (Octave-Info-error "No cross references in this node")))))
  938.     (goto-char (match-beginning 0))
  939.     (if (looking-at "\\* Menu:")
  940.     (Octave-Info-prev-reference))))
  941.  
  942. (defun Octave-Info-index (topic)
  943.   "Look up a string in the index for this file.
  944. The index is defined as the first node in the top-level menu whose
  945. name contains the word \"Index\", plus any immediately following
  946. nodes whose names also contain the word \"Index\".
  947. If there are no exact matches to the specified topic, this chooses
  948. the first match which is a case-insensitive substring of a topic.
  949. Use the `,' command to see the other matches.
  950. Give a blank topic name to go to the Index node itself."
  951.   (interactive "sIndex topic: ")
  952.   (let ((orignode Octave-Info-current-node)
  953.     (rnode nil)
  954.     (pattern (format "\n\\* \\([^\n:]*%s[^\n:]*\\):[ \t]*\\([^.\n]*\\)\\.[ \t]*\\([0-9]*\\)"
  955.              (regexp-quote topic)))
  956.     node)
  957.     (Octave-Info-goto-node "Top")
  958.     (or (search-forward "\n* menu:" nil t)
  959.     (Octave-Info-error "No index"))
  960.     (or (re-search-forward "\n\\* \\(.*\\<Index\\>\\)" nil t)
  961.     (Octave-Info-error "No index"))
  962.     (goto-char (match-beginning 1))
  963.     (let ((Octave-Info-history nil))
  964.       (Octave-Info-goto-node (Info-extract-menu-node-name)))
  965.     (or (equal topic "")
  966.     (let ((matches nil)
  967.           (exact nil)
  968.           (Octave-Info-history nil)
  969.           found)
  970.       (while
  971.           (progn
  972.         (goto-char (point-min))
  973.         (while (re-search-forward pattern nil t)
  974.           (setq matches
  975.             (cons (list (buffer-substring (match-beginning 1)
  976.                               (match-end 1))
  977.                     (buffer-substring (match-beginning 2)
  978.                               (match-end 2))
  979.                     Octave-Info-current-node
  980.                     (string-to-int (concat "0"
  981.                                (buffer-substring
  982.                                 (match-beginning 3)
  983.                                 (match-end 3)))))
  984.                   matches)))
  985.         (and (setq node (Info-extract-pointer "next" t))
  986.              (string-match "\\<Index\\>" node)))
  987.         (Octave-Info-goto-node node))
  988.       (or matches
  989.           (progn
  990.         (Octave-Info-last)
  991.         (Octave-Info-error "No \"%s\" in index" topic)))
  992.       (while (setq found (assoc topic matches))
  993.         (setq exact (cons found exact)
  994.           matches (delq found matches)))
  995.       (setq Octave-Info-index-alternatives
  996.         (nconc exact (nreverse matches)))
  997.       (Octave-Info-index-next 0)))))
  998.  
  999. (defun Octave-Info-index-next (num)
  1000.   "Go to the next matching index item from the last `i' command."
  1001.   (interactive "p")
  1002.   (or Octave-Info-index-alternatives
  1003.       (Octave-Info-error "No previous `i' command in this file"))
  1004.   (while (< num 0)
  1005.     (setq num (+ num (length Octave-Info-index-alternatives))))
  1006.   (while (> num 0)
  1007.     (setq Octave-Info-index-alternatives
  1008.       (nconc (cdr Octave-Info-index-alternatives)
  1009.          (list (car Octave-Info-index-alternatives)))
  1010.       num (1- num)))
  1011.   (Octave-Info-goto-node (nth 1 (car Octave-Info-index-alternatives)))
  1012.   (if (> (nth 3 (car Octave-Info-index-alternatives)) 0)
  1013.       (forward-line (nth 3 (car Octave-Info-index-alternatives)))
  1014.     (forward-line 3)
  1015.     (let ((name (car (car Octave-Info-index-alternatives))))
  1016.       (if (or (re-search-forward (format
  1017.                   "\\(Function\\|Command\\): %s\\( \\|$\\)"
  1018.                   (regexp-quote name)) nil t)
  1019.           (search-forward (format "`%s'" name) nil t)
  1020.           (and (string-match "\\`.*\\( (.*)\\)\\'" name)
  1021.            (search-forward
  1022.             (format "`%s'" (substring name 0 (match-beginning 1)))
  1023.             nil t))
  1024.           (search-forward name nil t))
  1025.       (beginning-of-line)
  1026.     (goto-char (point-min)))))
  1027.   (message "Found \"%s\" in %s.  %s"
  1028.        (car (car Octave-Info-index-alternatives))
  1029.        (nth 2 (car Octave-Info-index-alternatives))
  1030.        (if (cdr Octave-Info-index-alternatives)
  1031.            "(Press `,' for more)"
  1032.          "(Only match)")))
  1033.  
  1034. (defun Octave-Info-mouse-follow-nearest-node (click)
  1035.   "\\<Octave-Info-mode-map>Follow a node reference near point.
  1036. Like \\[Octave-Info-menu], \\[Octave-Info-follow-reference], \\[Octave-Info-next], \\[Octave-Info-prev] or \\[Octave-Info-up] command, depending on where you click.
  1037. At end of the node's text, moves to the next node, or up if none."
  1038.   (interactive "e")
  1039.   (let* ((start (event-start click))
  1040.      (window (car start))
  1041.      (pos (car (cdr start))))
  1042.     (select-window window)
  1043.     (goto-char pos))
  1044.   (and (not (Octave-Info-try-follow-nearest-node))
  1045.        (save-excursion (forward-line 1) (eobp))
  1046.        (Octave-Info-next-preorder)))
  1047.  
  1048. (defun Octave-Info-follow-nearest-node ()
  1049.   "\\<Octave-Info-mode-map>Follow a node reference near point.
  1050. Like \\[Octave-Info-menu], \\[Octave-Info-follow-reference], \\[Octave-Info-next], \\[Octave-Info-prev] or \\[Octave-Info-up] command, depending on where point is.
  1051. If no reference to follow, moves to the next node, or up if none."
  1052.   (interactive)
  1053.   (or (Octave-Info-try-follow-nearest-node)
  1054.       (Octave-Info-next-preorder)))
  1055.  
  1056. (defun Octave-Info-try-follow-nearest-node ()
  1057.   "Follow a node reference near point.  Return non-nil if successful."
  1058.   (let (node)
  1059.     (cond
  1060.      ((setq node (Info-get-token (point) "\\*note[ \n]"
  1061.                  "\\*note[ \n]\\([^:]*\\):"))
  1062.       (Octave-Info-follow-reference node))
  1063.      ((setq node (Info-get-token (point) "\\* " "\\* \\([^:]*\\)::"))
  1064.       (Octave-Info-goto-node node))
  1065.      ((setq node (Info-get-token (point) "\\* " "\\* \\([^:]*\\):"))
  1066.       (Octave-Info-menu node))
  1067.      ((setq node (Info-get-token (point) "Up: " "Up: \\([^,\n\t]*\\)"))
  1068.       (Octave-Info-goto-node node))
  1069.      ((setq node (Info-get-token (point) "Next: " "Next: \\([^,\n\t]*\\)"))
  1070.       (Octave-Info-goto-node node))
  1071.      ((setq node (Info-get-token (point) "File: " "File: \\([^,\n\t]*\\)"))
  1072.       (Octave-Info-goto-node "Top"))
  1073.      ((setq node (Info-get-token (point) "Prev: " "Prev: \\([^,\n\t]*\\)"))
  1074.       (Octave-Info-goto-node node)))
  1075.     node))
  1076.  
  1077. (defvar Octave-Info-mode-map nil
  1078.   "Keymap containing Octave-Info commands.")
  1079. (if Octave-Info-mode-map
  1080.     nil
  1081.   (setq Octave-Info-mode-map (make-keymap))
  1082.   (suppress-keymap Octave-Info-mode-map)
  1083.   (define-key Octave-Info-mode-map "." 'beginning-of-buffer)
  1084.   (define-key Octave-Info-mode-map " " 'Octave-Info-scroll-up)
  1085.   (define-key Octave-Info-mode-map "\C-m" 'Octave-Info-follow-nearest-node)
  1086.   (define-key Octave-Info-mode-map "\t" 'Octave-Info-next-reference)
  1087.   (define-key Octave-Info-mode-map "\e\t" 'Octave-Info-prev-reference)
  1088.   (define-key Octave-Info-mode-map "1" 'Octave-Info-nth-menu-item)
  1089.   (define-key Octave-Info-mode-map "2" 'Octave-Info-nth-menu-item)
  1090.   (define-key Octave-Info-mode-map "3" 'Octave-Info-nth-menu-item)
  1091.   (define-key Octave-Info-mode-map "4" 'Octave-Info-nth-menu-item)
  1092.   (define-key Octave-Info-mode-map "5" 'Octave-Info-nth-menu-item)
  1093.   (define-key Octave-Info-mode-map "6" 'Octave-Info-nth-menu-item)
  1094.   (define-key Octave-Info-mode-map "7" 'Octave-Info-nth-menu-item)
  1095.   (define-key Octave-Info-mode-map "8" 'Octave-Info-nth-menu-item)
  1096.   (define-key Octave-Info-mode-map "9" 'Octave-Info-nth-menu-item)
  1097.   (define-key Octave-Info-mode-map "0" 'undefined)
  1098.   (define-key Octave-Info-mode-map "]" 'Octave-Info-forward-node)
  1099.   (define-key Octave-Info-mode-map "[" 'Octave-Info-backward-node)
  1100.   (define-key Octave-Info-mode-map "<" 'Octave-Info-top-node)
  1101.   (define-key Octave-Info-mode-map ">" 'Octave-Info-final-node)
  1102.   (define-key Octave-Info-mode-map "b" 'beginning-of-buffer)
  1103.   (define-key Octave-Info-mode-map "d" 'Octave-Info-directory)
  1104.   (define-key Octave-Info-mode-map "f" 'Octave-Info-follow-reference)
  1105.   (define-key Octave-Info-mode-map "g" 'Octave-Info-goto-node)
  1106.   (define-key Octave-Info-mode-map "i" 'Octave-Info-index)
  1107.   (define-key Octave-Info-mode-map "l" 'Octave-Info-last)
  1108.   (define-key Octave-Info-mode-map "m" 'Octave-Info-menu)
  1109.   (define-key Octave-Info-mode-map "n" 'Octave-Info-next)
  1110.   (define-key Octave-Info-mode-map "p" 'Octave-Info-prev)
  1111.   (define-key Octave-Info-mode-map "q" 'Octave-Info-exit)
  1112.   (define-key Octave-Info-mode-map "s" 'Octave-Info-search)
  1113.   ;; For consistency with Rmail.
  1114.   (define-key Octave-Info-mode-map "\M-s" 'Octave-Info-search)
  1115.   (define-key Octave-Info-mode-map "t" 'Octave-Info-top-node)
  1116.   (define-key Octave-Info-mode-map "u" 'Octave-Info-up)
  1117.   (define-key Octave-Info-mode-map "," 'Octave-Info-index-next)
  1118.   (define-key Octave-Info-mode-map "\177" 'Octave-Info-scroll-down)
  1119.   (define-key Octave-Info-mode-map [mouse-2]
  1120.     'Octave-Info-mouse-follow-nearest-node)
  1121.   )
  1122.  
  1123. (put 'octave-info-mode 'mode-class 'special)
  1124.  
  1125. (defun Octave-Info-mode ()
  1126.   "See Info-mode for details."
  1127.   (kill-all-local-variables)
  1128.   (setq major-mode 'Octave-Info-mode)
  1129.   (setq mode-name "Octave-Info")
  1130.   (use-local-map Octave-Info-mode-map)
  1131.   (set-syntax-table text-mode-syntax-table)
  1132.   (setq local-abbrev-table text-mode-abbrev-table)
  1133.   (setq case-fold-search t)
  1134.   (setq buffer-read-only t)
  1135.   (make-local-variable 'Octave-Info-current-file)
  1136.   (make-local-variable 'Octave-Info-current-subfile)
  1137.   (make-local-variable 'Octave-Info-current-node)
  1138.   (make-local-variable 'Octave-Info-tag-table-marker)
  1139.   (make-local-variable 'Octave-Info-history)
  1140.   (make-local-variable 'Octave-Info-index-alternatives)
  1141.   (if (memq (framep (selected-frame)) '(x pc pm))
  1142.       (progn
  1143.     (make-face 'octave-info-node)
  1144.     (make-face 'octave-info-menu-5)
  1145.     (make-face 'octave-info-xref)
  1146.     (or (face-differs-from-default-p 'octave-info-node)
  1147.         (if (face-differs-from-default-p 'bold-italic)
  1148.         (copy-face 'bold-italic 'octave-info-node)
  1149.           (copy-face 'bold 'octave-info-node)))
  1150.     (or (face-differs-from-default-p 'octave-info-menu-5)
  1151.         (set-face-underline-p 'octave-info-menu-5 t))
  1152.     (or (face-differs-from-default-p 'octave-info-xref)
  1153.         (copy-face 'bold 'octave-info-xref)))
  1154.     (setq Octave-Info-fontify nil))
  1155.   (Octave-Info-set-mode-line)
  1156.   (run-hooks 'Octave-Info-mode-hook))
  1157.  
  1158. (defun Octave-Info-fontify-node ()
  1159.   (save-excursion
  1160.     (let ((buffer-read-only nil))
  1161.       (goto-char (point-min))
  1162.       (if (looking-at "^File: [^,: \t]+,?[ \t]+")
  1163.       (progn
  1164.         (goto-char (match-end 0))
  1165.         (while
  1166.         (looking-at "[ \t]*[^:, \t\n]+:[ \t]+\\([^:,\t\n]+\\),?")
  1167.           (goto-char (match-end 0))
  1168.           (put-text-property (match-beginning 1) (match-end 1)
  1169.                  'face 'octave-info-xref)
  1170.           (put-text-property (match-beginning 1) (match-end 1)
  1171.                  'mouse-face 'highlight))))
  1172.       (goto-char (point-min))
  1173.       (while (re-search-forward "\n\\([^ \t\n].+\\)\n\\(\\*+\\|=+\\|-+\\)$"
  1174.                 nil t)
  1175.     (put-text-property (match-beginning 1) (match-end 1)
  1176.                'face
  1177.                (cdr (assq (preceding-char) Info-title-face-alist)))
  1178.     (put-text-property (match-end 1) (match-end 2)
  1179.                'invisible t))
  1180.       (goto-char (point-min))
  1181.       (while (re-search-forward "\\*Note[ \n\t]+\\([^:]*\\):" nil t)
  1182.     (if (= (char-after (1- (match-beginning 0))) ?\")
  1183.         nil
  1184.       (put-text-property (match-beginning 1) (match-end 1)
  1185.                  'face 'octave-info-xref)
  1186.       (put-text-property (match-beginning 1) (match-end 1)
  1187.                  'mouse-face 'highlight)))
  1188.       (goto-char (point-min))
  1189.       (if (and (search-forward "\n* Menu:" nil t)
  1190.            (not (string-match "\\<Index\\>" Octave-Info-current-node))
  1191.            (< (- (point-max) (point))
  1192.           Octave-Info-fontify-maximum-menu-size))
  1193.       (let ((n 0))
  1194.         (while (re-search-forward "^\\* \\([^:\t\n]*\\):" nil t)
  1195.           (setq n (1+ n))
  1196.           (if (memq n '(5 9))
  1197.           (put-text-property (match-beginning 0)
  1198.                      (1+ (match-beginning 0))
  1199.                      'face 'octave-info-menu-5))
  1200.           (put-text-property (match-beginning 1) (match-end 1)
  1201.                  'face 'octave-info-node)
  1202.           (put-text-property (match-beginning 1) (match-end 1)
  1203.                  'mouse-face 'highlight))))
  1204.       (set-buffer-modified-p nil))))
  1205.  
  1206. (provide 'octave-info)
  1207.  
  1208. ;;; octave-info.el ends here
  1209.