1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancements. ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
11 (defvar $manual_demo
"manual.demo")
13 (defvar *debug-display-html-help
* nil
14 "Set to non-NIL to get some debugging messages from hdescribe.")
16 (defmspec $example
(l)
17 (declare (special *need-prompt
*))
18 (let ((example (second l
)))
19 (when (symbolp example
)
20 ;; Coerce a symbol to be a string.
21 ;; Remove the first character if it is a dollar sign.
22 (setq example
(coerce (exploden (stripdollar example
)) 'string
)))
23 (unless (stringp example
)
25 (intl:gettext
"example: argument must be a symbol or a string; found: ~M") example
))
26 ;; Downcase the string. $example is not case sensitive.
27 (setq example
(string-downcase example
))
28 (with-open-file (st ($file_search1 $manual_demo
'((mlist) $file_search_demo
)))
29 (prog (tem all c-tag d-tag
)
31 (setq tem
(read-char st nil
))
32 (unless tem
(go notfound
))
33 (unless (eql tem
#\
&) (go again
))
34 (setq tem
(read-char st nil
))
35 (unless (eql tem
#\
&) (go again
))
36 ;; so we are just after having read &&
38 (setq tem
(read st nil nil
))
39 (unless tem
(go notfound
))
40 ;; Coerce the topic in tem to be a string.
41 (setq tem
(coerce (exploden tem
) 'string
))
42 (cond ((string= tem example
)
46 ;; at this stage we read maxima forms and print and eval
47 ;; until a peek sees '&' as the first character of next expression,
48 ;; but at first skip over whitespaces.
50 (when (member (setq tem
(peek-char nil st nil
))
51 '(#\tab
#\space
#\newline
#\linefeed
#\return
#\page
))
52 ;; Found whitespace. Read char and look for next char.
53 ;; The && label can be positioned anywhere before the next topic.
54 (setq tem
(read-char st nil
))
56 (cond ((or (null tem
) (eql tem
#\
&))
57 (setf *need-prompt
* t
)
59 (setq tem
(dbm-read st nil nil
))
61 (setq c-tag
(makelabel $inchar
))
62 (unless $nolabels
(setf (symbol-value c-tag
) (nth 2 tem
)))
64 (displa `((mlabel) ,c-tag
,(nth 2 tem
))))
65 (setq $%
(meval* (nth 2 tem
)))
66 (setq d-tag
(makelabel $outchar
))
67 (unless $nolabels
(setf (symbol-value d-tag
) $%
))
68 (when (eq (caar tem
) 'displayinput
)
69 (displa `((mlabel) ,d-tag
,$%
)))
73 (setf *need-prompt
* t
)
75 (return `((mlist) ,@(nreverse all
)))
77 (mtell (intl:gettext
"example: ~M not found. 'example();' returns the list of known examples.~%") example
)
80 (defun mread-noprompt (&rest read-args
)
81 (let ((*mread-prompt
* "") (*prompt-on-read-hang
*))
82 (declare (special *mread-prompt
* *prompt-on-read-hang
*))
83 (unless read-args
(setq read-args
(list #+(or sbcl cmu
) *standard-input
*
84 #-
(or sbcl cmu
) *query-io
*)))
85 (caddr (apply #'mread read-args
))))
87 ;; Some list creation utilities.
89 (defmspec $create_list
(l)
90 (cons '(mlist) (apply #'create-list1
(cadr l
) (cddr l
))))
92 (defun create-list1 (form &rest l
&aux lis var1 top
)
93 (cond ((null l
) (list (meval* form
)))
98 (unless (symbolp var1
) (merror (intl:gettext
"create_list: expected a symbol; found: ~A") var1
))
99 (setq lis
(meval* lis
))
100 (mbinding ((list var1
))
101 (cond ((and (numberp lis
)
103 (setq top
(car l
) l
(cdr l
))
104 (setq top
(meval* top
))
106 (loop for i from lis to top
109 (apply #'create-list1 form l
)))
111 (loop for v in
(cdr lis
)
114 (apply #'create-list1 form l
)))
115 (t (merror (intl:gettext
"create_list: unexpected arguments."))))))))
117 ;; The documentation is now in INFO format and can be printed using
118 ;; tex, or viewed using info or gnu emacs or using a web browser. All
119 ;; versions of maxima have a builtin info retrieval mechanism.
121 (defmspec $describe
(x)
122 (let ((topic ($sconcat
(cadr x
)))
123 (exact-p (or (null (caddr x
)) (eq (caddr x
) '$exact
))))
125 (cl-info::info-exact topic
)
126 (cl-info::info-inexact topic
))))
128 (defmspec $apropos
(s)
129 (setq s
(car (margs s
)))
130 (cond ((or (stringp s
)
131 (and (symbolp s
) (setq s
(string (stripdollar s
)))))
132 ;; A list of all Maxima names which contain the string S.
133 (let ((acc (apropos-list s
:maxima
)))
134 ;; Filter the names which are Maxima User symbols starting
135 ;; with % or $ and remove duplicates.
140 (cond ((eq x
'||
) nil
)
141 ((char= (get-first-char x
) #\$
) x
)
142 ;; Change to a verb, when present.
143 ((char= (get-first-char x
) #\%
) (or (get x
'noun
) x
))
148 (intl:gettext
"apropos: argument must be a string or symbol; found: ~M") s
))))
151 ;;; Display help in browser instead of the terminal
152 (defun display-html-help (x)
153 ;; The pattern is basically " <nnn>" where "nnn" is any number of
155 (let* ((topic ($sconcat x
))
156 (found-it (gethash topic cl-info
::*html-index
*)))
157 (when *debug-display-html-help
*
158 (format *debug-io
* "topic = ~S~%" topic
)
159 (format *debug-io
* "found-it = ~S~%" found-it
))
161 (destructuring-bind (base-name . id
)
163 (let ((url (concatenate 'string
166 (namestring base-name
)
170 (when *debug-display-html-help
*
171 (format *debug-io
* "URL: ~S~%" url
))
172 (setf command
(ignore-errors (format nil $browser url
)))
174 (when *debug-display-html-help
*
175 (format *debug-io
* "Command: ~S~%" command
))
178 (merror "Browser command must contain exactly one ~~A: ~S" $browser
))))))
181 (defun display-html-topics (wanted)
182 (when maxima
::*debug-display-html-help
*
183 (format *debug-io
* "wanted = ~S~%" wanted
))
184 (loop for
(dir entry
) in wanted
185 do
(display-html-help (car entry
))))
187 (defun display-text-topics (wanted)
188 (loop for item in wanted
189 do
(let ((doc (cl-info::read-info-text
(first item
) (second item
))))
191 (format t
"~A~%~%" doc
)
192 (format t
"Unable to find documentation for `~A'.~%~
193 Possible bug maxima-index.lisp or build_index.pl?~%"
194 (first (second item
)))))))
196 ;; Escape the characters that are special to XML. This mechanism excludes
197 ;; the possibility that any keyword might coincide with the any xml tag
198 ;; start or tag end marker.
200 (defun xml-fix-string (x)
202 (let* ((tmp-x (wxxml-string-substitute "&" #\
& x
))
203 (tmp-x (wxxml-string-substitute "<" #\
< tmp-x
))
204 (tmp-x (wxxml-string-substitute ">" #\
> tmp-x
))
205 (tmp-x (wxxml-string-substitute " " #\Return tmp-x
))
206 (tmp-x (wxxml-string-substitute " " #\Linefeed tmp-x
))
207 (tmp-x (wxxml-string-substitute " " #\Newline tmp-x
))
208 (tmp-x (wxxml-string-substitute """ #\" tmp-x
)))
214 (defun display-wxmaxima-topics (wanted)
215 (loop for
(dir entry
) in wanted
217 ;; Tell wxMaxima to jump to the manual entry for "keyword"
218 (format t
"<html-manual-keyword>~a</html-manual-keyword>~%"
219 (xml-fix-string (car entry
)))
220 ;; Tell the lisp to make sure that this string is actually output
221 ;; as soon as possible
224 ;; When a frontend is running, this function should be redefined to
225 ;; display the help in whatever way the frontend wants to.
226 (defun display-frontend-topics (wanted)
227 (declare (ignore wanted
))
228 (merror (intl:gettext
"output_format_for_help: frontend not implemented.")))
230 (defun set-output-format-for-help (assign-var val
)
231 "When $output_format_for_help is set, this function validates the
232 value and sets *help-display-function* to the function to display
233 the help item in the specified format."
234 ;; Don't need assign-var here. It should be $output_format_for_help
235 ;; since this function is only called when $output_format_for_help
237 (declare (ignore assign-var
))
240 (setf *help-display-function
* 'display-text-topics
))
242 (setf *help-display-function
* 'display-html-topics
))
245 (setf *help-display-function
* 'display-frontend-topics
)
246 (merror (intl:gettext
"output_format_for_help set to frontend, but no frontend is running."))))
248 (merror (intl:gettext
"output_format_for_help should be one of text, html, or frontend: ~M")