(?`): define the backquote (`) character to be in the quote character
[ess.git] / lisp / essd-r.el
blob97ee4d2dace5bdc295ba9647b363321397efddd0
1 ;;; essd-r.el --- R customization
3 ;; Copyright (C) 1997--2005 A.J. Rossini, Rich M. Heiberger, Martin
4 ;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
6 ;; Original Author: A.J. Rossini
7 ;; Created: 12 Jun 1997
8 ;; Maintainers: ESS-core <ESS-core@stat.math.ethz.ch>
10 ;; Keywords: start up, configuration.
12 ;; This file is part of ESS.
14 ;; This file is free software; you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; any later version.
19 ;; This file is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs; see the file COPYING. If not, write to
26 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
28 ;;; Commentary:
29 ;;; This file defines all the R customizations for ESS. See essl-s.el
30 ;;; for general S language customizations.
32 ;;; Autoloads and Requires
34 (ess-message "[essd-r:] (require 'essl-s)")
35 (require 'essl-s)
37 (require 'essd-r-args); for now
39 ;; modify S Syntax table:
40 (setq R-syntax-table S-syntax-table)
42 ;; In R 2.x, back tick now is a quote character, so lets tell Emacs
43 ;; that it is; the problem below for older R should no longer be a
44 ;; serious issue.
45 ;;R >= 1.8: back tick `string` -- unfortunately no *pair* checking:
46 ;; breaks when things like `..' are used:
47 (modify-syntax-entry ?` "\"" R-syntax-table)
48 (modify-syntax-entry ?_ "_" R-syntax-table) ; foo_bar is symbol in R >=1.9
50 (ess-message "[essd-r:] (autoload ..) & (def** ..)")
52 (autoload 'inferior-ess "ess-inf" "Run an ESS process.")
53 (autoload 'ess-mode "ess-mode" "Edit an ESS process.")
55 ;;; Code:
57 (defvar R-customize-alist
58 (append
59 '((ess-local-customize-alist . 'R-customize-alist)
60 (ess-dialect . "R")
61 (ess-suffix . "R")
62 (ess-dump-filename-template . (ess-replace-regexp-in-string
63 "S$" ess-suffix ; in the one from custom:
64 ess-dump-filename-template-proto))
65 (ess-mode-syntax-table . R-syntax-table)
66 (ess-mode-editing-alist . R-editing-alist)
67 (ess-change-sp-regexp . ess-R-change-sp-regexp)
68 (ess-help-sec-regex . ess-help-R-sec-regex)
69 (ess-help-sec-keys-alist . ess-help-R-sec-keys-alist)
70 (ess-loop-timeout . ess-S-loop-timeout);fixme: dialect spec.
71 (ess-cmd-delay . ess-R-cmd-delay)
72 (ess-function-pattern . ess-R-function-pattern)
73 (ess-object-name-db-file . "ess-r-namedb.el" )
74 (ess-imenu-mode-function . 'ess-imenu-R)
75 (inferior-ess-program . inferior-R-program-name)
76 (inferior-ess-objects-command . inferior-R-objects-command)
77 (inferior-ess-font-lock-keywords . inferior-ess-R-font-lock-keywords)
78 (inferior-ess-search-list-command . "search()\n")
79 (inferior-ess-help-command . "help(\"%s\", htmlhelp=FALSE)\n")
80 (inferior-ess-help-filetype . nil)
81 (inferior-ess-exit-command . "q()")
82 (inferior-ess-exit-prompt . "Save workspace image? [y/n/c]: ")
83 (inferior-ess-primary-prompt . "\\([A-Z][][A-Za-z0-9.]*\\)*> ")
84 (inferior-ess-secondary-prompt . "+ ?")
85 ;;harmful for shell-mode's C-a: -- but "necessary" for ESS-help?
86 (inferior-ess-start-file . nil) ;; "~/.ess-R"
87 (inferior-ess-start-args . "")
88 (ess-STERM . "iESS")
89 (ess-editor . R-editor)
90 (ess-pager . R-pager)
92 S-common-cust-alist)
93 "Variables to customize for R")
95 (defvar ess-r-versions '("R-1" "R-2" "R-devel" "R-patched")
96 "List of partial strings for versions of R to access within ESS.
97 Each string specifies the start of a filename. If a filename
98 beginning with one of these strings is found on `exec-path', a M-x
99 command for that version of R is made available. For example, if the
100 file \"R-1.8.1\" is found and this variable includes the string
101 \"R-1\", a function called `M-x R-1.8.1' will be available to run that
102 version of R.
103 If duplicate versions of the same program are found (which happens if
104 the same path is listed on `exec-path' more than once), they are
105 ignored by calling `ess-uniq-list'.
106 Set this variable to nil to disable searching for other versions of R.
107 If you set this variable, you need to restart Emacs (and set this variable
108 before ess-site is loaded) for it to take effect.")
110 ;;;### autoload
111 (defun R (&optional start-args)
112 "Call 'R', the 'GNU S' system from the R Foundation.
113 Optional prefix (C-u) allows to set command line arguments, such as
114 --vsize. This should be OS agnostic.
115 If you have certain command line arguments that should always be passed
116 to R, put them in the variable `inferior-R-args'."
117 (interactive "P")
118 (setq ess-customize-alist R-customize-alist)
119 (ess-write-to-dribble-buffer ;; for debugging only
120 (format
121 "\n(R): ess-dialect=%s, buf=%s, start-arg=%s\n current-prefix-arg=%s\n"
122 ess-dialect (current-buffer) start-args current-prefix-arg))
123 (let* ((r-always-arg
124 (if (or ess-microsoft-p (eq system-type 'cygwin))
125 "--ess "
126 "--no-readline "))
127 (r-start-args
128 (concat r-always-arg
129 inferior-R-args " " ; add space just in case
130 (if start-args
131 (read-string
132 (concat "Starting Args [other than `"
133 r-always-arg
134 "'] ? "))
135 nil)))
136 ;;Micro$ ?: default-process-coding-system ;-breaks UTF locales on Unix:
138 (if ess-microsoft-p
139 (setq default-process-coding-system '(undecided-dos . undecided-dos)))
140 (inferior-ess r-start-args) ;; (R)
141 (ess-write-to-dribble-buffer
142 (format "(R): inferior-ess-language-start=%s\n"
143 inferior-ess-language-start))
144 ;; currently rely on baseenv() which is in R only since version 2.2:
145 (ess-eval-linewise
146 "if(!exists(\"baseenv\", mode=\"function\")) baseenv <- function() NULL"
147 nil nil nil 'wait-prompt);; solving "lines running together"
148 (if inferior-ess-language-start
149 (ess-eval-linewise inferior-ess-language-start
150 nil nil nil 'wait-prompt))))
152 ;;;### autoload
153 (defun R-mode (&optional proc-name)
154 "Major mode for editing R source. See `ess-mode' for more help."
155 (interactive)
156 (setq ess-customize-alist R-customize-alist)
157 ;;(setq imenu-generic-expression R-imenu-generic-expression)
158 (ess-mode R-customize-alist proc-name)
159 (if (fboundp 'ess-add-toolbar) (ess-add-toolbar))
160 ;; ECB needs seminatic stuff.
161 ;; (if (featurep 'semantic)
162 ;; (setq semantic-toplevel-bovine-table r-toplevel-bovine-table))
163 (if ess-imenu-use-S
164 (progn (require 'ess-menu)
165 (ess-imenu-R)))
166 ;; MM: ^^^^^^^^^^^ should really use ess-imenu-mode-function from the
167 ;; alist above!
171 (fset 'r-mode 'R-mode)
173 (defun ess-r-versions-create ()
174 "Generate the `M-x R-X.Y' functions for starting other versions of R.
175 See `ess-r-versions' for strings that determine which functions are created.
177 The local variable `ess-r-versions-created' is used to return list of
178 the new R defuns, if any, that were created. The defuns will normally
179 be placed on the menubar upon ESS initialisation."
182 (if (not ess-r-versions)
183 nil ;nothing to return
184 ;; else, if ess-r-versions is non-nil, let's try to find those R versions.
185 ;; This works by creating a temp buffer where the template function is
186 ;; edited so that X.Y is replaced by the version name
187 (let ((template "")
188 (beg)
189 (versions)
190 (version)
191 (eval-buf (get-buffer-create "*ess-temp-r-evals*"))
192 (ess-r-versions-created)
194 ;; This is the template function used for creating M-x R-X.Y.
195 (setq template "(defun R-X.Y (&optional start-args)
196 \"Call R-X.Y, i.e., the R version 'R-X.Y' using ESS.
197 This function was generated by `ess-r-versions-create'.\"
198 (interactive \"P\")
199 (let ((inferior-R-program-name \"R-X.Y\"))
200 (R start-args)))
203 (save-excursion
204 (set-buffer eval-buf)
205 ;; clear the buffer.
206 (delete-region (point-min) (point-max))
208 ;; Find which versions of R we want. Remove the pathname, leaving just
209 ;; the name of the executable.
210 (setq versions
211 (ess-uniq-list
212 (mapcar 'file-name-nondirectory
213 (apply 'nconc
214 (mapcar 'ess-find-exec-completions
215 ess-r-versions)))))
216 (ess-write-to-dribble-buffer
217 (format "(R): ess-r-versions-create making M-x defuns for %s"
218 (mapconcat 'identity versions " ")))
219 (setq ess-r-versions-created versions) ;keep copy for returning at end.
220 ;; Iterate over each string in VERSIONS, creating a new defun each time.
221 (while versions
222 (setq version (car versions)
223 versions (cdr versions))
224 (setq beg (point))
225 (insert template)
226 (goto-char beg)
227 (while (search-forward "R-X.Y" nil t)
228 (replace-match version t t))
229 (goto-char (point-max))
231 ;; buffer has now been created with defuns, so eval them!
232 (eval-buffer)
233 (kill-buffer eval-buf)
235 ess-r-versions-created)))
238 (defun ess-find-rterm (&optional ess-R-root-dir)
239 "Find the full path of all occurences of Rterm.exe under the ESS-R-ROOT-DIR.
240 If ESS-R-ROOT-DIR is nil, construct it by looking for an occurence of Rterm.exe
241 in the exec-path. If there are no occurences of Rterm.exe in the exec-path,
242 then use \"c:/progra~1/R/\" which is the default location for the R distribution."
243 (let* ((Rpath)
244 (rwxxyy)
245 (rw)
246 (Rterm nil))
247 (if (not ess-R-root-dir)
248 (progn
249 (setq Rpath (executable-find "Rterm"))
250 (setq ess-R-root-dir
251 (if Rpath
252 (expand-file-name
253 (concat
254 (file-name-directory Rpath)
255 "../../"))
256 "c:/progra~1/R/"))))
257 (setq rwxxyy (append (file-name-all-completions "rw" ess-R-root-dir)
258 (file-name-all-completions "R-1" ess-R-root-dir)
259 (file-name-all-completions "R-2" ess-R-root-dir)
260 (file-name-all-completions "R-devel" ess-R-root-dir)
261 (file-name-all-completions "R-patched" ess-R-root-dir)
262 )) ;; this needs to rewritten to use (append '("rw") ess-r-versions)
263 (while rwxxyy
264 (setq rw (car rwxxyy))
265 (setq rwxxyy (cdr rwxxyy))
266 (setq Rterm (cons (ess-replace-regexp-in-string "[\\]" "/"
267 (concat ess-R-root-dir rw "bin/Rterm.exe"))
268 Rterm)))
269 Rterm))
271 (defun ess-rterm-versions-create ()
272 "Generate the `M-x rwxxyy' functions for starting other versions of R.
273 See `ess-rterm-versions' for strings that determine which functions
274 are created.
276 The result `ess-rterm-versions-created' will store a list of the new
277 Rterm defuns, if any, that were created. The defuns will normally be
278 placed on the menubar upon ESS initialisation."
280 ;; This works by creating a temp buffer where the template function is
281 ;; edited so that R-X.Y is replaced by the version name
282 (let ((template "")
283 (beg)
284 (versions)
285 (version)
286 (version-root)
287 (eval-buf (get-buffer-create "*ess-temp-r-evals*"))
288 (ess-rterm-versions-created)
291 ;; This is the template function used for creating M-x R-X.Y.
292 (setq template "(defun R-X.Y (&optional start-args)
293 \"Call R-X.Y, i.e., the R version 'R-X.Y' using ESS.
294 This function was generated by `ess-rterm-versions-create'.\"
295 (interactive \"P\")
296 (let ((inferior-R-program-name \"Rterm-X.Y\"))
297 (R start-args)))
300 (save-excursion
301 (set-buffer eval-buf)
302 ;; clear the buffer.
303 (delete-region (point-min) (point-max))
305 ;; Find which versions of R we want. Remove the pathname, leaving just
306 ;; the name of the executable.
307 (setq versions ess-rterm-versions)
308 (ess-write-to-dribble-buffer
309 (format "(R): ess-rterm-versions-create making M-x defuns for %s"
310 (mapconcat 'identity versions " ")))
312 ;; Iterate over each string in VERSIONS, creating a new defun each time.
313 (while versions
314 (setq version (car versions)
315 versions (cdr versions)
316 version-root (file-name-nondirectory
317 (substring (file-name-directory
318 (substring
319 (file-name-directory version)
320 0 -1))
321 0 -1)))
322 (setq beg (point))
323 (insert template)
324 (goto-char beg)
325 (while (search-forward "R-X.Y" nil t)
326 (replace-match version-root t t))
327 (goto-char beg)
328 (while (search-forward "Rterm-X.Y" nil t)
329 (replace-match version t t))
330 (goto-char (point-max))
331 (setq ess-rterm-versions-created
332 (cons version-root ess-rterm-versions-created))
334 ;; buffer has now been created with defuns, so eval them!
335 (eval-buffer)
336 (kill-buffer eval-buf)
338 ess-rterm-versions-created))
340 ;;;### autoload
341 (defun Rnw-mode ()
342 "Major mode for editing Sweave(R) source.
343 See `noweb-mode' and `R-mode' for more help."
344 (interactive)
345 (require 'ess-noweb);; << probably someplace else
346 (noweb-mode 1); turn it on
347 (noweb-set-doc-mode 'latex-mode)
348 (noweb-set-code-mode 'R-mode)
349 (run-hooks 'Rnw-mode-hook))
351 (fset 'Snw-mode 'Rnw-mode); just a synonym (for now or ever)
354 (autoload 'ess-transcript-mode "ess-trns"
355 "Major mode for editing S transcript files." t)
357 (defun R-transcript-mode ()
358 "Does the right thing."
359 (interactive)
360 (ess-transcript-mode R-customize-alist))
362 (fset 'r-transcript-mode 'R-transcript-mode)
364 (defun R-fix-T-F (&optional from quietly)
365 "Fix T/F into TRUE and FALSE *cautiously*, i.e. not in comments and strings;
366 starting from the current position (point)."
367 (interactive "d\nP"); point and prefix (C-u)
368 (save-excursion
369 (goto-char from)
370 (ess-rep-regexp "\\(\\([][=,()]\\|<-\\|_\\) *\\)T\\>" "\\1TRUE"
371 'fixcase nil (not quietly))
372 (goto-char from)
373 (ess-rep-regexp "\\(\\([][=,()]\\|<-\\|_\\\) *\\)F\\>" "\\1FALSE"
374 'fixcase nil (not quietly))))
376 ;; From: Sebastian Luque <spluque@gmail.com>
377 ;; To: ess-help@stat.math.ethz.ch
378 ;; Date: Mon, 01 May 2006 19:17:49 -0500
380 ;; Without knowing how to tell R to use w3m from within Emacs, and after
381 ;; switching to Konqueror's window for the millionth time, I wrote the
382 ;; following function:
384 ;; This emulates some of the functionality of RSiteSearch() and tests ok in
385 ;; my system GNU Emacs 22.0.50.1 (i486-pc-linux-gnu, X toolkit, Xaw3d scroll
386 ;; bars) of 2006-04-27 on pacem, modified by Debian. This has the benefit of
387 ;; displaying results with whatever you've told browse-url to use; in my
388 ;; case, w3m with the emacs-w3m package.
390 ;; My elisp skills are rather poor, so comments and suggestions for
391 ;; improvement are welcome.
392 ;; --
393 ;; Seb
396 ;; MM _FIXME_: This only works correctly for Emacs 22.0.50 (alpha)
397 ;; for 21.x it has problems in the (completing-read-multiple .)
398 ;; at the end
399 (defun R-site-search (string)
400 "Search the R archives for STRING, using default criteria. If
401 called with a prefix, options are available for
402 1) matches per page,
403 2) sections of the archives to search (separated by value of `crm-default-separator'),
404 3) for displaying results in long or short formats, and
405 4) for sorting by any given field.
406 Completion is available for supplying options."
407 (interactive "sSearch string: ")
408 (let ((site "http://search.r-project.org/cgi-bin/namazu.cgi?query=")
409 (okstring (replace-regexp-in-string " +" "+" string)))
410 (if current-prefix-arg
411 (let ((mpp (concat
412 "&max="
413 (completing-read
414 "Matches per page: "
415 '(("20" 1) ("30" 2) ("40" 3) ("50" 4) ("100" 5)))))
416 (format (concat
417 "&result="
418 (completing-read
419 "Format: " '("normal" "short")
420 nil t "normal" nil "normal")))
421 (sortby (concat
422 "&sort="
423 (completing-read
424 "Sort by: "
425 '(("score" 1) ("date:late" 2) ("date:early" 3)
426 ("field:subject:ascending" 4)
427 ("field:subject:decending" 5)
428 ("field:from:ascending" 6) ("field:from:decending" 7)
429 ("field:size:ascending" 8) ("field:size:decending" 9))
430 nil t "score" nil "score")))
431 (restrict (concat
432 "&idxname="
433 (mapconcat
434 'identity
435 (completing-read-multiple
436 "Limit search to: "
437 '(("Rhelp02a" 1) ("functions" 2) ("docs" 3)
438 ("Rhelp01" 4))
439 nil t "Rhelp02a,functions,docs" nil
440 "Rhelp02a,functions,docs") "&idxname="))))
441 (browse-url (concat site okstring mpp format sortby restrict)))
442 ;; else: without prefix use defaults:
443 (browse-url (concat site okstring "&max=20&result=normal&sort=score"
444 "&idxname=Rhelp02a&idxname=functions&idxname=docs")))))
447 \f ; provides
449 (provide 'essd-r)
451 \f ; Local variables section
453 ;;; This file is automatically placed in Outline minor mode.
454 ;;; The file is structured as follows:
455 ;;; Chapters: ^L ;
456 ;;; Sections: ;;*;;
457 ;;; Subsections: ;;;*;;;
458 ;;; Components: defuns, defvars, defconsts
459 ;;; Random code beginning with a ;;;;* comment
461 ;;; Local variables:
462 ;;; mode: emacs-lisp
463 ;;; outline-minor-mode: nil
464 ;;; mode: outline-minor
465 ;;; outline-regexp: "\^L\\|\\`;\\|;;\\*\\|;;;\\*\\|(def[cvu]\\|(setq\\|;;;;\\*"
466 ;;; End:
468 ;;; essd-r.el ends here