rdired.el --- prototype object browser for R, looks like dired mode.

Stephen Eglen eglen at pcg.wustl.edu
Fri Oct 25 16:50:07 CEST 2002


Hi,

Here's a first version of some code that I just put together.  It
provides a dired-like interface to the objects in your *R* environment
(i.e. the objects returned by `ls()' from the R prompt).  I'm sending
it here in case others might find it useful, or if it stimulates any
discussion.  If you use dired (the Emacs directory editor) a bit, you
might find some of the keybindings here intuitive.

It is far from polished, but should work out of the box by following
the instructions underneath ";; Installation."  I'd be keen to hear
feedback, good or bad!

Tested only on Emacs 21.3 pretest and XEmacs 21.1.14, using R 1.6.

Best wishes,
Stephen
----------------------------------------------------------------------
;;; rdired.el --- prototype object browser for R, looks like dired mode.
;; Author: Stephen Eglen <stephen at anc.ed.ac.uk>
;; Maintainer: Stephen Eglen <stephen at anc.ed.ac.uk>
;; Created: Thu 24 Oct 2002

;; This file is not part of GNU Emacs.

;; rdired.el is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; rdired.el is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;; This provides a dired-like buffer for R objects.  Instead of
;; operating on files, we operate on R objects in the current
;; environment.  Objects can be viewed, edited, deleted, plotted and
;; so on.

;; Installation.  
;; After loading this library, you will also need to load the
;; following function, rdired-objects, into R.  This function produces
;; a nicely formatted data frame which is shown by rdired.

;; Here is a sample session.  First in *R*, load in the following
;; lines: (Remove ;; first)
;;
;; rdired.objects <- function(objs) {
;;   ## Produce a formatted data frame of the objects OBJS.
;;   mode <- sapply(objs, function(x) {
;;     eval(parse(text=(paste('mode(',x,')',sep=''))))})
;;   length <- sapply(objs, function(x) {
;;     eval(parse(text=(paste('length(',x,')',sep=''))))
;;   })

;;   d <- data.frame(mode, length)
;;   row.names(d) <- paste('  ', row.names(d), sep='') #add space for marks.
;;   d
;; }

;; ## Then load in a few variables so that you have something to see:
;; s <- sin(seq(from=0, to=8*pi, length=100))
;; x <- c(1, 4, 9)
;; y <- rnorm(20)
;; z <- TRUE

;; Then in Emacs, do "M-x rdired" and you should see the following in
;; the buffer *R dired*:
;;                       mode length
;;   rdired.objects  function      1
;;   s                numeric    100
;;   x              character      1
;;   y                numeric     20
;;   z                logical      1

;; Type "?" in the buffer to see the documentation.  e.g. when the
;; cursor is on the line for `s', type 'p' to plot it, or `v' to view
;; its contents in a buffer.  Then type 'd' to mark it for deletion.

;; Tested only on Emacs 21.3 pretest and XEmacs 21.1.14, using R 1.6.

;; Todo - compare functionality with ess-mouse-me (ess-mous.el).

;; Todo - how to decide which R process to communicate with, if more than
;; one running.  Or what if no R process is yet running?

;; Todo - How to select alternative environments?  Currently only 
;; shows objects in the .GlobalEnv?

;; Todo - problem with fix -- have to wait for fix() command to return
;; before *R* buffer can be used again.  This can get stuck, umm. not
;; sure what is going wrong here.  Maybe add a hook to the temp buffer
;; so that when buffer is killed, we send an instruction to R to
;; update the value of the variable to the contents of the buffer.
;; This way *R* doesn't have to wait.

;; Todo - once I have settled on form of rdired.objects(), either hard-
;; code it into the lisp file or find out how to place it somewhere where
;; it can't be deleted by rdired itself (or keep hidden)!

;; Todo - bug in dired.objects -- x above should be a numeric() not
;; a character()! This is because of local variable x in sapply() call.


(defun rdired-mode ()
  "Major mode for output from `rdired'.
Rdired provides a dired-like mode for R objects.  rdired shows the list
of current objects in the current environment, one-per-line.  You can then
examine these objects, plot them, and so on.
\\{rdired-mode-map}"
  (kill-all-local-variables)
  (make-local-variable 'revert-buffer-function)
  (setq revert-buffer-function 'rdired-revert-buffer)
  (use-local-map rdired-mode-map)
  (setq major-mode 'rdired-mode)
  (setq mode-name "RDired")
  )

(defun rdired ()
  "Run dired-like mode on R objects.
This is the main function.  See documentation for rdired-mode though
for more information!"
  (interactive)
  (if (get-buffer rdired-buffer)
      (progn
	(set-buffer rdired-buffer)
	(setq buffer-read-only nil)))
  (ess-execute "rdired.objects(objs=ls())"
	       nil 
	       (substring rdired-buffer 1 (- (length rdired-buffer) 1))
	       ;; note: *...* added around buffer name
	       )
  (pop-to-buffer rdired-buffer)

  ;; todo: not sure how to make rdired-sort-num buffer local?
  ;;(set (make-local-variable 'rdired-sort-num) 2)
  ;;(make-variable-buffer-local 'rdired-sort-num)
  (setq rdired-sort-num 1)
  (setq buffer-read-only t)
  (rdired-mode)
  )

(defvar rdired-buffer "*R dired*"
  "Name of buffer for displaying R objects.")

(defvar rdired-mode-map nil
  "Keymap for the *R dired* buffer.")

(if rdired-mode-map
    ()
  (setq rdired-mode-map (make-sparse-keymap))
  
  (define-key rdired-mode-map "?" 'rdired-help)
  (define-key rdired-mode-map "d" 'rdired-delete)
  (define-key rdired-mode-map "u" 'rdired-undelete)
  (define-key rdired-mode-map "x" 'rdired-expunge)
  ;; editing requires a little more work.
  ;;(define-key rdired-mode-map "e" 'rdired-edit)
  (define-key rdired-mode-map "v" 'rdired-view)
  (define-key rdired-mode-map "V" 'rdired-View)
  (define-key rdired-mode-map "p" 'rdired-plot)
  (define-key rdired-mode-map "s" 'rdired-sort)
  (define-key rdired-mode-map "q" 'rdired-quit)
  (define-key rdired-mode-map "y" 'rdired-type)	;what type?
  (define-key rdired-mode-map "g" 'revert-buffer))

(defun rdired-object ()
  "Return name of object on current line."
  ;;todo - return nil if on last line or first (header) line.
  (buffer-substring
   (+ 2 (save-excursion (beginning-of-line) (point)))
   (save-excursion 
     (beginning-of-line) 
     (if (looking-at " ")
	 nil
       (forward-char 2)
       (search-forward " ")		;assume space follows object name.
       (1- (point))
       ))))

(defun rdired-object ()
  "Return name of object on current line."
  ;;todo - return nil if on last line or first (header) line.
  (save-excursion
    (beginning-of-line) 
    (forward-char 2)
    (if (looking-at " ")
	nil				;on first line
      ;;
      (let (beg end)
	(setq beg (point))
	(search-forward " ")		;assume space follows object name.
	(buffer-substring beg (1- (point)))))))

(defun rdired-edit ()
  "Edit (fix) the object at point."
  (interactive)
  (let ((objname (rdired-object)))
    (ess-command (concat "edit(" objname ")\n"))))

(defun rdired-view ()
  "View the object at point."
  (interactive)
  (let ((objname (rdired-object)))
    (ess-execute ;;(concat "edit(" objname ")\n")
     objname
     nil "R view" )))

(defun rdired-View ()
  "View the object at point in its own buffer.
Like `rdired-view', but the object gets its own buffer name."
  (interactive)
  (let ((objname (rdired-object)))
    (ess-execute ;;(concat "edit(" objname ")\n")
     objname
     nil (concat "R view " objname ))))

(defun rdired-plot ()
  "Plot the object on current line."
  (interactive)
  (let ((objname (rdired-object)))
    (ess-command (concat "plot(" objname ")\n"))))

(defun rdired-type ()
  "Run the mode() on command at point.
Named type because of similarity
with the dired command bound to y key."
  (interactive)
  (let ((objname (rdired-object))
	;; create a temp buffer, and then show output in echo area
	(tmpbuf (get-buffer-create "**rdired-mode**")))
    (if objname
	(progn
	  (ess-command (concat "mode(" objname ")\n")  tmpbuf )
	  (set-buffer tmpbuf)
	  (message (concat 
		    objname ": "
		    (buffer-substring (+ 4 (point-min)) (1- (point-max)))))
	  (kill-buffer tmpbuf)))))

(defun rdired-delete (arg)
  "Mark the current (or next ARG) objects for deletion.
If point is on first line, all objects are marked for deletion."
  "Delete the object on current line."
  ;; todo -- allow prefix numeric arg for deleting next n lines.
  (interactive "p")
  (rdired-mark "D" arg))

(defun rdired-undelete (arg)
  "Unmark the current (or next ARG) objects.
If point is on first line, all objects will be unmarked."
  (interactive "p")
  (rdired-mark " " arg))

(defun rdired-mark (mark-char arg)
  "Mark the object, using MARK-CHAR,  on current line (or next ARG lines)."
  ;; If we are on first line, mark all lines.
  (if (eq (point-min) 
	  (save-excursion (beginning-of-line) (point)))
      (progn
	(forward-line 1)
	(setq arg (count-lines (point) (point-max)))))
  (while (and (> arg 0) (not (eobp)))
    (setq arg (1- arg))
    (save-excursion 
      (setq buffer-read-only nil)
      (beginning-of-line)
      (progn
	(insert mark-char)
	(delete-char 1)
	(setq buffer-read-only t)))
    (forward-line 1)))

(defun rdired-expunge ()
  "Delete the marked objects.
User is queried first to check that 
objects should really be deleted."
  (interactive)
  (let ((objs "rm("))
    (save-excursion
      (goto-line 2)
      (while (< (count-lines (point-min) (point)) 
		(count-lines (point-min) (point-max)))
	(beginning-of-line)
	(if (looking-at "^D ")
	    (setq objs (concat objs (rdired-object) ", " )))
	(forward-line 1)
	))
    (if (> (length objs) 3) 
	;; found objects to deletee
	(progn
	  (setq objs (concat 
		      (substring objs 0 (- (length objs) 2))
		      ")\n"))
	  (if (yes-or-no-p objs)
	      (progn
		(ess-command objs)
		(rdired)
		)))
      ;; else nothing to delete
      (message "no objects set to delete")
      )))

(defun rdired-quit ()
  "Quit the R dired buffer."
  (interactive)
  (kill-buffer rdired-buffer))

(defun rdired-revert-buffer (ignore noconfirm)
  "Update the buffer list (in case object list has changed).
Arguments IGNORE and NOCONFIRM currently not used."
  (rdired))

(defun rdired-help ()
  "Show help for `rdired-mode'."
  (interactive)
  (describe-function 'rdired-mode))

(defun rdired-sort ()
  "Sort the rdired output according to one of the columns.
Rotate between the alternative sorting methods."
  (interactive)
  (setq rdired-sort-num (1+ rdired-sort-num))
  (let ((buffer-read-only nil)
	(beg (save-excursion
	       (goto-char (point-min))
	       (forward-line 1)
	       (point)))
	(end (point-max)))
  (if (> rdired-sort-num 3)
      (setq rdired-sort-num 1))
  (cond ((eq rdired-sort-num 1)
	 (sort-fields 1 beg end))
	((eq rdired-sort-num 2)
	 (sort-fields 2 beg end))
	((eq rdired-sort-num 3)
	 (sort-numeric-fields 3 beg end)))))
  
;;; rdired.el ends here.

-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
ess-help mailing list -- To (un)subscribe, send
subscribe	or	unsubscribe
(in the "body", not the subject !)  To: ess-help-request at stat.math.ethz.ch
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._



More information about the ESS-help mailing list