home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / modes / S-mode / S.el < prev    next >
Encoding:
Text File  |  1992-06-29  |  90.3 KB  |  2,451 lines

  1. ;;;; -*- Mode: Emacs-Lisp -*- 
  2. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3. ;;;; 
  4. ;;;; File            : S.el
  5. ;;;; Authors         : Doug Bates
  6. ;;;;                 : Ed Kademan
  7. ;;;;                 : Frank Ritter
  8. ;;;;                 : David Smith
  9. ;;;; Created On      : October 14, 1991
  10. ;;;; Last Modified By: David Smith
  11. ;;;; Last Modified On: Mon Jun 29 15:04:26 CST 1992
  12. ;;;; Version         : 3.41
  13. ;;;; 
  14. ;;;; Lisp-dir-entry  : S-mode|
  15. ;;;;                   Doug Bates, Ed Kademan, Frank Ritter, David Smith|
  16. ;;;;                   dsmith@stats.adelaide.edu.au|
  17. ;;;;                   Interface to the S/Splus statistical software packages|
  18. ;;;;                   92-06-29|
  19. ;;;;                   3.4|
  20. ;;;;                   /attunga.stats.adelaide.edu.au:pub/S-mode/S-mode3.4.tar.Z
  21. ;;;;
  22. ;;;; PURPOSE
  23. ;;;;     Interface to the S/Splus statistical software packages
  24. ;;;; 
  25. ;;;; Copyright 1989,1991,1992 Doug Bates    bates@stat.wisc.edu
  26. ;;;;                          Ed Kademan    kademan@stat.wisc.edu
  27. ;;;;                          Frank Ritter  ritter@psy.cmu.edu
  28. ;;;;                                            (or  @cs.cmu.edu)
  29. ;;;;                          David Smith   dsmith@stats.adelaide.edu.au
  30. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  31.  
  32. ;;; The Changelog is at the end of this file.
  33.  
  34. ;;; CREDITS.
  35. ;;; Thanks to shiba@shun.isac.co.jp (Ken'ichi "Modal" Shibayama) for
  36. ;;;   the indenting code.
  37. ;;; Thanks also to maechler@stat.math.ethz.ch (Martin Maechler) for
  38. ;;;   suggestions and bug fixes.
  39. ;;; S-eval-line-and-next-line is based on a function by Rod Ball 
  40. ;;;   (rod@marcam.dsir.govt.nz)
  41. ;;;
  42. ;;; Also thanks from David Smith to the previous authors for all their
  43. ;;; help and suggestions.
  44.  
  45. ;;; BRIEF OVERVIEW
  46. ;;; Supports stuctured editing of S (a statistics package)
  47. ;;; functions that is integrated with a running S process in a
  48. ;;; buffer.  
  49.  
  50. ;;; GENERAL DISCLAIMER
  51. ;;; 
  52. ;;; This program is free software; you can redistribute it
  53. ;;; and/or modify it under the terms of the GNU General Public
  54. ;;; License as published by the Free Software Foundation; either
  55. ;;; version 1, or (at your option) any later version.
  56. ;;; 
  57. ;;; This program is distributed in the hope that it will be
  58. ;;; useful, but WITHOUT ANY WARRANTY; without even the implied
  59. ;;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  60. ;;; PURPOSE.  See the GNU General Public License for more
  61. ;;; details.
  62. ;;; 
  63. ;;; You should have received a copy of the GNU General Public
  64. ;;; License along with this program; if not, write to the Free
  65. ;;; Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
  66. ;;; 02139, USA.
  67. ;;; 
  68. ;;; In short: you may use this code any way you like, as long as you
  69. ;;; don't charge money for it, remove this notice, or hold anyone liable
  70. ;;; for its results.
  71.  
  72. ;;; OVERVIEW OF S MODE
  73. ;;; 
  74. ;;; S is a statistics package available from Bell Labs
  75. ;;; particularly suited for descriptive and exploratory
  76. ;;; statistics.  s-mode is built on top of comint (the general
  77. ;;; command interpreter mode written by Olin Shivers), and so
  78. ;;; comint.el (or comint.elc) should be either loaded or in your
  79. ;;; load path when you invoke it.
  80. ;;; 
  81. ;;; Aside from the general features offered by comint such as
  82. ;;; command history editing and job control, inferior S mode
  83. ;;; allows you to dump and load S objects into and from external
  84. ;;; files, and to display help on functions.  It also provides
  85. ;;; name completion while you do these.  For more detailed
  86. ;;; information see the documentation strings for S,
  87. ;;; inferior-S-mode, S-mode, and comint-mode.  There are also
  88. ;;; many variables and hooks available for customizing (see
  89. ;;; the variables below that have document strings that start
  90. ;;; with an "*").
  91.  
  92. ;;; INSTALLATION
  93. ;;; Save this file in an appropriate directory and put the following
  94. ;;; line in your .emacs:
  95. ;;; 
  96. ;;;     (autoload 'S "~/elisp/S" "" t)
  97. ;;; 
  98. ;;; where "~/elisp/S.el" is the path name of this file.  That
  99. ;;; way, all you will have to do to get S running is to type
  100. ;;; "M-x S" from within emacs. You may also want to change some
  101. ;;; options, by putting lines such as the following in your .emacs:
  102. ;;; 
  103. ;;;     (setq inferior-S-program "S") ; command to run S
  104. ;;;    (setq S-version-running "2.3") ; Running the old version
  105. ;;;    (setq S-ask-about-display t) ; Ask for an X-display
  106. ;;;     (setq S-source-directory
  107. ;;;      (expand-file-name "~/S-Src/"))
  108. ;;;    (setq S-keep-dump-files t)
  109. ;;;                  ; Make a directory of backup object source files
  110. ;;;
  111. ;;; See the section "User changeable variables" below for more options.
  112.  
  113. ;;; GETTING LATER RELEASES OF S MODE
  114. ;;; The latest version is available from statlib by sending a
  115. ;;; blank message with subject "send index from S" to
  116. ;;; statlib@stat.cmu.edu, and following the directions from
  117. ;;; there.  Comint is probably already available at your site, 
  118. ;;; and already in your load path.  If it is not, you can get it
  119. ;;; from archive.cis.ohio-state.edu (login anonymous, passwd id)
  120. ;;; in directory /pub/gnu/emacs/elisp-archive/as-is/comint.el.Z
  121. ;;; This version has been tested and works with (at least) 
  122. ;;; comint-version 2.03.  You probably have copies of comint.el 
  123. ;;; on your system.  Copies are also available from ritter@cs.cmu.edu,
  124. ;;; and shivers@cs.cmu.edu.
  125. ;;;
  126. ;;; S-mode is also available for anonymous FTP from
  127. ;;; attunga.stats.adelaide.edu.au in the directory pub/S-mode. It is
  128. ;;; alsa avaliable from the Emacs-lisp archive on
  129. ;;; archive.cis.ohio-state.edu.
  130.  
  131. ;;; RELEASE 2.1 INFORMATION
  132. ;;;
  133. ;;; Improvements since last release (unnumbered of Summer 1990):
  134. ;;; * Better description provided of functions loaded.
  135. ;;; * Better header for this file.
  136. ;;; * S-directory is now a prescriptive rather than just 
  137. ;;;   descriptive variable.  
  138. ;;; * better syntax table, so |#; are better recognized and
  139. ;;;   commands using them work better.
  140. ;;; * we have a version number.
  141. ;;;
  142. ;;; RELEASE 3.4 INFORMATION
  143. ;;; 
  144. ;;; * Works with version 3.0 S
  145. ;;; * Command-line completion of S object names
  146. ;;; * Recognition of attached data frames 
  147. ;;; * Dedicated S Help mode
  148. ;;; * Tek graphics support
  149. ;;; * Several bugfixes and code cleanups
  150. ;;; * Texinfo documentation
  151. ;;;
  152. ;;; Remaining Bugs:
  153. ;;; 
  154. ;;; * It would be nice to use .Last.value when running S+
  155. ;;; * It would be nice to use S VERSION when running S+
  156. ;;; Until the end of August 1992, please report bugs to me at
  157. ;;; dsmith@stats.adelaide.edu.au. After this date, mail to that address
  158. ;;; will not be answered for some time; please contact Frank Ritter
  159. ;;; (Frank_Ritter@SHAMO.SOAR.CS.CMU.EDU) or any of the other authors then
  160. ;;; (please CC: to me as well though -- you never know, I might just
  161. ;;; answer!) Comments, suggestions, words of praise and large cash
  162. ;;; donations are also more than welcome.
  163.  
  164. ;;; Inits and provides
  165. ;;;=====================================================
  166. ;;;
  167.  
  168. (require 'comint)
  169. (require 'comint-extra)
  170. (autoload 'comint-isearch "comint-isearch" 
  171.       "Isearch for comint [full documentation when loaded]" t)
  172. (provide 'S)
  173.  
  174. (defconst S-mode-version "3.41" 
  175.   "Version of S-mode currently loaded.")
  176.  
  177. ;; this will appear for just a short while, but it's a
  178. ;; chance to teach...
  179. (message 
  180.  (concat (substitute-command-keys
  181.       "Type \\[describe-mode] for help on S-mode version ")
  182.      S-mode-version))
  183.  
  184.  
  185.  
  186. ;;; User changeable variables
  187. ;;;=====================================================
  188. ;;; Users note: Variables with document strings starting
  189. ;;; with a * are the ones you can generally change safely, and
  190. ;;; may have to upon occasion.
  191.  
  192. ;;; System dependent variables
  193.  
  194. (defvar inferior-S-program "Splus"
  195.   "*Program name for invoking an inferior S.")
  196.  
  197. (defvar inferior-Splus-args nil
  198.   "*String of arguments passed to the S process on startup if the name of
  199. the S program is `Splus'.")
  200.  
  201. (defvar S-version-running "3.0"
  202.   "Version of S being run.")
  203. ;;; The value of this variable affects the
  204. ;;; default values of the following variables:
  205. ;;; 
  206. ;;;     inferior-S-help-command
  207. ;;;     inferior-S-search-list-command
  208. ;;;     S-dump-error-re
  209. ;;; 
  210. ;;; Modifications to these variables are made at *load* time (provided, of
  211. ;;; course, they have not already been given values), hence changing the
  212. ;;; value of S-version-running after this package is loaded will have no
  213. ;;; effect.
  214. ;;; 
  215. ;;; Currently the string \"3.0\" is the only value of this variable with
  216. ;;; any real meaning; in this case the defaults are set to comply with the
  217. ;;; August '91 (3.0) version of S/Splus, defaults which also work for
  218. ;;; version 2.3. Any other value than \"3.0\" sets the defaults to comply
  219. ;;; with the 1988 version of S/Splus.")
  220. ;;;
  221. ;;; Please reserve the following values as special:
  222. ;;;   "3.0"    Version 3.0 (August '91) of S/Splus
  223. ;;;   "2.3"    Version 2.3 of S/Splus
  224. ;;;   "old"    Any older version
  225.  
  226. (defvar S-plus (assoc inferior-S-program '(("Splus") ("S+")))
  227.   "Set to t if Splus is being used instead of vanilla S")
  228. ;;; Used for setting default values of other variables, and hence
  229. ;;; has no effect after S.el has been loaded.
  230.  
  231. (defvar inferior-S-prompt "\\(\\+\\|[a-zA-Z0-9() ]*>\\) *"
  232.   "The regular expression inferior S mode uses for recognizing prompts
  233. Do not anchor to bol with `^'.")
  234.  
  235. (defvar inferior-S-primary-prompt "[a-zA-Z0-9() ]*> *"
  236.   "Regular expression used by S-mode to detect the primary prompt.
  237. Do not anchor to bol with `^'.")
  238.  
  239. ;;; Initialising the environment
  240.  
  241. (defvar S-ask-for-S-directory t
  242.   "*If non-nil, the process directory will be requested each time S is run")
  243.  
  244. (defvar S-ask-about-display nil
  245.   "*If non-nil, asks for a value for the DISPLAY environment
  246. variable, to make X-windows work with S")
  247.  
  248. (defvar X-displays-list '("unix:0.0")
  249.   "List of strings that are candidates for the DISPLAY environment variable.")
  250.  
  251. (defvar S-directory (file-name-as-directory (getenv "HOME"))
  252.   "*The directory S is run from.  It must end in a slash.
  253. Provided as a default if S-ask-for-S-directory is non-nil.")
  254.  
  255. ;;; Editing functions
  256.  
  257. (defvar S-insert-function-templates t
  258.   "*Boolean flag specifying action when editing a non-existent object.
  259. If t, then when the text of a dumped object contains S-dumped-missing-re,
  260. then it will be replaced by S-function-template.")
  261.  
  262.   ;; By K.Shibayama 5.14.1992
  263.  
  264. (defvar S-indent-level 2
  265.   "*Indentation of S statements with respect to containing block.")
  266.  
  267. (defvar S-brace-imaginary-offset 0
  268.   "*Imagined indentation of a S open brace that actually follows a statement.")
  269.  
  270. (defvar S-brace-offset 0
  271.   "*Extra indentation for braces, compared with other text in same context.")
  272.  
  273. (defvar S-continued-statement-offset 2
  274.   "*Extra indent for lines not starting new statements.")
  275.  
  276. (defvar S-continued-brace-offset 0
  277.   "*Extra indent for substatements that start with open-braces.
  278. This is in addition to S-continued-statement-offset.")
  279.  
  280. (defvar S-arg-function-offset 2
  281.   "*Extra indent for internal substatements of function `foo' that called
  282. in `arg=foo(...)' form. 
  283. If not number, the statements are indented at open-parenthesis following foo.")
  284.  
  285. (defvar S-expression-offset 4
  286.   "*Extra indent for internal substatements of `expression' that specified
  287. in `obj <- expression(...)' form. 
  288. If not number, the statements are indented at open-parenthesis following 
  289. `expression'.")
  290.  
  291. (defvar S-auto-newline nil
  292.   "*Non-nil means automatically newline before and after braces
  293. inserted in S code.")
  294.  
  295. (defvar S-tab-always-indent t
  296.   "*Non-nil means TAB in S mode should always reindent the current line,
  297. regardless of where in the line point is when the TAB command is used.")
  298.    
  299. (defvar S-default-style 'GNU
  300.   "*The default value of S-style")
  301.  
  302. (defvar S-style S-default-style
  303.   "*The buffer specific S indentation style.")
  304.  
  305. ;;; Dump files
  306.  
  307. (defvar S-source-directory "/tmp/"
  308.   "*Directory in which to place dump files.  
  309. The directory generated by S-source-directory-generator (if it is
  310. non-nil) is used preferentially, and the value of S-source-directory
  311. is used only of the generated directory can not be written or
  312. created.")
  313.  
  314. (defvar S-source-directory-generator nil
  315.   "*Function which, when called with no args, will return a directory
  316. name (ending in a slash) into which S objects should be dumped. If this is
  317. nil of the directory does not exist and cannot be created, the value of
  318. S-source-directory is used.")
  319. ;;; Possible value:
  320. ;;; '(lambda () (file-name-as-directory 
  321. ;;;          (expand-file-name (concat (car S-search-list) "/.Src"))))
  322. ;;; This always dumps to a sub-directory (".Src") of the current S
  323. ;;; working directory (i.e. first elt of search list)
  324.  
  325. (defvar S-dump-filename-template (concat (user-login-name) ".%s.S")
  326.   "*Template for filenames of dumped objects.
  327. %s is replaced by the object name.")
  328. ;;; This gives filenames like `user.foofun.S', so as not to clash with
  329. ;;; other users if you are using a shared directory. Other alternatives:
  330. ;;; "%s.S" ; Don't bother uniquifying if using your own directory(ies)
  331. ;;; "dump" ; Always dump to a specific filename. This makes it impossible
  332. ;;;          to edit more than one object at a time, though.
  333. ;;; (make-temp-name "scr.") ; Another way to uniquify
  334.  
  335. (defvar S-keep-dump-files nil
  336.   "*If nil, delete dump files ater use. Otherwise, never delete.")
  337. ;;; Boolean flag which determines what to do with the dump files
  338. ;;; generated by \\[S-dump-object-into-edit-buffer], as follows:
  339. ;;; 
  340. ;;;     If nil: dump files are deleted after each use, and so appear
  341. ;;; only transiently. The one exception to this is when a loading error
  342. ;;; occurs, in which case the file is retained until the error is
  343. ;;; corrected and the file re-loaded.
  344. ;;; 
  345. ;;;     If non-nil: dump files are not deleted, and backups are kept
  346. ;;; as usual.  This provides a simple method for keeping an archive of S
  347. ;;; functions in text-file form.
  348. ;;; 
  349. ;;; Auto-save is always enabled in dump-file buffers to enable recovery
  350. ;;; from crashes.
  351.  
  352. (defvar S-function-template " function( )\n{\n\n}\n"
  353.   "Function template used when editing nonexistent objects. 
  354. The edit buffer will contain the object name in quotes, followed by
  355. \"<-\", followed by this string.")
  356.  
  357. ;;; Interacting with the S process
  358.  
  359. (defvar S-execute-in-process-buffer nil
  360.   "*If non-nil, the S-execute- commands output to the process buffer.
  361. Otherwise, they get their own temporary buffer.")
  362.  
  363. (defvar S-eval-visibly-p nil
  364.   "*If non-nil, the S-eval- commands display the text to be evaluated 
  365. in the process buffer.")
  366.  
  367. (defvar S-tek-mode nil
  368.   "*Grab Tek Graphics?
  369. Toggle with \\[S-tek-mode-toggle].")
  370.  
  371. (defvar S-tek-possible-graph-prompts "Selection: "
  372.   "Prompts that might follow TEK graphics. 
  373. If S mode seems to lock up when grabbing graphics, it probably means
  374. you need something else in here. Your prompt is assumed: you don't
  375. need to include it. Separate options with \\|")
  376.  
  377. (defvar S-tek-pause-for-graphics (not (string= (getenv "TERM") "xterm"))
  378.   "If t, wait for a key to be pressed before returning to text mode.
  379. Use this option when graphics and text share the same screen.")
  380.  
  381. ;;; Help mode
  382.  
  383. (defvar S-help-sec-keys-alist 
  384.   '((?a . "ARGUMENTS:") 
  385.     (?b . "BACKGROUND:") (?B . "BUGS:")
  386.     (?d . "DETAILS:") (?D . "DESCRIPTION:")
  387.     (?e . "EXAMPLES:") 
  388.     (?n . "NOTE:") (?o . "OPTIONAL ARGUMENTS:") (?r . "REQUIRED ARGUMENTS:") 
  389.     (?R . "REFERENCES:") 
  390.     (?s . "SIDE EFFECTS:") (?S . "SEE ALSO:") (?u . "USAGE:") (?v . "VALUE:"))
  391.   "Alist of (key . string) pairs for use in section searching.")
  392. ;;; `key' indicates the keystroke to use to search for the section heading
  393. ;;; `string' in an S help file. `string' is used as part of a
  394. ;;; regexp-search, and so specials should be quoted.
  395.  
  396. ;;; Hooks
  397.  
  398. (defvar S-mode-hook '()
  399.   "*Hook for customizing S mode each time it is entered.")
  400.  
  401. (defvar S-mode-load-hook '()
  402.   "*Hook to call when S.el is loaded.")
  403.  
  404. (defvar S-pre-run-hook nil
  405.   "*Hook to call before starting up S.
  406. Good for setting up your directory.")
  407. ;; You can put something like:
  408. ;; (setq S-directory (file-name-as-directory (concat (getenv "HOME") "/S")))
  409. ;; in your ~/.emacs file and S will always start up in your ~/S directory.
  410. ;; Alternatively, you can get S to start up in the directory you start 
  411. ;; Emacs from by putting this in your .emacs:
  412. ;; (setq S-pre-run-hook '((lambda () (setq S-directory default-directory))))
  413.  
  414.  
  415.  
  416. ;;; System variables
  417. ;;;=====================================================
  418. ;;; Users note: You will rarely have to change these 
  419. ;;; variables.
  420.  
  421. (defvar S-change-sp-regexp
  422.   "\\(attach(\\([^)]\\|$\\)\\|detach(\\|collection(\\|library(\\)"
  423.   "The regexp for matching the S commands that change the search path.")
  424.  
  425. (defvar S-function-pattern
  426.   (concat
  427.    "\\(" ; EITHER
  428.    "\\s\"" ; quote
  429.    "\\(\\sw\\|\\s_\\)+" ; symbol
  430.    "\\s\"" ; quote
  431.    "\\s-*\\(<-\\|_\\)\\(\\s-\\|\n\\)*" ; whitespace, assign, whitespace/nl
  432.    "function\\s-*(" ; function keyword, parenthesis
  433.    "\\)\\|\\(" ; OR
  434.    "\\<\\(\\sw\\|\\s_\\)+" ; symbol
  435.    "\\s-*\\(<-\\|_\\)\\(\\s-\\|\n\\)*" ; whitespace, assign, whitespace/nl
  436.    "function\\s-*(" ; function keyword, parenthesis
  437.    "\\)")
  438.   "The regular expression for matching the beginning of an S function.")
  439.  
  440. (defvar S-source-modes '(S-mode)
  441.   "A list of modes used to determine if a buffer contains S source code.")
  442. ;;; If a file is loaded into a buffer that is in one of these major modes, it
  443. ;;; is considered an S source file.  The function S-load-file uses this to
  444. ;;; determine defaults.
  445.  
  446. (defvar inferior-S-load-command "source(\"%s\")\n"
  447.   "Format-string for building the S command to load a file.")
  448. ;;; This format string should use %s to substitute a file name
  449. ;;; and should result in an S expression that will command the inferior S
  450. ;;; to load that file.
  451.  
  452. (defvar inferior-S-dump-command "dump(\"%s\",file=\"%s\")\n"
  453.   "Format-string for building the S command to dump an object into a file.")
  454. ;;; Use first %s to substitute an object name
  455. ;;;     second %s substitutes the dump file name.
  456.  
  457. (defvar inferior-S-help-command 
  458.   (if S-plus
  459.       "help(\"%s\",pager=\"cat\",window=F)\n" 
  460.     "help(\"%s\")\n")
  461.   "Format-string for building the S command to ask for help on an object.")
  462. ;;; This format string should use %s to substitute an object name.
  463.  
  464. (defvar inferior-S-search-list-command "search()\n"
  465.   "S command that prints out the search list.")
  466. ;;; i.e. The list of directories and (recursive) objects that S uses when
  467. ;;; it searches for objects.
  468.  
  469. (defvar inferior-S-names-command "names(%s)\n"
  470.   "Format string for S command to extract names from an object.")
  471. ;;; %s is replaced by the object name -- usually a list or data frame
  472.  
  473. (defvar inferior-S-objects-command 
  474.   (if (string= S-version-running "3.0")
  475.       "objects(%d)"
  476.     "ls()")
  477.   "Format string for S command to get a list of objects at position %d")
  478. ;;; Don't include a newline at the end! Used in S-execute-objects
  479.  
  480. (defvar S-dumped-missing-re "\nDumped\n\\'"
  481.   "If a dumped object's buffer matches this re, then it is replaced
  482. by S-function-template.")
  483.  
  484. (defvar S-dump-error-re 
  485.   (if (string= S-version-running "3.0") "\nDumped\n\\'" "[Ee]rror")
  486.   "Regexp used to detect an error when loading a file.")
  487.  
  488. (defvar S-error-buffer-name " *S-errors*"
  489.   "Name of buffer to keep error messages in.")
  490.  
  491. (defvar S-loop-timeout 20000
  492.   "Integer specifying how many loops S-mode will wait for the prompt for
  493. before signalling an error.")
  494.  
  495. (defvar S-search-list nil
  496.   "The list of directories and (recursive) objects to search for S objects.")
  497.  
  498. (defvar S-sl-modtime-alist nil
  499.   "Alist of modtimes for all S directories accessed this session.")
  500.  
  501. (defvar S-sp-change nil
  502.   "This symbol flags a change in the S search path.")
  503.  
  504. (defvar S-prev-load-dir/file nil
  505.   "This symbol saves the (directory . file) pair used in the last
  506. S-load-file command.  Used for determining the default in the next one.")
  507.  
  508. (defvar inferior-S-get-prompt-command "options()$prompt\n"
  509.   "Command to find the value of the current S prompt.")
  510.  
  511. (defvar S-temp-buffer-p nil
  512.   "*Flags whether the current buffer is a temporary buffer created by S-mode.
  513. Such buffers will be killed by \\[S-quit] or \\[S-cleanup].
  514. Source buffers and help buffers have this flag set.
  515. This is a buffer-local variable.")
  516. (make-variable-buffer-local 'S-temp-buffer-p)
  517.  
  518. (defvar S-local-variables-string "
  519.  
  520. # Local Variables:
  521. # mode:S
  522. # S-temp-buffer-p:t
  523. # End:
  524. ")
  525.  
  526. (defvar S-style-alist 
  527. '((GNU (S-indent-level . 2)
  528.        (S-continued-statement-offset . 2)
  529.        (S-brace-offset . 0)
  530.        (S-arg-function-offset . 4)
  531.        (S-expression-offset . 2))
  532.   (BSD (S-indent-level . 8)
  533.        (S-continued-statement-offset . 8)
  534.        (S-brace-offset . -8)
  535.        (S-arg-function-offset . 0)
  536.        (S-expression-offset . 8))
  537.   (K&R (S-indent-level . 5)
  538.        (S-continued-statement-offset . 5)
  539.        (S-brace-offset . -5)
  540.        (S-arg-function-offset . 0)
  541.        (S-expression-offset . 5))
  542.   (C++ (S-indent-level . 4)
  543.        (S-continued-statement-offset . 4)
  544.        (S-brace-offset . -4)
  545.        (S-arg-function-offset . 0)
  546.        (S-expression-offset . 4)))
  547. "Predefined formatting styles for S code")
  548.  
  549. (defvar S-tek-simple-prompt nil
  550.   "Explicit version of primary S prompt.")
  551.  
  552.  
  553.  
  554. ;;; S-mode helper functions and code
  555. ;;;=====================================================
  556. ;;;
  557.  
  558. (defvar inferior-S-mode-map nil)
  559. (if inferior-S-mode-map
  560.     nil
  561.   (setq inferior-S-mode-map (full-copy-sparse-keymap comint-mode-map))
  562.   (define-key inferior-S-mode-map "\r" 'inferior-S-send-input)
  563.   (define-key inferior-S-mode-map "\eP" 'comint-msearch-input)
  564.   (define-key inferior-S-mode-map "\eN" 'comint-psearch-input)
  565.   (define-key inferior-S-mode-map "\C-c\C-b" 'comint-msearch-input-matching)
  566.   (define-key inferior-S-mode-map "\eS" 'comint-next-similar-input)
  567.   (define-key inferior-S-mode-map "\er" 'comint-isearch)
  568.   (define-key inferior-S-mode-map "\C-c\C-l" 'S-load-file)
  569.   (define-key inferior-S-mode-map "\C-x`" 'S-parse-errors)
  570.   (define-key inferior-S-mode-map "\C-c\C-d" 'S-dump-object-into-edit-buffer)
  571.   (define-key inferior-S-mode-map "\C-c\C-h" 'S-display-help-on-object)
  572.   (define-key inferior-S-mode-map "\C-c\C-t" 'S-tek-mode-toggle)
  573.   (define-key inferior-S-mode-map "\C-c\C-q" 'S-quit)
  574.   (define-key inferior-S-mode-map "\C-c\C-e" 'S-execute)
  575.   (define-key inferior-S-mode-map "\C-c\C-s" 'S-execute-search)
  576.   (define-key inferior-S-mode-map "\C-c\C-x" 'S-execute-objects)
  577.   (define-key inferior-S-mode-map "\C-c\C-a" 'S-execute-attach)
  578.   (define-key inferior-S-mode-map "\C-c\C-z" 'S-abort)       ; these mask in
  579.   (define-key inferior-S-mode-map "\C-c\C-o" 'S-kill-output) ; comint-m-map
  580.   (define-key inferior-S-mode-map "\C-c\C-v" 'S-view-at-bottom)
  581.   (define-key inferior-S-mode-map "\t" 'S-complete-object-name)) 
  582.  
  583. (defvar S-mode-syntax-table nil "Syntax table for S-mode.")
  584. (if S-mode-syntax-table
  585.     nil
  586.   (setq S-mode-syntax-table (make-syntax-table c-mode-syntax-table))
  587.   (modify-syntax-entry ?# "<" S-mode-syntax-table)  ; now an open comment
  588.   (modify-syntax-entry ?\n ">" S-mode-syntax-table) ; close comment
  589.   (modify-syntax-entry ?_ "." S-mode-syntax-table)  
  590.   (modify-syntax-entry ?. "w" S-mode-syntax-table)  ; making S names same as
  591.   (modify-syntax-entry ?$ "w" S-mode-syntax-table)  ; words makes coding easier
  592.   (modify-syntax-entry ?* "." S-mode-syntax-table)
  593.   (modify-syntax-entry ?< "." S-mode-syntax-table)
  594.   (modify-syntax-entry ?> "." S-mode-syntax-table)
  595.   (modify-syntax-entry ?/ "." S-mode-syntax-table))
  596.  
  597.  
  598. (defvar inferior-S-mode-hook '()
  599.   "*Hook for customizing inferior S mode.
  600. Called after inferior-S-mode is entered and variables have been initialised.")
  601.  
  602.  
  603. ;;;
  604. ;;; Starting up
  605. ;;;
  606.  
  607. (defun S ()
  608.   "Run an inferior S process, input and output via buffer *S*.
  609. If there is a process already running in *S*, just switch to that buffer.
  610. Takes the program name from the variable inferior-S-program.
  611. The S program name is used to make a symbol name such as `inferior-S-args'.
  612. If that symbol is a variable its value is used as a string of arguments
  613. when invoking S.
  614. \(Type \\[describe-mode] in the process buffer for a list of commands.)"
  615.   (interactive)
  616.   (if (not (comint-check-proc "*S*"))
  617.       (let* ((symbol-string
  618.               (concat "inferior-" inferior-S-program "-args"))
  619.              (switches-symbol (intern-soft symbol-string))
  620.              (switches
  621.               (if (and switches-symbol (boundp switches-symbol))
  622.                   (symbol-value switches-symbol))))
  623.         (run-hooks 'S-pre-run-hook)
  624.     (if S-ask-for-S-directory (S-set-directory))
  625.     (if S-ask-about-display (S-set-display))
  626.     (set-buffer
  627.          (if switches
  628.              (inferior-S-make-comint switches)
  629.            (inferior-S-make-comint)))
  630.         (inferior-S-mode)
  631.         (inferior-S-wait-for-prompt)
  632.         (goto-char (point-max))
  633.     (setq S-sl-modtime-alist nil)
  634.     (S-tek-get-simple-prompt)
  635.     (S-get-search-list)))
  636.   (switch-to-buffer "*S*"))
  637.  
  638. (defun S-set-directory nil
  639.   "Interactively set S-directory."
  640.   (setq S-directory
  641.     (expand-file-name
  642.      (file-name-as-directory
  643.       (read-file-name
  644.        "From which directory? " S-directory S-directory t)))))
  645.  
  646. (defun S-set-display nil
  647.   "Interactively set DISPLAY variable for S process"
  648.   (let* ((matches (append (mapcar
  649.                '(lambda (envelt)
  650.                   (if (string-match "^DISPLAY=\\(.*\\)$" envelt)
  651.                   (substring envelt (match-beginning 1) (match-end 1))))
  652.                process-environment)
  653.               (list (getenv "DISPLAY"))))
  654.      (initial (eval (cons 'or matches))))
  655.     (setq process-environment 
  656.       (comint-update-env
  657.        process-environment
  658.        (list (concat
  659.           "DISPLAY="
  660.           (completing-read 
  661.            "Which X-display? "
  662.            (mapcar 'list X-displays-list)
  663.            nil
  664.            nil
  665.            initial)))))))
  666.  
  667. ;;; define two commands consistent with other comint modes, run-s &
  668. ;;; run-S.
  669. (fset 'run-s (fset 'run-S (symbol-function 'S)))
  670.  
  671. (defun inferior-S-mode () 
  672.   "Major mode for interacting with an inferior S process.  
  673. Runs an S interactive job as a subprocess of Emacs, with I/O through an
  674. Emacs buffer.  Variable inferior-S-program controls which S
  675. is run.
  676.  
  677. Commands are sent to the S process by typing them, and pressing
  678. \\[inferior-S-send-input]. Pressing \\[S-complete-object-name] completes known
  679. object names. Other keybindings for this mode are:
  680.  
  681. \\{inferior-S-mode-map}
  682.  
  683. When editing S objects, the use of \\[S-load-file] is advocated.
  684. S-load-file keeps source files (if S-keep-dump-files is non-nil) in
  685. the directory specified by S-source-directory-generator, with the
  686. filename chosen according to S-dump-filename-template. When a file is
  687. loaded, S-mode parses error messages and jumps to the appropriate file
  688. if errors occur. The S-eval- commands do not do this.
  689.  
  690. Customization: Entry to this mode runs the hooks on comint-mode-hook and
  691. inferior-S-mode-hook (in that order).
  692.  
  693. You can send text to the inferior S process from other buffers containing
  694. S source. The key bindings of these commands can be found by typing 
  695. ^h m (help for mode) in the other buffers.
  696.     S-eval-region sends the current region to the S process.
  697.     S-eval-buffer sends the current buffer to the S process.
  698.     S-eval-function sends the current function to the S process.
  699.     S-eval-line sends the current line to the S process.
  700.     S-beginning-of-function and S-end-of-function move the point to
  701.         the beginning and end of the current S function.
  702.     S-switch-to-S switches the current buffer to the S process buffer.
  703.     S-switch-to-end-of-S switches the current buffer to the S process
  704.         buffer and puts point at the end of it.
  705.  
  706.     S-eval-region-and-go, S-eval-buffer-and-go,
  707.         S-eval-function-and-go, and S-eval-line-and-go switch to the S
  708.         process buffer after sending their text.
  709.  
  710.     S-dump-object-into-edit-buffer moves an S object into a temporary file
  711.         and buffer for editing
  712.     S-load-file sources a file of commands to the S process.
  713.  
  714. Commands:
  715. Return after the end of the process' output sends the text from the 
  716.     end of process to point.
  717. Return before the end of the process' output copies the sexp ending at point
  718.     to the end of the process' output, and sends it.
  719. Delete converts tabs to spaces as it moves back.
  720. C-M-q does Tab on each line starting within following expression.
  721. Paragraphs are separated only by blank lines.  Crosshatches start comments.
  722. If you accidentally suspend your process, use \\[comint-continue-subjob]
  723. to continue it."
  724.   (interactive)
  725.   (comint-mode)
  726.   (setq comint-prompt-regexp (concat "^" inferior-S-prompt))
  727.   (setq major-mode 'inferior-S-mode)
  728.   (setq mode-name "Inferior S")
  729.   (setq mode-line-process '(": %s"))
  730.   (use-local-map inferior-S-mode-map)
  731.   (set-syntax-table S-mode-syntax-table)
  732.   (setq comint-input-sentinel 'S-search-path-tracker)
  733.   (setq comint-get-old-input 'inferior-S-get-old-input)
  734.   (make-local-variable 'scroll-step)
  735.   (setq scroll-step 4)
  736.   (make-local-variable 'input-ring-size)
  737.   (setq input-ring-size 50)
  738.   (run-hooks 'inferior-S-mode-hook))
  739.  
  740. ;;; This function is a modification of make-comint from the comint.el
  741. ;;; code of Olin Shivers.
  742. (defun inferior-S-make-comint (&rest switches)
  743.   (let* ((name "S")
  744.          (buffer (get-buffer-create (concat "*" name "*")))
  745.          (proc (get-buffer-process buffer)))
  746.     ;; If no process, or nuked process, crank up a new one and put buffer in
  747.     ;; comint mode. Otherwise, leave buffer and existing process alone.
  748.     (cond ((or (not proc) (not (memq (process-status proc) '(run stop))))
  749.            (save-excursion
  750.              (set-buffer buffer)
  751.              (setq default-directory S-directory)
  752.              (comint-mode)) ; Install local vars, mode, keymap, ...
  753.            (comint-exec buffer name inferior-S-program nil switches)))
  754.     buffer))
  755.  
  756. (defun inferior-S-send-input ()
  757.   "Sends the command on the current line to the S process."
  758.   (interactive)
  759.   (comint-send-input)
  760.   (if (and S-sp-change
  761.            (inferior-S-wait-for-prompt))
  762.       (progn
  763.         (S-get-search-list)
  764.         (setq S-sp-change nil))
  765.     ;; Is this TEK graphics output?
  766.     (if S-tek-mode 
  767.     (progn
  768.       (require 'S-tek)
  769.       (S-tek-snarf-graphics)))))
  770.  
  771. (defun inferior-S-get-old-input ()
  772.   "Returns the S command surrounding point."
  773.   (save-excursion
  774.     (beginning-of-line)
  775.     (if (not (looking-at inferior-S-prompt))
  776.     (S-error "No command on this line."))
  777.     (if (looking-at inferior-S-primary-prompt) nil
  778.     (re-search-backward (concat "^" inferior-S-primary-prompt)))
  779.     (comint-skip-prompt)
  780.     (let (command
  781.        (beg (point)))
  782.       (end-of-line)
  783.       (setq command (buffer-substring beg (point)))
  784.       (forward-line 1)
  785.       (while (and (looking-at inferior-S-prompt) 
  786.           (not (looking-at inferior-S-primary-prompt)))
  787.     ;; looking at secondary prompt
  788.     (comint-skip-prompt)
  789.     (setq beg (point))
  790.     (end-of-line)
  791.     (setq command (concat command " " (buffer-substring beg (point))))
  792.     (forward-line 1))
  793.       command)))
  794.  
  795. (defun S-error (msg)
  796.   "Something bad has happened. Display the S buffer, and cause an error 
  797. displaying MSG."
  798.   (display-buffer (process-buffer (get-process "S")))
  799.   (error msg))
  800.               
  801. (defun inferior-S-wait-for-prompt ()
  802.   "Wait until the S process is ready for input."
  803.   (let* ((cbuffer (current-buffer))
  804.          (sprocess (get-process "S"))
  805.          (sbuffer (process-buffer sprocess))
  806.          r
  807.      (timeout 0))
  808.     (set-buffer sbuffer)
  809.     (while (progn
  810.          (if (not (eq (process-status sprocess) 'run))
  811.          (S-error "S process has died unexpectedly.")
  812.            (if (> (setq timeout (1+ timeout)) S-loop-timeout)
  813.            (S-error "Timeout waiting for prompt. Check inferior-S-prompt or S-loop-timeout."))
  814.            (accept-process-output)
  815.            (goto-char (point-max))
  816.            (beginning-of-line)
  817.            (setq r (looking-at inferior-S-prompt))
  818.            (not (or r (looking-at ".*\\?\\s *"))))))
  819.     (goto-char (point-max))
  820.     (set-buffer cbuffer)
  821.     (symbol-value r)))
  822.  
  823. (defun S-dump-object-into-edit-buffer (object)
  824.   "Edit an S object in its own buffer.  Without a prefix argument,
  825. this simply finds the file pointed to by S-dump-filename. If this file
  826. does not exist, or if a prefix argument is given, a dump() command is
  827. sent to the S process to generate the source buffer."
  828.   (interactive (S-read-object-name "Object to edit: "))
  829.   (let* ((filename (concat (if S-source-directory-generator 
  830.                    (funcall S-source-directory-generator) 
  831.                  S-source-directory)
  832.                (format S-dump-filename-template object)))
  833.          (complete-dump-command (format inferior-S-dump-command
  834.                                         object filename))
  835.      (old-buff (get-file-buffer filename)))
  836.     (if S-source-directory-generator
  837.     (let ((the-dir (file-name-directory filename)))
  838.       ;; If the directory doesn't exist, create if possible and approved.
  839.       (if (not (file-writable-p filename)) ; Can't create file
  840.           (if (and (not (file-exists-p the-dir)) ; No such directory
  841.                (file-writable-p    ; Can we create dir in parent?
  842.             (file-name-directory (directory-file-name the-dir)))
  843.                (y-or-n-p    ; Approved
  844.             (format "Directory %s does not exist. Create it? " the-dir))) ; and we want to create it
  845.           (make-directory (directory-file-name the-dir))
  846.         (setq filename (concat S-source-directory 
  847.                        (format S-dump-filename-template object)))))))
  848.     ;; Try and find a buffer or filename before asking S
  849.     (catch 'found-text
  850.       (if (not current-prefix-arg)
  851.       (cond 
  852.        (old-buff 
  853.         (pop-to-buffer old-buff)
  854.         (message "Popped to edit buffer.")
  855.         (throw 'found-text nil))
  856.        ((file-exists-p filename) 
  857.         (find-file-other-window filename)
  858.         (message "Read %s" filename)
  859.         (throw 'found-text nil))))
  860.       (S-command complete-dump-command)
  861.       (let ((old-buff (get-file-buffer filename)))
  862.     (if old-buff
  863.         (kill-buffer old-buff)))    ;make sure we start fresh
  864.       ;; Generate a buffer with the dumped data
  865.       (find-file-other-window filename)
  866.       (S-mode)
  867.       (auto-save-mode 1)        ; Auto save in this buffer
  868.       (setq S-temp-buffer-p t)        ; Flag as a temp buffer
  869.       (if S-insert-function-templates
  870.       (progn 
  871.         (goto-char (point-max))
  872.         (if (re-search-backward S-dumped-missing-re nil t)
  873.         (replace-match S-function-template t t))
  874.         (goto-char (point-min))))    ;It might be nice to go between braces here
  875.       ;; Insert the local variables stuff
  876.       (save-excursion
  877.     (goto-char (point-max))
  878.     (insert S-local-variables-string)
  879.     (if S-keep-dump-files nil
  880.       (set-buffer-modified-p nil)))
  881.       (message "Dumped in %s" filename)
  882.       (if S-keep-dump-files nil 
  883.       (delete-file filename))) ; In case buffer is killed
  884.     (setq S-prev-load-dir/file
  885.       (cons (file-name-directory filename)
  886.         (file-name-nondirectory filename)))))
  887.  
  888. (defun S-read-object-name (p-string)
  889.   (let* ((default (S-read-object-name-default))
  890.          (prompt-string (if default
  891.                             (format "%s(default %s) " p-string default)
  892.                           p-string))
  893.          (S-object-list (S-get-object-list))
  894.          (spec (completing-read prompt-string S-object-list)))
  895.     (list (cond
  896.            ((string= spec "") default)
  897.            (t spec)))))
  898.  
  899. (defun S-read-object-name-default ()
  900.  (save-excursion
  901.    ;; The following line circumvents an 18.57 bug in following-char
  902.    (if (eobp) (backward-char 1)) ; Hopefully buffer is not empty!
  903.    ;; Get onto a symbol
  904.    (catch 'nosym ; bail out if there's no symbol at all before point
  905.      (while (/= (char-syntax (following-char)) ?w)
  906.        (if (bobp) (throw 'nosym nil) (backward-char 1)))
  907.      (let* 
  908.      ((end (progn (forward-sexp 1) (point)))
  909.       (beg (progn (backward-sexp 1) (point))))
  910.        (buffer-substring beg end)))))
  911.  
  912. (defun S-object-names (dir)
  913.   "Return alist of S object names in directory (or object) DIR"
  914.   (if (string-match "^/" dir) 
  915.       (mapcar 'list (directory-files dir))
  916.     ;;It might be an object name; try to get names
  917.     (let ((tbuffer (generate-new-buffer "names-list"))
  918.       (objname dir)
  919.       names)
  920.       (save-excursion
  921.     (set-buffer tbuffer)
  922.     (buffer-flush-undo tbuffer)
  923.     (S-command (format inferior-S-names-command objname) tbuffer)
  924.     (goto-char (point-min))
  925.     (if (not (looking-at "\\s-*\\[1\\]"))
  926.         (setq names nil)
  927.       (goto-char (point-max))
  928.       (while (re-search-backward "\"\\([^\"]*\\)\"" nil t)
  929.         (setq names (cons (buffer-substring (match-beginning 1)
  930.                         (match-end 1)) names))))
  931.     (kill-buffer tbuffer))
  932.       (mapcar 'list names))))
  933.  
  934. (defun S-resynch nil
  935. "Reread all directories/objects in S-search-list to form completions."
  936.  (interactive)
  937.  (setq S-sl-modtime-alist nil)
  938.  (S-get-search-list))
  939.        
  940. (defun S-extract-onames-from-alist (dir) 
  941. "Extract the object names for directory (or object) DIR from S-sl-modtime-alist
  942. generating a new set if the directory has been recently modified."
  943.   (let* ((assoc-res (assoc dir S-sl-modtime-alist))
  944.      (data-cell (cdr assoc-res))
  945.      (last-mtime (car data-cell))
  946.      (new-mtime (S-dir-modtime dir))
  947.      (old-objs (cdr data-cell)))
  948.     (if (equal new-mtime last-mtime) old-objs
  949.       (setcar data-cell new-mtime)
  950.       (setcdr data-cell (S-object-names dir)))))
  951.  
  952. (defun S-dir-modtime (dir)
  953. "Return the last modtime if dir is a directory, and nil otherwise."
  954. ;; Attached dataframes return a modtime of nil. It probably wouldn't be
  955. ;; too difficult to find the modtime of the actual object by searching for 
  956. ;; it along S-search-list, but one hardly ever modifies dataframes after
  957. ;; they're attached, and I couldn't be bothered anyway.
  958.   (if (string-match "^/" dir) 
  959.       (nth 5 (file-attributes dir))))
  960.  
  961. (defun S-get-search-list ()
  962.   "Get the list of directories and (recursive) objects that S searches
  963. when it looks for objects."
  964.   (save-excursion
  965.   (let ((tbuffer (generate-new-buffer "search-list"))
  966.     dir-assoc
  967.         dir)
  968.     (setq S-search-list nil)
  969.     (buffer-flush-undo tbuffer)
  970.     (set-buffer tbuffer)
  971.     (S-command inferior-S-search-list-command tbuffer)
  972.     (goto-char (point-max))
  973.     (while (re-search-backward "\"\\([^\"]*\\)\"" nil t)
  974.       (setq dir (buffer-substring (match-beginning 1) (match-end 1)))
  975.       (if (and (string-match "^[^/]" dir)
  976.            (file-directory-p (concat S-directory dir)))
  977.           (setq dir (concat S-directory dir)))
  978.       (setq S-search-list (cons dir S-search-list))
  979.       (setq dir-assoc (assoc dir S-sl-modtime-alist))
  980.       (if (not dir-assoc)
  981.       (let (conselt)
  982.         (setq conselt (cons dir
  983.                 (cons (S-dir-modtime dir)
  984.                       (S-object-names dir))))
  985.         (setq S-sl-modtime-alist (cons conselt S-sl-modtime-alist)))))
  986.     (kill-buffer tbuffer))))
  987.  
  988. (defun S-get-object-list ()
  989.   "Return the alist of current S object names."
  990. ;;; suitable for use with completing-read
  991.   (S-get-object-list-r S-search-list))
  992.  
  993. (defun S-get-object-list-r (s-list)
  994.   "Return the alist of current S object names, recursive version.
  995. S-LIST is the search list of directories (or objects) for S." 
  996.   (let* ((dir (car s-list))
  997.          (dir-list (cdr s-list)))
  998.     (if (null dir)
  999.         nil
  1000.       (append (S-extract-onames-from-alist dir)
  1001.               (S-get-object-list-r dir-list)))))
  1002.  
  1003. (defun S-command (com &optional buf visible)
  1004.   "Send the S process command COM and delete the output
  1005. from the S process buffer.  If an optional second argument BUF exists
  1006. save the output in that buffer. If optional third arg VISIBLE is
  1007. non-nil, both the command and the output appear in the S process
  1008. buffer."
  1009.   (let* ((cbuffer (current-buffer))
  1010.          (sprocess (get-process "S"))
  1011.          sbuffer
  1012.      start-of-output
  1013.      point-holder)
  1014.     (if sprocess nil (error "No S process running!"))
  1015.     (setq sbuffer (process-buffer sprocess))
  1016.     (set-buffer sbuffer)
  1017.     (setq point-holder (point-marker))
  1018.     (goto-char (marker-position (process-mark sprocess)))
  1019.     (beginning-of-line)
  1020.     (if (looking-at inferior-S-primary-prompt) nil
  1021.       (goto-char (marker-position point-holder))
  1022.       (S-error 
  1023.        "S process not ready. Finish your command before trying again."))
  1024.     (if visible
  1025.     (progn
  1026.       (goto-char (marker-position (process-mark sprocess)))
  1027.       (insert-before-markers com) ))
  1028.     (setq start-of-output (marker-position (process-mark sprocess)))
  1029.     (process-send-string sprocess com)
  1030.     (while (progn
  1031.              (accept-process-output sprocess)
  1032.              (goto-char (marker-position (process-mark sprocess)))
  1033.              (beginning-of-line)
  1034.          (if (< (point) start-of-output) (goto-char start-of-output))
  1035.          (not (looking-at inferior-S-primary-prompt))))
  1036.     (if buf
  1037.         (append-to-buffer buf start-of-output (point)))
  1038.     (if visible (goto-char (marker-position (process-mark sprocess)))
  1039.       (delete-region start-of-output
  1040.              (marker-position (process-mark sprocess)))
  1041.       (goto-char (marker-position point-holder)))
  1042.     (set-buffer cbuffer)))
  1043.  
  1044. (defun S-eval-visibly (text &optional invisibly)
  1045.   "Evaluate TEXT in the S process buffer as if it had been typed in.
  1046. If optional secod arg INVISIBLY is non-nil, don't echo commands. If 
  1047. if is a string, just include that string.
  1048. Waits for prompt after each line of input, so won't break on large texts."
  1049.   (let* ((cbuffer (current-buffer))
  1050.          (sprocess (get-process "S"))
  1051.          (sbuffer (process-buffer sprocess))
  1052.      start-of-output
  1053.      com pos)
  1054.     (set-buffer sbuffer)
  1055.     (goto-char (marker-position (process-mark sprocess)))
  1056.     (setq comint-last-input-end (point-marker))
  1057.     (if (stringp invisibly)
  1058.     (insert-before-markers (concat "*** " invisibly " ***\n")))
  1059.     (while (> (length text) 0)
  1060.       (setq pos (string-match "\n\\|$" text))
  1061.       (setq com (concat (substring text 0 pos) "\n"))
  1062.       (setq text (substring text (min (length text) (1+ pos))))
  1063.       (goto-char (marker-position (process-mark sprocess)))
  1064.       (if invisibly nil (insert-before-markers com))
  1065.       (setq start-of-output (marker-position (process-mark sprocess)))
  1066.       (process-send-string sprocess com)
  1067.       (while (progn
  1068.            (accept-process-output sprocess)
  1069.            (goto-char (marker-position (process-mark sprocess)))
  1070.            (beginning-of-line)
  1071.            (if (< (point) start-of-output) (goto-char start-of-output))
  1072.            (not (looking-at inferior-S-prompt)))))
  1073.     (goto-char (marker-position (process-mark sprocess)))
  1074.     (set-buffer cbuffer)))
  1075.  
  1076. (defun S-execute (command &optional invert buff message)
  1077.   "Send a command to the S process.
  1078. A newline is automatically added to COMMAND. Prefix arg (or second arg INVERT)
  1079. means invert the meaning of S-execute-in-process-buffer. If INVERT is 'buffer,
  1080. output is forced to go to the process buffer.
  1081. If the output is going to a buffer, name it *BUFF*. This buffer is erased
  1082. before use. Optional fourth arg MESSAGE is text to print at the top of the
  1083. buffer (defaults to the command if BUFF is not given.)"
  1084.   (interactive "sCommand: \nP")
  1085.   (let ((the-command (concat command "\n"))
  1086.     (buff-name (concat "*" (or buff "S-output") "*"))
  1087.     (in-pbuff (if invert (or (eq invert 'buffer) 
  1088.                  (not S-execute-in-process-buffer))
  1089.             S-execute-in-process-buffer)))
  1090.     (if in-pbuff 
  1091.     (S-eval-visibly the-command)
  1092.       (with-output-to-temp-buffer buff-name
  1093.     (if message (princ message)
  1094.       (if buff nil
  1095.           ;; Print the command in the buffer if it has not been
  1096.           ;; given a special name
  1097.         (princ "> ")
  1098.         (princ the-command)))
  1099.     (S-command the-command (get-buffer buff-name) nil))
  1100.       (save-excursion
  1101.     (set-buffer (get-buffer buff-name))
  1102.     (setq S-temp-buffer-p t)))))
  1103.  
  1104. (defun S-execute-in-tb nil
  1105.   "Like S-execute, but always evaluates in temp buffer."
  1106.   (interactive)
  1107.   (let ((S-execute-in-process-buffer nil))
  1108.     (call-interactively 'S-execute)))
  1109.  
  1110. (defun S-execute-objects (posn)
  1111.   "Send the objects() command to the S process.
  1112. By default, gives the objects at position 1.
  1113. A prefix argument toggles the meaning of S-execute-in-process-buffer.
  1114. A prefix argument of 2 or more means get objects for that position.
  1115. A negative prefix argument gets the objects for that position
  1116.   and toggles S-execute-in-process-buffer as well."
  1117.   (interactive "P")
  1118.   (let* ((num-arg (if (listp posn) 
  1119.               (if posn -1 1)
  1120.             (prefix-numeric-value posn)))
  1121.     (the-posn (if (< num-arg 0) (- num-arg) num-arg))
  1122.     (invert (< num-arg 0))
  1123.     (the-command (format inferior-S-objects-command the-posn))
  1124.     (the-message (concat ">>> Position "
  1125.                  the-posn
  1126.                  " ("
  1127.                  (nth (1- the-posn) S-search-list)
  1128.                  ")\n")))
  1129.     (S-execute the-command invert "S objects" the-message)))
  1130.  
  1131. (defun S-execute-search (invert)
  1132.   "Send the search() command to the S process."
  1133.   (interactive "P")
  1134.   (S-execute "search()" invert "S search list"))
  1135.  
  1136. (defun S-execute-attach (dir &optional posn)
  1137.   "Attach a directory in the S process with the attach() command.
  1138. When used interactively, user is prompted for DIR to attach and
  1139. prefix argument is used for POSN (or 2, if absent.) 
  1140. Doesn't work for data frames."
  1141.   (interactive "DAttach directory: \nP")
  1142.   (S-execute (concat "attach(\"" 
  1143.              (directory-file-name (expand-file-name dir))
  1144.              "\""
  1145.              (if posn (concat "," (prefix-numeric-value posn)))
  1146.              ")") 'buffer))
  1147.  
  1148. (defun S-view-at-bottom ()
  1149.   "Move to the end of the buffer, and place cursor on bottom line of window."
  1150.   (interactive)
  1151.   (goto-char (point-max))
  1152.   (recenter -1))
  1153.  
  1154. (defun S-kill-output ()
  1155.   "Kill all output from last S command."
  1156.   ;; A version of comint-kill-output that doesn't nuke the prompt.
  1157.   (interactive)
  1158.   (let* ((sprocess (get-process "S"))
  1159.     (pmark (process-mark sprocess))
  1160.     (oldpoint (point-marker)))
  1161.     (goto-char pmark)
  1162.     (re-search-backward inferior-S-primary-prompt)
  1163.     (kill-region comint-last-input-end (point))
  1164.     (insert "*** output flushed ***\n")
  1165.     (goto-char oldpoint)
  1166.     (recenter -1)))
  1167.  
  1168. (defun S-load-file (filename)
  1169.   "Load an S source file into an inferior S process."
  1170.   (interactive (comint-get-source "Load S file: "
  1171.                                   S-prev-load-dir/file
  1172.                                   S-source-modes
  1173.                                   nil))
  1174.   (catch 'give-up               ; In case we don't want to load after all
  1175.     (let ((buff (get-file-buffer filename))
  1176.       tbuffer-p)
  1177.       (if buff                ; Buffer exists
  1178.       (save-excursion
  1179.         (set-buffer buff)
  1180.         (setq tbuffer-p S-temp-buffer-p)
  1181.         (if (buffer-modified-p buff) ; Buff exists and has changed
  1182.         ;; save BUFF, but don't make a backup
  1183.         ;; if we're about to delete it
  1184.         (if tbuffer-p        ; i.e. a result from a dump command
  1185.             (save-buffer (if S-keep-dump-files 1 0))
  1186.           ;; Better check if it's just any old buffer
  1187.           (if (y-or-n-p (format "Buffer %s modified. Save it? "
  1188.                     (buffer-name buff)))
  1189.               (save-buffer)
  1190.             ;; Maybe we should just give up here ...
  1191.             (message
  1192.              "Using current disk version (don't say I didn't warn you!)")))
  1193.           ;; Buffer hasn't changed lately, might need to write
  1194.           ;; it back if the file is gone
  1195.           (if tbuffer-p
  1196.           (if (y-or-n-p 
  1197.                "Buffer hasn't changed. Really load it into S? ")
  1198.               (if (file-exists-p (buffer-file-name buff)) nil
  1199.             (set-buffer-modified-p t) ; so save will work
  1200.             (save-buffer 0))
  1201.             (message "No load performed.")
  1202.             (throw 'give-up nil))))))
  1203.       (setq S-prev-load-dir/file
  1204.         (cons (file-name-directory filename)
  1205.           (file-name-nondirectory filename)))
  1206.       (let ((errbuffer (get-buffer-create S-error-buffer-name)))
  1207.     (save-excursion 
  1208.       (set-buffer errbuffer)
  1209.       (erase-buffer)
  1210.       (S-command (format inferior-S-load-command filename) errbuffer)
  1211.       (goto-char (point-max))
  1212.       (if (re-search-backward S-dump-error-re nil t)
  1213.           (progn
  1214.         (message "Errors: Use %s to find error." 
  1215.              (substitute-command-keys 
  1216.               "\\<inferior-S-mode-map>\\[S-parse-errors]"))
  1217.         ;; This load failed, so set buffer as modified so the
  1218.         ;; user will be warned if he tries to kill it
  1219.         (if buff
  1220.             (progn
  1221.               (set-buffer buff)
  1222.               (set-buffer-modified-p t)))) 
  1223.         (message "Load successful.")
  1224.         (if (and tbuffer-p (not S-keep-dump-files)) 
  1225.         (delete-file filename)))))))
  1226.   (S-switch-to-S t))
  1227.  
  1228. (defun S-parse-errors (showerr)
  1229.   "Jump to error in last loaded S source file.
  1230. With prefix argument, only shows the errors S reported."
  1231.   (interactive "P")
  1232.   (let ((errbuff (get-buffer S-error-buffer-name)))
  1233.     (if (not errbuff)
  1234.     (error "You need to do a load first!")
  1235.       (set-buffer errbuff)
  1236.       (goto-char (point-max))
  1237.       (if 
  1238.       (re-search-backward
  1239.        "^\\(Syntax error: .*\\) at line \\([0-9]*\\), file \\(.*\\)$"
  1240.        nil
  1241.        t)
  1242.       (let* ((filename (buffer-substring (match-beginning 3) (match-end 3))) 
  1243.          (fbuffer (get-file-buffer filename)) 
  1244.          (linenum (string-to-int (buffer-substring (match-beginning 2) (match-end 2))))
  1245.          (errmess (buffer-substring (match-beginning 1) (match-end 1))))
  1246.         (if showerr 
  1247.         (display-buffer errbuff)
  1248.           (if fbuffer nil
  1249.         (setq fbuffer (find-file-noselect filename))
  1250.         (save-excursion
  1251.           (set-buffer fbuffer)
  1252.           (S-mode))) 
  1253.           (pop-to-buffer fbuffer)
  1254.           (goto-line linenum))
  1255.         (princ errmess t))
  1256.     (message "Not a syntax error.")
  1257.     (display-buffer errbuff)))))
  1258.  
  1259.       
  1260. (defun S-search-path-tracker (str)
  1261.   "Check if input STR changed the search path."
  1262. ;;; This function monitors user input to the inferior S process so that
  1263. ;;; emacs can keep the S-search-list up to date.  Completing-read uses this
  1264. ;;; list indirectly when it prompts for help or for an object to dump.
  1265.   (if (string-match S-change-sp-regexp str)
  1266.       (setq S-sp-change t)))
  1267.  
  1268. (defun S-cleanup ()
  1269.   "Delete all of S-mode's temporary buffers and files
  1270. (if S-keep-dump-files is nil) leaving you in the S process buffer.
  1271. Auto-save files and S help buffers are also deleted. Buffers whose
  1272. contents do not match with S's idea of the objects value *usually*
  1273. have the modified flag set, and you will be warned before such buffers
  1274. are killed. The exception to this is buffers which were saved in a
  1275. previous session before being loaded into S, and then read this
  1276. session.
  1277.  
  1278. It's a good idea to run this before you quit. It is run automatically by 
  1279. \\[S-quit]."
  1280.   (interactive)
  1281.   (if (yes-or-no-p "Delete all temporary files and buffers? ")
  1282.       (progn
  1283.     (mapcar '(lambda (buf)
  1284.            (set-buffer buf)
  1285.            (let ((fname (buffer-file-name buf))
  1286.              (asfnm buffer-auto-save-file-name))
  1287.              (if S-temp-buffer-p
  1288.              (progn
  1289.                (kill-buffer buf)
  1290.                (if (or (buffer-name buf)
  1291.                    S-keep-dump-files)
  1292.                    ;; Don't do anything if buffer was not
  1293.                    ;; killed or dump files are kept
  1294.                    nil 
  1295.                  ;; if the file exists, it stays! (consider
  1296.                  ;; dumping an object with an existing file)
  1297. ;;;                  (if (and fname (file-exists-p fname))
  1298. ;;;                      (delete-file fname))
  1299.                  ;; Auto-save files can go, since they're
  1300.                  ;; only associated with modified buffers
  1301.                  (if (and asfnm (file-exists-p asfnm))
  1302.                  (delete-file asfnm)))))))
  1303.         (buffer-list))
  1304.     (S-switch-to-S nil))))
  1305.  
  1306. (defun S-quit ()
  1307.   "Issue the q() command to S, and clean up."
  1308.   (interactive)
  1309.   (let ((sprocess (get-process "S")))
  1310.     (if (not sprocess) (error "No S process running."))
  1311.     (if (yes-or-no-p "Really quit from S? ")
  1312.     (save-excursion 
  1313.       (S-cleanup)
  1314.       (S-switch-to-S nil)
  1315.       (goto-char (marker-position (process-mark sprocess)))
  1316.       (insert "q()\n")
  1317.       (process-send-string sprocess "q()\n")))))
  1318.  
  1319. (defun S-abort ()
  1320.   "Kill the S process, without executing .Last or terminating devices.
  1321. If you want to finish your session, use \\[S-quit] instead."
  1322. ;;; Provided as a safety measure over the default binding of C-c C-z in 
  1323. ;;; comint-mode-map. 
  1324.   (interactive)
  1325.   (ding)
  1326.   (message "WARNING: q() will not be executed and graphics devices won't finish properly!")
  1327.   (sit-for 5)
  1328.   (if (yes-or-no-p "Still abort? ")
  1329.       (comint-quit-subjob)
  1330.     (message "Good move.")))
  1331.       
  1332.  
  1333.  
  1334. ;;;
  1335. ;;; Tek terminal Graphics support
  1336. ;;;
  1337.  
  1338. (defun S-tek-mode-toggle nil
  1339.   "Toggle S-tek-mode.
  1340. Resets the S-tek-simple-prompt when S-tek-mode is turned on."
  1341.   (interactive)
  1342.   (message (if (setq S-tek-mode (not S-tek-mode))
  1343.            "Tek mode is now ON." 
  1344.          "Tek mode is now OFF."))
  1345.   (if S-tek-mode (S-tek-get-simple-prompt)))
  1346.  
  1347. (defun S-tek-get-simple-prompt nil
  1348.   "Find the exact version of the current prompt."
  1349.   (interactive)
  1350.   (let ((tbuffer (generate-new-buffer "*S-exact-prompt*")))
  1351.     (buffer-flush-undo tbuffer)
  1352.     (set-buffer tbuffer)
  1353.     (S-command inferior-S-get-prompt-command tbuffer)
  1354.     (goto-char (point-max))
  1355.     (re-search-backward "\"\\([^\"]*\\)\"" nil t)
  1356.     (setq S-tek-simple-prompt
  1357.       (buffer-substring (match-beginning 1) (match-end 1)))
  1358.     (kill-buffer tbuffer)))
  1359.  
  1360. ;;; 25/6/92 dsmith
  1361. ;;; Rest of code moved to S-tek.el
  1362.  
  1363.  
  1364.  
  1365. ;;; S mode
  1366. ;;;======================================================
  1367. ;;;
  1368.  
  1369. (defvar S-mode-map nil)
  1370. (if S-mode-map
  1371.     nil
  1372.   (setq S-mode-map (make-sparse-keymap))
  1373.   (define-key S-mode-map "\C-c\C-r"    'S-eval-region)
  1374.   (define-key S-mode-map "\C-c\M-r" 'S-eval-region-and-go)
  1375.   (define-key S-mode-map "\C-c\C-b"    'S-eval-buffer)
  1376.   (define-key S-mode-map "\C-c\M-b" 'S-eval-buffer-and-go)
  1377.   (define-key S-mode-map "\C-c\C-f"    'S-eval-function)
  1378.   (define-key S-mode-map "\C-c\M-f" 'S-eval-function-and-go)
  1379.   (define-key S-mode-map "\M-\C-x"  'S-eval-function)
  1380.   (define-key S-mode-map "\C-c\C-n"     'S-eval-line-and-next-line)
  1381.   (define-key S-mode-map "\C-c\C-j"    'S-eval-line)
  1382.   (define-key S-mode-map "\C-c\M-j" 'S-eval-line-and-go)
  1383.   (define-key S-mode-map "\M-\C-a"  'S-beginning-of-function)
  1384.   (define-key S-mode-map "\M-\C-e"  'S-end-of-function)
  1385.   (define-key S-mode-map "\C-c\C-y"    'S-switch-to-S)
  1386.   (define-key S-mode-map "\C-c\C-z" 'S-switch-to-end-of-S)
  1387.   (define-key S-mode-map "\C-c\C-l"    'S-load-file)
  1388.   (define-key S-mode-map "\C-c\C-h"    'S-display-help-on-object)
  1389.   (define-key S-mode-map "\C-c\C-d" 'S-dump-object-into-edit-buffer)
  1390.   (define-key S-mode-map "\C-c\C-e" 'S-execute-in-tb)
  1391.   (define-key S-mode-map "\M-\t"    'S-complete-object-name)
  1392.   (define-key S-mode-map "{" 'S-electric-brace)
  1393.   (define-key S-mode-map "}" 'S-electric-brace)
  1394.   (define-key S-mode-map "\e\C-h" 'S-mark-function)
  1395.   (define-key S-mode-map "\e\C-q" 'S-indent-exp)
  1396.   (define-key S-mode-map "\177" 'backward-delete-char-untabify)
  1397.   (define-key S-mode-map "\t" 'S-indent-command)
  1398. )
  1399.  
  1400. (defun S-mode ()
  1401.   "Major mode for editing S source.
  1402.  
  1403. \\{S-mode-map}
  1404.  
  1405. Customization: Entry to this mode runs the hooks in S-mode-hook.
  1406.  
  1407. You can send text to the inferior S process from other buffers containing
  1408. S source.
  1409.     S-eval-region sends the current region to the S process.
  1410.     S-eval-buffer sends the current buffer to the S process.
  1411.     S-eval-function sends the current function to the S process.
  1412.     S-eval-line sends the current line to the S process.
  1413.     S-beginning-of-function and S-end-of-function move the point to
  1414.         the beginning and end of the current S function.
  1415.     S-switch-to-S switches the current buffer to the S process buffer.
  1416.     S-switch-to-end-of-S switches the current buffer to the S process
  1417.         buffer and puts point at the end of it.
  1418.  
  1419.     S-eval-region-and-go, S-eval-buffer-and-go,
  1420.         S-eval-function-and-go, and S-eval-line-and-go switch to the S
  1421.         process buffer after sending their text.
  1422.  
  1423.     S-load-file sources a file of commands to the S process.
  1424.     S-make-function inserts a function template in the buffer.
  1425.  
  1426. \\[S-indent-command] indents for S code. 
  1427. \\[backward-delete-char-untabify] converts tabs to spaces as it moves back.
  1428. Comments are indented in a similar way to Emacs-lisp mode:
  1429.        `###'     beginning of line
  1430.        `##'      the same level of indentation as the code
  1431.        `#'       the same column on the right, or to the right of such a
  1432.                  column if that is not possible.(default value 40). 
  1433.                  \\[indent-for-comment] command automatically inserts such a
  1434.                  `#' in the right place, or aligns such a comment if it is 
  1435.                  already inserted.
  1436. \\[S-indent-exp] command indents each line of the S grouping following point.
  1437.  
  1438. Variables controlling indentation style:
  1439.  S-tab-always-indent
  1440.     Non-nil means TAB in S mode should always reindent the current line,
  1441.     regardless of where in the line point is when the TAB command is used.
  1442.  S-auto-newline
  1443.     Non-nil means automatically newline before and after braces inserted in S 
  1444.     code.
  1445.  S-indent-level
  1446.     Indentation of S statements within surrounding block.
  1447.     The surrounding block's indentation is the indentation of the line on 
  1448.     which the open-brace appears.
  1449.  S-continued-statement-offset
  1450.     Extra indentation given to a substatement, such as the then-clause of an 
  1451.     if or body of a while.
  1452.  S-continued-brace-offset
  1453.     Extra indentation given to a brace that starts a substatement.
  1454.     This is in addition to S-continued-statement-offset.
  1455.  S-brace-offset
  1456.     Extra indentation for line if it starts with an open brace.
  1457.  S-arg-function-offset 
  1458.     Extra indent for internal substatements of function `foo' that called
  1459.     in `arg=foo(...)' form. 
  1460.    If not number, the statements are indented at open-parenthesis following 
  1461.    `foo'.
  1462.  S-expression-offset
  1463.     Extra indent for internal substatements of `expression' that specified
  1464.     in `obj <- expression(...)' form. 
  1465.     If not number, the statements are indented at open-parenthesis following 
  1466.     `expression'.
  1467.  S-brace-imaginary-offset
  1468.     An open brace following other text is treated as if it were
  1469.     this far to the right of the start of its line.
  1470.  
  1471. Furthermore, \\[S-set-style] command enables you to set up predefined S-mode 
  1472. indentation style. At present, predefined style are `BSD', `GNU', `K&R' `C++'
  1473.  (quoted from C language style)."
  1474.   (interactive)
  1475.   (setq major-mode 'S-mode)
  1476.   (setq mode-name "S")
  1477.   (use-local-map S-mode-map)
  1478.   (set-syntax-table S-mode-syntax-table)
  1479.   (make-local-variable 'paragraph-start)
  1480.   (setq paragraph-start (concat "^$\\|" page-delimiter))
  1481.   (make-local-variable 'paragraph-separate)
  1482.   (setq paragraph-separate paragraph-start)
  1483.   (make-local-variable 'paragraph-ignore-fill-prefix)
  1484.   (setq paragraph-ignore-fill-prefix t)
  1485.   (make-local-variable 'indent-line-function)
  1486.   (setq indent-line-function 'S-indent-line)
  1487.   (make-local-variable 'require-final-newline)
  1488.   (setq require-final-newline t)
  1489.   (make-local-variable 'comment-start)
  1490.   (setq comment-start "#")
  1491.   (make-local-variable 'comment-start-skip)
  1492.   (setq comment-start-skip "#+ *")
  1493.   (make-local-variable 'comment-column)
  1494.   (setq comment-column 40)
  1495.   (make-local-variable 'comment-indent-hook)
  1496.   (setq comment-indent-hook 'S-comment-indent)
  1497.   (make-local-variable 'parse-sexp-ignore-comments)
  1498.   (setq parse-sexp-ignore-comments nil)
  1499.   (run-hooks 'S-mode-hook))
  1500.  
  1501. ;;; Emacs will set the mode for a file based on the file's header.
  1502. ;;; The mode name is indicated by putting it between -*- on the top line. 
  1503. ;;; (Other commands can go here too, see an Emacs manual.)
  1504. ;;; For a file you also load, you will want a leading # (comment to S)
  1505. ;;; Emacs will downcase the name of the mode, e.g., S, so we must provide
  1506. ;;; s-mode in lower case too.  That is, "#-*-S-*-" invokes s-mode and not S-mode.
  1507. (fset 's-mode 'S-mode)
  1508.  
  1509. (defun S-eval-region (start end toggle &optional message)
  1510.   "Send the current region to the inferior S process.
  1511. With prefix argument, toggle meaning of S-eval-visibly-p."
  1512.   (interactive "r\nP")
  1513.   (let ((visibly (if toggle (not S-eval-visibly-p) S-eval-visibly-p)))
  1514.     (if visibly
  1515.     (S-eval-visibly (buffer-substring start end))
  1516.       (S-eval-visibly (buffer-substring start end)
  1517.               (or message "Eval region")))))
  1518.  
  1519. (defun S-eval-region-and-go (start end vis)
  1520.   "Send the current region to the inferior S and switch to the process buffer.
  1521. Arg has same meaning as for S-eval-region."
  1522.   (interactive "r\nP")
  1523.   (S-eval-region start end vis)
  1524.   (S-switch-to-S t))
  1525.  
  1526. (defun S-eval-buffer (vis)
  1527.   "Send the current buffer to the inferior S process.
  1528. Arg has same meaning as for S-eval-region."
  1529.   (interactive "P")
  1530.   (S-eval-region (point-min) (point-max) vis "Eval buffer"))
  1531.  
  1532. (defun S-eval-buffer-and-go (vis)
  1533.   "Send the current buffer to the inferior S and switch to the process buffer.
  1534. Arg has same meaning as for S-eval-region."
  1535.   (interactive)
  1536.   (S-eval-buffer vis)
  1537.   (S-switch-to-S t))
  1538.  
  1539. (defun S-eval-function (vis)
  1540.   "Send the current function to the inferior S process.
  1541. Arg has same meaning as for S-eval-region."
  1542.   (interactive "P")
  1543.   (save-excursion
  1544.     (S-end-of-function)
  1545.     (let ((end (point)))
  1546.       (S-beginning-of-function)
  1547.       (princ (concat "Loading: " (S-extract-word-name)) t)
  1548.       (S-eval-region (point) end vis 
  1549.              (concat "Eval function " (S-extract-word-name))))))
  1550.  
  1551. (defun S-eval-function-and-go (vis)
  1552.   "Send the current function to the inferior S process and switch to
  1553. the process buffer. Arg has same meaning as for S-eval-region."
  1554.   (interactive "P")
  1555.   (S-eval-function vis)
  1556.   (S-switch-to-S t))
  1557.  
  1558. (defun S-eval-line (vis)
  1559.   "Send the current line to the inferior S process.
  1560. Arg has same meaning as for S-eval-region."
  1561.   (interactive "P")
  1562.   (save-excursion
  1563.     (end-of-line)
  1564.     (let ((end (point)))
  1565.       (beginning-of-line)
  1566.       (princ (concat "Loading line: " (S-extract-word-name) " ...") t)
  1567.       (S-eval-region (point) end vis "Eval line"))))
  1568.  
  1569. (defun S-eval-line-and-go (vis)
  1570.   "Send the current line to the inferior S process and switch to the
  1571. process buffer. Arg has same meaning as for S-eval-region."
  1572.   (interactive "P")
  1573.   (S-eval-line vis)
  1574.   (S-switch-to-S t))
  1575.  
  1576. (defun S-eval-line-and-next-line ()
  1577.   "Evaluate the current line visibly and move to the next line."
  1578.   ;; From an idea by Rod Ball (rod@marcam.dsir.govt.nz)
  1579.   (interactive)
  1580.   (save-excursion
  1581.     (end-of-line)
  1582.     (let ((end (point)))
  1583.       (beginning-of-line)
  1584.       (S-eval-visibly (buffer-substring (point) end))))
  1585.   (next-line 1))
  1586.  
  1587. (defun S-beginning-of-function nil
  1588.   "Leave the point at the beginning of the current S function."
  1589.   (interactive)
  1590.   (let ((init-point (point))
  1591.     beg end done)
  1592.     (if (search-forward "(" nil t) (forward-char 1))
  1593.     ;; in case we're sitting in a function header
  1594.     (while (not done)
  1595.       (if 
  1596.       (re-search-backward S-function-pattern (point-min) t)
  1597.       nil
  1598.     (goto-char init-point)
  1599.     (error "Point is not in a function."))
  1600.       (setq beg (point))
  1601.       (forward-list 1) ; get over arguments
  1602.       (forward-sexp 1) ; move over braces
  1603.       (setq end (point))
  1604.       (goto-char beg)
  1605.       ;; current function must begin and end around point  
  1606.       (setq done (and (>= end init-point) (<= beg init-point))))))
  1607.  
  1608. (defun S-end-of-function nil
  1609.   "Leave the point at the end of the current S function."
  1610.   (interactive)
  1611.   (S-beginning-of-function)
  1612.   (forward-list 1) ; get over arguments
  1613.   (forward-sexp 1) ; move over braces
  1614.   )
  1615.  
  1616. (defun S-extract-word-name ()
  1617.   "Get the word you're on."
  1618.   (save-excursion
  1619.     (re-search-forward "\\<\\w+\\>" nil t)
  1620.     (buffer-substring (match-beginning 0) (match-end 0))))
  1621.  
  1622. (defun S-switch-to-S (eob-p)
  1623.   "Switch to the inferior S process buffer.
  1624. With argument, positions cursor at end of buffer."
  1625.   (interactive "P")
  1626.   (cond ((comint-check-proc "*S*")
  1627.          (pop-to-buffer "*S*")
  1628.          (cond (eob-p
  1629.                 (goto-char (point-max)))))
  1630.         (t
  1631.          (message "No inferior S process")
  1632.          (ding))))
  1633.  
  1634. (defun S-switch-to-end-of-S nil
  1635.   "Switch to the end of the inferior S process buffer."
  1636.   (interactive)
  1637.   (S-switch-to-S t))
  1638.  
  1639. (defun S-make-function ()
  1640.   "Insert a function template."
  1641.   (interactive)
  1642.   (insert "fu <- function()\n{\n\t\n}\n")
  1643.   (forward-line -2)
  1644.   (end-of-line))
  1645.  
  1646. (defun S-complete-object-name (&optional listcomp)
  1647.   ;;Based on lisp-complete-symbol
  1648.   "Perform completion on S object preceding point.  The object is
  1649. compared against those objects known by S-get-object-list and any
  1650. additional characters up to ambiguity are inserted.  Completion only
  1651. works on globally-known objects (including elements of attached data
  1652. frames), and thus is most suitable for interactive command-line entry,
  1653. and not so much for function editing since local objects (e.g.
  1654. argument names) aren't known.
  1655.  
  1656. Use \\[S-resynch] to re-read the names of the attached directories.
  1657. This is done automatically (and transparently) if a directory is
  1658. modified, so the most up-to-date list of object names is always
  1659. available. However attached dataframes are *not* updated, so this
  1660. command may be necessary if you modify an attached dataframe.
  1661.  
  1662. If ARG is non-nil, no completion is attempted, but the available
  1663. completions are listed.
  1664.  
  1665. If the character proceding point is not a symbol element,
  1666. indent-for-tab-command is run."
  1667.   (interactive "P")
  1668.   (if (memq (char-syntax (preceding-char)) '(?w ?_)) 
  1669.       (let* ((end (point))
  1670.          (buffer-syntax (syntax-table))
  1671.          (beg (unwind-protect
  1672.               (save-excursion
  1673.             (set-syntax-table S-mode-syntax-table)
  1674.             (backward-sexp 1)
  1675.             (point))
  1676.             (set-syntax-table buffer-syntax)))
  1677.          (full-prefix (buffer-substring beg end))
  1678.          ;; See if we're indexing a list with `$'
  1679.          (pattern full-prefix)
  1680.          components
  1681.          (listname (if (string-match "\\(.+\\)\\$\\(\\sw\\|\\s_\\)*$"
  1682.                      full-prefix) 
  1683.                (progn
  1684.                  (setq pattern 
  1685.                    (if (not (match-beginning 2)) ""
  1686.                      (substring full-prefix
  1687.                         (match-beginning 2)
  1688.                         (match-end 2))))
  1689.                  (substring full-prefix (match-beginning 1)
  1690.                     (match-end 1)))))
  1691.          (completion (try-completion pattern
  1692.                      (if listname
  1693.                          (setq components
  1694.                            (S-object-names listname))
  1695.                        (S-get-object-list)))))
  1696.     (if listcomp (setq completion full-prefix))
  1697.     (cond ((eq completion t)
  1698.            (message "[sole completion]"))
  1699.           ((null completion)
  1700.            (message "Can't find completion for \"%s\"" full-prefix)
  1701.            (ding))
  1702.           ((not (string= pattern completion))
  1703.            (delete-region 
  1704.         (if listname (+ beg (length listname) 1) beg)
  1705.         end)
  1706.            (insert completion))
  1707.           (t 
  1708.            (message "Making completion list...")
  1709.            (let ((list (all-completions pattern
  1710.                         (if listname components
  1711.                           (S-get-object-list)))))
  1712.          (with-output-to-temp-buffer " *Completions*"
  1713.            (display-completion-list list)))
  1714.            (message "Making completion list...%s" "done"))))
  1715.     (indent-for-tab-command)))
  1716.  
  1717. ;;; S code formatting functions
  1718.  
  1719. (defun S-comment-indent ()
  1720.   (if (looking-at "###")
  1721.       (current-column)
  1722.     (if (looking-at "##")
  1723.     (let ((tem (S-calculate-indent)))
  1724.       (if (listp tem) (car tem) tem))
  1725.       (skip-chars-backward " \t")
  1726.       (max (if (bolp) 0 (1+ (current-column)))
  1727.        comment-column))))
  1728.  
  1729. (defun S-electric-brace (arg)
  1730.   "Insert character and correct line's indentation."
  1731.   (interactive "P")
  1732.   (let (insertpos)
  1733.     (if (and (not arg)
  1734.          (eolp)
  1735.          (or (save-excursion
  1736.            (skip-chars-backward " \t")
  1737.            (bolp))
  1738.          (if S-auto-newline (progn (S-indent-line) (newline) t) nil)))
  1739.     (progn
  1740.       (insert last-command-char)
  1741.       (S-indent-line)
  1742.       (if S-auto-newline
  1743.           (progn
  1744.         (newline)
  1745.         ;; (newline) may have done auto-fill
  1746.         (setq insertpos (- (point) 2))
  1747.         (S-indent-line)))
  1748.       (save-excursion
  1749.         (if insertpos (goto-char (1+ insertpos)))
  1750.         (delete-char -1))))
  1751.     (if insertpos
  1752.     (save-excursion
  1753.       (goto-char insertpos)
  1754.       (self-insert-command (prefix-numeric-value arg)))
  1755.       (self-insert-command (prefix-numeric-value arg)))))
  1756.  
  1757. (defun S-indent-command (&optional whole-exp)
  1758.   "Indent current line as S code, or in some cases insert a tab character.
  1759. If S-tab-always-indent is non-nil (the default), always indent current line.
  1760. Otherwise, indent the current line only if point is at the left margin
  1761. or in the line's indentation; otherwise insert a tab.
  1762.  
  1763. A numeric argument, regardless of its value,
  1764. means indent rigidly all the lines of the expression starting after point
  1765. so that this line becomes properly indented.
  1766. The relative indentation among the lines of the expression are preserved."
  1767.   (interactive "P")
  1768.   (if whole-exp
  1769.       ;; If arg, always indent this line as S
  1770.       ;; and shift remaining lines of expression the same amount.
  1771.       (let ((shift-amt (S-indent-line))
  1772.         beg end)
  1773.     (save-excursion
  1774.       (if S-tab-always-indent
  1775.           (beginning-of-line))
  1776.       (setq beg (point))
  1777.       (backward-up-list 1)
  1778.       (forward-list 1)
  1779.       (setq end (point))
  1780.       (goto-char beg)
  1781.       (forward-line 1)
  1782.       (setq beg (point)))
  1783.     (if (> end beg)
  1784.         (indent-code-rigidly beg end shift-amt)))
  1785.     (if (and (not S-tab-always-indent)
  1786.          (save-excursion
  1787.            (skip-chars-backward " \t")
  1788.            (not (bolp))))
  1789.     (insert-tab)
  1790.       (S-indent-line))))
  1791.  
  1792. (defun S-indent-line ()
  1793.   "Indent current line as S code.
  1794. Return the amount the indentation changed by."
  1795.   (let ((indent (S-calculate-indent nil))
  1796.     beg shift-amt
  1797.     (case-fold-search nil)
  1798.     (pos (- (point-max) (point))))
  1799.     (beginning-of-line)
  1800.     (setq beg (point))
  1801.     (cond ((eq indent nil)
  1802.        (setq indent (current-indentation)))
  1803.       (t
  1804.        (skip-chars-forward " \t")
  1805.        (if (looking-at "###")
  1806.            (setq indent 0))
  1807.        (if (and (looking-at "#") (not (looking-at "##")))
  1808.            (setq indent comment-column)
  1809.          (if (eq indent t) (setq indent 0))
  1810.          (if (listp indent) (setq indent (car indent)))
  1811.          (cond ((and (looking-at "else\\b")
  1812.              (not (looking-at "else\\s_")))
  1813.             (setq indent (save-excursion
  1814.                    (S-backward-to-start-of-if)
  1815.                    (current-indentation))))
  1816.            ((= (following-char) ?})
  1817.             (setq indent (- indent S-indent-level)))
  1818.            ((= (following-char) ?{)
  1819.             (setq indent (+ indent S-brace-offset)))))))
  1820.     (skip-chars-forward " \t")
  1821.     (setq shift-amt (- indent (current-column)))
  1822.     (if (zerop shift-amt)
  1823.     (if (> (- (point-max) pos) (point))
  1824.         (goto-char (- (point-max) pos)))
  1825.       (delete-region beg (point))
  1826.       (indent-to indent)
  1827.       ;; If initial point was within line's indentation,
  1828.       ;; position after the indentation.  
  1829.       ;; Else stay at same point in text.
  1830.       (if (> (- (point-max) pos) (point))
  1831.       (goto-char (- (point-max) pos))))
  1832.     shift-amt))
  1833.  
  1834. (defun S-calculate-indent (&optional parse-start)
  1835.   "Return appropriate indentation for current line as S code.
  1836. In usual case returns an integer: the column to indent to.
  1837. Returns nil if line starts inside a string, t if in a comment."
  1838.   (save-excursion
  1839.     (beginning-of-line)
  1840.     (let ((indent-point (point))
  1841.       (case-fold-search nil)
  1842.       state
  1843.       containing-sexp)
  1844.       (if parse-start
  1845.       (goto-char parse-start)
  1846.     (beginning-of-defun))
  1847.       (while (< (point) indent-point)
  1848.     (setq parse-start (point))
  1849.     (setq state (parse-partial-sexp (point) indent-point 0))
  1850.     (setq containing-sexp (car (cdr state))))
  1851.       (cond ((or (nth 3 state) (nth 4 state))
  1852.          ;; return nil or t if should not change this line
  1853.          (nth 4 state))
  1854.         ((null containing-sexp)
  1855.          ;; Line is at top level.  May be data or function definition,
  1856.          0)   ; Unless it starts a function body
  1857.         ((/= (char-after containing-sexp) ?{)
  1858.          ;; line is expression, not statement:
  1859.          ;; indent to just after the surrounding open.
  1860.          (goto-char containing-sexp)
  1861.          (let ((bol (save-excursion (beginning-of-line) (point))))
  1862.            (cond ((and (numberp S-arg-function-offset)
  1863.                 (re-search-backward "=[ \t]*\\s\"*\\(\\w\\|\\s_\\)+\\s\"*[ \t]*" bol t))
  1864.               (forward-sexp -1)
  1865.               (+ (current-column) S-arg-function-offset))
  1866.              ((and (numberp S-expression-offset)
  1867.                (re-search-backward "<-[ \t]*expression[ \t]*" bol t))
  1868.               (forward-sexp -1)
  1869.               (+ (current-column) S-expression-offset))
  1870.              (t
  1871.               (progn (goto-char (1+ containing-sexp))
  1872.                  (current-column))))))
  1873.         (t
  1874.          ;; Statement level.  Is it a continuation or a new statement?
  1875.          ;; Find previous non-comment character.
  1876.          (goto-char indent-point)
  1877.          (S-backward-to-noncomment containing-sexp)
  1878.          ;; Back up over label lines, since they don't
  1879.          ;; affect whether our line is a continuation.
  1880.          (while (eq (preceding-char) ?\,)
  1881.            (S-backward-to-start-of-continued-exp containing-sexp)
  1882.            (beginning-of-line)
  1883.            (S-backward-to-noncomment containing-sexp))
  1884.          ;; Now we get the answer.
  1885.          (if (S-continued-statement-p)
  1886.          ;; This line is continuation of preceding line's statement;
  1887.          ;; indent  S-continued-statement-offset  more than the
  1888.          ;; previous line of the statement.
  1889.          (progn
  1890.            (S-backward-to-start-of-continued-exp containing-sexp)
  1891.            (+ S-continued-statement-offset (current-column)
  1892.               (if (save-excursion (goto-char indent-point)
  1893.                       (skip-chars-forward " \t")
  1894.                       (eq (following-char) ?{))
  1895.               S-continued-brace-offset 0)))
  1896.            ;; This line starts a new statement.
  1897.            ;; Position following last unclosed open.
  1898.            (goto-char containing-sexp)
  1899.            ;; Is line first statement after an open-brace?
  1900.            (or
  1901.          ;; If no, find that first statement and indent like it.
  1902.          (save-excursion
  1903.            (forward-char 1)
  1904.            (while (progn (skip-chars-forward " \t\n")
  1905.                  (looking-at "#"))
  1906.              ;; Skip over comments following openbrace.
  1907.              (forward-line 1))
  1908.            ;; The first following code counts
  1909.            ;; if it is before the line we want to indent.
  1910.            (and (< (point) indent-point)
  1911.             (current-column)))
  1912.          ;; If no previous statement,
  1913.          ;; indent it relative to line brace is on.
  1914.          ;; For open brace in column zero, don't let statement
  1915.          ;; start there too.  If S-indent-level is zero,
  1916.          ;; use S-brace-offset + S-continued-statement-offset instead.
  1917.          ;; For open-braces not the first thing in a line,
  1918.          ;; add in S-brace-imaginary-offset.
  1919.          (+ (if (and (bolp) (zerop S-indent-level))
  1920.             (+ S-brace-offset S-continued-statement-offset)
  1921.               S-indent-level)
  1922.             ;; Move back over whitespace before the openbrace.
  1923.             ;; If openbrace is not first nonwhite thing on the line,
  1924.             ;; add the S-brace-imaginary-offset.
  1925.             (progn (skip-chars-backward " \t")
  1926.                (if (bolp) 0 S-brace-imaginary-offset))
  1927.             ;; If the openbrace is preceded by a parenthesized exp,
  1928.             ;; move to the beginning of that;
  1929.             ;; possibly a different line
  1930.             (progn
  1931.               (if (eq (preceding-char) ?\))
  1932.               (forward-sexp -1))
  1933.               ;; Get initial indentation of the line we are on.
  1934.               (current-indentation))))))))))
  1935.  
  1936. (defun S-continued-statement-p ()
  1937.   (let ((eol (point)))
  1938.     (save-excursion
  1939.       (cond ((memq (preceding-char) '(nil ?\, ?\; ?\} ?\{ ?\]))
  1940.          nil)
  1941.         ((bolp))
  1942.         ((= (preceding-char) ?\))
  1943.          (forward-sexp -2)
  1944.          (looking-at "if\\b[ \t]*(\\|function\\b[ \t]*(\\|for\\b[ \t]*(\\|while\\b[ \t]*("))
  1945.         ((progn (forward-sexp -1) 
  1946.             (and (looking-at "else\\b\\|repeat\\b")
  1947.              (not (looking-at "else\\s_\\|repeat\\s_"))))
  1948.          (skip-chars-backward " \t")
  1949.          (or (bolp)
  1950.          (= (preceding-char) ?\;)))
  1951.         (t
  1952.          (progn (goto-char eol)
  1953.             (skip-chars-backward " \t")
  1954.             (or (and (> (current-column) 1)
  1955.                  (save-excursion (backward-char 1)
  1956.                          (looking-at "[-:+*/_><=]")))
  1957.             (and (> (current-column) 3)
  1958.                  (progn (backward-char 3)
  1959.                     (looking-at "%[^ \t]%"))))))))))
  1960.  
  1961. (defun S-backward-to-noncomment (lim)
  1962.   (let (opoint stop)
  1963.     (while (not stop)
  1964.       (skip-chars-backward " \t\n\f" lim)
  1965.       (setq opoint (point))
  1966.       (beginning-of-line)
  1967.       (skip-chars-forward " \t")
  1968.       (setq stop (or (not (looking-at "#")) (<= (point) lim)))
  1969.       (if stop (goto-char opoint)
  1970.     (beginning-of-line)))))
  1971.  
  1972. (defun S-backward-to-start-of-continued-exp (lim)
  1973.   (if (= (preceding-char) ?\))
  1974.       (forward-sexp -1))
  1975.   (beginning-of-line)
  1976.   (if (<= (point) lim)
  1977.       (goto-char (1+ lim)))
  1978.   (skip-chars-forward " \t"))
  1979.  
  1980. (defun S-backward-to-start-of-if (&optional limit)
  1981.   "Move to the start of the last ``unbalanced'' if."
  1982.   (or limit (setq limit (save-excursion (beginning-of-defun) (point))))
  1983.   (let ((if-level 1)
  1984.     (case-fold-search nil))
  1985.     (while (not (zerop if-level))
  1986.       (backward-sexp 1)
  1987.       (cond ((looking-at "else\\b")
  1988.          (setq if-level (1+ if-level)))
  1989.         ((looking-at "if\\b")
  1990.          (setq if-level (1- if-level)))
  1991.         ((< (point) limit)
  1992.          (setq if-level 0)
  1993.          (goto-char limit))))))
  1994.  
  1995. (defun S-mark-function ()
  1996.   "Put mark at end of S function, point at beginning."
  1997.   (interactive)
  1998.   (push-mark (point))
  1999.   (S-end-of-function)
  2000.   (push-mark (point))
  2001.   (S-beginning-of-function))
  2002.  
  2003. (defun S-indent-exp ()
  2004.   "Indent each line of the S grouping following point."
  2005.   (interactive)
  2006.   (let ((indent-stack (list nil))
  2007.     (contain-stack (list (point)))
  2008.     (case-fold-search nil)
  2009.     restart outer-loop-done inner-loop-done state ostate
  2010.     this-indent last-sexp
  2011.     at-else at-brace
  2012.     (opoint (point))
  2013.     (next-depth 0))
  2014.     (save-excursion
  2015.       (forward-sexp 1))
  2016.     (save-excursion
  2017.       (setq outer-loop-done nil)
  2018.       (while (and (not (eobp)) (not outer-loop-done))
  2019.     (setq last-depth next-depth)
  2020.     ;; Compute how depth changes over this line
  2021.     ;; plus enough other lines to get to one that
  2022.     ;; does not end inside a comment or string.
  2023.     ;; Meanwhile, do appropriate indentation on comment lines.
  2024.     (setq innerloop-done nil)
  2025.     (while (and (not innerloop-done)
  2026.             (not (and (eobp) (setq outer-loop-done t))))
  2027.       (setq ostate state)
  2028.       (setq state (parse-partial-sexp (point) (progn (end-of-line) (point))
  2029.                       nil nil state))
  2030.       (setq next-depth (car state))
  2031.       (if (and (car (cdr (cdr state)))
  2032.            (>= (car (cdr (cdr state))) 0))
  2033.           (setq last-sexp (car (cdr (cdr state)))))
  2034.       (if (or (nth 4 ostate))
  2035.           (S-indent-line))
  2036.       (if (nth 4 state)
  2037.           (and (S-indent-line)
  2038.            (setcar (nthcdr 4 state) nil)))
  2039.       (if (or (nth 3 state))
  2040.           (forward-line 1)
  2041.         (setq innerloop-done t)))
  2042.     (if (<= next-depth 0)
  2043.         (setq outer-loop-done t))
  2044.     (if outer-loop-done
  2045.         nil
  2046.       ;; If this line had ..))) (((.. in it, pop out of the levels
  2047.       ;; that ended anywhere in this line, even if the final depth
  2048.       ;; doesn't indicate that they ended.
  2049.       (while (> last-depth (nth 6 state))
  2050.         (setq indent-stack (cdr indent-stack)
  2051.           contain-stack (cdr contain-stack)
  2052.           last-depth (1- last-depth)))
  2053.       (if (/= last-depth next-depth)
  2054.           (setq last-sexp nil))
  2055.       ;; Add levels for any parens that were started in this line.
  2056.       (while (< last-depth next-depth)
  2057.         (setq indent-stack (cons nil indent-stack)
  2058.           contain-stack (cons nil contain-stack)
  2059.           last-depth (1+ last-depth)))
  2060.       (if (null (car contain-stack))
  2061.           (setcar contain-stack (or (car (cdr state))
  2062.                     (save-excursion (forward-sexp -1)
  2063.                             (point)))))
  2064.       (forward-line 1)
  2065.       (skip-chars-forward " \t")
  2066.       (if (eolp)
  2067.           nil
  2068.         (if (and (car indent-stack)
  2069.              (>= (car indent-stack) 0))
  2070.         ;; Line is on an existing nesting level.
  2071.         ;; Lines inside parens are handled specially.
  2072.         (if (/= (char-after (car contain-stack)) ?{)
  2073.             (setq this-indent (car indent-stack))
  2074.           ;; Line is at statement level.
  2075.           ;; Is it a new statement?  Is it an else?
  2076.           ;; Find last non-comment character before this line
  2077.           (save-excursion
  2078.             (setq at-else (looking-at "else\\W"))
  2079.             (setq at-brace (= (following-char) ?{))
  2080.             (S-backward-to-noncomment opoint)
  2081.             (if (S-continued-statement-p)
  2082.             ;; Preceding line did not end in comma or semi;
  2083.             ;; indent this line  S-continued-statement-offset
  2084.             ;; more than previous.
  2085.             (progn
  2086.               (S-backward-to-start-of-continued-exp (car contain-stack))
  2087.               (setq this-indent
  2088.                 (+ S-continued-statement-offset (current-column)
  2089.                    (if at-brace S-continued-brace-offset 0))))
  2090.               ;; Preceding line ended in comma or semi;
  2091.               ;; use the standard indent for this level.
  2092.               (if at-else
  2093.               (progn (S-backward-to-start-of-if opoint)
  2094.                  (setq this-indent (current-indentation)))
  2095.             (setq this-indent (car indent-stack))))))
  2096.           ;; Just started a new nesting level.
  2097.           ;; Compute the standard indent for this level.
  2098.           (let ((val (S-calculate-indent
  2099.                (if (car indent-stack)
  2100.                    (- (car indent-stack))))))
  2101.         (setcar indent-stack
  2102.             (setq this-indent val))))
  2103.         ;; Adjust line indentation according to its contents
  2104.         (if (= (following-char) ?})
  2105.         (setq this-indent (- this-indent S-indent-level)))
  2106.         (if (= (following-char) ?{)
  2107.         (setq this-indent (+ this-indent S-brace-offset)))
  2108.         ;; Put chosen indentation into effect.
  2109.         (or (= (current-column) this-indent)
  2110.         (= (following-char) ?\#)
  2111.         (progn
  2112.           (delete-region (point) (progn (beginning-of-line) (point)))
  2113.           (indent-to this-indent)))
  2114.         ;; Indent any comment following the text.
  2115.         (or (looking-at comment-start-skip)
  2116.         (if (re-search-forward comment-start-skip (save-excursion (end-of-line) (point)) t)
  2117.             (progn (indent-for-comment) (beginning-of-line)))))))))
  2118. ; (message "Indenting S expression...done")
  2119.   )
  2120.  
  2121. ;; Predefined styles
  2122. (defun S-set-style (&optional style)
  2123.   "Set up the S-mode style variables from the S-style variable or if
  2124.   STYLE argument is given, use that.  It makes the S indentation style 
  2125.   variables buffer local."
  2126.  
  2127.   (interactive)
  2128.  
  2129.   (let ((S-styles (mapcar 'car S-style-alist)))
  2130.     
  2131.     (if (interactive-p)
  2132.     (setq style
  2133.           (let ((style-string ; get style name with completion
  2134.              (completing-read
  2135.               (format "Set S mode indentation style to (default %s): "
  2136.                   S-default-style)
  2137.               (vconcat S-styles)
  2138.               (function (lambda (arg) (memq arg S-styles)))
  2139.               )))
  2140.         (if (string-equal "" style-string)
  2141.             S-default-style
  2142.           (intern style-string))
  2143.         )))
  2144.     
  2145.     (setq style (or style S-style)) ; use S-style if style is nil
  2146.     
  2147.     (make-local-variable 'S-style)
  2148.     (if (memq style S-styles)
  2149.     (setq S-style style)
  2150.       (error (concat "Bad S style: " style))
  2151.       )
  2152.     (message "S-style: %s" S-style)
  2153.       
  2154.     ; finally, set the indentation style variables making each one local
  2155.     (mapcar (function (lambda (S-style-pair)
  2156.             (make-local-variable (car S-style-pair))
  2157.             (set (car S-style-pair)
  2158.                  (cdr S-style-pair))))
  2159.         (cdr (assq S-style S-style-alist)))
  2160.     S-style))
  2161.  
  2162.  
  2163.  
  2164. ;;; S-help-mode
  2165. ;;;======================================================
  2166. ;;;
  2167.  
  2168. (defvar S-help-mode-map nil "Keymap for S help mode.")
  2169. (defvar S-help-mode-hook nil "Functions to call when entering more mode. ")
  2170.  
  2171. (defvar S-help-sec-map nil "Sub-keymap for S help mode.")
  2172.  
  2173. (defun S-skip-to-help-section nil
  2174.   "Jump to a section heading of a help buffer. The section selected is
  2175. determined by the command letter used to invoke the command, as indicated
  2176. by S-help-sec-keys-alist. Use \\[S-describe-sec-map] to see which keystrokes
  2177. find which sections."
  2178.   (interactive)
  2179.   (let ((old-point (point)))
  2180.     (goto-char (point-min))
  2181.     (let ((the-sec (cdr (assoc last-command-char S-help-sec-keys-alist))))
  2182.       (if (not the-sec) (error "Invalid section key: %c" last-command-char)
  2183.     (if (re-search-forward (concat "^" the-sec) nil t) nil
  2184.         (message "No %s section in this help. Sorry." the-sec)
  2185.         (goto-char old-point))))))
  2186.  
  2187. (defun S-skip-to-next-section nil
  2188.   "Jump to next section in S help buffer."
  2189.   (interactive)
  2190.   (let ((case-fold-search nil))
  2191.     (if (re-search-forward "^[A-Z. ---]+:$" nil t) nil
  2192.       (message "No more sections."))))
  2193.  
  2194. (defun S-skip-to-previous-section nil
  2195.   "Jump to previous section in S help buffer."
  2196.   (interactive)
  2197.   (let ((case-fold-search nil))
  2198.     (if (re-search-backward "^[A-Z. ---]+:$" nil t) nil
  2199.       (message "No previous section."))))
  2200.  
  2201. (defun S-describe-help-mode nil
  2202. "Display help for S-mode"
  2203.  (interactive)
  2204.  (describe-function 'S-help-mode))
  2205.  
  2206. (defun S-kill-buffer-and-go nil
  2207.   "Kill the current buffer and switch back to S"
  2208.   (interactive)
  2209.   (kill-buffer (current-buffer))
  2210.   (S-switch-to-S nil))
  2211.  
  2212. (defun S-describe-sec-map nil
  2213.   "Display help for the `s' key."
  2214.   (interactive)
  2215.   (describe-function 'S-skip-to-help-section)
  2216.   (save-excursion
  2217.     (set-buffer "*Help*")
  2218.     (goto-char (point-max))
  2219.     (insert "\n\nCurrently defined keys are:
  2220.  
  2221. Keystroke    Section
  2222. ---------    -------\n")
  2223.     (mapcar '(lambda (cs) (insert "    " (car cs) "        " (cdr cs) "\n")) S-help-sec-keys-alist)
  2224.     (insert "\nFull list of key definitions:\n" (substitute-command-keys "\\{S-help-sec-map}"))))
  2225.  
  2226. (defun S-find-help-file (p-string)
  2227.   (let* ((default (S-read-object-name-default))
  2228.          (prompt-string (if default
  2229.                             (format "%s(default %s) " p-string default)
  2230.                           p-string))
  2231.      (help-files-list (S-get-help-files-list))
  2232.          (spec (completing-read prompt-string help-files-list)))
  2233.     (list (cond
  2234.            ((string= spec "") default)
  2235.            (t spec)))))
  2236.  
  2237. (defun S-get-help-files-list nil
  2238.   (mapcar 'list
  2239.       (apply 'append
  2240.          (mapcar '(lambda (dirname)
  2241.                 (if (file-directory-p dirname) 
  2242.                 (directory-files dirname)))
  2243.              (mapcar '(lambda (str) (concat str "/.Help"))
  2244.                  S-search-list)))))
  2245.       
  2246. (if S-help-sec-map
  2247.     nil
  2248.   (setq S-help-sec-map (make-keymap))
  2249.   (mapcar '(lambda (key) 
  2250.         (define-key S-help-sec-map (char-to-string key) 
  2251.           'S-skip-to-help-section))
  2252.         (mapcar 'car S-help-sec-keys-alist))
  2253.   (define-key S-help-sec-map "?" 'S-describe-sec-map)
  2254.   (define-key S-help-sec-map ">" 'end-of-buffer)
  2255.   (define-key S-help-sec-map "<" 'beginning-of-buffer)
  2256. )
  2257.  
  2258. (defun S-display-help-on-object (object)
  2259.   "Display the help page for OBJECT in the *Help* buffer. 
  2260. If prefix arg is given, forces a query of the S process for the help
  2261. file.  Otherwise just pops to an existing buffer if it exists."
  2262.   (interactive (S-find-help-file "Help on: "))
  2263.   (let* ((hb-name (concat "*help(" object ")*"))
  2264.      (old-hb-p (get-buffer hb-name))
  2265.      (tbuffer (get-buffer-create hb-name)))
  2266.     (set-buffer tbuffer)
  2267.     (if (or (not old-hb-p) current-prefix-arg)
  2268.     ;; Ask S for the help file
  2269.     (progn
  2270.       (setq S-temp-buffer-p t)        ; Flag as a temp buffer
  2271.       (delete-region (point-min) (point-max))
  2272.       (S-help-mode)
  2273.       (S-command (format inferior-S-help-command object) tbuffer)
  2274.       (S-nuke-help-bs)
  2275.       (goto-char (point-min))))
  2276.     (let (nodocs)
  2277.       (save-excursion
  2278.     (goto-char (point-min))
  2279.     (setq nodocs 
  2280.           (re-search-forward "\\`No documentation available.*$" nil t))
  2281.     (if nodocs
  2282.         (progn
  2283.           (princ (buffer-substring (match-beginning 0) (match-end 0)) t)
  2284.           ;; Avoid using 'message here -- may be %'s in string
  2285.           (ding)
  2286.           (kill-buffer tbuffer))
  2287.       (if (eq major-mode 'S-help-mode) (switch-to-buffer tbuffer)
  2288.         (pop-to-buffer tbuffer)))))))
  2289.  
  2290. ;;; This function is a modification of nuke-nroff-bs in man.el from the
  2291. ;;; standard emacs 18 lisp library.
  2292. (defun S-nuke-help-bs ()
  2293.   (interactive "*")
  2294.   ;; Nuke underlining and overstriking (only by the same letter)
  2295.   (goto-char (point-min))
  2296.   (while (search-forward "\b" nil t)
  2297.     (let* ((preceding (char-after (- (point) 2)))
  2298.            (following (following-char)))
  2299.       (cond ((= preceding following)
  2300.              ;; x\bx
  2301.              (delete-char -2))
  2302.             ((= preceding ?\_)
  2303.              ;; _\b
  2304.              (delete-char -2))
  2305.             ((= following ?\_)
  2306.              ;; \b_
  2307.              (delete-region (1- (point)) (1+ (point)))))))
  2308.   ;; Crunch blank lines
  2309.   (goto-char (point-min))
  2310.   (while (re-search-forward "\n\n\n\n*" nil t)
  2311.     (replace-match "\n\n"))
  2312.   ;; Nuke blanks lines at start.
  2313.   (goto-char (point-min))
  2314.   (skip-chars-forward "\n")
  2315.   (delete-region (point-min) (point)))
  2316.  
  2317. (if S-help-mode-map
  2318.     nil
  2319.   (setq S-help-mode-map (make-keymap))
  2320.   (suppress-keymap S-help-mode-map)  
  2321.   (define-key S-help-mode-map " " 'scroll-up)
  2322.   (define-key S-help-mode-map "b" 'scroll-down)
  2323.   (define-key S-help-mode-map "q" 'S-switch-to-end-of-S)
  2324.   (define-key S-help-mode-map "\177" 'scroll-down) ; DEL
  2325.   (define-key S-help-mode-map "s" S-help-sec-map)
  2326.   (define-key S-help-mode-map "h" 'S-display-help-on-object)
  2327.   (define-key S-help-mode-map "r" 'S-eval-region)
  2328.   (define-key S-help-mode-map "n" 'S-skip-to-next-section)
  2329.   (define-key S-help-mode-map "p" 'S-skip-to-previous-section)
  2330.   (define-key S-help-mode-map "/" 'isearch-forward)
  2331.   (define-key S-help-mode-map ">" 'end-of-buffer)
  2332.   (define-key S-help-mode-map "<" 'beginning-of-buffer)
  2333.   (define-key S-help-mode-map "x" 'S-kill-buffer-and-go)
  2334.   (define-key S-help-mode-map "?" 'S-describe-help-mode)
  2335.   (define-key S-help-mode-map "\C-c\C-r"    'S-eval-region)
  2336.   (define-key S-help-mode-map "\C-c\M-r" 'S-eval-region-and-go)
  2337.   (define-key S-help-mode-map "\C-c\C-f"    'S-eval-function)
  2338.   (define-key S-help-mode-map "\M-\C-x"  'S-eval-function)
  2339.   (define-key S-help-mode-map "\C-c\M-f" 'S-eval-function-and-go)
  2340.   (define-key S-help-mode-map "\C-c\C-j"    'S-eval-line)
  2341.   (define-key S-help-mode-map "\C-c\M-j" 'S-eval-line-and-go)
  2342.   (define-key S-help-mode-map "\M-\C-a"  'S-beginning-of-function)
  2343.   (define-key S-help-mode-map "\M-\C-e"  'S-end-of-function)
  2344.   (define-key S-help-mode-map "\C-c\C-y"    'S-switch-to-S)
  2345.   (define-key S-help-mode-map "\C-c\C-z" 'S-switch-to-end-of-S)
  2346.   (define-key S-help-mode-map "\C-c\C-l"    'S-load-file)
  2347.   (define-key S-help-mode-map "\C-c\C-h"    'S-display-help-on-object))
  2348.  
  2349. ;;; Largely ripped from more-mode.el,
  2350. ;;;  by Wolfgang Rupprecht wolfgang@mgm.mit.edu
  2351.  
  2352. (defun S-help-mode ()
  2353.   "Mode for viewing S help files.
  2354. Use SPC and DEL to page back and forth through the file.
  2355. Use `s' to jump to a particular section; `s ?' for help.
  2356. Use `q' to return to your S session; `x' to kill this buffer first.
  2357. The usual commands for evaluating S source are available.
  2358. Other keybindings are as follows:
  2359. \\{S-help-mode-map}"
  2360.   (interactive)
  2361.   (setq major-mode 'S-help-mode)
  2362.   (setq mode-name "S Help")
  2363.   (use-local-map S-help-mode-map)
  2364.   (run-hooks S-help-mode-hook))
  2365.  
  2366. (run-hooks 'S-mode-load-hook)
  2367.  
  2368.  
  2369. ;;; Revision notes:
  2370. ;;  Release 2.1 on October 14, 1991 to statlib@stat.cmu.edu, 
  2371. ;;     and to the elisp archives at OSU (brennan@dg-rtp.dg.com (Dave Brennan))
  2372. ;;  and announced on internet.s-news, netnews.gnu.emacs.sources, & 
  2373. ;;    andrew.programs.S
  2374. ;; -------------------------------------------------------
  2375. ;;     Jul 26          1991  Frank Ritter
  2376. ;;   * added S-mode-load-hook & S-pre-run-hook
  2377. ;;     and testing by neilc@research.att.com
  2378. ;;     Jul 9           1991  Frank Ritter
  2379. ;;   * Changed S-command to use a register rather than 
  2380. ;;       the kill ring.
  2381. ;;   * Better file header, comments now at 60 col so 
  2382. ;;       mailers wont' eat them.
  2383. ;;   * Better S-extract-word-name.
  2384. ;;   * Added S-mode-version variable
  2385. ;;   * Changed syntax table to read |#; appropriately
  2386. ;;
  2387. ;; Wed Nov 28 11:03:50 1990  Ed Kademan  (kademan at hermes)
  2388. ;;   * Make the S-mode-syntax-table a slightly modified
  2389. ;;       version of the c-mode-syntax-table instead of a
  2390. ;;       version of the one for lisp.
  2391. ;; 
  2392. ;; Sat Nov 10 12:41:52 1990  Ed Kademan  (kademan at hermes)
  2393. ;;   * Made run-S and run-s commands synonymous with the
  2394. ;;       function S.
  2395. ;; 
  2396. ;; Fri Oct 19 12:41:52 1990  Ed Kademan  (kademan at hermes)
  2397. ;;   * Made S-directory a user modifiable variable.  S will
  2398. ;;       run from that directory.
  2399. ;; 
  2400. ;; Thu Oct 18 12:41:52 1990  Ed Kademan  (kademan at hermes)
  2401. ;;   * Added function S-nuke-help-bs to clean up nroff
  2402. ;;       style text in the S help buffer.  This function is
  2403. ;;       a modification of nuke-nroff-bs from man.el.
  2404. ;; -------------------------------------------------------
  2405. ;; Unnumbered version released dated Thu Jun 14 09:56:56 CDT 1990
  2406. ;;
  2407. ;; Fri Jan 17 1992 Dave Smith (dsmith@stats.adelaide.edu.au)
  2408. ;;   * Help mode for reading files. When asking for an object to
  2409. ;;     run help on, completion is over those help files that exist.
  2410. ;;   * Added object name completion, and made S-get-object-list
  2411. ;;     efficient enough to make it worthwile.
  2412. ;;   * Error parsing for loaded files
  2413. ;;   * Better customization of file-names, with sensible defaults
  2414. ;;   * Sensible buffer names for object buffers
  2415. ;;   * Corrected definition for `.' in syntax table
  2416. ;;   * Improved (and simplified) S-read-object-name-default
  2417. ;;   * Included pager='cat' to default help-command specification
  2418. ;;   * Added a call to run-hook for S-pre-run-hook
  2419. ;;   * Changed keymaps to conform with GNU guidelines
  2420. ;;     (i.e. no \C-letter bindings)
  2421. ;;   * S-command has a new third argument, visible
  2422. ;;
  2423. ;; Tue May 27 1992 Dave Smith (dsmith@stats.adelaide.edu.au)
  2424. ;;   * now copes with dynamically changing prompts (reported by Doug Bates)
  2425. ;;
  2426. ;; Thu May 29 1992 Dave Smith (dsmith@stats.adelaide.edu.au)
  2427. ;;   * Added S-execute, modified S-execute-* to use it.
  2428. ;;
  2429. ;; Mon Jun 22 1992 dsmith
  2430. ;;   * Added S-mode editing commands written by Ken'ichi Shibayama
  2431. ;;     (shiba@isac.co.jp). A big win. 
  2432. ;;   * Removed the redundant argument to S-switch-to-end-of-S
  2433. ;;   * S-function-pattern improved
  2434. ;;   * added S-eval-visibly, S-eval-visibly-p and modified S-eval-*
  2435. ;;     to use them
  2436. ;;   * added S-eval-line-and-next-line
  2437. ;;   * eval commands can now echo in the process buffer
  2438. ;;   * added S-kill-output and S-view-at-bottom
  2439. ;;   * added a binding for comint-isearch and autoloaded it
  2440. ;;   * added S-execute-in-tb. S-parse-errors now takes prefix arg.
  2441. ;;
  2442. ;; Thu Jun 25 1992 dsmith
  2443. ;;   * Moved some doctrings to comments (Frank Ritter)
  2444. ;;   * The Tek stuff now lives in a separate file (Frank Ritter)
  2445. ;;   * Fiddly C-c ESC M-. bindings in S mode and Help mode moved
  2446. ;;       to C-c M-. bindings (Martin Maechler)
  2447. ;;   * S-execute-objects now uses variable inferior-S-objects-command
  2448. ;;       whose value depends on S version. (Ken'ichi Shibayama)
  2449. ;;   * Symbols given uniform prefixes: S- or inferior-S- (Frank Ritter)
  2450.  
  2451.