1
;;; ess-r-d.el --- R customization
3
;; Copyright (C) 1997--2007 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)
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.
29
;;; This file defines all the R customizations for ESS. See ess-s-l.el
30
;;; for general S language customizations.
32
;;; Autoloads and Requires
34
(ess-message "[ess-r-d:] (require 'ess-s-l)")
37
(require 'ess-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
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 "[ess-r-d:] (autoload ..) & (def** ..)")
52
(autoload 'inferior-ess "ess-inf" "Run an ESS process.")
53
(autoload 'ess-mode "ess-mode" "Edit an ESS process.")
57
(defvar R-customize-alist
59
'((ess-local-customize-alist . 'R-customize-alist)
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-command . inferior-ess-r-help-command)
81
(inferior-ess-help-filetype . nil)
82
(inferior-ess-exit-command . "q()")
83
(inferior-ess-exit-prompt . "Save workspace image? [y/n/c]: ")
84
(inferior-ess-primary-prompt . "\\([A-Z][][A-Za-z0-9.]*\\)?> ")
85
(inferior-ess-secondary-prompt . "+ ?")
86
;;harmful for shell-mode's C-a: -- but "necessary" for ESS-help?
87
(inferior-ess-start-file . nil) ;; "~/.ess-R"
88
(inferior-ess-start-args . "")
90
(ess-editor . R-editor)
94
"Variables to customize for R -- set up later than emacs initialization.")
96
(defvar ess-r-versions '("R-1" "R-2" "R-devel" "R-patched")
97
"List of partial strings for versions of R to access within ESS.
98
Each string specifies the start of a filename. If a filename
99
beginning with one of these strings is found on `exec-path', a M-x
100
command for that version of R is made available. For example, if the
101
file \"R-1.8.1\" is found and this variable includes the string
102
\"R-1\", a function called `M-x R-1.8.1' will be available to run that
104
If duplicate versions of the same program are found (which happens if
105
the same path is listed on `exec-path' more than once), they are
106
ignored by calling `ess-uniq-list'.
107
Set this variable to nil to disable searching for other versions of R.
108
If you set this variable, you need to restart Emacs (and set this variable
109
before ess-site is loaded) for it to take effect.")
112
(defun R (&optional start-args)
113
"Call 'R', the 'GNU S' system from the R Foundation.
114
Optional prefix (C-u) allows to set command line arguments, such as
115
--vsize. This should be OS agnostic.
116
If you have certain command line arguments that should always be passed
117
to R, put them in the variable `inferior-R-args'."
119
(setq ess-customize-alist R-customize-alist)
120
(ess-write-to-dribble-buffer ;; for debugging only
122
"\n(R): ess-dialect=%s, buf=%s, start-arg=%s\n current-prefix-arg=%s\n"
123
ess-dialect (current-buffer) start-args current-prefix-arg))
125
(if (or ess-microsoft-p (eq system-type 'cygwin))
130
inferior-R-args " " ; add space just in case
133
(concat "Starting Args [other than `"
138
;;Micro$ ?: default-process-coding-system ;-breaks UTF locales on Unix:
140
(setq default-process-coding-system '(undecided-dos . undecided-dos)))
141
(inferior-ess r-start-args) ;; -> .. (ess-multi ...) -> .. (inferior-ess-mode) ..
142
;;-------------------------
143
(ess-write-to-dribble-buffer
144
(format "(R): inferior-ess-language-start=%s\n"
145
inferior-ess-language-start))
146
;; can test only now that R is running:
147
(if (ess-current-R-at-least '2.5.0)
149
(if ess-use-R-completion ;; use R's completion mechanism (pkg "rcompgen" or "utils")
150
(progn ; nothing to happen here -- is all in ess-complete-object-name
151
(ess-write-to-dribble-buffer "resetting completion to 'ess-R-complete-object-name")
153
;; problem with ess-help-command
155
(if (ess-current-R-at-least '2.10.0)
157
;; else R version <= 2.9.2
158
"function(..., help_type) help(..., htmlhelp= (help_type==\"html\"))")))
161
(concat ".help.ESS <- " my-R-help-cmd) nil nil nil 'wait-prompt)
164
;; else R version <= 2.4.1
166
;; for R <= 2.1.x : define baseenv() :
168
"if(!exists(\"baseenv\", mode=\"function\")) baseenv <- function() NULL"
169
nil nil nil 'wait-prompt);; solving "lines running together"
171
(if inferior-ess-language-start
172
(ess-eval-linewise inferior-ess-language-start
173
nil nil nil 'wait-prompt))))
176
(defun R-mode (&optional proc-name)
177
"Major mode for editing R source. See `ess-mode' for more help."
179
(setq ess-customize-alist R-customize-alist)
180
;;(setq imenu-generic-expression R-imenu-generic-expression)
181
(ess-mode R-customize-alist proc-name)
182
(if (fboundp 'ess-add-toolbar) (ess-add-toolbar))
183
;; ECB needs seminatic stuff.
184
;; (if (featurep 'semantic)
185
;; (setq semantic-toplevel-bovine-table r-toplevel-bovine-table))
187
(progn (require 'ess-menu)
189
;; MM: ^^^^^^^^^^^ should really use ess-imenu-mode-function from the
194
(fset 'r-mode 'R-mode)
196
(defun ess-r-versions-create ()
197
"Generate the `M-x R-x.y' functions for starting other versions of R.
198
On MS Windows, this works using `ess-rterm-version-paths'; otherwise,
199
see `ess-r-versions' for strings that determine which functions are created.
201
The result is a list of the new R defuns, if any, that were created. The
202
defuns will normally be placed on the menubar and stored as
203
`ess-r-versions-created' upon ESS initialisation."
205
(if (not ess-r-versions)
206
nil ;nothing to return
207
;; else, if ess-r-versions is non-nil, let's try to find those R versions.
208
;; This works by creating a temp buffer where the template function is
209
;; edited so that X.Y is replaced by the version name
211
(eval-buf (get-buffer-create "*ess-temp-r-evals*"))
214
;; This is the template function used for creating M-x R-X.Y.
216
"(defun R-X.Y (&optional start-args)
217
\"Call R-X.Y, i.e., the R version 'R-X.Y' using ESS.
218
This function was generated by `ess-r-versions-create'.\"
220
(let ((use-dialog-box nil);; Win-only: dialog box won't return a directory
221
(inferior-R-program-name \""
222
(if ess-microsoft-p "Rterm" "R") "-X.Y\"))
228
(set-buffer eval-buf)
230
(delete-region (point-min) (point-max))
232
;; Find which versions of R we want. Remove the pathname, leaving just
233
;; the name of the executable.
235
(if ess-microsoft-p ess-rterm-version-paths
236
;; ^^^^^^^^^^^^^^^^^^^^^^^ created in
237
;; ./ess-site.el at start
240
(mapcar 'file-name-nondirectory
242
(mapcar 'ess-find-exec-completions
244
(ess-write-to-dribble-buffer
245
(format "(R): ess-r-versions-create making M-x defuns for \n %s\n"
246
(mapconcat 'identity versions "\n ")))
247
(if (not ess-microsoft-p)
248
(setq r-versions-created versions)) ;keep copy for returning at end.
250
;; Iterate over each string in VERSIONS, creating a new defun each time.
252
(let* ((version (car versions))
253
(this-version version)
256
(setq versions (cdr versions))
257
(when ess-microsoft-p
259
version (file-name-nondirectory ;; two levels up; don't want "bin" ...
260
(directory-file-name (file-name-directory
261
(directory-file-name (file-name-directory version)))))
262
r-versions-created (cons version r-versions-created)))
266
(while (search-forward "R-X.Y" nil t)
267
(replace-match version t t))
268
(when ess-microsoft-p
270
(while (search-forward "Rterm-X.Y" nil t)
271
(replace-match this-version t t)))
272
(goto-char (point-max)))
274
;; buffer has now been created with defuns, so eval them!
276
(kill-buffer eval-buf)
278
r-versions-created)))
280
(defvar ess-newest-R nil
281
"Stores the newest version of R that has been found. Used as a cache,
282
within ess-find-newest-R. Do not use this value directly, but
283
instead call the function \\[ess-find-newest-R].")
285
(defun ess-find-newest-R ()
286
"Find the newest version of R on the system. Once the value is found,
287
cache it in the variable `ess-newest-R' for future use as finding the
288
newest version of R can be potentially time-consuming."
290
(progn (message "Finding all versions of R on your system...")
296
ess-rterm-version-paths
297
(add-to-list 'ess-r-versions-created
298
inferior-R-program-name))))))
300
(defun ess-check-R-program-name ()
301
"Check if `inferior-R-program-name' points to an executable version of R.
302
If not, try to find the newest version of R elsewhere on the system, and
303
update `inferior-R-program-name' accordingly."
304
(unless (executable-find inferior-R-program-name)
305
;; need to check if we can find another name.
306
(let ((newest (ess-find-newest-R)))
308
(setq inferior-R-program-name newest)
309
(message "Sorry, no version of R could be found on your system.")))))
311
(defun R-newest (&optional start-args)
312
"Find the newest version of R available, and run it.
313
Subsequent calls to R-newest will run that version, rather than searching
314
again for the newest version. Providing an optional prefix arg (C-u) will
315
prompt for command line arguments."
317
(let ((rnewest (ess-find-newest-R)))
319
(error "No version of R could be found.")
320
;; Else: we have a working version of R.
321
;; Have to be careful to avoid recursion...
322
(message (concat "Newest version of R is " rnewest))
326
(file-name-nondirectory
327
(substring (file-name-directory
328
(substring (file-name-directory rnewest) 0 -1))
331
;;(fset 'R-newest (intern rnewest))
332
(R-newest start-args))))
334
;; (ess-r-version-date "R-2.5.1") (ess-r-version-date "R-patched")
335
;; (ess-r-version-date "R-1.2.1") (ess-r-version-date "R-1.8.1")
336
;; Note that for R-devel, ver-string is something like
337
;; R version 2.6.0 Under development (unstable) (2007-07-14 r42234)
338
;; Antique examples are 'R 1.0.1 (April 14, 2000)' or 'R 1.5.1 (2002-06-17).'
339
(defun ess-r-version-date (rver)
340
"Return the date of the version of R named RVER.
341
The date is returned as a date string. If the version of R could
342
not be found from the output of the RVER program, \"-1\" is
346
(setq ver-string (shell-command-to-string
347
(concat rver " --version")))
349
"R \\(version \\)?[1-9][^\n]+ (\\(2[0-9-]+\\)\\( r[0-9]+\\)?)"
351
(setq date (match-string 2 ver-string)))
354
(defun ess-current-R-version ()
355
"Get the version of R currently running in the ESS buffer as a string"
356
(ess-make-buffer-current)
357
(car (ess-get-words-from-vector "as.character(getRversion())\n")))
359
(defun ess-current-R-at-least (version)
360
"Is the version of R (in the ESS buffer) at least (\">=\") VERSION ?
361
Examples: (ess-current-R-at-least '2.7.0)
362
or (ess-current-R-at-least \"2.5.1\")"
363
(ess-make-buffer-current)
365
(car (ess-get-words-from-vector
366
(format "as.character(getRversion() >= \"%s\")\n" version)))))
369
(defun ess-newest-r (rvers)
370
"Check all the versions of RVERS to see which is the newest.
371
Return the name of the newest version of R."
372
(let ((rtimes (mapcar 'ess-r-version-date rvers)))
373
;; SJE: 2007-07-13 -- following line is a temp var to check that
374
;; the newest version of R is found correctly.
375
(setq ess-temp-newest rtimes)
376
(ess-find-newest-date rtimes)))
378
;; Test case for following defun:
379
;; (setq a '( ("2003-10-04" . "R-1.7")
380
;; ("2006-11-19" . "R-2.2")
381
;; ("2007-07-01" . "R-dev")
382
;; ("-1" . "R-broken")
383
;; ("2005-12-30" . "R-2.0")))
384
;; (ess-find-newest-date a)
385
(defun ess-find-newest-date (rvers)
386
"Find the newest version of R given in the a-list RVERS.
387
Each element of RVERS is a dotted pair (date . R-version), where
388
date is given as e.g.\"2007-11-30\" so that we can compare dates
389
as strings. If a date is listed as \"-1\", that version of R
392
If the value returned is nil, no valid newest version of R could be found."
396
(setq this-r (car rvers)
398
(when (string< new-time (car this-r))
399
(setq new-time (car this-r)
400
new-r (cdr this-r))))
404
(defun ess-find-rterm (&optional ess-R-root-dir)
405
"Find the full path of all occurences of Rterm.exe under the ESS-R-ROOT-DIR.
406
If ESS-R-ROOT-DIR is nil, construct it by looking for an occurence of Rterm.exe
407
in the exec-path. If there are no occurences of Rterm.exe in the exec-path,
408
then use `ess-program-files' (which evaluates to something like \"c:/progra~1/R/\"
409
in English locales) which is the default location for the R distribution."
410
(if (not ess-R-root-dir)
411
(let ((Rpath (executable-find "Rterm")))
415
(concat (file-name-directory Rpath) "../../")
416
(concat ess-program-files "/R/"))))
417
(ess-write-to-dribble-buffer
418
(format "(ess-find-rterm): ess-R-root-dir = '%s'\n" ess-R-root-dir))
421
(when (file-directory-p ess-R-root-dir) ; otherwise file-name-all-.. errors
423
(ess-replace-regexp-in-string "[\\]" "/" ess-R-root-dir))
425
(ess-drop-non-directories
427
(mapcar '(lambda (r-prefix)
428
(file-name-all-completions r-prefix ess-R-root-dir))
429
(append '("rw") ess-r-versions))))))
430
(mapcar '(lambda (dir)
431
(concat ess-R-root-dir
432
(ess-replace-regexp-in-string "[\\]" "/" dir)
436
;; From Jim (James W.) MacDonald, based on code by Deepayan Sarkar,
437
;; originally named 'alt-ess-complete-object-name'.
438
;; Use rcompgen in ESS
439
;; Can be activated by something like
440
;; (define-key inferior-ess-mode-map "\t" 'ess-R-complete-object-name)
441
(defun ess-R-complete-object-name ()
442
"Completion in R via R's completion utilities (formerly 'rcompgen').
443
To be used instead of ESS' completion engine for R versions >= 2.5.0
444
(or slightly older versions of R with an attached and working 'rcompgen' package)."
446
(ess-make-buffer-current)
447
(let* ((comint-completion-addsuffix nil)
448
(beg-of-line (save-excursion (comint-bol nil) (point)))
449
(end-of-line (point-at-eol))
450
(line-buffer (buffer-substring beg-of-line end-of-line))
451
(NS (if (ess-current-R-at-least '2.7.0)
454
(token-string ;; setup, including computation of the token
457
(format (concat NS ".assignLinebuffer('%s')\n") line-buffer))
458
(ess-command (format (concat NS ".assignEnd(%d)\n")
459
(- (point) beg-of-line)))
460
(car (ess-get-words-from-vector
461
(concat NS ".guessTokenFromLine()\n")))))
463
(possible-completions ;; compute and retrieve possible completions
465
(ess-command (concat NS ".completeToken()\n"))
466
(ess-get-words-from-vector
467
(concat NS ".retrieveCompletions()\n")))))
469
(or (comint-dynamic-simple-complete token-string
470
possible-completions)
475
"Major mode for editing Sweave(R) source.
476
See `noweb-mode' and `R-mode' for more help."
478
(require 'ess-noweb);; << probably someplace else
479
(noweb-mode 1); turn it on
480
(noweb-set-doc-mode 'latex-mode)
481
(noweb-set-code-mode 'R-mode)
482
(run-hooks 'Rnw-mode-hook))
484
(fset 'Snw-mode 'Rnw-mode); just a synonym (for now or ever)
487
(autoload 'ess-transcript-mode "ess-trns"
488
"Major mode for editing S transcript files." t)
490
(defun R-transcript-mode ()
491
"Does the right thing."
493
(ess-transcript-mode R-customize-alist))
495
(fset 'r-transcript-mode 'R-transcript-mode)
497
(defun R-fix-T-F (&optional from quietly)
498
"Fix T/F into TRUE and FALSE *cautiously*, i.e. not in comments and strings;
499
starting from the current position (point)."
500
(interactive "d\nP"); point and prefix (C-u)
503
(ess-rep-regexp "\\(\\([][=,()]\\|<-\\) *\\)T\\>" "\\1TRUE"
504
'fixcase nil (not quietly))
506
(ess-rep-regexp "\\(\\([][=,()]\\|<-\\) *\\)F\\>" "\\1FALSE"
507
'fixcase nil (not quietly))))
509
;; From: Sebastian Luque <spluque@gmail.com>
510
;; To: ess-help@stat.math.ethz.ch
511
;; Date: Mon, 01 May 2006 19:17:49 -0500
513
;; Without knowing how to tell R to use w3m from within Emacs, and after
514
;; switching to Konqueror's window for the millionth time, I wrote the
515
;; following function:
517
;; This emulates some of the functionality of RSiteSearch() and tests ok in
518
;; my system GNU Emacs 22.0.50.1 (i486-pc-linux-gnu, X toolkit, Xaw3d scroll
519
;; bars) of 2006-04-27 on pacem, modified by Debian. This has the benefit of
520
;; displaying results with whatever you've told browse-url to use; in my
521
;; case, w3m with the emacs-w3m package.
523
;; My elisp skills are rather poor, so comments and suggestions for
524
;; improvement are welcome.
529
;; MM _FIXME_: This only works correctly for Emacs 22.0.50 (alpha)
530
;; for 21.x it has problems in the (completing-read-multiple .)
532
(defun R-site-search (string)
533
"Search the R archives for STRING, using default criteria. If
534
called with a prefix, options are available for
536
2) sections of the archives to search (separated by value of `crm-default-separator'),
537
3) for displaying results in long or short formats, and
538
4) for sorting by any given field.
539
Completion is available for supplying options."
540
(interactive "sSearch string: ")
541
(let ((site "http://search.r-project.org/cgi-bin/namazu.cgi?query=")
542
(okstring (replace-regexp-in-string " +" "+" string)))
543
(if current-prefix-arg
548
'(("20" 1) ("30" 2) ("40" 3) ("50" 4) ("100" 5)))))
552
"Format: " '("normal" "short")
553
nil t "normal" nil "normal")))
558
'(("score" 1) ("date:late" 2) ("date:early" 3)
559
("field:subject:ascending" 4)
560
("field:subject:decending" 5)
561
("field:from:ascending" 6) ("field:from:decending" 7)
562
("field:size:ascending" 8) ("field:size:decending" 9))
563
nil t "score" nil "score")))
568
(completing-read-multiple
570
'(("Rhelp02a" 1) ("functions" 2) ("docs" 3)
572
nil t "Rhelp02a,functions,docs" nil
573
"Rhelp02a,functions,docs") "&idxname="))))
574
(browse-url (concat site okstring mpp format sortby restrict)))
575
;; else: without prefix use defaults:
576
(browse-url (concat site okstring "&max=20&result=normal&sort=score"
577
"&idxname=Rhelp02a&idxname=functions&idxname=docs")))))
584
; Local variables section
586
;;; This file is automatically placed in Outline minor mode.
587
;;; The file is structured as follows:
590
;;; Subsections: ;;;*;;;
591
;;; Components: defuns, defvars, defconsts
592
;;; Random code beginning with a ;;;;* comment
596
;;; outline-minor-mode: nil
597
;;; mode: outline-minor
598
;;; outline-regexp: "\^L\\|\\`;\\|;;\\*\\|;;;\\*\\|(def[cvu]\\|(setq\\|;;;;\\*"
601
;;; ess-r-d.el ends here