1 ;;; essd-sp4.el --- S-PLUS 4.x customization
3 ;; Copyright (C) 1998--2002 Richard M. Heiberger <rmh@fisher.stat.temple.edu>
4 ;; Copyright (C) 2003--2004 A.J. Rossini, Rich M. Heiberger, Martin
5 ;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
7 ;; Original Author: Richard M. Heiberger <rmh@fisher.stat.temple.edu>
8 ;; Created: December 1998
9 ;; Maintainers: ESS-core <ESS-core@stat.math.ethz.ch>
11 ;; Keywords: start up, configuration.
13 ;; This file is part of ESS.
15 ;; This file is free software; you can redistribute it and/or modify
16 ;; it under the terms of the GNU General Public License as published by
17 ;; the Free Software Foundation; either version 2, or (at your option)
20 ;; This file is distributed in the hope that it will be useful,
21 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
22 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 ;; GNU General Public License for more details.
25 ;; You should have received a copy of the GNU General Public License
26 ;; along with GNU Emacs; see the file COPYING. If not, write to
27 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
30 ;;; This file defines all the S-PLUS 4.x customizations for ess-mode
33 ;;; Requires and Autoloads:
38 (autoload 'inferior-ess "ess-inf" "Run an ESS process.")
39 (autoload 'ess-mode "ess-mode" "Edit an ESS process.")
43 (defvar S+4-dialect-name "S+4"
44 "Name of 'dialect' for S-PLUS 4.x.");easily changeable in a user's .emacs
46 (defvar inferior-S+4-multipleinstances "/MULTIPLEINSTANCES"
47 "Default \"/MULTIPLEINSTANCES\" opens up a new instance of S+4 in a
48 GUI window and connects it to the '(ddeESS [S+4])' window. The
49 alternative nil uses an existing S+4 GUI (if there is one) and
50 connects it to the '(ddeESS [S+4])' window.")
52 (defvar S+4-customize-alist
54 '((ess-local-customize-alist . 'S+4-customize-alist)
55 (ess-dialect . S+4-dialect-name)
56 (ess-loop-timeout . ess-S-loop-timeout);fixme: dialect spec.
57 (ess-object-name-db-file . "ess-sp4-namedb.el" )
58 (inferior-ess-program . inferior-S+4-program-name)
59 (inferior-ess-help-command . "help(\"%s\")\n")
61 (inferior-ess-start-file . nil) ;"~/.ess-S+4")
62 (inferior-ess-start-args . (concat
63 inferior-S+4-multipleinstances " "
64 inferior-S+4-print-command
66 (directory-file-name default-directory)))
67 ;; (inferior-ess-ddeclient . "ddeclient")
68 ;; (inferior-ess-client-name . "S-PLUS")
69 ;; (inferior-ess-client-command . "SCommand")
70 (ess-STERM . "ddeESS")
74 "Variables to customize for S+4")
76 (defvar Sqpe+4-customize-alist
78 '((ess-local-customize-alist . 'Sqpe+4-customize-alist)
79 (ess-dialect . S+4-dialect-name)
80 (ess-loop-timeout . 500000 );fixme: dialect specific custom.v
81 (ess-object-name-db-file . "ess-sp4-namedb.el" )
82 (inferior-ess-program . inferior-Sqpe+4-program-name)
83 (inferior-ess-help-command . "help(\"%s\")\n")
84 (inferior-ess-search-list-command . "searchPaths()\n")
85 (inferior-ess-start-file . nil) ;"~/.ess-S+4")
86 (inferior-ess-language-start . (concat
88 "STERM='" ess-STERM "'"
90 (concat ", editor='" ess-editor "'"))
92 (concat ", pager='" ess-pager "'"))
98 "Variables to customize for Sqpe+4.")
101 ;;; There are extra complications in S+4 (compared to S+3) because
103 ;;; (1) The StatSci supplied Splus.exe doesn't work in an emacs
104 ;;; buffer. It works as as a GUI window and we must send commands
105 ;;; to it through ddeclient. Nonetheless, we need to give it a
106 ;;; process name and be sure that that there is a valid running
107 ;;; process in the '(ddeESS [S+4])' buffer. Therefore we create an
108 ;;; ESS process in the buffer as a placeholder and start a shell
109 ;;; in the ESS buffer. From the shell we start Splus. Once Splus
110 ;;; finishes initializing and kills the original shell, we start
111 ;;; another shell. We have a buffer-local variable
112 ;;; inferior-ess-ddeclient, initialized to nil. When there is a
113 ;;; non-nil value of inferior-ess-ddeclient we send lines to
114 ;;; inferior-ess-ddeclient rather than to the Splus process.
115 ;;; (2) There is no Splus process running in the '(ddeESS [S+4])'
116 ;;; buffer. Therefore inferior-ess will never see a prompt,
117 ;;; unless we first change it to the null prompt "^". Then once
118 ;;; the process has started, we change it back.
119 ;;; (3) When M-x S+4 starts Splus by a shell command, then Splus is an
120 ;;; independent process and will be survive if the '(ddeESS [S+4])'
121 ;;; buffer is killed (or emacs is quit). The '(ddeESS [S+4])' is
122 ;;; made read-only and a warning is placed in it saying that "You
123 ;;; can't type anything here." Actually, if the standalone Splus
124 ;;; is killed and the '(ddeESS [S+4])' is made writable (C-x C-q),
125 ;;; then '(ddeESS [S+4])' becomes a shell buffer.
127 (defun S+4 (&optional proc-name)
128 "Call 'S-PLUS 4.x', the 'GUI Thing' from StatSci. Put S-Plus in an
129 independent MS-Window (Splus persists even if the '(ddeESS [S+4])'
130 window is killed in emacs). Do this by creating a comint process that
131 calls sh. Send a shell command in that sh buffer to call Splus. When
132 it completes set up a shell as a placeholder in the '(ddeESS [S+4])'
133 buffer. The S-Plus options are correctly set. In particular, the
134 S-Plus Commands window is opened if the Options/General
135 Settings/Startup menu says it should be. There is a 30 second delay
136 during startup in which the screen will not be refreshed. This delay
137 is here to allow slow disks to start the Splus program."
140 (setq ess-customize-alist S+4-customize-alist)
141 (ess-write-to-dribble-buffer
142 (format "\n(S+4): ess-dialect=%s, buf=%s\n" ess-dialect
144 (setq ess-customize-alist ; change inferior-ess-program
145 (append ess-customize-alist '((inferior-ess-program . "sh"))))
146 (setq ess-customize-alist ; change inferior-ess-primary-prompt
147 (append ess-customize-alist '((inferior-ess-primary-prompt . "^"))))
148 (setq ess-customize-alist ; change inferior-ess-start-args
149 (append ess-customize-alist '((inferior-ess-start-args . "-i"))))
150 (let ((s-proj (getenv "S_PROJ"))
151 (manpath (getenv "MANPATH")))
152 (cd (w32-short-file-name (directory-file-name default-directory)))
153 (setenv "S_PROJ" default-directory)
154 ;; I don't know why this PATH/MANPATH game is needed,
155 ;; except that it doesn't work without it.
156 (setenv "MANPATH" (getenv "PATH"))
158 (sleep-for 2) ; need to wait, else working too fast! The Splus
159 ; command in '(ddeESS [S+4])' should follow the "$"
160 ; prompt. If not, then increase the sleep-for time!
161 (setenv "MANPATH" manpath)
162 (setenv "S_PROJ" s-proj))
163 (setq ess-customize-alist S+4-customize-alist)
164 (ess-setq-vars-local ess-customize-alist)
165 ;;; the next three lines belong in customize-alist, but can't be there
166 ;;; because of the broken ess-setq-vars-default usage in ess-inf.el
167 (setq inferior-ess-ddeclient "ddeclient")
168 (setq inferior-ess-client-name "S-PLUS")
169 (setq inferior-ess-client-command "SCommand")
170 ;;; end of what belongs in customize-alist
171 (setq comint-process-echoes nil)
172 (setq comint-input-sender 'comint-simple-send)
173 (goto-char (point-max))
174 (insert (concat inferior-S+4-program-name " "
175 inferior-ess-start-args)) ; Note: there is no final "&".
176 ;; Without the "&", the results of !system.command come to '(ddeESS [S+4])'
177 ;; With the "&", the results of !system.command in S get lost.
178 (inferior-ess-send-input)
179 (sleep-for 30) ; Need to wait, else working too fast!
180 ; If the ess-current-process-name doesn't appear in the
181 ; Splus Commands window increase the sleep-for time!
182 (setq ess-local-process-name ess-current-process-name)
183 (ess-eval-linewise (concat "#" ess-current-process-name))
184 (beginning-of-buffer)
186 "This is a placeholder buffer. You can't type anything here.
187 Use `C-x b RET' to return to your file.\n
188 Anything sent to this process from an S-mode buffer goes
189 directly to the associated Splus Commands window.\n
190 The S-Plus Commands window must be visible.
191 You may need to open the S-Plus Commands window manually (by clicking on
192 Splus/Window/Commands Window).\n
193 Any results of the !system.command typed at the S prompt in the
194 Splus Commands window appear in this buffer.\n\n")
195 (goto-char (point-max)) ; comint-mode-map makes '(ddeESS [S+4])'
196 ;; (use-local-map comint-mode-map) ;a shell buffer after Splus is finished.
197 (set-buffer-process-coding-system 'raw-text-dos 'raw-text-unix)
198 (toggle-read-only t) ; force buffer to be read-only
199 (setq mode-name "ddeESS")
200 ;; (ess-eval-linewise inferior-S+4-editor-pager-command)
201 (if inferior-ess-language-start
202 (ess-eval-linewise inferior-ess-language-start))
208 (defun S+4-existing (&optional proc-name)
209 "Call 'S-PLUS 4.x', the 'GUI Thing' from StatSci. Do so by finding
210 an existing S-Plus in an independent MS-Window (if there is one) and
211 set up a '(ddeESS [S+4])' buffer in emacs. If there is no existing
212 S-Plus, then a new one will be opened in the default directory,
213 usually something like c:/Program Files/spls45se/users/yourname.
214 If you have a HOME environment variable, it will open it there."
216 (let* ((inferior-S+4-multipleinstances " & # ")) ; Note: there is a final "&".
217 ;; Without the "&", there is a core dump.
218 ;; With the "&", the results of !system.command in S get lost.
219 ;; We are picking up an existing S-Plus process for sending to.
220 ;; It doesn't know about us, so nothing comes back.
223 (set-buffer (car (buffer-list))) ; get the ESS buffer just created
224 (toggle-read-only nil) ; permit writing in ESS buffer
225 (goto-char (point-max))
229 "This is S+4-existing.
230 Results of the !system.command typed at the S prompt in the
231 Splus Commands window blink a DOS window and you won't see them.\n\n")
232 (toggle-read-only t) ; restore ESS buffer to be read-only
236 ;;; There are extra complications in Sqpe+4 (compared to S+3) because
237 ;;; (1) The StatSci supplied Sqpe.exe won't work without SHOME as an
238 ;;; environment variable and Sqpe does not take command line
240 ;;; (2) Sqpe.exe comes up with options(interactive=F), which means it
241 ;;; doesn't provide prompts by default, and we must change it to T so
242 ;;; it will provide prompts.
244 (defun Sqpe+4 (&optional proc-name)
245 "Call 'Sqpe' from 'S-PLUS 4.x', the 'Real Thing' from StatSci."
247 (setq ess-customize-alist Sqpe+4-customize-alist)
248 (let* ((shome-nil-p (equal (getenv "SHOME") nil)))
249 (if shome-nil-p (setenv "SHOME" inferior-Sqpe+4-SHOME-name))
250 (ess-write-to-dribble-buffer
251 (format "\n(Sqpe+4): ess-dialect=%s, buf=%s\n" ess-dialect
253 (setq ess-customize-alist ; change inferior-ess-primary-prompt
254 (append ess-customize-alist '((inferior-ess-primary-prompt . "^"))))
256 (setq ess-customize-alist Sqpe+4-customize-alist) ; restore i-e-p-p in alist
257 (ess-setq-vars-local ess-customize-alist) ; restore i-e-p-p in buffer
258 (setq inferior-ess-prompt ; define with correct i-e-p-p
259 ;; Do not anchor to bol with `^' ; (copied from ess-inf.el)
261 inferior-ess-primary-prompt
263 inferior-ess-secondary-prompt
265 (setq comint-prompt-regexp (concat "^" inferior-ess-prompt))
266 ; define with correct i-e-p-p
267 (setq comint-input-sender 'inferior-ess-input-sender)
268 (add-hook 'comint-output-filter-functions 'shell-strip-ctrl-m nil t)
269 (goto-char (point-max))
270 (insert "options(interactive=T)")
271 (inferior-ess-send-input)
272 (setq mode-name "iESS(Sqpe)")
273 ;; (ess-eval-linewise inferior-S+4-editor-pager-command)
274 (if inferior-ess-language-start
275 (ess-eval-linewise inferior-ess-language-start))
276 (if shome-nil-p (setenv "SHOME" nil))))
280 (defun S+4-mode (&optional proc-name)
281 "Major mode for editing S+4 source. See `ess-mode' for more help."
283 (setq ess-customize-alist S+4-customize-alist)
284 (ess-mode S+4-customize-alist proc-name)
285 (if ess-imenu-use-S (ess-imenu-R)))
287 (defun S+4-transcript-mode ()
288 "S-PLUS 4.x transcript mode."
290 (ess-transcript-mode S+4-customize-alist))
293 (defun S+4-msdos (&optional proc-name)
294 "Call 'S-PLUS 4.x', the 'GUI Thing' from StatSci. Put S-Plus in an
295 independent MS-Window (Splus persists even if the '(ddeESS [S+4])'
296 window is killed in emacs). Do this by creating a comint process that
297 calls sh. Send a shell command in that sh buffer to call Splus. When
298 it completes set up a shell as a placeholder in the '(ddeESS [S+4])'
299 buffer. The S-Plus options are correctly set. In particular, the
300 S-Plus Commands window is opened if the Options/General
301 Settings/Startup menu says it should be. There is a 30 second delay
302 during startup in which the screen will not be refreshed. This delay
303 is here to allow slow disks to start the Splus program."
306 (setq ess-customize-alist S+4-customize-alist)
307 (ess-write-to-dribble-buffer
308 (format "\n(S+4): ess-dialect=%s, buf=%s\n" ess-dialect
310 (setq ess-customize-alist ; change inferior-ess-program
311 (append ess-customize-alist '((inferior-ess-program
312 . (getenv "COMSPEC")))))
313 (setq ess-customize-alist ; change inferior-ess-primary-prompt
314 (append ess-customize-alist '((inferior-ess-primary-prompt . "^"))))
315 (setq ess-customize-alist ; change inferior-ess-start-args
316 (append ess-customize-alist '((inferior-ess-start-args . ""))))
317 (let ((s-proj (getenv "S_PROJ")))
318 (cd (w32-short-file-name (directory-file-name default-directory)))
319 (setenv "S_PROJ" default-directory)
321 (sleep-for 2) ; need to wait, else working too fast! The Splus
322 ; command in '(ddeESS [S+4])' should follow the "$"
323 ; prompt. If not, then increase the sleep-for time!
324 (setenv "S_PROJ" s-proj))
325 (setq ess-customize-alist S+4-customize-alist)
326 (ess-setq-vars-local ess-customize-alist)
327 ;;; the next three lines belong in customize-alist, but can't be there
328 ;;; because of the broken ess-setq-vars-default usage in ess-inf.el
329 (setq inferior-ess-ddeclient "ddeclient")
330 (setq inferior-ess-client-name "S-PLUS")
331 (setq inferior-ess-client-command "SCommand")
332 ;;; end of what belongs in customize-alist
333 (setq comint-input-sender 'comint-simple-send)
334 (setq comint-process-echoes nil)
335 (set-buffer-process-coding-system 'raw-text-dos 'raw-text-dos)
336 (goto-char (point-max))
337 (insert (concat inferior-S+4-program-name " "
338 inferior-ess-start-args)) ; Note: there is no final "&".
339 ; Without the "&", the results of !system.command come to '(ddeESS [S+4])'
340 ; With the "&", the results of !system.command in S get lost.
341 (inferior-ess-send-input)
342 (sleep-for 30) ; Need to wait, else working too fast!
343 ; If the ess-current-process-name doesn't appear in the
344 ; Splus Commands window increase the sleep-for time!
345 ;;; from msdos-minor-mode
346 (setq comint-process-echoes t)
347 (add-hook 'comint-output-filter-functions 'shell-strip-ctrl-m nil t)
348 ;;; end from msdos-minor-mode
349 (setq ess-local-process-name ess-current-process-name)
350 (ess-eval-linewise (concat "#" ess-current-process-name))
351 (beginning-of-buffer)
353 "This is a placeholder buffer. You can't type anything here.
354 Use 'C-x b RET' to return to your file.\n
355 Anything sent to this process from an S-mode buffer goes
356 directly to the associated Splus Commands window.\n
357 The S-Plus Commands window must be visible.
358 You may need to open the S-Plus Commands window manually
359 (by clicking on Splus/Window/Commands Window).\n
360 There is a 30 second delay when this program starts during which the
361 emacs screen will be partially blank.\n
363 `q()' from S-Plus and
364 then C-x C-q exit from the `'(ddeESS [S+4])'' buffer,
365 or take the risk of not being able to shut down your computer
366 and suffering through scandisk.\n
367 Any results of the !system.command typed at the S prompt in the
368 Splus Commands window (are supposed to) appear in this buffer.\n\n")
369 (goto-char (point-max)) ; comint-mode-map makes '(ddeESS [S+4])'
370 (use-local-map comint-mode-map) ; a shell buffer after Splus is finished.
371 (toggle-read-only t) ; force buffer to be read-only
372 (setq mode-name "ddeESS")
373 ;; (ess-eval-linewise inferior-S+4-editor-pager-command)
374 (if inferior-ess-language-start
375 (ess-eval-linewise inferior-ess-language-start))
378 (defun S+4-msdos-existing (&optional proc-name)
379 "Call 'S-PLUS 4.x', the 'GUI Thing' from StatSci. Do so by finding
380 an existing S-Plus in an independent MS-Window (if there is one) and
381 set up a '(ddeESS [S+4])' buffer in emacs. If there is no existing
382 S-Plus, then a new one will be opened in the default directory,
383 usually something like c:/Program Files/spls45se/users/yourname.
384 If you have a HOME environment variable, it will open it there."
386 (let* ((inferior-S+4-multipleinstances ""))
387 (S+4-msdos proc-name))
389 (set-buffer (car (buffer-list))) ; get the ESS buffer just created
390 (toggle-read-only nil) ; permit writing in ESS buffer
391 (goto-char (point-max))
395 "This is S+4-msdos-existing.
396 Results of the !system.command typed at the S prompt in the
397 Splus Commands window blink a DOS window and you won't see them.\n\n")
398 (toggle-read-only t) ; restore ESS buffer to be read-only
405 \f ; Local variables section
407 ;;; This file is automatically placed in Outline minor mode.
408 ;;; The file is structured as follows:
411 ;;; Subsections: ;;;*;;;
412 ;;; Components: defuns, defvars, defconsts
413 ;;; Random code beginning with a ;;;;* comment
417 ;;; outline-minor-mode: nil
418 ;;; mode: outline-minor
419 ;;; outline-regexp: "\^L\\|\\`;\\|;;\\*\\|;;;\\*\\|(def[cvu]\\|(setq\\|;;;;\\*"
422 ;;; essd-s+4.el ends here