Fix bug #4260: translate fails with go tag in final position
[maxima.git] / src / macdes.lisp
blob7818fb03afdb5eca5acb737c779de594581ea1c3
1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancements. ;;;;;
4 ;;; ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
9 (in-package :maxima)
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)
24 (merror
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)
30 again
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)
43 (go doit))
44 (t (push tem all)
45 (go again)))
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.
49 doit
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))
55 (go doit))
56 (cond ((or (null tem) (eql tem #\&))
57 (setf *need-prompt* t)
58 (return '$done)))
59 (setq tem (dbm-read st nil nil))
60 (incf $linenum)
61 (setq c-tag (makelabel $inchar))
62 (unless $nolabels (setf (symbol-value c-tag) (nth 2 tem)))
63 (let ($display2d)
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 ,$%)))
70 (go doit)
72 notfound
73 (setf *need-prompt* t)
74 (if (= (length l) 1)
75 (return `((mlist) ,@(nreverse all)))
76 (progn
77 (mtell (intl:gettext "example: ~M not found. 'example();' returns the list of known examples.~%") example)
78 (return '$done)))))))
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)))
95 (setq var1 (first l)
96 lis (second l)
97 l (cddr l))
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)
102 (progn
103 (setq top (car l) l (cdr l))
104 (setq top (meval* top))
105 (numberp top)))
106 (loop for i from lis to top
107 do (mset var1 i)
108 append
109 (apply #'create-list1 form l)))
110 (($listp lis)
111 (loop for v in (cdr lis)
112 do (mset var1 v)
113 append
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))))
124 (if exact-p
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.
136 (remove-duplicates
137 (cons '(mlist)
138 (delete-if-not
139 #'(lambda (x)
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))
144 (t nil)))
145 acc)) :test #'eq)))
147 (merror
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
154 ;; digits.
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))
160 (when found-it
161 (destructuring-bind (base-name . id)
162 found-it
163 (let ((url (concatenate 'string
164 $url_base
166 (namestring base-name)
168 id))
169 command)
170 (when *debug-display-html-help*
171 (format *debug-io* "URL: ~S~%" url))
172 (setf command (ignore-errors (format nil $browser url)))
173 (cond (command
174 (when *debug-display-html-help*
175 (format *debug-io* "Command: ~S~%" command))
176 ($system command))
178 (merror "Browser command must contain exactly one ~~A: ~S" $browser))))))
179 topic))
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))))
190 (if doc
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.
199 #+(or)
200 (defun xml-fix-string (x)
201 (when (stringp x)
202 (let* ((tmp-x (wxxml-string-substitute "&amp;" #\& x))
203 (tmp-x (wxxml-string-substitute "&lt;" #\< tmp-x))
204 (tmp-x (wxxml-string-substitute "&gt;" #\> tmp-x))
205 (tmp-x (wxxml-string-substitute "&#13;" #\Return tmp-x))
206 (tmp-x (wxxml-string-substitute "&#13;" #\Linefeed tmp-x))
207 (tmp-x (wxxml-string-substitute "&#13;" #\Newline tmp-x))
208 (tmp-x (wxxml-string-substitute "&quot;" #\" tmp-x)))
209 tmp-x)
213 #+(or)
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
222 (finish-output)))
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
236 ;; is assigned.
237 (declare (ignore assign-var))
238 (case val
239 ($text
240 (setf *help-display-function* 'display-text-topics))
241 ($html
242 (setf *help-display-function* 'display-html-topics))
243 ($frontend
244 (if $maxima_frontend
245 (setf *help-display-function* 'display-frontend-topics)
246 (merror (intl:gettext "output_format_for_help set to frontend, but no frontend is running."))))
247 (otherwise
248 (merror (intl:gettext "output_format_for_help should be one of text, html, or frontend: ~M")
249 val))))