emacs-matlab/matlab-topic.el

204 lines
7.4 KiB
EmacsLisp

;;; matlab-topic.el --- Help browsing via Emacs buffers.
;;
;; Copyright (C) 2019 Eric Ludlam
;;
;; Author: Eric Ludlam <zappo@gnu.org>
;;
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see https://www.gnu.org/licenses/.
;;; Commentary:
;;
;; Browsing topics via the MATLAB shell in an Emacs buffer is a nice
;; feature. Moving as optional as this is rarely used.
;;; Code:
(require 'matlab)
(require 'matlab-shell)
(require 'view)
(defvar matlab-shell-topic-mouse-face-keywords
'(;; These are subtopic fields...
("^\\(\\w+/\\w+\\)[ \t]+-" 1 font-lock-reference-face)
;; These are functions...
("^[ \t]+\\(\\w+\\)[ \t]+-" 1 font-lock-function-name-face)
;; Here is a See Also line...
("[ \t]+See also "
("\\(\\w+\\)\\([,.]\\| and\\|$\\) *" nil nil (1 font-lock-reference-face))))
"These are keywords we also want to put mouse-faces on.")
(defvar matlab-shell-topic-font-lock-keywords
(append matlab-shell-topic-mouse-face-keywords
'(("^[^:\n]+:$" 0 font-lock-keyword-face)
;; These are subheadings...
("^[ \t]+\\([^.\n]+[a-zA-Z.]\\)$" 1 'underline)
))
"Keywords useful for highlighting a MATLAB TOPIC buffer.")
(defvar matlab-shell-help-font-lock-keywords
(append matlab-shell-topic-mouse-face-keywords
'(;; Function call examples
("[ \t]\\([A-Z]+\\)\\s-*=\\s-*\\([A-Z]+[0-9]*\\)("
(1 font-lock-variable-name-face)
(2 font-lock-function-name-face))
("[ \t]\\([A-Z]+[0-9]*\\)("
(1 font-lock-function-name-face))
;; Parameters: Not very accurate, unfortunately.
("[ \t]\\([A-Z]+[0-9]*\\)("
("'?\\(\\w+\\)'?\\([,)]\\) *" nil nil
(1 font-lock-variable-name-face))
)
;; Reference uppercase words
("\\<\\([A-Z]+[0-9]*\\)\\>" 1 font-lock-reference-face)))
"Keywords for regular help buffers.")
;; View-major-mode is an emacs20 thing. This gives us a small compatibility
;; layer.
(eval-and-compile
(if (not (fboundp 'view-major-mode)) (defalias 'view-major-mode 'view-mode)))
(defvar matlab-shell-help-mode-map
(let ((km (make-sparse-keymap)))
(define-key km [return] 'matlab-shell-help-choose)
(define-key km "q" 'bury-buffer)
(define-key km [(control h) (control m)] matlab-help-map)
(if (string-match "XEmacs" emacs-version)
(define-key km [button2] 'matlab-shell-help-click)
(define-key km [mouse-2] 'matlab-shell-help-click)
(define-key km [mouse-1] 'matlab-shell-help-click)
)
(set-keymap-parent km view-mode-map)
km)
"Keymap used in MATLAB help mode.")
(easy-menu-define
matlab-shell-help-mode-menu matlab-shell-help-mode-map
"MATLAB shell Help menu"
'("MATLAB Help"
["Describe This Command" matlab-shell-help-choose t]
"----"
["Describe Command" matlab-shell-describe-command t]
["Describe Variable" matlab-shell-describe-variable t]
["Command Apropos" matlab-shell-apropos t]
"----"
["Exit" bury-buffer t]))
;; Need this to fix wierd problem in define-derived-mode
(defvar matlab-shell-help-mode-syntax-table (make-syntax-table)
"Syntax table used in `matlab-shell-help-mode'.")
;;;###autoload
(define-derived-mode matlab-shell-help-mode
view-major-mode "M-Help"
"Major mode for viewing MATLAB help text.
Entry to this mode runs the normal hook `matlab-shell-help-mode-hook'.
Commands:
\\{matlab-shell-help-mode-map}"
:syntax-table matlab-shell-help-mode-syntax-table
(make-local-variable 'font-lock-defaults)
(setq font-lock-defaults '((matlab-shell-help-font-lock-keywords)
t nil ((?_ . "w"))))
;; This makes sure that we really enter font lock since
;; kill-all-local-variables is not used by old view-mode.
(and (boundp 'global-font-lock-mode) global-font-lock-mode
(not font-lock-mode) (font-lock-mode 1))
(matlab-shell-help-mouse-highlight-subtopics)
(font-lock-ensure)
)
(defun matlab-shell-help-click (e)
"Click on an item in a MATLAB help buffer we want more information on.
Must be bound to event E."
(interactive "e")
(mouse-set-point e)
(matlab-shell-help-choose))
(defun matlab-shell-help-choose ()
"Choose the help to expand on that is under the cursor.
This can fill the help buffer with new information. If the help is a
command, use `matlab-shell-describe-command' instead of changing the help
buffer."
(interactive)
(let ((topic nil) (fun nil) (p (point)))
(save-excursion
(beginning-of-line)
(if (looking-at "^\\w+/\\(\\w+\\)[ \t]+-")
(setq topic (match-string 1))
(if (looking-at "^[ \t]+\\(\\(\\w\\|_\\)+\\)[ \t]+-")
(setq fun (match-string 1))
(if (and (not (looking-at "^[ \t]+See also"))
(not (save-excursion (forward-char -2)
(looking-at ",$"))))
;;(error "You did not click on a subtopic, function or reference")
nil
(goto-char p)
(forward-word -1)
(if (not (looking-at "\\(\\(\\w\\|_\\)+\\)\\([.,]\\| and\\|\n\\)"))
;;(error "You must click on a reference")
nil
(setq topic (match-string 1)))))))
;;(message "Opening item %s..." (or topic fun))
(when (or fun topic)
(matlab-shell-describe-command (downcase (or fun topic))))
))
(defun matlab-shell-help-mouse-highlight-subtopics ()
"Put a `mouse-face' on all clickable targets in this buffer."
(save-excursion
(let ((el matlab-shell-topic-mouse-face-keywords)
(inhibit-read-only t))
(while el
(goto-char (point-min))
(while (re-search-forward (car (car el)) nil t)
(let ((cd (car (cdr (car el)))))
(if (numberp cd)
(put-text-property (match-beginning cd) (match-end cd)
'mouse-face 'highlight)
(while (re-search-forward (car cd) nil t)
(put-text-property (match-beginning (car (nth 3 cd)))
(match-end (car (nth 3 cd)))
'mouse-face 'highlight)))))
(setq el (cdr el))))))
(defvar mouse-grabbed-buffer) ;; Suppress compilation warning in Emacs (an XEmacs only variable)
(defvar mode-motion-extent) ;; Suppress compilation warning in Emacs (an XEmacs only variable)
(defun matlab-shell-topic-highlight-line (event)
"A value of `mode-motion-hook' which will highlight topics under the mouse.
EVENT is the user mouse event."
;; XEMACS only function
(let* ((buffer (when (fboundp 'event-buffer) (event-buffer event)))
(point (and buffer (when (fboundp 'event-point) (event-point event)))))
(if (and buffer (not (eq buffer mouse-grabbed-buffer)))
(save-excursion
(save-window-excursion
(set-buffer buffer)
(when (fboundp 'mode-motion-ensure-extent-ok) (mode-motion-ensure-extent-ok event))
(if (not point)
(when (fboundp 'detach-extent) (detach-extent mode-motion-extent))
(goto-char point)
(end-of-line)
(setq point (point))
(beginning-of-line)
(if (or (looking-at "^\\w+/\\(\\w+\\)[ \t]+-")
(looking-at "^[ \t]+\\(\\(\\w\\|_\\)+\\)[ \t]+-"))
(when (fboundp 'set-extent-endpoints)
(set-extent-endpoints mode-motion-extent (point) point))
(when (fboundp 'detach-extent) (detach-extent mode-motion-extent)))))))))
(provide 'matlab-topic)
;;; matlab-topic.el ends here