Christophe Weblog Wiki Code Publications Music
implement swank:find-definitions-for-emacs
[swankr.git] / swank.R
diff --git a/swank.R b/swank.R
index 578d61c75a83f45f2a82081d9a09d89dc10d243e..1dc95b48800c305489292bc95f4cdb92f381e16e 100644 (file)
--- a/swank.R
+++ b/swank.R
@@ -59,12 +59,32 @@ sendToEmacs <- function(slimeConnection, obj) {
   cat(sprintf("%06x", nchar(payload)), payload, sep="")
 }
 
+callify <- function(form) {
+  ## we implement here the conversion from Lisp S-expression (or list)
+  ## expressions of code into our own, swankr, calling convention,
+  ## with slimeConnection and sldbState as first and second arguments.
+  ## as.call() gets us part of the way, but we need to walk the list
+  ## recursively to mimic CL:EVAL; we need to avoid converting R
+  ## special operators which we are punning (only `quote`, for now)
+  ## into this calling convention.
+  if(is.list(form)) {
+    if(form[[1]] == quote(quote)) {
+      as.call(form)
+    } else {
+      as.call(c(list(form[[1]], quote(slimeConnection), quote(sldbState)), lapply(form[-1], callify)))
+    }
+  } else {
+    form
+  }
+}
+
 emacsRex <- function(slimeConnection, sldbState, form, pkg, thread, id, level=0) {
   ok <- FALSE
   value <- NULL
   tryCatch({
     withCallingHandlers({
-      value <- do.call(eval(form[[1]]), c(list(slimeConnection), list(sldbState), form[-1]))
+      call <- callify(form)
+      value <- eval(call)
       ok <- TRUE
     }, error=function(c) {
       newSldbState <- makeSldbState(c, if(is.null(sldbState)) 0 else sldbState$level+1, id)
@@ -239,6 +259,12 @@ printToString <- function(val) {
 }
 
 `swank:swank-require` <- function (slimeConnection, sldbState, contribs) {
+  for(contrib in contribs) {
+    filename <- sprintf("%s.R", as.character(contrib))
+    if(file.exists(filename)) {
+      source(filename, verbose=TRUE)
+    }
+  }
   list()
 }
 
@@ -246,10 +272,22 @@ printToString <- function(val) {
   list("R", "R")
 }
 
+sendReplResult <- function(slimeConnection, value) {
+  string <- printToString(value)
+  sendToEmacs(slimeConnection,
+              list(quote(`:write-string`),
+                   paste(string, collapse="\n"),
+                   quote(`:repl-result`)))
+}
+
+sendReplResultFunction <- sendReplResult
+
 `swank:listener-eval` <- function(slimeConnection, sldbState, string) {
-  val <- eval(parse(text=string), envir = globalenv())
-  string <- printToString(val)
-  sendToEmacs(slimeConnection, list(quote(`:write-string`), paste(string, collapse="\n"), quote(`:repl-result`)))
+  string <- gsub("#\\.\\(swank:lookup-presented-object-or-lose([^)]*)\\)", ".(`swank:lookup-presented-object-or-lose`(slimeConnection, sldbState,\\1))", string)
+  expr <- parse(text=string)[[1]]
+  lookedup <- do.call("bquote", list(expr))
+  value <- eval(lookedup, envir = globalenv())
+  sendReplResultFunction(slimeConnection, value)
   list()
 }
 
@@ -311,9 +349,8 @@ computeRestartsForEmacs <- function (sldbState) {
   if(is.null(srcfile)) {
     list(quote(`:error`), "no srcfile")
   } else {
-    filename <- get("filename", srcfile)
     list(quote(`:location`),
-         list(quote(`:file`), filename),
+         list(quote(`:file`), sprintf("%s/%s", srcfile$wd, srcfile$filename)),
          list(quote(`:line`), srcref[[1]], srcref[[2]]-1),
          FALSE)
   }
@@ -381,3 +418,28 @@ computeRestartsForEmacs <- function (sldbState) {
            finally={sink(); output <- readLines(f); close(f)})
   list(output, printToString(value))
 }
+
+`swank:find-definitions-for-emacs` <- function(slimeConnection, sldbState, string) {
+  if(exists(string, envir = globalenv())) {
+    thing <- get(string, envir = globalenv())
+    if(inherits(thing, "function")) {
+      body <- body(thing)
+      srcref <- attr(body, "srcref")
+      srcfile <- attr(body, "srcfile")
+      if(is.null(srcfile)) {
+        list()
+      } else {
+        filename <- get("filename", srcfile)
+        list(list(sprintf("function %s", string),
+                  list(quote(`:location`),
+                       list(quote(`:file`), sprintf("%s/%s", srcfile$wd, srcfile$filename)),
+                       list(quote(`:line`), srcref[[2]][[1]], srcref[[2]][[2]]-1),
+                       list())))
+      }
+    } else {
+      list()
+    }
+  } else {
+    list()
+  }
+}