rework `swank:simple-completions`
authorChristophe Rhodes <csr21@cantab.net>
Sun, 29 Apr 2012 13:15:22 +0000 (14:15 +0100)
committerChristophe Rhodes <csr21@cantab.net>
Sun, 29 Apr 2012 13:15:22 +0000 (14:15 +0100)
In the process, implement looking up foo$bar$baz, and passing those
completions back.  It's not completely robust to somewhat exotic
syntax, as it assumes that the text being completed can be used
directly as character vectors naming objects or fields; it is good
enough to get started, and now a lot less annoying to
use (particularly when lots of fields have underscores in them...)

BUGS.org
swank.R

index 31743fd..3e65f0a 100644 (file)
--- a/BUGS.org
+++ b/BUGS.org
@@ -79,7 +79,7 @@
 
   To reproduce, C-c I globalenv() RET, or hit RET on environment
   presentations in the debugger (if presentations are on).
-* OPEN #22 completion of named list fields                         :WISHLIST:
+* RESOLVED #22 completion of named list fields               :WISHLIST:FIXED:
   It is very nice in ESS to be able to type df$ TAB and get a
   completion list of the data frame's columns.  Supporting it in
   swankr should be really easy.
diff --git a/swank.R b/swank.R
index 979bd84..3b1f3d7 100644 (file)
--- a/swank.R
+++ b/swank.R
@@ -455,20 +455,44 @@ computeRestartsForEmacs <- function (sldbState) {
 }
 
 `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)
+    } 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 <- 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)
   }
   matches <- apropos(sprintf("^%s", literal2rx(prefix)), ignore.case=FALSE)
   nmatches <- length(matches)
-  if(nmatches == 0) {
-    list(list(), "")
+  if((nmatches == 0) && ((dollar <- regexpr("$", prefix, fixed=TRUE)) > -1)) {
+    symbolFieldsCompletion(globalenv(), prefix)
   } 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(matches)
   }
 }