[ESS] Easy argument list: r-autoyas

Vitalie Spinu spinuvit.list at gmail.com
Sun Mar 20 12:23:43 CET 2011


Rainer M Krug <r.m.krug at gmail.com> writes:

> On 03/15/2011 07:09 PM, Vitalie Spinu wrote:
>> Rainer M Krug <r.m.krug at gmail.com> writes:
>>> this sounds perfect - but it seems to break org-modes functionality of
>>> editing a code block with C- '. Or is it only my setup?
>>>

I've read Erik's introduction to org babel with R. It's indeed an amassing
stuff over there. Thanks.

With the most recent org-mode (7.5) I can not reproduce your problem. 

If you are using Sven's setup, the only thing what might remotely cause your
problem is the ess-hook which loads the r-autoyas.el each time you execute
C-'. Try to get the (load ... ) part off the hook.

Below is the version I am using. It has a couple of small improvements,
among which the automatic split of long completions along multiple lines.

But it's different from what Sven originally intended.  It works only after
the opened "(", so what C-M-TAB after 'plot(' causes the expansion, and
not after 'plot' directly as in Sven's version.

If you want the expansion to work immediately after 'plot' with my code,
use:

(define-key ess-mode-map (kbd "C-M-<tab>") '(lambda () (interactive)
                                              (insert "(")
                                              (r-autoyas-expand)))

I have in mind to implement an automatic autoyas detection of existing
arguments. Say, you already have plot(xxx, yyy, col="red") in you
buffer. You call the r-autoyas-expand inside (...) and xxx, yyy are
recognized correctly as x and y arguments of plot, col="red" is left
untouched and all other arguments (except x, y and col) are proposed for
completion.

In order for the this idea to work r-autoyas should work only after "(".

Vitalie.

======================================================

(defun r-autoyas-exit-snippet-delete-remaining ()
  "Exit yas snippet and delete the remaining argument list."
  (interactive "*")
  (let ((deletefrom (point)))
    (yas/exit-snippet (car (yas/snippets-at-point)))
    (yas/check-commit-snippet)
    (if (char-equal (char-after) (string-to-char ")"))
        (delete-region deletefrom (point))
      (insert ")")
      (delete-region deletefrom (1- (point)))
      )
    )
  )

(defun r-autoyas-expand (&optional funname)
  "Insert argument list (in parentheses) of R function before the
point as intelligent yas snippets and expand the snippets."
  (interactive "*")
  (if (null funname)
      (setq funname (ess-r-args-current-function)))
  (ess-command (concat "r.autoyas.create('" funname "')\n")
               (get-buffer-create "*r-autoyas*"))
  (unless (null funname)
    (let (snippet)
      (with-current-buffer "*r-autoyas*"
        (if (< (length (buffer-string)) 10);; '[1] " "' if no valid fun
            (message "No valid function!")
          (delete-region 1 6)
          (goto-char (point-max))
          (delete-backward-char 2)
          (goto-char (point-min))
          (replace-string "\\\"" "\"")
          (goto-char (point-min))
          (replace-string "\\\\" "\\")
          (fill-paragraph)
          (setq snippet (buffer-string))
          ))
      (when snippet
        (yas/expand-snippet snippet)
        ))))

(defun r-autoyas-inject-commands ()
  (ess-eval-linewise
   "r.autoyas.esc <- function(str) {
  str <- gsub('$', '\\\\$', str, fixed=TRUE)
  str <- gsub('`', '\\\\`', str, fixed=TRUE)
  return(str)
  };
  r.autoyas.create <- function(funcname) {
  if (existsFunction(deffun <- paste(funcname,'.default', sep=''))) {
  funcname <- deffun
  } else if(!existsFunction(funcname)) {
  return(' ')
  }
  formals <- formals(funcname)
  dots <- match('...', names(formals))
  if (!is.na(dots) & !is.null(options()[['r.autoyas.dotreplace']][[funcname]])) {
  formals2 <- NULL
  if (dots > 1) formals2 <- formals[1:(dots-1)]
  formals2 <- append(formals2, options()[['r.autoyas.dotreplace']][[funcname]])
  if (dots < length(formals)) formals2 <- append(formals2, formals[(dots+1):length(formals)])
  formals <- formals2
  }
  nr <- 0
  closebrackets <- 0
  str <- NULL
  for (field in names(formals)) {
  type <- typeof(formals[[field]])
  if (type=='symbol' & field!='...') {
  nr <- nr+2
  str <- append(str, paste('${',nr-1,':, ',field,'=${',nr,':',' }}', sep=''))
  } else if (type=='symbol' & field=='...') {
  nr <- nr+2
  str <- append(str, paste('${',nr-1,':, ${',nr,':',field,'}}', sep=''))
  } else if (type=='character') {
  nr <- nr+2
  str <- append(str, paste('${',nr-1,':, ',field,'=${',nr,':\\'',gsub('\\'', '\\\\\\'', r.autoyas.esc(encodeString(formals[[field]])), fixed=TRUE),'\\'}}', sep=''))
  } else if (type=='logical') {
  nr <- nr+2
  str <- append(str, paste('${',nr-1,':, ',field,'=${',nr,':',as.character(formals[[field]]),'}}', sep=''))
  } else if (type=='double') {
  nr <- nr+2
  str <- append(str, paste('${',nr-1,':, ',field,'=${',nr,':',as.character(formals[[field]]),'}}', sep=''))
  } else if (type=='NULL') {
  nr <- nr+2
  str <- append(str, paste('${',nr-1,':, ',field,'=${',nr,':NULL}}', sep=''))
  } else if (type=='language') {
  nr <- nr+2
  str <- append(str, paste('${',nr-1,':, ',field,'=${',nr,':',r.autoyas.esc(deparse(formals[[field]])),'}}', sep=''))
  }
  }
  str <- paste(str, sep='', collapse='')
  if (grepl(', ', str, fixed=TRUE)) str <- sub(', ', '', str) # remove 1st ', ' (from 1st field)
  str
  }\n"
   t nil nil t)
  )

(defadvice yas/abort-snippet (around r-delete-remaining)
  (if (member major-mode '(ess-mode inferior-ess-mode))
      (r-autoyas-exit-snippet-delete-remaining)
    ad-do-it)
  )
(ad-activate 'yas/abort-snippet)

(add-hook 'ess-post-run-hook 'r-autoyas-inject-commands t)

(define-key ess-mode-map (kbd "C-M-<tab>") 'r-autoyas-expand)


;; optionally if you want the smart (but annoying) "(":
;; (define-key ess-mode-map (kbd "(") '(lambda () (interactive)
;;                                      (insert "(")
;;                                      (r-autoyas-expand)))



More information about the ESS-help mailing list