Christophe Weblog Wiki Code Publications Music
update protocol version to 2014-09-13
[swankr.git] / swank.R
diff --git a/swank.R b/swank.R
index 99012ec57ec4bc7ed9b6d80010145476d40f108d..57ead0ac9f803a1d2729f737d739c0d4a10fcb69 100644 (file)
--- a/swank.R
+++ b/swank.R
@@ -293,7 +293,7 @@ printToString <- function(val) {
 `swank:connection-info` <- function (slimeConnection, sldbState) {
   list(quote(`:pid`), Sys.getpid(),
        quote(`:package`), list(quote(`:name`), "R", quote(`:prompt`), "R> "),
-       quote(`:version`), "2012-04-23",
+       quote(`:version`), "2014-09-13",
        quote(`:encoding`), list(quote(`:coding-systems`), list("utf-8-unix")),
        quote(`:lisp-implementation`), list(quote(`:type`), "R",
                                            quote(`:name`), "R",
@@ -314,6 +314,8 @@ printToString <- function(val) {
   list("R", "R")
 }
 
+`swank-repl:create-repl` <- `swank:create-repl`
+
 makeReplResult <- function(value) {
   string <- printToString(value)
   list(quote(`:write-string`), string,
@@ -344,6 +346,12 @@ sendReplResultFunction <- sendReplResult
   list()
 }
 
+`swank-repl:listener-eval` <- `swank:listener-eval`
+
+`swank:clear-repl-variables` <- function(slimeConnection, sldbState) {
+  list()
+}
+
 `swank:autodoc` <- function(slimeConnection, sldbState, rawForm, ...) {
   list("No Arglist Information", TRUE)
 }
@@ -361,6 +369,41 @@ sendReplResultFunction <- sendReplResult
   }
 }
 
+`swank:describe-function` <- function(slimeConnection, sldbState, op, package) {
+  ## FIXME: maybe not the best match?
+  `swank:operator-arglist`(slimeConnection, sldbState, op, package)
+}
+
+helpFilesWithTopicString <- function(value) {
+  output <- capture.output(tools:::Rd2txt(utils:::.getHelpFile(value),
+                                          options=list(underline_titles=FALSE)))
+  paste(output, collapse="\n")
+}
+
+`swank:describe-symbol` <- function(slimeConnection, sldbState, op, package) {
+  value <- help(op)
+  helpFilesWithTopicString(value)
+}
+
+`swank:apropos-list-for-emacs` <- function(slimeConnection, sldbState, name, onlyExternal, package, caseSensitive) {
+  x <- help.search(name, fields="alias", package=.packages())$matches
+  brieflyDescribe <- function(name, title) {
+    if (exists(name, globalenv())) {
+      val <- get(name, globalenv())
+      kind <- if("function" %in% class(val)) quote(`:function`) else quote(`:variable`)
+      list(quote(`:designator`), name, kind, title)
+    } else {
+      ## maybe
+      list(quote(`:designator`), name, quote(`:type`), title)
+    }
+  }
+  mapply(brieflyDescribe, x[,"name"], x[,"title"], SIMPLIFY=FALSE)
+}
+
+`swank:describe-definition-for-emacs` <- function(slimeConnection, sldbState, name, kind) {
+  `swank:describe-symbol`(slimeConnection, sldbState, name, NULL)
+}
+
 `swank:throw-to-toplevel` <- function(slimeConnection, sldbState) {
   condition <- simpleCondition("Throw to toplevel")
   class(condition) <- c("swankTopLevel", class(condition))
@@ -454,43 +497,46 @@ computeRestartsForEmacs <- function (sldbState) {
        list())
 }
 
-`swank:simple-completions` <- function(slimeConnection, sldbState, prefix, package) {
-  symbolFieldsCompletion <- function(object, rest) {
-    ## FIXME: this is hacky, ignoring several syntax issues (use of
-    ## and/or necessity for backquoting identifiers: e.g. fields
-    ## containing hyphens)
-    if((dollar <- regexpr("$", rest, fixed=TRUE)) == -1) {
-      matches <- grep(sprintf("^%s", literal2rx(rest)), names(object), value=TRUE)
-      matches <- sprintf("%s$%s", gsub("\\$[^$]*$", "", prefix), matches)
-      returnMatches(matches)
+symbolFieldsCompletion <- function(object, prefix, rest) {
+  ## FIXME: this is hacky, ignoring several syntax issues (use of
+  ## and/or necessity for backquoting identifiers: e.g. fields
+  ## containing hyphens)
+  if((dollar <- regexpr("$", rest, fixed=TRUE)) == -1) {
+    matches <- grep(sprintf("^%s", literal2rx(rest)), names(object), value=TRUE)
+    matches <- sprintf("%s$%s", gsub("\\$[^$]*$", "", prefix), matches)
+    returnMatches(matches)
+  } else {
+    if(exists(substr(rest, 1, dollar-1), object)) {
+      symbolFieldsCompletion(get(substr(rest, 1, dollar-1), object), prefix, substr(rest, dollar+1, nchar(rest)))
     } else {
-      if(exists(substr(rest, 1, dollar-1), object)) {
-        symbolFieldsCompletion(get(substr(rest, 1, dollar-1), object), substr(rest, dollar+1, nchar(rest)))
-      } else {
-        returnMatches(character(0))
-      }
+      returnMatches(character(0))
     }
   }
-  returnMatches <- function(matches) {
-    nmatches <- length(matches)
-    if(nmatches == 0) {
-      list(list(), "")
-    } else {
-      longest <- matches[order(nchar(matches))][1]
-      while(length(grep(sprintf("^%s", literal2rx(longest)), matches)) < nmatches) {
-        longest <- substr(longest, 1, nchar(longest)-1)
-      }
-      list(as.list(matches), longest)
+}
+
+returnMatches <- function(matches) {
+  nmatches <- length(matches)
+  if(nmatches == 0) {
+    list(list(), "")
+  } else {
+    longest <- matches[order(nchar(matches))][1]
+    while(length(grep(sprintf("^%s", literal2rx(longest)), matches)) < nmatches) {
+      longest <- substr(longest, 1, nchar(longest)-1)
     }
+    list(as.list(matches), longest)
   }
-  literal2rx <- function(string) {
-    ## list of ERE metacharacters from ?regexp
-    gsub("([.\\|()[{^$*+?])", "\\\\\\1", string)
-  }
+}
+
+literal2rx <- function(string) {
+  ## list of ERE metacharacters from ?regexp
+  gsub("([.\\|()[{^$*+?])", "\\\\\\1", string)
+}
+
+`swank:simple-completions` <- function(slimeConnection, sldbState, prefix, package) {
   matches <- apropos(sprintf("^%s", literal2rx(prefix)), ignore.case=FALSE)
   nmatches <- length(matches)
   if((nmatches == 0) && ((dollar <- regexpr("$", prefix, fixed=TRUE)) > -1)) {
-    symbolFieldsCompletion(globalenv(), prefix)
+    symbolFieldsCompletion(globalenv(), prefix, prefix)
   } else {
     returnMatches(matches)
   }
@@ -514,6 +560,23 @@ computeRestartsForEmacs <- function (sldbState) {
                     ifelse(x[3]==1, x[6]+colOffset-1, x[6]))))
   }
   transformSrcrefs <- function(s) {
+    ## horrendous KLUDGE: we need to short-circuit here for "name"
+    ## objects, rather than having a nice uniform behaviour, because
+    ## for expressions of the form x[y,] there is an empty "name"
+    ## which ends up becoming a `missing' object when passed through
+    ## the switch; why, I do not know, but it is then impossible to
+    ## return it, because returning it attempts to evaluate it and
+    ## evaluating it is an error.  Fortunately it appears that names
+    ## don't have srcrefs attached.
+    if(mode(s) == "name") {
+      return(s)
+    }
+    if(is(s, "srcref")) {
+      ## more monumental KLUDGE: parsing (in 2.14, at least) appears
+      ## to put srcrefs directly in `length 2' objects, which we need
+      ## to frob directly.
+      return(frob(list(s))[[1]])
+    }
     srcrefs <- attr(s, "srcref")
     attribs <- attributes(s)
     new <- 
@@ -525,6 +588,9 @@ computeRestartsForEmacs <- function (sldbState) {
     if(!is.null(attr(s, "srcref"))) {
       attr(new, "srcref") <- frob(srcrefs)
     }
+    if(!is.null(attr(s, "wholeSrcref"))) {
+      attr(new, "wholeSrcref") <- frob(list(attr(s, "wholeSrcref")))[[1]]
+    }
     new
   }
   withRestarts({