Initial Commit
[packages] / xemacs-packages / ess / lisp / essd-sas.el
1 ;;; essd-sas.el --- SAS customization
2
3 ;; Copyright (C) 1997--2001 Richard M. Heiberger and A. J. Rossini
4 ;; Copyright (C) 2002--2004 A.J. Rossini, Rich M. Heiberger, Martin
5 ;;      Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
6
7 ;; Original Author: Richard M. Heiberger <rmh@astro.ocis.temple.edu>
8 ;; Created: 20 Aug 1997
9 ;; Maintainers: ESS-core <ESS-core@stat.math.ethz.ch>
10
11 ;; Keywords: start up, configuration.
12
13 ;; This file is part of ESS.
14
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)
18 ;; any later version.
19
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.
24
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.
28
29 ;;; Commentary:
30 ;; This file defines all the SAS customizations for ESS behaviors.  See
31 ;; essl-sas and essa-sas for the underlying general modifications.
32
33
34 ;;; Autoloads:
35
36 (ess-message "[essd-sas:] require 'comint & 'shell ...")
37 (require 'comint)
38 (require 'shell)
39 (require 'executable)
40
41 ;;(ess-message "[essd-sas:] require 'essa-sas ...")
42 ;;(require 'essa-sas)
43 (ess-message "[essd-sas:] require 'essl-sas ...")
44 (require 'essl-sas)
45 (ess-message "[essd-sas:] (autoload ..) (def** ..) ...")
46
47
48 (autoload 'inferior-ess "ess-inf" no-doc t)
49 (autoload 'ess-mode "ess-mode" no-doc t)
50 (autoload 'ess-proc-name "ess-inf" no-doc nil)
51
52 (defvar inferior-SAS-args "-stdio -linesize 80 -noovp -nosyntaxcheck"
53   "*Arguments to use for starting SAS.")
54
55 (defvar inferior-SAS-args-temp nil
56   "Hack variable, needed for args preprocessing.
57 Better logic needed!  (see 2 uses, in this file).")
58
59 ;;; Code:
60
61 (defun ess-SAS-pre-run-hook (temp-ess-dialect)
62   "Set up log and list files for interactive SAS."
63
64   (let* ((ess-shell-buffer-name-flag (get-buffer "*shell*"))
65          ess-shell-buffer-name
66          ;; isn't pretty yet.
67          ;;  ess-local-process-name is defined after this function.
68          ;;  it needs to be defined prior to this function.
69          (tmp-procname (let ((ntry 0)
70                              (done nil))
71                          ;; find a non-existent process
72                          (while (not done)
73                            (setq ntry (1+ ntry)
74                                  done (not
75                                        (get-process (ess-proc-name
76                                                      ntry
77                                                      temp-ess-dialect)))))
78                          (ess-proc-name ntry temp-ess-dialect)))
79          ;; Following was tmp-local-process-name.  Stolen from inferior-ess
80          (ess-sas-lst-bufname (concat "*" tmp-procname ".lst*"))
81          (ess-sas-log-bufname (concat "*" tmp-procname ".log*"))
82          (explicit-shell-file-name "/bin/sh")
83          inferior-SAS-redirect-args
84          ess-sas-lst
85          ess-sas-log)
86
87     (ess-write-to-dribble-buffer
88      (format "(ess-SAS-pre-run-hook 1): ess-lang=%s, ess-dialect=%s, temp-dialect=%s, buf=%s \n"
89              ess-language
90              ess-dialect
91              temp-ess-dialect
92              (current-buffer)))
93     ;; If someone is running a *shell* buffer, rename it to avoid
94     ;; inadvertent nuking.
95     (if ess-shell-buffer-name-flag
96         (save-excursion
97           (set-buffer "*shell*")
98           (setq ess-shell-buffer-name
99                 (rename-buffer "*ess-shell-regular*" t))))
100
101     ;; Construct the LST buffer for output
102     (if (get-buffer ess-sas-lst-bufname)
103         nil
104       (shell)
105       (accept-process-output (get-buffer-process (current-buffer)))
106       (sleep-for 2) ; need to wait, else working too fast!
107       (setq ess-sas-lst (ess-insert-accept "tty"))
108       (SAS-listing-mode)
109       (shell-mode)
110       (ess-listing-minor-mode t)
111       (rename-buffer ess-sas-lst-bufname t))
112
113      ;; Construct the LOG buffer for output
114     (if (get-buffer  ess-sas-log-bufname)
115         nil
116       (shell)
117       (accept-process-output (get-buffer-process (current-buffer)))
118       (sleep-for 2) ; need to wait, else working too fast!
119       (setq ess-sas-log (ess-insert-accept "tty"))
120       (SAS-log-mode)
121       (shell-mode)
122       (ess-transcript-minor-mode t)
123       (rename-buffer ess-sas-log-bufname t))
124
125     (setq inferior-SAS-redirect-args (concat " "
126                                              ess-sas-lst
127                                              " "
128                                              ess-sas-log
129                                              " ")
130           inferior-SAS-args-temp (concat inferior-SAS-redirect-args
131                                          inferior-SAS-args))
132
133     ;; Restore the *shell* buffer
134     (if ess-shell-buffer-name-flag
135         (save-excursion
136           (set-buffer ess-shell-buffer-name)
137           (rename-buffer "*shell*")))
138
139     (delete-other-windows)
140     (split-window-vertically)
141     (split-window-vertically)
142     (switch-to-buffer (nth 2 (buffer-list)))
143     (other-window 2)
144     (switch-to-buffer ess-sas-log-bufname)
145     (split-window-vertically)
146     (other-window 1)
147     (switch-to-buffer ess-sas-lst-bufname)
148     (other-window 2)
149
150     ;;workaround
151     (setq inferior-SAS-program-name
152           (concat ess-etc-directory "ess-sas-sh-command"))
153     (setq inferior-ess-program inferior-SAS-program-name)))
154
155 (defun ess-insert-accept (command)
156   "Submit command to process, get next line."
157   (interactive)
158   (goto-char (point-max))
159   (insert command)
160   (comint-send-input)
161   (accept-process-output (get-buffer-process (current-buffer)))
162   (forward-line -1)
163   (let* ((beg (point))
164          (ess-tty-name (progn (end-of-line) (buffer-substring beg (point)))))
165     (goto-char (point-max))
166     ess-tty-name))
167
168
169 (defvar SAS-customize-alist
170   '((ess-local-customize-alist     . 'SAS-customize-alist)
171     (ess-language                  . "SAS")
172     (ess-dialect                   . "SAS")
173     (ess-mode-editing-alist        . SAS-editing-alist) ; from essl-sas.el
174     (ess-mode-syntax-table         . SAS-syntax-table)
175     (inferior-ess-program          . inferior-SAS-program-name)
176     (ess-help-sec-regex            . "^[A-Z. ---]+:$")
177     (ess-help-sec-keys-alist       . " ")
178     (ess-object-name-db-file       . "ess-sas-namedb.el")
179     (inferior-ess-objects-command  . "objects(%d)");;FIXME
180     (inferior-ess-help-command     . "help(\"%s\",pager=\"cat\",window=F)\n");;FIXME
181     (inferior-ess-exit-command     . "endsas;\n")
182     (ess-loop-timeout              .  500000 )
183     (inferior-ess-primary-prompt   . "^")
184     (inferior-ess-secondary-prompt . "^")
185     (comint-use-prompt-regexp-instead-of-fields . t) ;; emacs 21 and up
186     (inferior-ess-start-file       . nil) ;"~/.ess-SAS")
187     (inferior-ess-start-args       . inferior-SAS-args-temp)
188     ;; (ess-pre-run-hook              . 'ess-SAS-pre-run-hook)
189     (ess-local-process-name        . nil))
190   "Variables to customize for SAS")
191
192 ;;; The functions of interest (mode, inferior mode)
193
194 (defvar sas-mode-local-map nil "contains modified local keymap for SAS")
195
196 (defun SAS-mode (&optional proc-name)
197   "Major mode for editing SAS source.  See ess-mode for more help."
198   (interactive)
199   (setq ess-customize-alist SAS-customize-alist)
200   (ess-mode SAS-customize-alist proc-name)
201
202   ;; Local map settings, AFTER initialization (only if not yet defined)
203   (if sas-mode-local-map
204       nil
205     (setq sas-mode-local-map (copy-keymap (current-local-map)))
206     (ess-sas-edit-keys-set ess-sas-edit-keys-toggle)
207     (if ess-sas-local-unix-keys (ess-sas-local-unix-keys))
208     (if ess-sas-local-pc-keys (ess-sas-local-pc-keys))
209     (if ess-sas-global-unix-keys (ess-sas-global-unix-keys))
210     (if ess-sas-global-pc-keys (ess-sas-global-pc-keys)))
211   (define-key sas-mode-local-map "\C-ci" 'ess-eval-line-and-step-invisibly)
212   (define-key sas-mode-local-map ";" 'ess-electric-run-semicolon)
213   
214   (define-key sas-mode-local-map "\C-c\C-p" 'ess-sas-file-path)
215   (define-key sas-mode-local-map "\C-c\C-b" 'ess-sas-submit)
216   (define-key sas-mode-local-map "\C-c\C-r" 'ess-sas-submit-region)
217   (define-key sas-mode-local-map "\C-c\C-x" 'ess-sas-goto-log)
218   (define-key sas-mode-local-map "\C-c\C-y" 'ess-sas-goto-lst)
219
220   (use-local-map sas-mode-local-map))
221
222 ;; rmh Jul 10 2003
223 (defun ess-electric-run-semicolon (arg)
224   "Insert character.  If the line contains \"run;\" and nothing else then indent line."
225   (interactive "P")
226   (let (insertpos)
227     (if (and (not arg)
228              (eolp)
229              (save-excursion
230                    (skip-chars-backward " \t")
231                    (backward-word 1)
232                    (and (looking-at "run")
233                         (progn
234                         ;; if ess-sas-edit-keys-toggle, then
235                         ;; call ess-sas-backward-delete-tab
236                         ;; rather than skip-chars-backward
237                           (if ess-sas-edit-keys-toggle (ess-sas-backward-delete-tab)
238                               (skip-chars-backward " \t"))
239                           (bolp)))))
240         (progn
241           (insert last-command-char)
242           (ess-indent-line)
243           (save-excursion
244             (if insertpos (goto-char (1+ insertpos)))
245             (delete-char -1))))
246     (if insertpos
247         (save-excursion
248           (goto-char insertpos)
249           (self-insert-command (prefix-numeric-value arg)))
250       (self-insert-command (prefix-numeric-value arg)))))
251
252 (defun SAS ()
253   "Call 'SAS', from SAS Institute."
254   (interactive)
255   (setq-default ess-customize-alist SAS-customize-alist)
256   (let* ((temp-dialect "SAS")) ;(cdr (rassoc ess-dialect SAS-customize-alist))))
257     (ess-write-to-dribble-buffer
258      (format "(SAS): ess-dial=%s, temp-dial=%s\n"
259              ess-dialect
260              temp-dialect))
261     (ess-SAS-pre-run-hook temp-dialect)
262     (inferior-ess)
263     (save-excursion
264       (set-buffer "*SAS*")
265       (use-local-map sas-mode-local-map))))
266
267
268 (defun ess-multi-frame-SAS ()
269   "Put running SAS buffers into separate frames.
270 Load this function M-x load-file essx-sas.el RET.
271 Then find-file myfile.sas.  If myfile.sas is already in a buffer, kill-buffer
272 it and then find-file it again.
273 Place the cursor in a myfile.sas buffer.  Run SAS with M-x SAS,
274 Return the cursor to the myfile.sas buffer,
275 then enter C-c C-w to put *SAS* *SAS.log* *SAS.lst* buffers into
276 their own frames."
277   (interactive)
278   (delete-other-windows)
279   (save-excursion
280       (set-buffer "*SAS*")
281       (make-frame)
282       (set-buffer "*SAS.log*")
283       (make-frame)
284       (set-buffer "*SAS.lst*")
285       (make-frame)))
286
287
288 (define-key ess-mode-map "\C-c\C-w"        'ess-multi-frame-SAS)
289
290 \f ; Provide package
291
292 (provide 'essd-sas)
293
294 \f ; Local variables section
295
296 ;;; This file is automatically placed in Outline minor mode.
297 ;;; The file is structured as follows:
298 ;;; Chapters:     ^L ;
299 ;;; Sections:    ;;*;;
300 ;;; Subsections: ;;;*;;;
301 ;;; Components:  defuns, defvars, defconsts
302 ;;;              Random code beginning with a ;;;;* comment
303
304 ;;; Local variables:
305 ;;; mode: emacs-lisp
306 ;;; outline-minor-mode: nil
307 ;;; mode: outline-minor
308 ;;; outline-regexp: "\^L\\|\\`;\\|;;\\*\\|;;;\\*\\|(def[cvu]\\|(setq\\|;;;;\\*"
309 ;;; End:
310
311 ;;; essd-sas.el ends here