From 4ec966035d2dfbede7a330cbdbf321d4be72cb92 Mon Sep 17 00:00:00 2001
From: stepan <stepan.sindelar@oracle.com>
Date: Thu, 5 Apr 2018 17:59:15 +0200
Subject: [PATCH] Make SVG related functions public and add their documentation

---
 .../fastrGrid/FastRGridExternalLookup.java    |  3 +
 .../r/library/fastrGrid/device/SVGDevice.java | 18 ++++--
 .../fastrGrid/grDevices/R/fastrGridDevices.R  | 29 ++++++++--
 .../r/library/fastrGrid/grDevices/Rd/awt.Rd   | 26 +++++++++
 .../library/fastrGrid/grDevices/Rd/svg.off.Rd | 28 +++++++++
 .../fastrGrid/grDevices/Rd/svg.string.Rd      | 24 ++++++++
 .../fastrGrid/grDevices/SvgString.java        | 48 +++++++++++++++
 .../r/nodes/builtin/base/BasePackage.java     |  2 +
 .../r/nodes/builtin/base/R/base_overrides.R   |  1 +
 .../foreign/CallAndExternalFunctions.java     |  6 +-
 .../r/nodes/builtin/fastr/FastRHelp.java      | 58 ++++++++++++++++---
 .../r/nodes/builtin/utils/R/utils_overrides.R |  4 +-
 .../r/test/library/fastr/TestInterop.java     | 16 -----
 .../r/test/library/utils/TestHelp.java        | 54 +++++++++++++++++
 14 files changed, 279 insertions(+), 38 deletions(-)
 create mode 100644 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/Rd/awt.Rd
 create mode 100644 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/Rd/svg.off.Rd
 create mode 100644 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/Rd/svg.string.Rd
 create mode 100644 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/SvgString.java
 create mode 100644 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestHelp.java

diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java
index 6d6a78006a..754b02266a 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java
@@ -37,6 +37,7 @@ import com.oracle.truffle.r.library.fastrGrid.grDevices.DevSize;
 import com.oracle.truffle.r.library.fastrGrid.grDevices.InitWindowedDevice;
 import com.oracle.truffle.r.library.fastrGrid.grDevices.PDF;
 import com.oracle.truffle.r.library.fastrGrid.grDevices.SavePlot;
+import com.oracle.truffle.r.library.fastrGrid.grDevices.SvgString;
 import com.oracle.truffle.r.library.fastrGrid.graphics.CPar;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RInternalCodeBuiltinNode;
@@ -64,6 +65,8 @@ public final class FastRGridExternalLookup {
                 return new DevCurr();
             case "devoff":
                 return DevOff.create();
+            case "svgstring":
+                return new SvgString();
             case "PDF":
                 return new PDF();
             case "devCairo":
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java
index 413d1c638d..4867d5a0b0 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java
@@ -59,10 +59,16 @@ public class SVGDevice implements GridDevice, FileGridDevice {
     }
 
     public String closeAndGetContents() {
-        closeSVGDocument();
+        closeSVGDocument(data);
         return data.toString();
     }
 
+    public String getContents() {
+        StringBuilder result = new StringBuilder(data);
+        closeSVGDocument(result);
+        return result.toString();
+    }
+
     @Override
     public void openNewPage() {
         // We stay compatible with GnuR: opening new page wipes out what has been drawn without
@@ -207,7 +213,7 @@ public class SVGDevice implements GridDevice, FileGridDevice {
     }
 
     private void saveFile() throws DeviceCloseException {
-        closeSVGDocument();
+        closeSVGDocument(data);
         try {
             Files.write(Paths.get(filename), Collections.singleton(data.toString()), StandardCharsets.UTF_8);
         } catch (IOException e) {
@@ -215,15 +221,15 @@ public class SVGDevice implements GridDevice, FileGridDevice {
         }
     }
 
-    private void closeSVGDocument() {
-        if (data.length() == 0) {
+    private void closeSVGDocument(StringBuilder sb) {
+        if (sb.length() == 0) {
             return;
         }
         if (cachedCtx != null) {
             // see #appendStyle
-            data.append("</g>");
+            sb.append("</g>");
         }
-        data.append("</svg>");
+        sb.append("</svg>");
     }
 
     // closes opened <g> tag if necessary
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/R/fastrGridDevices.R b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/R/fastrGridDevices.R
index f32979e54a..ef9033a667 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/R/fastrGridDevices.R
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/R/fastrGridDevices.R
@@ -20,21 +20,40 @@
 # questions.
 
 eval(expression({
+
+    assignInNs <- function(x, val) {
+        ns <- asNamespace("grDevices")
+        unlockBinding(x, ns)
+        assign(x, val, envir = ns, inherits = T)
+        lockBinding(x, ns)
+    }
+
     # This should be preffered way of starting the FastR java device.
     # For compatibility reasons, both X11 and awt end up calling C_X11.
     # In the future, this function may support extra parameters like a
     # reference to java 2D graphics object, which will be used for the drawing.
-    awt <- function(width = NULL, height = NULL, graphicsObj = NULL) {
-        .External2(grDevices:::C_X11, ".FASTR.AWT", width, height, graphicsObj)
-    }
+    assignInNs('awt', function(width = NULL, height = NULL, graphicsObj = NULL) {
+        invisible(.External2(grDevices:::C_X11, ".FASTR.AWT", width, height, graphicsObj))
+    })
+
     # Allows to get the SVG code from SVG device, it also closes the device,
     # but the contents are not saved to the given file.
-    svg.off <- function(which = dev.cur()) {
+    assignInNs('svg.off', function(which = dev.cur()) {
         if (which == 1) {
             stop("cannot shut down device 1 (the null device)")
         }
         .External(C_devoff, as.integer(-which))
-    }
+    })
+
+    # Allows to get the SVG code from SVG device without closing it
+    svgStringSymbol <- list(name='svgstring')
+    assignInNs('svg.string', function() {
+        .External(svgStringSymbol)
+    })
+
+    # Adds help files for the new public functions
+    .fastr.addHelpPath('/com/oracle/truffle/r/library/fastrGrid/grDevices/Rd')
+
     # GnuR version only works with "X11cairo" device. Our version of savePlot
     # works with "awt" device and "X11cairo", which is for us only alias for
     # "awt". Moreover, we only support formats that awt supports.
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/Rd/awt.Rd b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/Rd/awt.Rd
new file mode 100644
index 0000000000..3b1d1f58bd
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/Rd/awt.Rd
@@ -0,0 +1,26 @@
+\name{awt}
+\alias{awt}
+\title{Opens the AWT device, which is an interactive window.}
+\usage{
+awt(width = NULL, height = NULL, graphicsObj = NULL)
+}
+\arguments{
+\item{width}{window width in AWT units (~pixel).}
+\item{height}{window height in AWT units (~pixel).}
+\item{java.awt.graphicsObj}{Java object of type \code{java.awt.Graphics2D}.}
+}
+\value{
+Invisible NULL.
+}
+\description{
+The AWT device draws into given Java \code{java.awt.Graphics2D} object.
+If \code{NULL} is given as \code{graphicsObj}, then the function creates a
+window whose \code{Graphics2D} is used, i.e. plots will be drawn into the window.
+In FastR \code{X11} is aliased to \code{awt}.
+}
+\examples{
+awt()
+}
+\seealso{
+\code{X11}
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/Rd/svg.off.Rd b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/Rd/svg.off.Rd
new file mode 100644
index 0000000000..8083d822d1
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/Rd/svg.off.Rd
@@ -0,0 +1,28 @@
+\name{svg.off}
+\alias{svg.off}
+\title{Closes the SVG device and returns the SVG code as a character vector.}
+\usage{
+svg.off(which = dev.cur())
+}
+\arguments{
+\item{which}{device number.}
+}
+\value{
+Character vector with a single element.
+}
+\description{
+The semantics is the same as for \code{dev.off} function from the graphics package,
+except that \code{svg.off} does not write into any file and returns the SVG code as
+a character vector. \code{svg.off} can be invoked only when SVG device has been opened
+with \code{svg}.
+}
+\examples{
+library(grid)
+svg()
+grid.rect()
+print(svg.off())
+}
+\seealso{
+\code{dev.off}
+}
+
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/Rd/svg.string.Rd b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/Rd/svg.string.Rd
new file mode 100644
index 0000000000..3a511fa64e
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/Rd/svg.string.Rd
@@ -0,0 +1,24 @@
+\name{svg.string}
+\alias{svg.string}
+\title{Returns SVG code of the current plot.}
+\usage{
+svg.string()
+}
+\value{
+Character vector with a single element.
+}
+\description{
+Returns SVG code of the current plot.
+\code{svg.string} can be invoked only when SVG device has been opened using \code{svg}.
+Unlike \code{svg.off} this function does not close the SVG device.
+}
+\examples{
+library(grid)
+svg()
+grid.rect()
+print(svg.string())
+}
+\seealso{
+\code{svg.off}
+}
+
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/SvgString.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/SvgString.java
new file mode 100644
index 0000000000..ba9f84f251
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/SvgString.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.library.fastrGrid.grDevices;
+
+import com.oracle.truffle.r.library.fastrGrid.GridContext;
+import com.oracle.truffle.r.library.fastrGrid.device.GridDevice;
+import com.oracle.truffle.r.library.fastrGrid.device.SVGDevice;
+import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.runtime.RError.Message;
+
+/**
+ * FastR specific external used to implement {@code svg.string}, which returns the SVG code of
+ * current drawing.
+ */
+public class SvgString extends RExternalBuiltinNode.Arg0 {
+    @Override
+    public Object execute() {
+        GridContext ctx = GridContext.getContext();
+        if (ctx.getCurrentDeviceIndex() <= 0) {
+            throw error(Message.GENERIC, "No device opened.");
+        }
+        GridDevice dev = ctx.getCurrentDevice();
+        if (!(dev instanceof SVGDevice)) {
+            throw error(Message.GENERIC, "No SVG device opened, use svg() to open one.");
+        }
+        return ((SVGDevice) dev).getContents();
+    }
+}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
index 406d3eb5d2..c6fcd9a521 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
@@ -99,6 +99,7 @@ import com.oracle.truffle.r.nodes.builtin.fastr.FastRContext;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRContextFactory;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRDebug;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRDebugNodeGen;
+import com.oracle.truffle.r.nodes.builtin.fastr.FastRHelp.FastRAddHelpPath;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRHelp.FastRHelpPath;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRHelp.FastRHelpRd;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRHelpFactory.FastRHelpPathNodeGen;
@@ -445,6 +446,7 @@ public class BasePackage extends RBuiltinPackage {
         add(FastrDqrls.class, FastrDqrlsNodeGen::create);
         add(FastRDebug.class, FastRDebugNodeGen::create);
         add(FastRSetBreakpoint.class, FastRSetBreakpointNodeGen::create);
+        add(FastRAddHelpPath.class, FastRAddHelpPath::create);
         add(FastRHelpPath.class, FastRHelpPathNodeGen::create);
         add(FastRHelpRd.class, FastRHelpRdNodeGen::create);
         add(FastRIdentity.class, FastRIdentityNodeGen::create);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/R/base_overrides.R b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/R/base_overrides.R
index 9b10332922..58a96ab5a8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/R/base_overrides.R
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/R/base_overrides.R
@@ -10,6 +10,7 @@
 #
 
 eval(expression({
+.fastr.addHelpPath('/com/oracle/truffle/r/nodes/builtin/base/Rd')
 .libPaths <- local({
     .lib.loc <- character()            # Profiles need to set this.
     function(new) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
index e5aa670388..70b8e12f2d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
@@ -798,8 +798,9 @@ public class CallAndExternalFunctions {
         }
 
         @SuppressWarnings("unused")
-        @Specialization(limit = "1", guards = {"cached.symbol == symbol"})
+        @Specialization(limit = "1", guards = {"cached.symbol == symbol", "builtin == null"})
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName,
+                        @Cached("lookupBuiltin(symbol)") RExternalBuiltinNode builtin,
                         @Cached("new(symbol)") CallNamedFunctionNode cached,
                         @Cached("createBinaryProfile()") ConditionProfile registeredProfile) {
             if (registeredProfile.profile(isRegisteredRFunction(cached.nativeCallInfo))) {
@@ -913,8 +914,9 @@ public class CallAndExternalFunctions {
         }
 
         @SuppressWarnings("unused")
-        @Specialization(limit = "1", guards = {"cached.symbol == symbol"})
+        @Specialization(limit = "1", guards = {"cached.symbol == symbol", "builtin == null"})
         protected Object callNamedFunction(RList symbol, RArgsValuesAndNames args, Object packageName,
+                        @Cached("lookupBuiltin(symbol)") RExternalBuiltinNode builtin,
                         @Cached("new(symbol)") CallNamedFunctionNode cached) {
             Object list = encodeArgumentPairList(args, cached.nativeCallInfo.name);
             return dispatch(cached.nativeCallInfo, new Object[]{CALL, getOp(), list, RHO});
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRHelp.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRHelp.java
index 4f0b1b556e..de2ff48697 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRHelp.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRHelp.java
@@ -30,20 +30,62 @@ import com.oracle.truffle.api.dsl.Specialization;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.fastr.FastRHelpFactory.FastRAddHelpPathNodeGen;
 import com.oracle.truffle.r.runtime.RError;
 import static com.oracle.truffle.r.runtime.RVisibility.ON;
 
 import com.oracle.truffle.r.runtime.ResourceHandlerFactory;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.nodes.RNode;
+
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.util.ArrayList;
 
 public class FastRHelp {
 
-    @RBuiltin(name = ".fastr.interop.helpPath", visibility = ON, kind = PRIMITIVE, parameterNames = {"builtinName"}, behavior = COMPLEX)
+    private static ArrayList<String> paths;
+
+    private static synchronized void initPaths() {
+        if (paths == null) {
+            paths = new ArrayList<>(3);
+        }
+    }
+
+    private static synchronized void addPath(String path) {
+        initPaths();
+        paths.add(path);
+    }
+
+    private static synchronized String[] getPaths() {
+        initPaths();
+        return paths.toArray(new String[paths.size()]);
+    }
+
+    @RBuiltin(name = ".fastr.addHelpPath", visibility = ON, kind = PRIMITIVE, parameterNames = {"path"}, behavior = COMPLEX)
+    public abstract static class FastRAddHelpPath extends RBuiltinNode.Arg1 {
+
+        static {
+            Casts casts = new Casts(FastRAddHelpPath.class);
+            casts.arg("path").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
+        }
+
+        @Specialization()
+        @TruffleBoundary
+        public Object helpPath(String path) {
+            addPath(path);
+            return RNull.instance;
+        }
+
+        public static FastRAddHelpPath create() {
+            return FastRAddHelpPathNodeGen.create();
+        }
+    }
+
+    @RBuiltin(name = ".fastr.helpPath", visibility = ON, kind = PRIMITIVE, parameterNames = {"builtinName"}, behavior = COMPLEX)
     public abstract static class FastRHelpPath extends RBuiltinNode.Arg1 {
 
         static {
@@ -54,18 +96,20 @@ public class FastRHelp {
         @Specialization()
         @TruffleBoundary
         public Object helpPath(String builtinName) {
-            String path = "/com/oracle/truffle/r/nodes/builtin/base/Rd/" + builtinName + ".Rd";
-            try (InputStream in = ResourceHandlerFactory.getHandler().getResourceAsStream(getClass(), path)) {
-                if (in != null) {
-                    return path;
+            for (String path : getPaths()) {
+                String filename = path + '/' + builtinName + ".Rd";
+                try (InputStream in = ResourceHandlerFactory.getHandler().getResourceAsStream(getClass(), filename)) {
+                    if (in != null) {
+                        return filename;
+                    }
+                } catch (IOException ex) {
                 }
-            } catch (IOException ex) {
             }
             return RNull.instance;
         }
     }
 
-    @RBuiltin(name = ".fastr.interop.helpRd", visibility = ON, kind = PRIMITIVE, parameterNames = {"path"}, behavior = COMPLEX)
+    @RBuiltin(name = ".fastr.helpRd", visibility = ON, kind = PRIMITIVE, parameterNames = {"path"}, behavior = COMPLEX)
     public abstract static class FastRHelpRd extends RBuiltinNode.Arg1 {
 
         static {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/R/utils_overrides.R b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/R/utils_overrides.R
index bc72ccbeb2..db7cf13a49 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/R/utils_overrides.R
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/utils/R/utils_overrides.R
@@ -39,7 +39,7 @@ index.search <- function (topic, paths, firstOnly = FALSE)
     res <- index.search.orig(topic, paths, firstOnly)
     
     if(length(res) == 0) {
-        fastrHelpRd <- .fastr.interop.helpPath(topic)
+        fastrHelpRd <- .fastr.helpPath(topic)
         if(!is.null(fastrHelpRd)) {
             res <- fastrHelpRd
         }
@@ -52,7 +52,7 @@ eval(expression({
 .getHelpFile.orig <- utils:::.getHelpFile
 .getHelpFile <- function (file) 
 {
-    fastrHelpRd <- .fastr.interop.helpRd(file)
+    fastrHelpRd <- .fastr.helpRd(file)
     if(!is.null(fastrHelpRd)) {
         return(tools::parse_Rd(textConnection(fastrHelpRd)))
     }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java
index 0ab685c7b6..fd8c622bad 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java
@@ -107,22 +107,6 @@ public class TestInterop extends TestBase {
                         "cat('Error in fo@bitLength :\n  cannot get a slot (\"bitLength\") from an object of type \"external object\"\n')");
     }
 
-    @Test
-    public void testHelp() {
-        assertHelpResult(fastREval("?as.external.byte", ContextKind.SHARE_PARENT_RW, false), "==== R Help on ‘as.external.byte’ ====", "converted to a byte", "byteClass$valueOf(javaByte)");
-        assertHelpResult(fastREval("help(as.external.byte)", ContextKind.SHARE_PARENT_RW, false), "==== R Help on ‘as.external.byte’ ====", "converted to a byte", "byteClass$valueOf(javaByte)");
-        assertHelpResult(fastREval("example(as.external.byte)", ContextKind.SHARE_PARENT_RW, false), null, "byteClass$valueOf(javaByte)", "[1] 123");
-    }
-
-    private static void assertHelpResult(String result, String startsWith, String... contains) {
-        if (startsWith != null) {
-            assertTrue(result.startsWith(startsWith));
-        }
-        for (String s : contains) {
-            assertTrue(result.contains(s));
-        }
-    }
-
     /**
      * Used for testing interop functionality.
      */
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestHelp.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestHelp.java
new file mode 100644
index 0000000000..aa0e530f8d
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestHelp.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.test.library.utils;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
+import com.oracle.truffle.r.test.TestBase;
+
+public class TestHelp extends TestBase {
+    @Test
+    public void testInteropHelp() {
+        assertHelpResult(fastREval("?as.external.byte", ContextKind.SHARE_PARENT_RW, false), "==== R Help on ‘as.external.byte’ ====", "converted to a byte", "byteClass$valueOf(javaByte)");
+        assertHelpResult(fastREval("help(as.external.byte)", ContextKind.SHARE_PARENT_RW, false), "==== R Help on ‘as.external.byte’ ====", "converted to a byte", "byteClass$valueOf(javaByte)");
+        assertHelpResult(fastREval("example(as.external.byte)", ContextKind.SHARE_PARENT_RW, false), null, "byteClass$valueOf(javaByte)", "[1] 123");
+    }
+
+    @Test
+    public void testGrDevicesHelp() {
+        assertHelpResult(fastREval("?svg.off", ContextKind.SHARE_PARENT_RW, false), "==== R Help on ‘svg.off’ ====", "SVG");
+        assertHelpResult(fastREval("help(svg.off)", ContextKind.SHARE_PARENT_RW, false), "==== R Help on ‘svg.off’ ====", "SVG");
+    }
+
+    private static void assertHelpResult(String result, String startsWith, String... contains) {
+        if (startsWith != null) {
+            assertTrue(result.startsWith(startsWith));
+        }
+        for (String s : contains) {
+            assertTrue(result.contains(s));
+        }
+    }
+}
-- 
GitLab