1 ;;; ess-rdired.el --- prototype object browser for R, looks like dired mode.
3 ;; Copyright (C) 2002--2004 A.J. Rossini, Rich M. Heiberger, Martin
4 ;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
6 ;; Original Author: Stephen Eglen <stephen@anc.ed.ac.uk>
7 ;; Created: Thu 24 Oct 2002
8 ;; Maintainers: ESS-core <ESS-core@stat.math.ethz.ch>
10 ;; This file is part of ESS
12 ;; This file is not part of GNU Emacs.
14 ;; ess-rdired.el 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 ;; ess-rdired.el 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 the
26 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
27 ;; Boston, MA 02111-1307, USA.
29 ;; This provides a dired-like buffer for R objects. Instead of
30 ;; operating on files, we operate on R objects in the current
31 ;; environment. Objects can be viewed, edited, deleted, plotted and
34 ;; Installation and usage.
36 ;; Load in this library, e.g. with the command:
37 ;; (autoload 'ess-rdired "ess-rdired" "View *R* objects in a dired-like buffer." t)
39 ;; After loading this file, do "M-x R" to start an R session, then
40 ;; create a few variables:
41 ;; s <- sin(seq(from=0, to=8*pi, length=100))
46 ;; Then in Emacs, do "M-x ess-rdired" and you should see the following in
47 ;; the buffer *R dired*:
54 ;; Type "?" in the buffer to see the documentation. e.g. when the
55 ;; cursor is on the line for `s', type 'p' to plot it, or `v' to view
56 ;; its contents in a buffer. Then type 'd' to mark it for deletion.
60 ;; Most of the hardwork is done by the R routine .rdired.objects(),
61 ;; which, when called, produces the list of objects in a tidy format.
62 ;; This function is stored within the lisp variable `ess-rdired-objects',
63 ;; and can be altered to provide other information if you so need it.
64 ;; (Martin Maechler suggested providing output from str() here.)
66 ;; Tested on Emacs 21.2, 21.3 pretest and XEmacs 21.1.14, using R 1.6.
68 ;; Todo - compare functionality with ess-mouse-me (ess-mous.el).
70 ;; Todo - How to select alternative environments? Currently only
71 ;; shows objects in the .GlobalEnv? See BrowseEnv() in 1.6.x for way
72 ;; of browsing other environments.
74 ;; Todo - problem with fix -- have to wait for fix() command to return
75 ;; before *R* buffer can be used again. This can get stuck, umm. not
76 ;; sure what is going wrong here. Maybe add a hook to the temp buffer
77 ;; so that when buffer is killed, we send an instruction to R to
78 ;; update the value of the variable to the contents of the buffer.
79 ;; This way *R* doesn't have to wait.
81 ;; Todo - small bug in .rdired.objects -- if we have a variable called
82 ;; `my.x', its value is replaced by the value of my.x used in the
83 ;; sapply() calls within .rdired.objects().
86 (defvar ess-rdired-objects ".rdired.objects <- function(objs) {
88 \"No objects to view!\"
90 mode <- sapply(objs, function(my.x) {
91 eval(parse(text=(paste('data.class(',my.x,')',sep=''))))})
92 length <- sapply(objs, function(my.x) {
93 eval(parse(text=(paste('length(',my.x,')',sep=''))))
95 d <- data.frame(mode, length)
96 row.names(d) <- paste(' ', row.names(d), sep='')
99 }; .rdired.objects(ls())"
100 "Function to call within R to print information on objects. The last
101 line of this string should be the instruction to call the
102 function which prints the output for rdired.")
104 (defvar ess-rdired-buffer "*R dired*"
105 "Name of buffer for displaying R objects.")
107 (defvar ess-rdired-mode-map nil
108 "Keymap for the *R dired* buffer.")
110 (if ess-rdired-mode-map
112 (setq ess-rdired-mode-map (make-sparse-keymap))
114 (define-key ess-rdired-mode-map "?" 'ess-rdired-help)
115 (define-key ess-rdired-mode-map "d" 'ess-rdired-delete)
116 (define-key ess-rdired-mode-map "u" 'ess-rdired-undelete)
117 (define-key ess-rdired-mode-map "x" 'ess-rdired-expunge)
118 ;; editing requires a little more work.
119 ;;(define-key ess-rdired-mode-map "e" 'ess-rdired-edit)
120 (define-key ess-rdired-mode-map "v" 'ess-rdired-view)
121 (define-key ess-rdired-mode-map "V" 'ess-rdired-View)
122 (define-key ess-rdired-mode-map "p" 'ess-rdired-plot)
123 (define-key ess-rdired-mode-map "s" 'ess-rdired-sort)
124 (define-key ess-rdired-mode-map "q" 'ess-rdired-quit)
125 (define-key ess-rdired-mode-map "y" 'ess-rdired-type) ;what type?
126 (define-key ess-rdired-mode-map " " 'ess-rdired-next-line)
127 (define-key ess-rdired-mode-map [backspace] 'ess-rdired-previous-line)
128 (define-key ess-rdired-mode-map "\C-n" 'ess-rdired-next-line)
129 (define-key ess-rdired-mode-map "\C-p" 'ess-rdired-previous-line)
131 ;; R mode keybindings.
132 (define-key ess-rdired-mode-map "\C-c\C-s" 'ess-rdired-switch-process)
133 (define-key ess-rdired-mode-map "\C-c\C-y" 'ess-switch-to-ESS)
134 (define-key ess-rdired-mode-map "\C-c\C-z" 'ess-switch-to-end-of-ESS)
136 (define-key ess-rdired-mode-map [down] 'ess-rdired-next-line)
137 (define-key ess-rdired-mode-map [up] 'ess-rdired-previous-line)
138 (define-key ess-rdired-mode-map "g" 'revert-buffer)
139 (if (featurep 'xemacs)
140 (define-key ess-rdired-mode-map [button2] 'ess-rdired-mouse-view)
141 (define-key ess-rdired-mode-map [mouse-2] 'ess-rdired-mouse-view)
144 (defun ess-rdired-mode ()
145 "Major mode for output from `ess-rdired'.
146 `ess-rdired' provides a dired-like mode for R objects. It shows the
147 list of current objects in the current environment, one-per-line. You
148 can then examine these objects, plot them, and so on.
149 \\{ess-rdired-mode-map}"
150 (kill-all-local-variables)
151 (make-local-variable 'revert-buffer-function)
152 (setq revert-buffer-function 'ess-rdired-revert-buffer)
153 (use-local-map ess-rdired-mode-map)
154 (setq major-mode 'ess-rdired-mode)
155 (setq mode-name (concat "RDired " ess-local-process-name)))
158 "Run dired-like mode on R objects.
159 This is the main function. See documentation for `ess-rdired-mode' though
160 for more information!"
162 (if (get-buffer ess-rdired-buffer)
164 (set-buffer ess-rdired-buffer)
165 (setq buffer-read-only nil)))
167 (ess-execute ess-rdired-objects
169 (substring ess-rdired-buffer 1 (- (length ess-rdired-buffer) 1))
172 (pop-to-buffer ess-rdired-buffer)
173 ;; When definiting the function .rdired.objects(), a "+ " is printed
174 ;; for every line of the function definition; these are deleted
176 (delete-char (* (1- (length (split-string ess-rdired-objects "\n"))) 2))
178 ;; todo: not sure how to make ess-rdired-sort-num buffer local?
179 ;;(set (make-local-variable 'ess-rdired-sort-num) 2)
180 ;;(make-variable-buffer-local 'ess-rdired-sort-num)
181 (setq ess-rdired-sort-num 1)
182 (ess-rdired-insert-set-properties (save-excursion
183 (goto-char (point-min))
187 (setq buffer-read-only t)
191 (defun ess-rdired-object ()
192 "Return name of object on current line."
201 (search-forward " ") ;assume space follows object name.
202 (buffer-substring-no-properties beg (1- (point)))))))
204 (defun ess-rdired-edit ()
205 "Edit (fix) the object at point."
207 (let ((objname (ess-rdired-object)))
208 (ess-command (concat "edit(" objname ")\n"))))
210 (defun ess-rdired-view ()
211 "View the object at point."
213 (let ((objname (ess-rdired-object)))
214 (ess-execute objname nil "R view" )))
216 (defun ess-rdired-View ()
217 "View the object at point in its own buffer.
218 Like `ess-rdired-view', but the object gets its own buffer name."
220 (let ((objname (ess-rdired-object)))
221 (ess-execute ;;(concat "edit(" objname ")\n")
223 nil (concat "R view " objname ))))
225 (defun ess-rdired-plot ()
226 "Plot the object on current line."
228 (let ((objname (ess-rdired-object)))
229 (ess-command (concat "plot(" objname ")\n"))))
231 (defun ess-rdired-type ()
232 "Run the mode() on command at point.
233 Named type because of similarity
234 with the dired command bound to y key."
236 (let ((objname (ess-rdired-object))
237 ;; create a temp buffer, and then show output in echo area
238 (tmpbuf (get-buffer-create "**ess-rdired-mode**")))
241 (ess-command (concat "mode(" objname ")\n") tmpbuf )
245 (buffer-substring (+ 4 (point-min)) (1- (point-max)))))
246 (kill-buffer tmpbuf)))))
248 (defun ess-rdired-delete (arg)
249 "Mark the current (or next ARG) objects for deletion.
250 If point is on first line, all objects are marked for deletion."
252 (ess-rdired-mark "D" arg))
254 (defun ess-rdired-undelete (arg)
255 "Unmark the current (or next ARG) objects.
256 If point is on first line, all objects will be unmarked."
258 (ess-rdired-mark " " arg))
260 (defun ess-rdired-mark (mark-char arg)
261 "Mark the object, using MARK-CHAR, on current line (or next ARG lines)."
262 ;; If we are on first line, mark all lines.
263 (let ((buffer-read-only nil)
266 (save-excursion (beginning-of-line) (point)))
268 ;; we are on first line, so make a note of point, and count
269 ;; how many objects we want to delete. Then at end of defun,
273 (setq arg (count-lines (point) (point-max)))))
274 (while (and (> arg 0) (not (eobp)))
285 (defun ess-rdired-expunge ()
286 "Delete the marked objects.
287 User is queried first to check that objects should really be deleted."
293 (while (< (count-lines (point-min) (point))
294 (count-lines (point-min) (point-max)))
296 (if (looking-at "^D ")
297 (setq count (1+ count)
298 objs (concat objs (ess-rdired-object) ", " )))
302 ;; found objects to delete
305 (substring objs 0 (- (length objs) 2))
307 (if (yes-or-no-p (format "Delete %d %s " count
308 (if (> count 1) "objects" "object")))
313 ;; else nothing to delete
314 (message "no objects set to delete")
317 ;; Fancy delete method, based on dired. Bit too much for our needs?
318 ;; (defun ess-rdired-expunge ()
319 ;; "Delete the marked objects.
320 ;; User is queried first to check that objects should really be deleted."
326 ;; (while (< (count-lines (point-min) (point))
327 ;; (count-lines (point-min) (point-max)))
328 ;; (beginning-of-line)
329 ;; (if (looking-at "^D ")
331 ;; (setq objs (cons (ess-rdired-object) objs ))
332 ;; (setq cmd (concat cmd (ess-rdired-object) ", "))
336 ;; (if (> (length objs) 0)
337 ;; ;; found objects to delete
339 ;; (dired-mark-pop-up "*RDired deletions*" 'delete
340 ;; objs dired-deletion-confirmer
341 ;; (format "delete %s "
342 ;; (dired-mark-prompt nil objs)))
343 ;; ;; should delete the objects.
345 ;; (setq cmd (concat (substring cmd 0 (- (length cmd) 2))
349 ;; ;; else nothing to delete
350 ;; (message "no objects set to delete")
353 (defun ess-rdired-quit ()
354 "Quit the R dired buffer."
356 (kill-buffer ess-rdired-buffer))
358 (defun ess-rdired-revert-buffer (ignore noconfirm)
359 "Update the buffer list (in case object list has changed).
360 Arguments IGNORE and NOCONFIRM currently not used."
363 (defun ess-rdired-help ()
364 "Show help for `ess-rdired-mode'."
366 (describe-function 'ess-rdired-mode))
368 (defun ess-rdired-sort ()
369 "Sort the rdired output according to one of the columns.
370 Rotate between the alternative sorting methods."
372 (setq ess-rdired-sort-num (1+ ess-rdired-sort-num))
373 (let ((buffer-read-only nil)
375 (goto-char (point-min))
379 (if (> ess-rdired-sort-num 3)
380 (setq ess-rdired-sort-num 1))
381 (cond ((eq ess-rdired-sort-num 1)
382 (sort-fields 1 beg end))
383 ((eq ess-rdired-sort-num 2)
384 (sort-fields 2 beg end))
385 ((eq ess-rdired-sort-num 3)
386 (sort-numeric-fields 3 beg end)))))
388 (defun ess-rdired-next-line (arg)
389 "Move down lines then position at object.
390 Optional prefix ARG says how many lines to move; default is one line."
393 (ess-rdired-move-to-object))
395 (defun ess-rdired-previous-line (arg)
396 "Move up lines then position at object.
397 Optional prefix ARG says how many lines to move; default is one line."
400 (ess-rdired-move-to-object))
402 (defun ess-rdired-move-to-object ()
403 "Put point at start of object."
408 (defun ess-rdired-mouse-view (event)
409 "In rdired, visit the object on the line you click on."
413 (if (featurep 'xemacs)
415 (setq window (event-window event)
416 pos (event-point event))
418 (setq window (posn-window (event-end event))
419 pos (posn-point (event-end event))))
420 (if (not (windowp window))
421 (error "No file chosen"))
422 (set-buffer (window-buffer window))
426 (defun ess-rdired-insert-set-properties (beg end)
427 "Add mouse highlighting to each object name in the R dired buffer."
430 (while (< (point) end)
431 (ess-rdired-move-to-object)
437 '(mouse-face highlight
438 help-echo "mouse-2: view object in other window"))
441 (defun ess-rdired-switch-process ()
442 "Switch to examine different *R* process.
443 If you have multiple R processes running, e.g. *R*, *R:2*, *R:3*, you can
444 use this command to choose which R process you would like to examine.
445 After switching to a new process, the buffer is updated."
450 ;;; ess-rdired.el ends here.