diff --git a/NEWS.md b/NEWS.md index 1cd90c6..1c05c6a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,10 @@ # 1.7.0 - Added checks for network availability +- Added command-line switcher +- Supports file uploads to and exports from RStudio Server +- Added more web resource URLs +- Added Preference to always check/force that RStudio owns .R and .Rmd files # 1.4.0 diff --git a/RSwitch.xcworkspace/xcuserdata/hrbrmstr.xcuserdatad/UserInterfaceState.xcuserstate b/RSwitch.xcworkspace/xcuserdata/hrbrmstr.xcuserdatad/UserInterfaceState.xcuserstate index 5612eb0..bdaf7ea 100644 Binary files a/RSwitch.xcworkspace/xcuserdata/hrbrmstr.xcuserdatad/UserInterfaceState.xcuserstate and b/RSwitch.xcworkspace/xcuserdata/hrbrmstr.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/RSwitch/Swift/Downloaders/DownloadFromRStudioServer.swift b/RSwitch/Swift/Downloaders/DownloadFromRStudioServer.swift index 8364457..ab2419a 100644 --- a/RSwitch/Swift/Downloaders/DownloadFromRStudioServer.swift +++ b/RSwitch/Swift/Downloaders/DownloadFromRStudioServer.swift @@ -10,50 +10,40 @@ import Foundation import Cocoa func download_from_studio_server(fromRS : String, toFS : String) { - - NSLog("download from rstudio server") let rsURL = URL(string: fromRS)! let fsURL = URL(string: toFS)! URLSession.shared.configuration.timeoutIntervalForRequest = 300.0 - //URLSession.shared.downloadTask(with: <#T##URLRequest#>) - let task = URLSession.shared.downloadTask(with: rsURL) { localURL, urlResponse, error in if (error != nil) { - NSLog("dler \(String(describing: error))") + NSLog("Error exporting from RStudio Server; \(String(describing: error))") } else { if let localURL = localURL { - NSLog("We've got the data"); - if (FileManager.default.fileExists(atPath: fsURL.path)) { - NSLog("Deleting old file") do { try FileManager.default.removeItem(at: fsURL) } catch { - NSLog("error deleting old file") + NSLog("Error removing file during RStudio Server export; \(error)") } } do { - NSLog("Trying to move the data from \(localURL) to \(fsURL)"); try FileManager.default.moveItem(at: localURL, to: fsURL) - NSWorkspace.shared.openFile( - fsURL.deletingLastPathComponent().absoluteString, withApplication: "Finder" - ) + NSWorkspace.shared.openFile(fsURL.deletingLastPathComponent().absoluteString, withApplication: "Finder") NSWorkspace.shared.activateFileViewerSelecting([fsURL]) } catch { - NSLog("Move Error \(error)") + NSLog("Error moving RStudio Server export file; \(error)") } } diff --git a/RSwitch/Swift/Notify.swift b/RSwitch/Swift/Notify.swift index b842c9f..3691033 100644 --- a/RSwitch/Swift/Notify.swift +++ b/RSwitch/Swift/Notify.swift @@ -49,13 +49,10 @@ extension AppDelegate : NSUserNotificationCenterDelegate { } func userNotificationCenter(_ center: NSUserNotificationCenter, shouldPresent notification: NSUserNotification) -> Bool { - print("should present") return(true) } func userNotificationCenter(_ center: NSUserNotificationCenter, didActivate notification: NSUserNotification) { - print("did activate") - print(notification) } } diff --git a/RSwitch/Swift/RStudioServerSessionWebViewController.swift b/RSwitch/Swift/RStudioServerSessionWebViewController.swift index 5548725..9483022 100644 --- a/RSwitch/Swift/RStudioServerSessionWebViewController.swift +++ b/RSwitch/Swift/RStudioServerSessionWebViewController.swift @@ -51,9 +51,6 @@ class RstudioServerSessionWebViewController: NSViewController, NSWindowDelegate extension RstudioServerSessionWebViewController: WKUIDelegate { func webView(_ webView: WKWebView, runOpenPanelWith parameters: WKOpenPanelParameters, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping ([URL]?) -> Void) { - - NSLog("PANELING!") - print("PANELING!") let openPanel = NSOpenPanel() @@ -79,9 +76,7 @@ extension RstudioServerSessionWebViewController: WKUIDelegate { let u = URL(string: navigationAction.request.url!.absoluteString)! if ((u.urlComponents?.path.starts(with: "/export/")) != nil) { - - NSLog("Navigation action thing: " + navigationAction.request.url!.absoluteString) - + let exportWindowController = NSStoryboard(name: "Main", bundle: nil).instantiateController(withIdentifier: "exportPopupPanel") as! ExportWebViewController let exportWV = (exportWindowController.contentViewController as! exportPopupViewController) @@ -89,42 +84,25 @@ extension RstudioServerSessionWebViewController: WKUIDelegate { exportWV.view.window?.title = navigationAction.request.url!.absoluteString exportWV.setupWebView(configuration: configuration) - //exportWindowController.showWindow(self) - - NSLog("Before exportWV.loadWebView") - -// exportWV.loadWebView(urlIn: navigationAction.request.url!.absoluteString) + exportWV.loadWebView(urlIn: "") - NSLog("After exportWV.loadWebView") - let urlPath = navigationAction.request.url!.absoluteString - - NSLog("loadWebView: \(urlPath)") - + // Check for "/export/" // If export, then get bring up a Save Panel and then download the file to that location if let url = URL(string: urlPath) { - - NSLog("URL path: \(url.path)") - + if (url.path.starts(with: "/export")) { - - NSLog(" Name: " + url.queryParameters["name"]!) - + let savePanel = NSSavePanel() savePanel.canCreateDirectories = true savePanel.nameFieldStringValue = url.queryParameters["name"]! savePanel.beginSheetModal(for:self.view.window!) { (response) in - if (response == NSApplication.ModalResponse.OK) { - + if (response == NSApplication.ModalResponse.OK) { download_from_studio_server(fromRS: url.absoluteString, toFS: savePanel.url!.absoluteString) - - } else { - - NSLog("Don't do anything!") } savePanel.close() } diff --git a/RSwitch/Swift/Utils/Associations.swift b/RSwitch/Swift/Utils/Associations.swift index 7195c55..339f03c 100644 --- a/RSwitch/Swift/Utils/Associations.swift +++ b/RSwitch/Swift/Utils/Associations.swift @@ -12,45 +12,27 @@ import ApplicationServices class FileAssociationUtils { - public static func getHandlers() { - - let workspace = NSWorkspace.shared; - - let setResR : String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, "R" as CFString, nil)?.takeRetainedValue() as String? ?? ""; - NSLog("UTI of .R extension: " + setResR); - - let handlerR : String = LSCopyDefaultRoleHandlerForContentType(setResR as CFString, LSRolesMask.all)?.takeRetainedValue() as String? ?? ""; - NSLog("Bundle ID of handler for .R files is: [" + handlerR + "]"); - - let rAppUrl : URL = (workspace.urlForApplication(withBundleIdentifier: handlerR))!.appendingPathComponent("Contents/Info.plist"); - NSLog("The Info.plist for the app that handles .R files is: " + rAppUrl.absoluteString); - - let rAppDict : NSDictionary = NSDictionary(contentsOf: rAppUrl)!; - NSLog("The name of the app that handles .R files is: " + (rAppDict.object(forKey: "CFBundleName") as! String)); - - let setResRmd : String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, "Rmd" as CFString, nil)?.takeRetainedValue() as String? ?? ""; - NSLog("UTI of .Rmd extension: " + setResRmd); - - let handlerRmd : String = LSCopyDefaultRoleHandlerForContentType(setResRmd as CFString, LSRolesMask.all)?.takeRetainedValue() as String? ?? ""; - NSLog("Bundle ID of handler for .Rmd files is: [" + handlerRmd + "]"); - - let rmdAppUrl : URL = (workspace.urlForApplication(withBundleIdentifier: handlerRmd))!.appendingPathComponent("Contents/Info.plist"); - NSLog("The Info.plist for the app that handles .Rmd files is: " + rmdAppUrl.absoluteString); - - let rmdAppDict : NSDictionary = NSDictionary(contentsOf: rmdAppUrl)!; - NSLog("The name of the app that handles .Rmd files is: " + (rmdAppDict.object(forKey: "CFBundleName") as! String)); - - } +// public static func getHandlers() { +// +// let workspace = NSWorkspace.shared; +// +// let setResR : String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, "R" as CFString, nil)?.takeRetainedValue() as String? ?? ""; +// let handlerR : String = LSCopyDefaultRoleHandlerForContentType(setResR as CFString, LSRolesMask.all)?.takeRetainedValue() as String? ?? ""; +// let rAppUrl : URL = (workspace.urlForApplication(withBundleIdentifier: handlerR))!.appendingPathComponent("Contents/Info.plist"); +// let rAppDict : NSDictionary = NSDictionary(contentsOf: rAppUrl)!; +// let setResRmd : String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, "Rmd" as CFString, nil)?.takeRetainedValue() as String? ?? ""; +// let handlerRmd : String = LSCopyDefaultRoleHandlerForContentType(setResRmd as CFString, LSRolesMask.all)?.takeRetainedValue() as String? ?? ""; +// let rmdAppUrl : URL = (workspace.urlForApplication(withBundleIdentifier: handlerRmd))!.appendingPathComponent("Contents/Info.plist"); +// let rmdAppDict : NSDictionary = NSDictionary(contentsOf: rmdAppUrl)!; +// } public static func setHandlers() { let setResR : String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, "R" as CFString, nil)?.takeRetainedValue() as String? ?? ""; - //NSLog("UTI of .R extension: " + setResR); LSSetDefaultRoleHandlerForContentType(setResR as CFString, LSRolesMask.all, "org.rstudio.RStudio" as CFString); let setResRmd : String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, "Rmd" as CFString, nil)?.takeRetainedValue() as String? ?? ""; - //NSLog("UTI of .Rmd extension: " + setResRmd); LSSetDefaultRoleHandlerForContentType(setResRmd as CFString, LSRolesMask.all, "org.rstudio.RStudio" as CFString); diff --git a/RSwitch/Swift/Utils/urls.swift b/RSwitch/Swift/Utils/urls.swift index 46b76e1..f30107a 100644 --- a/RSwitch/Swift/Utils/urls.swift +++ b/RSwitch/Swift/Utils/urls.swift @@ -18,7 +18,6 @@ class QueryParameters { let queryItems: [URLQueryItem] init(url: URL?) { queryItems = URLComponents(string: url?.absoluteString ?? "")?.queryItems ?? [] - print(queryItems) } subscript(name: String) -> String? { return queryItems.first(where: { $0.name == name })?.value diff --git a/RSwitch/Swift/exportPopupViewController.swift b/RSwitch/Swift/exportPopupViewController.swift index 0982e4b..1ae3471 100644 --- a/RSwitch/Swift/exportPopupViewController.swift +++ b/RSwitch/Swift/exportPopupViewController.swift @@ -33,41 +33,29 @@ class exportPopupViewController: NSViewController { func loadWebView(urlIn: String) { - urlPath = urlIn - - NSLog("loadWebView: \(urlPath)") - - // Check for "/export/" - // If export, then get bring up a Save Panel and then download the file to that location - - if let url = URL(string: urlPath) { - - NSLog("URL path: \(url.path)") - - if (url.path.starts(with: "/export")) { - - NSLog(" Name: " + url.queryParameters["name"]!) - - let savePanel = NSSavePanel() - - savePanel.canCreateDirectories = true - savePanel.nameFieldStringValue = url.queryParameters["name"]! - savePanel.beginSheetModal(for:self.view.window!) { (response) in - if (response == NSApplication.ModalResponse.OK) { - - download_from_studio_server(fromRS: url.absoluteString, toFS: savePanel.url!.absoluteString) - - } else { - - NSLog("Don't do anything!") - } - savePanel.close() - } - - - } - - } +// urlPath = urlIn +// +// // Check for "/export/" +// // If export, then get bring up a Save Panel and then download the file to that location +// +// if let url = URL(string: urlPath) { +// +// if (url.path.starts(with: "/export")) { +// +// let savePanel = NSSavePanel() +// +// savePanel.canCreateDirectories = true +// savePanel.nameFieldStringValue = url.queryParameters["name"]! +// savePanel.beginSheetModal(for:self.view.window!) { (response) in +// if (response == NSApplication.ModalResponse.OK) { +// download_from_studio_server(fromRS: url.absoluteString, toFS: savePanel.url!.absoluteString) +// } +// savePanel.close() +// } +// +// } +// +// } } @@ -88,13 +76,9 @@ extension exportPopupViewController: WKUIDelegate { extension exportPopupViewController: WKNavigationDelegate { - open func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - print("Export DID START \(String(describing: webView.url))") - } + open func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { } - func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - print("Export DID FINISH \(String(describing: webView.url))") - } + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { } } diff --git a/RSwitch/Swift/plotPopupViewController.swift b/RSwitch/Swift/plotPopupViewController.swift index cf8e81c..2818cf9 100644 --- a/RSwitch/Swift/plotPopupViewController.swift +++ b/RSwitch/Swift/plotPopupViewController.swift @@ -33,25 +33,13 @@ class plotPopupViewController: NSViewController { urlPath = urlIn - NSLog(urlPath) - // Check for "/export/" - // If export, then get bring up a Save Panel and then download the file to that location - if let url = URL(string: urlPath) { let urlRequest = URLRequest(url: url) - - NSLog("URL path: " + url.path) if (url.path.starts(with: "/export")) { - NSLog(" Name: " + url.queryParameters["name"]!) - - DispatchQueue.main.async { - self.webView.removeFromSuperview() - } - } else { webView.load(urlRequest) @@ -75,20 +63,6 @@ extension plotPopupViewController: WKUIDelegate { func webView(_ webView: WKWebView, runOpenPanelWith parameters: WKOpenPanelParameters, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping ([URL]?) -> Void) { - - NSLog("savePanel!") - - let savePanel = NSSavePanel() - - savePanel.canCreateDirectories = true - savePanel.beginSheetModal(for:self.view.window!) { (response) in - if (response == NSApplication.ModalResponse.OK) { - completionHandler([savePanel.url!]) - } else { - completionHandler(nil) - } - savePanel.close() - } } @@ -96,13 +70,9 @@ extension plotPopupViewController: WKUIDelegate { extension plotPopupViewController: WKNavigationDelegate { - open func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - print("DID START") - } + open func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {} - func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - print("DID FINISH") - } + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { } } diff --git a/guide/_site/index.html b/guide/_site/index.html index 082302f..34a9d7c 100644 --- a/guide/_site/index.html +++ b/guide/_site/index.html @@ -1,11 +1,10 @@ - + - @@ -14,6 +13,7 @@ Using RSwitch + @@ -87,7 +87,6 @@ code { } img { max-width:100%; - height: auto; } .tabbed-pane { padding-top: 12px; @@ -236,6 +235,7 @@ $(document).ready(function () { border: none; display: inline-block; border-radius: 4px; + background-color: transparent; } .tabset-dropdown > .nav-tabs.nav-tabs-open > li { @@ -264,6 +264,12 @@ $(document).ready(function () { } } +@media print { +.toc-content { + /* see https://github.com/w3c/csswg-drafts/issues/4434 */ + float: right; +} +} .toc-content { padding-left: 30px; @@ -376,8 +382,9 @@ div.tocify {

Credits

Many thanks to the following folks for their contributions to the project to help make RSwitch better for everyone:

@@ -391,6 +398,8 @@ div.tocify { ├── 3.5 ├── 3.6 ├── 3.7 +├── 4.0 +├── 4.1 └── Current

The “R Framework” is, well, R on your macOS system. All of the necessary supporting libraries, code, pacakges, configuration elements, etc. exist in the framework directory. Here is the top-level contents of the 3.5 version of the R Framework:

fs::dir_tree(path = "/Library/Frameworks/R.framework/Versions/3.5", recurse = 1)
@@ -456,17 +465,16 @@ div.tocify {
  • Resources@ -> Versions/Current/Resources
  • Versions/
  • -

    For the most control, you can install a coexisting version of R oldrel-1, oldrel (as of the date this document was created those would be R 3.4 and R 3.5), current release (R 3.6) and devel (3.7) by hand by going to the R for macOS Developer’s Page and downloading the tar.gz version of those distributions:

    +

    For the most control, you can install a coexisting version of R oldrel-1, oldrel (as of the date this document was created those would be R 3.5 and R 3.6), current release (R 4.0) and devel (4.1) by hand by going to R for macOS and downloading the tar.gz version of those distributions:

    Here are direct https links to the tarballs:

    Once downloaded, you can fire up a terminal prompt, head to the root directory (i.e. cd /) and run tar -xvzf path-to-thing-you-just-downloaded to lay out the contents of the tarball onto the filesystem. You can also use the .pkg versions if you prefer a clicky-installer wizard, but these installers will remove any previous versions of the framework (kinda defeating the purpose). You can still use the .pkg format by heading over to the command line and using pkgutil --forget to prevent said clobbering behavior (as noted in Section 4.2 of R Installation and Administration. For example:

    -
    sudo pkgutil --forget org.r-project.R.el-capitan.fw.pkg \
    +
    sudo pkgutil --forget org.r-project.R.el-capitan.fw.pkg \ # may need to use high-sierra vs el-capitan
                  --forget org.r-project.x86_64.tcltk.x11 \
                  --forget org.r-project.x86_64.texinfo \
                  --forget org.r-project.R.el-capitan.GUI.pkg
    @@ -491,7 +499,7 @@ div.tocify {

    Getting Help or Resources from the Internet

    Since RSwitch is designed to help you work with R on macOS it seemed only fitting to provide some handy links to resources like the R for macOS page, the CRAN R page, RStudio dailies link, etc. They’re all available via the fairly obvious sub-menu:

    -

    +

    and each item will open up in your default web browser. (File an issue if you’d like more links added)

    @@ -518,18 +526,46 @@ div.tocify {

    and you can then launch a task-specific browser for each instance you have defined:

    -

    This allows you to keep RStudio Server work separate from your internet browsing, creating a more focused workspace that you never have to worry about accidentally closing. Window size & position are preserved across launches, too.

    +

    This allows you to keep RStudio Server work separate from your internet browsing, creating a more focused workspace that you never have to worry about accidentally closing. Window size & position are preserved across launches, too and the keystrokes you are used to in RStudio Desktop on macOS are the same in this task-specific browser.

    +

    File uploads and downloads (“exports”) are also now supported.

    Have It Your Way

    -

    There’s a new minimal preferences system for showing/hiding the dock icon and for enabling background checks for and notifications when new RStudio Dailies are available:

    -

    +

    There’s a minimal preferences system for showing/hiding the dock icon and for enabling background checks for and notifications when new RStudio Dailies are available.

    +

    +

    Another (new) preference is “Ensure RStudio opens R/Rmd files”. Xcode and other developer-oriented programs seem to love to takeover either .R and .Rmd (sometimes both) and loading Xcode can take a while. Setting this preference will enable an hourly check for who owns those extensions and forces them back to RStudio in the event they are changed.

    Always On

    If you like RSwitch enough to keep it running all the time, just drag the item to the “Login Items” table of your user in the “Users & Groups” pane of “System Preferences”

    +
    +

    Taking Command(line)

    +

    There’s a new command-line switcher for folks who would rather not interact with a menu to change R versions. RSwitch.app comes with rswitch-cmd tucked into /Applications/RSwitch.app/Contents/Resources/. You can make it easier to type by making a symbolic link in /usr/local/bin/ (or your preferred path that’s on $PATH):

    +
    $ ln -s /Applications/RSwitch.app/Contents/Resources/rswitch-cmd /usr/local/bin/rswitch
    +

    Firing off just rswitch will bring up a list of available R installs with an asterisk signifying which one is active:

    +
    $ rswitch
    +2.14 (incomplete)
    +3.5
    +3.6
    +3.7
    +4.0 *
    +4.1
    +

    Just call it with the version you want to switch to and you are ready to go (you can also use --list or -l if you like typing more than you need to):

    +
    $ rswitch 4.1
    +$ rswitch --list
    +2.14 (incomplete)
    +3.5
    +3.6
    +3.7
    +4.0
    +4.1 *
    +

    You’ll receive an error message if the version specified cannot be found:

    +
    $ rswitch 4.4
    +R version 4.4 not found.
    +

    All non-successful operations will set a non-zero exit code in the event you are using the command-line utility in scripts.

    +

    Getting Help

    If you’re having trouble with RSwitch or have a feature request, head on over to any of the following social coding sites and file an issue:

    diff --git a/guide/_site/r-macos-downloads.png b/guide/_site/r-macos-downloads.png index bb39575..f448d96 100644 Binary files a/guide/_site/r-macos-downloads.png and b/guide/_site/r-macos-downloads.png differ diff --git a/guide/_site/rswitch-prefs.png b/guide/_site/rswitch-prefs.png new file mode 100644 index 0000000..6fa4f2e Binary files /dev/null and b/guide/_site/rswitch-prefs.png differ diff --git a/guide/_site/site_libs/header-attrs-2.1/header-attrs.js b/guide/_site/site_libs/header-attrs-2.1/header-attrs.js new file mode 100644 index 0000000..dd57d92 --- /dev/null +++ b/guide/_site/site_libs/header-attrs-2.1/header-attrs.js @@ -0,0 +1,12 @@ +// Pandoc 2.9 adds attributes on both header and div. We remove the former (to +// be compatible with the behavior of Pandoc < 2.8). +document.addEventListener('DOMContentLoaded', function(e) { + var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); + var i, h, a; + for (i = 0; i < hs.length; i++) { + h = hs[i]; + if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 + a = h.attributes; + while (a.length > 0) h.removeAttribute(a[0].name); + } +}); diff --git a/guide/_site/site_libs/navigation-1.1/codefolding.js b/guide/_site/site_libs/navigation-1.1/codefolding.js index 26ec126..8cb6311 100644 --- a/guide/_site/site_libs/navigation-1.1/codefolding.js +++ b/guide/_site/site_libs/navigation-1.1/codefolding.js @@ -22,7 +22,7 @@ window.initializeCodeFolding = function(show) { // create a collapsable div to wrap the code in var div = $('
    '); - if (show) + if (show || $(this)[0].classList.contains('fold-show')) div.addClass('in'); var id = 'rcode-643E0F36' + currentIndex++; div.attr('id', id); diff --git a/guide/_site/web-resources.png b/guide/_site/web-resources.png new file mode 100644 index 0000000..c34ab5b Binary files /dev/null and b/guide/_site/web-resources.png differ diff --git a/guide/index.Rmd b/guide/index.Rmd index f30b065..a6d2420 100644 --- a/guide/index.Rmd +++ b/guide/index.Rmd @@ -17,8 +17,9 @@ RSwitch is a macOS menubar application that works on macOS 10.14+ and provides h Many thanks to the following folks for their contributions to the project to help make RSwitch better for everyone: -- [Benjamin Guiastrennec](https://github.com/guiastrennec) for suggesting improvements to the documentation regarding how to use the installer packages from the [R for macOS Developer's Page](https://mac.r-project.org/) without clobbering existing R Framework installs. +- [Benjamin Guiastrennec](https://github.com/guiastrennec) for suggesting improvements to the documentation regarding how to use the installer packages from the [R for macOS Developer's Page](https://mac.r-project.org/) without clobbering existing R Framework installs and also for encouraging support for RStudio Sever file uploads and exports. - [Xavier Adam](https://github.com/xvrdm) for [adding books to the RSwitch library](https://github.com/hrbrmstr/RSwitch/pull/4). +- [Patrick Schratz](https://github.com/pat-s) for encourging the development of a command-line switcher to make it easier to use in automation (and sans mouse). ## Basic/Core Usage @@ -57,14 +58,14 @@ For the most control, you can install a coexisting version of R **oldrel**-1, ** Here are direct `https` links to the tarballs: -- [R 3.6](https://mac.r-project.org/el-capitan/R-3.6-branch/R-3.6-branch-el-capitan-sa-x86_64.tar.gz) (current) -- [R 4.0](https://mac.r-project.org/el-capitan/R-3.6-branch/R-4.0-branch-el-capitan-sa-x86_64.tar.gz) (current) -- [R 4.1](https://mac.r-project.org/el-capitan/R-devel/R-devel-el-capitan-sa-x86_64.tar.gz) (devel) +- [R 3.6](https://mac.r-project.org/el-capitan/R-3.6-branch/R-3.6-branch-el-capitan-sa-x86_64.tar.gz) (oldrel) +- [R 4.0](https://mac.r-project.org/high-sierra/R-4.0-branch/x86_64/R-4.0-branch.tar.gz) (current) +- [R 4.1](https://mac.r-project.org/high-sierra/R-devel/x86_64/R-devel.tar.gz) (devel) Once downloaded, you can fire up a terminal prompt, head to the root directory (i.e. `cd /`) and run `tar -xvzf path-to-thing-you-just-downloaded` to lay out the contents of the tarball onto the filesystem. You can also use the `.pkg` versions if you prefer a clicky-installer wizard, but these installers will remove any previous versions of the framework (kinda defeating the purpose). You can still use the `.pkg` format by heading over to the command line and using `pkgutil --forget` to prevent said clobbering behavior (as noted in [Section 4.2](https://cran.rstudio.org/doc/manuals/R-admin.html#Uninstalling-under-macOS) of _R Installation and Administration_. For example: ```{bash eval=FALSE} -sudo pkgutil --forget org.r-project.R.el-capitan.fw.pkg \ +sudo pkgutil --forget org.r-project.R.el-capitan.fw.pkg \ # may need to use high-sierra vs el-capitan --forget org.r-project.x86_64.tcltk.x11 \ --forget org.r-project.x86_64.texinfo \ --forget org.r-project.R.el-capitan.GUI.pkg @@ -100,7 +101,7 @@ and the Finder will open up to `~/Downloads` with the target file selected. Since RSwitch is designed to help you work with R on macOS it seemed only fitting to provide some handy links to resources like the R for macOS page, the CRAN R page, RStudio dailies link, etc. They're all available via the fairly obvious sub-menu: -![](rswitch-1.5.0-resources-reorg.png) +![](web-resources.png) and each item will open up in your default web browser. (File an issue if you'd like more links added) @@ -138,13 +139,17 @@ and you can then launch a task-specific browser for each instance you have defin ![](rswitch-1.5.0-rstudio-example.png) -This allows you to keep RStudio Server work separate from your internet browsing, creating a more focused workspace that you never have to worry about accidentally closing. Window size & position are preserved across launches, too. +This allows you to keep RStudio Server work separate from your internet browsing, creating a more focused workspace that you never have to worry about accidentally closing. Window size & position are preserved across launches, too and the keystrokes you are used to in RStudio Desktop on macOS are the same in this task-specific browser. + +File uploads and downloads ("exports") are also now supported. ## Have It Your Way -There's a new minimal preferences system for showing/hiding the dock icon and for enabling background checks for and notifications when new RStudio Dailies are available: +There's a minimal preferences system for showing/hiding the dock icon and for enabling background checks for and notifications when new RStudio Dailies are available. + +![](rswitch-prefs.png) -![](rswitch-1.5.0-prefs.png) +Another (new) preference is "Ensure RStudio opens R/Rmd files". Xcode and other developer-oriented programs seem to love to takeover either `.R` and `.Rmd` (sometimes both) and loading Xcode can take a while. Setting this preference will enable an hourly check for who owns those extensions and forces them back to RStudio in the event they are changed. ## Always On @@ -152,6 +157,48 @@ If you like RSwitch enough to keep it running all the time, just drag the item t ![](users-n-grps.png) +## Taking Command(line) + +There's a new command-line switcher for folks who would rather not interact with a menu to change R versions. `RSwitch.app` comes with `rswitch-cmd` tucked into `/Applications/RSwitch.app/Contents/Resources/`. You can make it easier to type by making a symbolic link in `/usr/local/bin/` (or your preferred path that's on `$PATH`): + +```shell +$ ln -s /Applications/RSwitch.app/Contents/Resources/rswitch-cmd /usr/local/bin/rswitch +``` + +Firing off just `rswitch` will bring up a list of available R installs with an asterisk signifying which one is active: + +```shell +$ rswitch +2.14 (incomplete) +3.5 +3.6 +3.7 +4.0 * +4.1 +``` + +Just call it with the version you want to switch to and you are ready to go (you can also use `--list` or `-l` if you like typing more than you need to): + +```shell +$ rswitch 4.1 +$ rswitch --list +2.14 (incomplete) +3.5 +3.6 +3.7 +4.0 +4.1 * +``` + +You'll receive an error message if the version specified cannot be found: + +```shell +$ rswitch 4.4 +R version 4.4 not found. +``` + +All non-successful operations will set a non-zero exit code in the event you are using the command-line utility in scripts. + ## Getting Help If you're having trouble with RSwitch or have a feature request, head on over to any of the following social coding sites and file an issue: diff --git a/guide/rswitch-1.5.0-prefs.png b/guide/rswitch-1.5.0-prefs.png deleted file mode 100644 index e7b2cbd..0000000 Binary files a/guide/rswitch-1.5.0-prefs.png and /dev/null differ diff --git a/guide/rswitch-1.5.0-resources-reorg.png b/guide/rswitch-1.5.0-resources-reorg.png deleted file mode 100644 index 4c9c865..0000000 Binary files a/guide/rswitch-1.5.0-resources-reorg.png and /dev/null differ diff --git a/guide/rswitch-prefs.png b/guide/rswitch-prefs.png new file mode 100644 index 0000000..6fa4f2e Binary files /dev/null and b/guide/rswitch-prefs.png differ diff --git a/guide/web-resources.png b/guide/web-resources.png new file mode 100644 index 0000000..c34ab5b Binary files /dev/null and b/guide/web-resources.png differ diff --git a/releases/RSwitch-1.7.0.app.zip b/releases/RSwitch-1.7.0.app.zip new file mode 100644 index 0000000..fc71c6a Binary files /dev/null and b/releases/RSwitch-1.7.0.app.zip differ diff --git a/rswitch-cmd/main.swift b/rswitch-cmd/main.swift index 62941fc..b9342a2 100644 --- a/rswitch-cmd/main.swift +++ b/rswitch-cmd/main.swift @@ -49,6 +49,7 @@ struct RSwitch: ParsableCommand { if (!versions.contains(rversion!)) { print("R version " + rversion! + " not found.", to: &outputStream) + Darwin.exit(3) } else { if (rversion! == targetPath) { print("Current R version already points to " + targetPath)