Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
2701 views
1
;;; ess-rutils.el --- R functions and keybindings to use in iESS.
2
3
;; Author: Sebastian Luque <[email protected]>
4
;; Created: Thu Nov 10 02:20:36 2004 (UTC)
5
;; Last-Updated: 2013-09-22T16:08:47+0000
6
;; By: Sebastian P. Luque
7
;; Version: $Id: ess-rutils.el 5939 2013-12-09 09:31:49Z maechler $
8
;; Compatibility: GNU Emacs >= 22.0.50.1
9
10
;; Copyright (c) 2005-2013 Sebastian P. Luque
11
12
;; This program is free software; you can redistribute it and/or modify
13
;; it under the terms of the GNU General Public License as published by
14
;; the Free Software Foundation; either version 3, or (at your option)
15
;; any later version.
16
;; This program is distributed in the hope that it will be useful,
17
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
;; GNU General Public License for more details.
20
21
;; A copy of the GNU General Public License is available at
22
;; http://www.r-project.org/Licenses/
23
24
;;; Commentary:
25
26
;; This library provides key bindings for performing basic R functions,
27
;; such as loading and managing packages, as well as object manipulation
28
;; (listing, viewing, and deleting), and an alternative to RSiteSearch()
29
;; that uses the browse-url function. Load the library with the method you
30
;; prefer (e.g. M-x load-file), but the easiest is probably to: a) make
31
;; sure your load-path variable includes the directory where ess-rutils.el
32
;; resides, and b) include (require 'ess-rutils) statement in your
33
;; ~/.emacs.
34
;;
35
;; Usage:
36
;;
37
;; Once R is started with M-x R, you should have the key bindings defined
38
;; at the end of this file working in your iESS process buffers. Simply
39
;; type the desired key binding.
40
;;
41
;; Acknowledgements:
42
;;
43
;; I am grateful to John Fox for having written his init.el file for
44
;; XEmacs, which motivated this Emacs alternative. I wanted to add some
45
;; object management comforts and came across Stephen Eglen's
46
;; ess-rdired.el, which provides a lot of these. ess-rutils.el builds upon
47
;; on a *lot* of ideas from ess-rdired.el.
48
49
;;; Code:
50
51
;; Autoloads and requires
52
(autoload 'ess-rdired "ess-rdired" "View *R* objects in a dired-like buffer." t)
53
(require 'ess-site)
54
55
(defvar ess-rutils-buf "*R temp*"
56
"Name of temporary R buffer.")
57
58
(defvar ess-rutils-mode-map nil
59
"Keymap for the *R temp* buffer.")
60
61
(defvar ess-rutils-rhtml-fn
62
(expand-file-name "ess-rutils-help-start.R" ess-etc-directory)
63
"Path to the file defining the R function .rutils.help.start().
64
This file is loaded into the inferior R process so that
65
`ess-rutils-html-docs' can use .rutils.help.start().")
66
67
(if ess-rutils-mode-map
68
()
69
(setq ess-rutils-mode-map (make-sparse-keymap))
70
(define-key ess-rutils-mode-map "l" 'ess-rutils-loadpkg)
71
(define-key ess-rutils-mode-map "i" 'ess-rutils-mark-install)
72
(define-key ess-rutils-mode-map "I" 'ess-rutils-install)
73
(define-key ess-rutils-mode-map "u" 'ess-rutils-unmark)
74
(define-key ess-rutils-mode-map "q" 'ess-rutils-quit)
75
(define-key ess-rutils-mode-map "?" 'ess-rutils-help))
76
77
(defun ess-rutils-mode ()
78
"Major mode for output from `ess-rutils-local-pkgs' and `ess-rutils-repos-pkgs'.
79
Useful bindings to handle package loading and installing.
80
\\{ess-rutils-mode-map}"
81
(kill-all-local-variables)
82
(use-local-map ess-rutils-mode-map)
83
(setq major-mode 'ess-rutils-mode)
84
(setq mode-name (concat "R utils " ess-local-process-name)))
85
86
(defun ess-rutils-local-pkgs ()
87
"List all packages in all libraries."
88
(interactive)
89
(if (get-buffer ess-rutils-buf)
90
(progn
91
(set-buffer ess-rutils-buf)
92
(setq buffer-read-only nil)))
93
(ess-execute
94
"writeLines(paste(' ', sort(.packages(all.available=TRUE)), sep=''))"
95
nil
96
(substring ess-rutils-buf 1 (- (length ess-rutils-buf) 1)))
97
(pop-to-buffer ess-rutils-buf)
98
(save-excursion
99
(beginning-of-line) (open-line 1)
100
(insert "**Available packages in all local R libraries**"))
101
(setq buffer-read-only t)
102
(ess-rutils-mode)
103
(if (featurep 'fit-frame)
104
(fit-frame)))
105
106
(defun ess-rutils-namepkg ()
107
"Return name of the package on current line."
108
(save-excursion
109
(beginning-of-line)
110
(if (looking-at "*")
111
nil
112
(forward-char 2)
113
(let (beg)
114
(setq beg (point))
115
(end-of-line) ;assume package names are separated by newlines.
116
(buffer-substring-no-properties beg (point))))))
117
118
(defun ess-rutils-loadpkg ()
119
"Load package from a library."
120
(interactive)
121
(let ((oklocal nil))
122
(save-excursion
123
(goto-char (point-min))
124
(if (search-forward "libraries**" nil t)
125
(setq oklocal t)))
126
(if oklocal
127
(progn
128
(setq pkg (ess-rutils-namepkg))
129
(ess-execute (concat "library('" pkg "', character.only=TRUE)")
130
'buffer))
131
nil)))
132
133
(defun ess-rutils-repos-pkgs ()
134
"List available packages from the repositories as listed by
135
getOptions(\"repos\") in the current R session."
136
(interactive)
137
(if (get-buffer ess-rutils-buf)
138
(progn
139
(set-buffer ess-rutils-buf)
140
(setq buffer-read-only nil)))
141
(ess-execute (concat "writeLines(paste(' \"', "
142
"rownames(available.packages()), '\"', sep=''))")
143
nil
144
(substring ess-rutils-buf 1 (- (length ess-rutils-buf) 1)))
145
(pop-to-buffer ess-rutils-buf)
146
(save-excursion
147
(kill-line 5)
148
(insert "**packages available to install**\n"))
149
(setq buffer-read-only t)
150
(ess-rutils-mode)
151
(if (featurep 'fit-frame)
152
(fit-frame)))
153
154
(defun ess-rutils-mark-install (arg)
155
"Mark the current package for installing.
156
ARG lines to mark is passed to `ess-rutils-mark'."
157
(interactive "p")
158
;; if this is not an install package buffer return nil.
159
(let ((okmark nil))
160
(save-excursion
161
(goto-char (point-min))
162
(if (search-forward "install**" nil t)
163
(setq okmark t)))
164
(if okmark
165
(ess-rutils-mark "I" arg)
166
nil)))
167
168
(defun ess-rutils-unmark (arg)
169
"Unmark the packages, passing ARG lines to unmark to `ess-rutils-mark'."
170
(interactive "p")
171
(ess-rutils-mark " " arg))
172
173
;; The next two functions almost verbatim from ess-rdired.el.
174
(defun ess-rutils-mark (mark-char arg)
175
"Use MARK-CHAR to mark package on current line, or next ARG lines."
176
;; If we are on first line, mark all lines.
177
(let ((buffer-read-only nil)
178
move)
179
(if (eq (point-min)
180
(save-excursion (beginning-of-line) (point)))
181
(progn
182
;; we are on first line, so make a note of point, and count
183
;; how many objects we want to delete. Then at end of defun,
184
;; restore point.
185
(setq move (point))
186
(forward-line 1)
187
(setq arg (count-lines (point) (point-max)))))
188
(while (and (> arg 0) (not (eobp)))
189
(setq arg (1- arg))
190
(beginning-of-line)
191
(progn
192
(insert mark-char)
193
(delete-char 1)
194
(forward-line 1)))
195
(if move
196
(goto-char move))))
197
198
(defun ess-rutils-install ()
199
"Install all packages flagged for installation, and return to the iESS buffer.
200
User is asked for confirmation."
201
(interactive)
202
(let ((inst "install.packages(c(")
203
(count 0))
204
(save-excursion
205
(goto-line 2)
206
;; as long as number of lines between buffer start and point is smaller
207
;; than the total number of lines in buffer, go to the beginning of the
208
;; line, check if line is flagged, and if it is, advance the counter by
209
;; one, create the root of install function, add the package name,
210
;; insert a comma, and move forward a line.
211
(while (< (count-lines (point-min) (point))
212
(count-lines (point-min) (point-max)))
213
(beginning-of-line)
214
(if (looking-at "^I ")
215
(setq count (1+ count)
216
inst (concat inst (ess-rutils-namepkg) ", " )))
217
(forward-line 1)))
218
(if (> count 0) ;found packages to install
219
(progn
220
;; Fix the install function created before and close it.
221
(setq inst (concat
222
(substring inst 0 (- (length inst) 2)) "))"))
223
;;
224
(if (yes-or-no-p (format "Install %d %s " count
225
(if (> count 1) "packages" "package")))
226
(progn
227
(ess-execute inst 'buffer)
228
(ess-rutils-quit))))
229
;; else nothing to install
230
(message "no packages flagged to install"))))
231
232
(defun ess-rutils-update-pkgs (lib repos)
233
"Update packages in library LIB and repos REPOS. Defaults are the first
234
element returned by .libPaths() for LIB, and the repository named CRAN
235
returned by getOption(\"repos\") for REPOS. This also uses checkBuilt=TRUE
236
to rebuild installed packages if needed."
237
(interactive "DPath to library to update: \nsrepos: ")
238
(if (string= "" lib)
239
(setq lib
240
(car (ess-get-words-from-vector
241
"as.character(.libPaths())\n"))))
242
(if (string= "" repos)
243
(setq repos
244
(car (ess-get-words-from-vector
245
"as.character(getOption(\"repos\")[\"CRAN\"])\n"))))
246
(ess-execute (concat "update.packages(lib.loc='"
247
lib "', repos='" repos
248
"', ask=FALSE, checkBuilt=TRUE)") 'buffer))
249
250
(defun ess-rutils-apropos (string)
251
"Search for STRING using apropos."
252
(interactive "sApropos search for? ")
253
(if (get-buffer ess-rutils-buf)
254
(progn
255
(set-buffer ess-rutils-buf)
256
(setq buffer-read-only nil)))
257
(ess-execute (concat "apropos('" string "')")
258
nil
259
(substring ess-rutils-buf 1 (- (length ess-rutils-buf) 1)))
260
(pop-to-buffer ess-rutils-buf)
261
(setq buffer-read-only t)
262
(ess-rutils-mode))
263
264
(defun ess-rutils-rm-all ()
265
"Remove all R objects."
266
(interactive)
267
(if (y-or-n-p "Delete all objects? ")
268
(ess-execute "rm(list=ls())" 'buffer)))
269
270
(defun ess-rutils-objs ()
271
"Manipulate R objects; wrapper for `ess-rdired'."
272
(interactive)
273
(ess-rdired)
274
(if (featurep 'fit-frame)
275
(fit-frame)))
276
277
(defun ess-rutils-load-wkspc (file)
278
"Load workspace FILE into R."
279
(interactive "fFile with workspace to load: ")
280
(ess-execute (concat "load('" file "')") 'buffer))
281
282
(defun ess-rutils-save-wkspc (file)
283
"Save FILE workspace.
284
File extension not required."
285
(interactive "FSave workspace to file (no extension): ")
286
(ess-execute (concat "save.image('" file ".RData')") 'buffer))
287
288
(defun ess-rutils-quit ()
289
"Kill the ess-rutils buffer and return to the iESS buffer."
290
(interactive)
291
(ess-switch-to-end-of-ESS)
292
(kill-buffer ess-rutils-buf))
293
294
(defun ess-rutils-html-docs (&optional remote)
295
"Use `browse-url' to navigate R html documentation.
296
Documentation is produced by a modified help.start(), that returns the URL
297
produced by GNU R's http server. This function is defined in a file given
298
by the path in variable `ess-rutils-rhtml-fn'. If called with a prefix,
299
the modified help.start() is called with update=TRUE. The optional REMOTE
300
argument should be a string with a valid URL for the 'R_HOME' directory on
301
a remote server (defaults to NULL)."
302
(interactive)
303
(let* ((update (if current-prefix-arg "update=TRUE" "update=FALSE"))
304
(remote (if (or (and remote (not (string= "" remote))))
305
(concat "remote=" remote) "remote=NULL"))
306
(rhtml (format ".rutils.help.start(%s, %s)\n" update remote))
307
(tmpbuf (get-buffer-create "**ess-rutils-mode**")))
308
(ess-command rhtml tmpbuf)
309
(set-buffer tmpbuf)
310
(let* ((begurl (search-backward "http://"))
311
(endurl (search-forward "index.html"))
312
(url (buffer-substring-no-properties begurl endurl)))
313
(browse-url url))
314
(kill-buffer tmpbuf)))
315
316
(defun ess-rutils-rsitesearch (string)
317
"Search the R archives for STRING, using default criteria, and show results
318
using `browse-url'. If called with a prefix, options are offered (with
319
completion) for matches per page, sections of the archives to search,
320
displaying results in long or short formats, and sorting by any given field.
321
Options should be separated by value of `crm-default-separator'."
322
(interactive "sSearch string: ")
323
(let ((site "http://search.r-project.org/cgi-bin/namazu.cgi?query=")
324
(okstring (ess-replace-regexp-in-string " +" "+" string)))
325
(if current-prefix-arg
326
(let ((mpp (concat
327
"&max="
328
(completing-read
329
"Matches per page: "
330
'(("20" 1) ("30" 2) ("40" 3) ("50" 4) ("100" 5)))))
331
(format (concat
332
"&result="
333
(completing-read
334
"Format: " '(("normal" 1) ("short" 2))
335
nil t "normal" nil "normal")))
336
(sortby (concat
337
"&sort="
338
(completing-read
339
"Sort by: "
340
'(("score" 1) ("date:late" 2) ("date:early" 3)
341
("field:subject:ascending" 4)
342
("field:subject:decending" 5)
343
("field:from:ascending" 6) ("field:from:decending" 7)
344
("field:size:ascending" 8) ("field:size:decending" 9))
345
nil t "score" nil "score")))
346
(restrict (concat
347
"&idxname="
348
(mapconcat
349
'identity
350
(completing-read-multiple
351
"Limit search to: "
352
'(("Rhelp02a" 1) ("functions" 2)
353
("docs" 3) ("Rhelp01" 4))
354
nil t "Rhelp02a,functions,docs" nil
355
"Rhelp02a,functions,docs") "&idxname="))))
356
(browse-url (concat site okstring mpp format sortby restrict)))
357
(browse-url (concat site okstring "&max=20&result=normal&sort=score"
358
"&idxname=Rhelp02a&idxname=functions&idxname=docs")))))
359
360
(defun ess-rutils-help ()
361
"Show help on `ess-rutils-mode'."
362
(interactive)
363
(describe-function 'ess-rutils-mode))
364
365
(defun ess-rutils-help-search (string)
366
"Search for STRING using help.search()."
367
(interactive "sString to search for? ")
368
(if (get-buffer ess-rutils-buf)
369
(progn
370
(set-buffer ess-rutils-buf)
371
(setq buffer-read-only nil)))
372
(ess-execute (concat "help.search('" string "')")
373
nil
374
(substring ess-rutils-buf 1 (- (length ess-rutils-buf) 1)))
375
(pop-to-buffer ess-rutils-buf)
376
(setq buffer-read-only t)
377
(ess-rutils-mode))
378
379
;; Customizable variable to allow ess-rutils-keys to activate default key bindings.
380
;; Suggested by Richard M. Heiberger.
381
(defcustom ess-rutils-keys t
382
"Non-nil means activate ess-rutils keybindings and menu."
383
:group 'ess-R
384
:type 'boolean)
385
386
;; Keybindings
387
(defun ess-rutils-keys ()
388
"Provide key bindings."
389
(interactive)
390
(when ess-rutils-keys
391
(define-key inferior-ess-mode-map [(control c) (control \.) (l)]
392
'ess-rutils-local-pkgs)
393
(define-key inferior-ess-mode-map [(control c) (control \.) (r)]
394
'ess-rutils-repos-pkgs)
395
(define-key inferior-ess-mode-map [(control c) (control \.) (u)]
396
'ess-rutils-update-pkgs)
397
(define-key inferior-ess-mode-map [(control c) (control \.) (a)]
398
'ess-rutils-apropos)
399
(define-key inferior-ess-mode-map [(control c) (control \.) (m)]
400
'ess-rutils-rm-all)
401
(define-key inferior-ess-mode-map [(control c) (control \.) (o)]
402
'ess-rutils-objs)
403
(define-key inferior-ess-mode-map [(control c) (control \.) (w)]
404
'ess-rutils-load-wkspc)
405
(define-key inferior-ess-mode-map [(control c) (control \.) (s)]
406
'ess-rutils-save-wkspc)
407
(define-key inferior-ess-mode-map [(control c) (control \.) (d)]
408
'ess-change-directory)
409
(define-key inferior-ess-mode-map [(control c) (control \.) (H)]
410
'ess-rutils-html-docs)))
411
412
(easy-menu-define ess-rutils-mode-menu inferior-ess-mode-menu
413
"Submenu of `inferior-ess-mode' to use with RUtils."
414
'("RUtils"
415
["Manage objects" ess-rutils-objs t]
416
["Remove objects" ess-rutils-rm-all t]
417
"------"
418
["Local packages" ess-rutils-local-pkgs t]
419
["Packages in repositories" ess-rutils-repos-pkgs t]
420
["Update packages" ess-rutils-update-pkgs t]
421
"------"
422
["Load workspace" ess-rutils-load-wkspc t]
423
["Save workspace" ess-rutils-save-wkspc t]
424
["Change directory" ess-change-directory t]
425
"------"
426
["Browse HTML" ess-rutils-html-docs t]
427
["Apropos" ess-rutils-apropos t]))
428
429
(when (featurep 'xemacs)
430
(defun ess-rutils-mode-xemacs-menu ()
431
"Hook to install `ess-rutils-mode' menu for XEmacs (with easymenu)."
432
(if 'inferior-ess-mode
433
;; Why does using nil for 2nd arg put menu at top level?
434
(easy-menu-add-item inferior-ess-mode-menu nil
435
ess-rutils-mode-menu)
436
(easy-menu-remove-item inferior-ess-mode-menu nil
437
ess-rutils-mode-menu)))
438
(add-hook 'inferior-ess-mode-hook 'ess-rutils-mode-xemacs-menu t))
439
440
(unless (featurep 'xemacs)
441
(easy-menu-add-item inferior-ess-mode-menu nil
442
ess-rutils-mode-menu))
443
444
(add-hook 'inferior-ess-mode-hook 'ess-rutils-keys t)
445
(add-hook 'ess-R-post-run-hook
446
(lambda ()
447
(ess--inject-code-from-file ess-rutils-rhtml-fn)) t)
448
449
450
(provide 'ess-rutils)
451
452
;;; ess-rutils.el ends here
453
454