2022-07-30 17:15:38 +00:00
|
|
|
|
;;; sclang-browser.el --- SuperCollider documentation browser -*- coding: utf-8; lexical-binding: t -*-
|
2009-01-02 19:06:25 +00:00
|
|
|
|
;;
|
2022-07-30 17:15:38 +00:00
|
|
|
|
;; Copyright 2003 stefan kersten <steve@k-hornz.de>
|
|
|
|
|
|
|
|
|
|
;;; License:
|
|
|
|
|
|
2009-01-02 19:06:25 +00:00
|
|
|
|
;; 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 2 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, write to the Free Software
|
2009-04-20 08:38:27 +00:00
|
|
|
|
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
2009-01-02 19:06:25 +00:00
|
|
|
|
;; USA
|
|
|
|
|
|
2022-07-30 17:15:38 +00:00
|
|
|
|
;;; Commentary:
|
|
|
|
|
;; Browser for SuperCollider documentation.
|
2009-01-02 19:06:25 +00:00
|
|
|
|
|
|
|
|
|
;; TODO: better factoring
|
2022-07-30 17:15:38 +00:00
|
|
|
|
;; - derive from view mode, make mode-map pluggable
|
|
|
|
|
;; - define derived mode for completion, definition, help
|
|
|
|
|
;; - update 'display-buffer-reuse-frames'
|
|
|
|
|
;; - update ‘view-return-to-alist’
|
|
|
|
|
|
|
|
|
|
(require 'sclang-util)
|
|
|
|
|
(require 'view)
|
|
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
|
|
(defun sclang-browser-fill-keymap ()
|
|
|
|
|
"Create keymap and bindings."
|
|
|
|
|
(let ((map (make-sparse-keymap)))
|
|
|
|
|
(set-keymap-parent map view-mode-map)
|
|
|
|
|
(define-key map "\r" 'sclang-browser-follow-link)
|
|
|
|
|
(define-key map [mouse-2] 'sclang-browser-mouse-follow-link)
|
|
|
|
|
(define-key map "\t" 'sclang-browser-next-link)
|
|
|
|
|
(define-key map [backtab] 'sclang-browser-previous-link)
|
|
|
|
|
(define-key map [(shift tab)] 'sclang-browser-previous-link)
|
|
|
|
|
(define-key map [?q] 'sclang-browser-quit)
|
|
|
|
|
map))
|
|
|
|
|
|
|
|
|
|
(defvar sclang-browser-mode-map (sclang-browser-fill-keymap))
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(defvar sclang-browser-mode-hook nil)
|
|
|
|
|
(defvar sclang-browser-show-hook nil)
|
2022-07-30 17:15:38 +00:00
|
|
|
|
(defvar sclang-browser-link-function nil)
|
|
|
|
|
(defvar sclang-browser-return-method nil)
|
2009-01-02 19:06:25 +00:00
|
|
|
|
|
|
|
|
|
(defun sclang-browser-beginning-of-link ()
|
2022-07-30 17:15:38 +00:00
|
|
|
|
"Beginning of link."
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(interactive)
|
|
|
|
|
(when (get-text-property (point) 'sclang-browser-link)
|
|
|
|
|
(while (and (not (bobp))
|
2022-07-30 17:15:38 +00:00
|
|
|
|
(get-text-property (point) 'sclang-browser-link))
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(forward-char -1))
|
|
|
|
|
(unless (bobp) (forward-char 1))
|
|
|
|
|
(point)))
|
|
|
|
|
|
|
|
|
|
(defun sclang-browser-next-link (&optional n)
|
2022-07-30 17:15:38 +00:00
|
|
|
|
"Next link (or N further)."
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(interactive)
|
|
|
|
|
(let* ((n (or n 1))
|
2022-07-30 17:15:38 +00:00
|
|
|
|
(prop 'sclang-browser-link)
|
|
|
|
|
(fwd (>= n 0))
|
|
|
|
|
(orig (point))
|
|
|
|
|
(beg (if fwd (point-min) (point-max)))
|
|
|
|
|
(end (if fwd (point-max) (point-min)))
|
|
|
|
|
(inc (if fwd 1 -1))
|
|
|
|
|
pos)
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(when (get-text-property (point) prop)
|
|
|
|
|
(while (and (/= (point) beg)
|
2022-07-30 17:15:38 +00:00
|
|
|
|
(get-text-property (point) prop))
|
|
|
|
|
(forward-char inc))
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(if (= (point) beg) (goto-char end)))
|
|
|
|
|
(while (not (eq pos orig))
|
|
|
|
|
(cond ((get-text-property (point) prop)
|
2022-07-30 17:15:38 +00:00
|
|
|
|
(sclang-browser-beginning-of-link)
|
|
|
|
|
(setq pos orig))
|
|
|
|
|
(t
|
|
|
|
|
(if (= (point) end) (goto-char beg))
|
|
|
|
|
(forward-char inc)
|
|
|
|
|
(setq pos (point)))))))
|
2009-01-02 19:06:25 +00:00
|
|
|
|
|
|
|
|
|
(defun sclang-browser-previous-link ()
|
2022-07-30 17:15:38 +00:00
|
|
|
|
"Previous link."
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(interactive)
|
|
|
|
|
(sclang-browser-next-link -1))
|
|
|
|
|
|
|
|
|
|
(defun sclang-browser-follow-link (&optional pos)
|
2022-07-30 17:15:38 +00:00
|
|
|
|
"Follow link (optionally POS)."
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(interactive)
|
|
|
|
|
(let* ((pos (or pos (point)))
|
2022-07-30 17:15:38 +00:00
|
|
|
|
(data (get-text-property pos 'sclang-browser-link)))
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(when (consp data)
|
|
|
|
|
(let ((fun (or (car data) sclang-browser-link-function))
|
2022-07-30 17:15:38 +00:00
|
|
|
|
(arg (cdr data)))
|
|
|
|
|
(when (functionp fun)
|
|
|
|
|
(condition-case nil
|
|
|
|
|
(funcall fun arg)
|
|
|
|
|
(error (sclang-message "Error in link function") nil)))))))
|
2009-01-02 19:06:25 +00:00
|
|
|
|
|
|
|
|
|
(defun sclang-browser-mouse-follow-link (event)
|
2022-07-30 17:15:38 +00:00
|
|
|
|
"Link. click. EVENT."
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(interactive "e")
|
|
|
|
|
(let* ((start (event-start event))
|
2022-07-30 17:15:38 +00:00
|
|
|
|
(window (car start))
|
|
|
|
|
(pos (cadr start)))
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(with-current-buffer (window-buffer window)
|
|
|
|
|
(sclang-browser-follow-link pos))))
|
|
|
|
|
|
|
|
|
|
(defun sclang-browser-mode ()
|
2022-07-30 17:15:38 +00:00
|
|
|
|
"Major mode for viewing hypertext and navigating references.
|
|
|
|
|
Entry to this mode runs the normal hook `sclang-browser-mode-hook'
|
|
|
|
|
|
2009-01-02 19:06:25 +00:00
|
|
|
|
Commands:
|
|
|
|
|
\\{sclang-browser-mode-map}"
|
|
|
|
|
(interactive)
|
2022-07-30 17:15:38 +00:00
|
|
|
|
(view-mode)
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(kill-all-local-variables)
|
|
|
|
|
(use-local-map sclang-browser-mode-map)
|
|
|
|
|
(setq mode-name "Browser")
|
|
|
|
|
(setq major-mode 'sclang-browser-mode)
|
|
|
|
|
(set (make-local-variable 'sclang-browser-link-function) nil)
|
|
|
|
|
(set (make-local-variable 'sclang-browser-return-method) nil)
|
|
|
|
|
(set (make-local-variable 'font-lock-defaults) nil)
|
|
|
|
|
(set (make-local-variable 'minor-mode-overriding-map-alist)
|
|
|
|
|
(list (cons 'view-mode sclang-browser-mode-map)))
|
2022-07-30 17:15:38 +00:00
|
|
|
|
(set (make-local-variable 'view-no-disable-on-exit) t)
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(run-hooks 'sclang-browser-mode-hook))
|
|
|
|
|
|
|
|
|
|
(defun sclang-browser-mode-setup ()
|
2022-07-30 17:15:38 +00:00
|
|
|
|
"Setup sclang-browser-mode."
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(sclang-browser-mode)
|
|
|
|
|
(setq buffer-read-only nil))
|
|
|
|
|
|
|
|
|
|
(defun sclang-browser-mode-finish ()
|
2022-07-30 17:15:38 +00:00
|
|
|
|
"Finish sclang-browser-mode."
|
|
|
|
|
(read-only-mode)
|
|
|
|
|
;; ‘view-return-to-alist’ is an obsolete variable (as of 24.1)
|
|
|
|
|
;;(setq view-return-to-alist
|
|
|
|
|
;; (list (cons (selected-window) sclang-browser-return-method)))
|
|
|
|
|
(view-mode -1)
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(run-hooks 'sclang-browser-show-hook))
|
|
|
|
|
|
|
|
|
|
(defun sclang-browser-quit ()
|
2022-07-30 17:15:38 +00:00
|
|
|
|
"Quit the sclang help browser."
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(interactive)
|
|
|
|
|
(when (eq major-mode 'sclang-browser-mode)
|
|
|
|
|
(kill-buffer (current-buffer))))
|
|
|
|
|
|
|
|
|
|
(defun sclang-browser-make-link (link-text &optional link-data link-function)
|
2022-07-30 17:15:38 +00:00
|
|
|
|
"Make a link using LINK-TEXT (optional LINK-DATA and LINK-FUNCTION)."
|
|
|
|
|
(propertize link-text
|
|
|
|
|
'mouse-face 'highlight
|
|
|
|
|
'sclang-browser-link (cons link-function link-data)))
|
2009-01-02 19:06:25 +00:00
|
|
|
|
|
|
|
|
|
(defun sclang-display-browser (buffer-name output-function)
|
2022-07-30 17:15:38 +00:00
|
|
|
|
"Display browser using BUFFER-NAME and OUTPUT-FUNCTION.
|
|
|
|
|
header: what to insert in the buffer.
|
|
|
|
|
link-list: list of (link-text link-function link-data)
|
|
|
|
|
link-function: function with args (link-text link-data)"
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(let ((temp-buffer-setup-hook '(sclang-browser-mode-setup))
|
2022-07-30 17:15:38 +00:00
|
|
|
|
(temp-buffer-show-hook '(sclang-browser-mode-finish)))
|
2009-01-02 19:06:25 +00:00
|
|
|
|
(with-output-to-temp-buffer buffer-name
|
|
|
|
|
(with-current-buffer standard-output
|
2022-07-30 17:15:38 +00:00
|
|
|
|
;; record return method
|
|
|
|
|
(setq sclang-browser-return-method
|
|
|
|
|
(cond ((special-display-p (buffer-name standard-output))
|
|
|
|
|
;; If the help output buffer is a special display buffer,
|
|
|
|
|
;; don't say anything about how to get rid of it.
|
|
|
|
|
;; First of all, the user will do that with the window
|
|
|
|
|
;; manager, not with Emacs.
|
|
|
|
|
;; Secondly, the buffer has not been displayed yet,
|
|
|
|
|
;; so we don't know whether its frame will be selected.
|
|
|
|
|
(cons (selected-window) t))
|
|
|
|
|
;; display-buffer-reuse-frames is obsolete since 24.3
|
|
|
|
|
;; replace with something like
|
|
|
|
|
;;+ (add-to-list 'display-buffer-alist
|
|
|
|
|
;;+ '("." nil (reusable-frames . t)))
|
|
|
|
|
;;- (display-buffer-reuse-frames
|
|
|
|
|
;;- (cons (selected-window) 'quit-window))
|
|
|
|
|
((not (one-window-p t))
|
|
|
|
|
(cons (selected-window) 'quit-window))
|
|
|
|
|
;; This variable is provided mainly for backward compatibility
|
|
|
|
|
;; and should not be used in new code.
|
|
|
|
|
;; (pop-up-windows
|
|
|
|
|
;; (cons (selected-window) t))
|
|
|
|
|
(t
|
|
|
|
|
(list (selected-window) (window-buffer)
|
|
|
|
|
(window-start) (window-point)))))
|
|
|
|
|
(funcall output-function)))))
|
2009-01-02 19:06:25 +00:00
|
|
|
|
|
|
|
|
|
(defmacro with-sclang-browser (buffer-name &rest body)
|
2022-07-30 17:15:38 +00:00
|
|
|
|
"Display browser in BUFFER-NAME and run BODY."
|
2009-01-02 19:06:25 +00:00
|
|
|
|
`(sclang-display-browser ,buffer-name (lambda () ,@body)))
|
|
|
|
|
|
|
|
|
|
;; =====================================================================
|
|
|
|
|
;; module setup
|
|
|
|
|
;; =====================================================================
|
|
|
|
|
|
|
|
|
|
(provide 'sclang-browser)
|
|
|
|
|
|
2022-07-30 17:15:38 +00:00
|
|
|
|
;;; sclang-browser.el ends here
|