Browse Source

Release

master v1.7.0
boB Rudis 4 years ago
parent
commit
41e68c4b3f
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 4
      NEWS.md
  2. BIN
      RSwitch.xcworkspace/xcuserdata/hrbrmstr.xcuserdatad/UserInterfaceState.xcuserstate
  3. 18
      RSwitch/Swift/Downloaders/DownloadFromRStudioServer.swift
  4. 3
      RSwitch/Swift/Notify.swift
  5. 34
      RSwitch/Swift/RStudioServerSessionWebViewController.swift
  6. 44
      RSwitch/Swift/Utils/Associations.swift
  7. 1
      RSwitch/Swift/Utils/urls.swift
  8. 66
      RSwitch/Swift/exportPopupViewController.swift
  9. 34
      RSwitch/Swift/plotPopupViewController.swift
  10. 64
      guide/_site/index.html
  11. BIN
      guide/_site/r-macos-downloads.png
  12. BIN
      guide/_site/rswitch-prefs.png
  13. 12
      guide/_site/site_libs/header-attrs-2.1/header-attrs.js
  14. 2
      guide/_site/site_libs/navigation-1.1/codefolding.js
  15. BIN
      guide/_site/web-resources.png
  16. 65
      guide/index.Rmd
  17. BIN
      guide/rswitch-1.5.0-prefs.png
  18. BIN
      guide/rswitch-1.5.0-resources-reorg.png
  19. BIN
      guide/rswitch-prefs.png
  20. BIN
      guide/web-resources.png
  21. BIN
      releases/RSwitch-1.7.0.app.zip
  22. 1
      rswitch-cmd/main.swift

4
NEWS.md

@ -1,6 +1,10 @@
# 1.7.0 # 1.7.0
- Added checks for network availability - 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 # 1.4.0

BIN
RSwitch.xcworkspace/xcuserdata/hrbrmstr.xcuserdatad/UserInterfaceState.xcuserstate

Binary file not shown.

18
RSwitch/Swift/Downloaders/DownloadFromRStudioServer.swift

@ -10,50 +10,40 @@ import Foundation
import Cocoa import Cocoa
func download_from_studio_server(fromRS : String, toFS : String) { func download_from_studio_server(fromRS : String, toFS : String) {
NSLog("download from rstudio server")
let rsURL = URL(string: fromRS)! let rsURL = URL(string: fromRS)!
let fsURL = URL(string: toFS)! let fsURL = URL(string: toFS)!
URLSession.shared.configuration.timeoutIntervalForRequest = 300.0 URLSession.shared.configuration.timeoutIntervalForRequest = 300.0
//URLSession.shared.downloadTask(with: <#T##URLRequest#>)
let task = URLSession.shared.downloadTask(with: rsURL) { let task = URLSession.shared.downloadTask(with: rsURL) {
localURL, urlResponse, error in localURL, urlResponse, error in
if (error != nil) { if (error != nil) {
NSLog("dler \(String(describing: error))") NSLog("Error exporting from RStudio Server; \(String(describing: error))")
} else { } else {
if let localURL = localURL { if let localURL = localURL {
NSLog("We've got the data");
if (FileManager.default.fileExists(atPath: fsURL.path)) { if (FileManager.default.fileExists(atPath: fsURL.path)) {
NSLog("Deleting old file")
do { do {
try FileManager.default.removeItem(at: fsURL) try FileManager.default.removeItem(at: fsURL)
} catch { } catch {
NSLog("error deleting old file") NSLog("Error removing file during RStudio Server export; \(error)")
} }
} }
do { do {
NSLog("Trying to move the data from \(localURL) to \(fsURL)");
try FileManager.default.moveItem(at: localURL, to: fsURL) try FileManager.default.moveItem(at: localURL, to: fsURL)
NSWorkspace.shared.openFile( NSWorkspace.shared.openFile(fsURL.deletingLastPathComponent().absoluteString, withApplication: "Finder")
fsURL.deletingLastPathComponent().absoluteString, withApplication: "Finder"
)
NSWorkspace.shared.activateFileViewerSelecting([fsURL]) NSWorkspace.shared.activateFileViewerSelecting([fsURL])
} catch { } catch {
NSLog("Move Error \(error)") NSLog("Error moving RStudio Server export file; \(error)")
} }
} }

3
RSwitch/Swift/Notify.swift

@ -49,13 +49,10 @@ extension AppDelegate : NSUserNotificationCenterDelegate {
} }
func userNotificationCenter(_ center: NSUserNotificationCenter, shouldPresent notification: NSUserNotification) -> Bool { func userNotificationCenter(_ center: NSUserNotificationCenter, shouldPresent notification: NSUserNotification) -> Bool {
print("should present")
return(true) return(true)
} }
func userNotificationCenter(_ center: NSUserNotificationCenter, didActivate notification: NSUserNotification) { func userNotificationCenter(_ center: NSUserNotificationCenter, didActivate notification: NSUserNotification) {
print("did activate")
print(notification)
} }
} }

34
RSwitch/Swift/RStudioServerSessionWebViewController.swift

@ -51,9 +51,6 @@ class RstudioServerSessionWebViewController: NSViewController, NSWindowDelegate
extension RstudioServerSessionWebViewController: WKUIDelegate { extension RstudioServerSessionWebViewController: WKUIDelegate {
func webView(_ webView: WKWebView, runOpenPanelWith parameters: WKOpenPanelParameters, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping ([URL]?) -> Void) { func webView(_ webView: WKWebView, runOpenPanelWith parameters: WKOpenPanelParameters, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping ([URL]?) -> Void) {
NSLog("PANELING!")
print("PANELING!")
let openPanel = NSOpenPanel() let openPanel = NSOpenPanel()
@ -79,9 +76,7 @@ extension RstudioServerSessionWebViewController: WKUIDelegate {
let u = URL(string: navigationAction.request.url!.absoluteString)! let u = URL(string: navigationAction.request.url!.absoluteString)!
if ((u.urlComponents?.path.starts(with: "/export/")) != nil) { 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 exportWindowController = NSStoryboard(name: "Main", bundle: nil).instantiateController(withIdentifier: "exportPopupPanel") as! ExportWebViewController
let exportWV = (exportWindowController.contentViewController as! exportPopupViewController) let exportWV = (exportWindowController.contentViewController as! exportPopupViewController)
@ -89,42 +84,25 @@ extension RstudioServerSessionWebViewController: WKUIDelegate {
exportWV.view.window?.title = navigationAction.request.url!.absoluteString exportWV.view.window?.title = navigationAction.request.url!.absoluteString
exportWV.setupWebView(configuration: configuration) exportWV.setupWebView(configuration: configuration)
//exportWindowController.showWindow(self)
NSLog("Before exportWV.loadWebView")
// exportWV.loadWebView(urlIn: navigationAction.request.url!.absoluteString)
exportWV.loadWebView(urlIn: "") exportWV.loadWebView(urlIn: "")
NSLog("After exportWV.loadWebView")
let urlPath = navigationAction.request.url!.absoluteString let urlPath = navigationAction.request.url!.absoluteString
NSLog("loadWebView: \(urlPath)")
// Check for "/export/" // Check for "/export/"
// If export, then get bring up a Save Panel and then download the file to that location // If export, then get bring up a Save Panel and then download the file to that location
if let url = URL(string: urlPath) { if let url = URL(string: urlPath) {
NSLog("URL path: \(url.path)")
if (url.path.starts(with: "/export")) { if (url.path.starts(with: "/export")) {
NSLog(" Name: " + url.queryParameters["name"]!)
let savePanel = NSSavePanel() let savePanel = NSSavePanel()
savePanel.canCreateDirectories = true savePanel.canCreateDirectories = true
savePanel.nameFieldStringValue = url.queryParameters["name"]! savePanel.nameFieldStringValue = url.queryParameters["name"]!
savePanel.beginSheetModal(for:self.view.window!) { (response) in 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) download_from_studio_server(fromRS: url.absoluteString, toFS: savePanel.url!.absoluteString)
} else {
NSLog("Don't do anything!")
} }
savePanel.close() savePanel.close()
} }

44
RSwitch/Swift/Utils/Associations.swift

@ -12,45 +12,27 @@ import ApplicationServices
class FileAssociationUtils { class FileAssociationUtils {
public static func getHandlers() { // public static func getHandlers() {
//
let workspace = NSWorkspace.shared; // let workspace = NSWorkspace.shared;
//
let setResR : String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, "R" as CFString, nil)?.takeRetainedValue() as String? ?? ""; // 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? ?? "";
// let rAppUrl : URL = (workspace.urlForApplication(withBundleIdentifier: handlerR))!.appendingPathComponent("Contents/Info.plist");
let handlerR : String = LSCopyDefaultRoleHandlerForContentType(setResR as CFString, LSRolesMask.all)?.takeRetainedValue() as String? ?? ""; // let rAppDict : NSDictionary = NSDictionary(contentsOf: rAppUrl)!;
NSLog("Bundle ID of handler for .R files is: [" + handlerR + "]"); // 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 rAppUrl : URL = (workspace.urlForApplication(withBundleIdentifier: handlerR))!.appendingPathComponent("Contents/Info.plist"); // let rmdAppUrl : URL = (workspace.urlForApplication(withBundleIdentifier: handlerRmd))!.appendingPathComponent("Contents/Info.plist");
NSLog("The Info.plist for the app that handles .R files is: " + rAppUrl.absoluteString); // let rmdAppDict : NSDictionary = NSDictionary(contentsOf: rmdAppUrl)!;
// }
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 setHandlers() { public static func setHandlers() {
let setResR : String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, "R" as CFString, nil)?.takeRetainedValue() as String? ?? ""; 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); LSSetDefaultRoleHandlerForContentType(setResR as CFString, LSRolesMask.all, "org.rstudio.RStudio" as CFString);
let setResRmd : String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, "Rmd" as CFString, nil)?.takeRetainedValue() as String? ?? ""; 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); LSSetDefaultRoleHandlerForContentType(setResRmd as CFString, LSRolesMask.all, "org.rstudio.RStudio" as CFString);

1
RSwitch/Swift/Utils/urls.swift

@ -18,7 +18,6 @@ class QueryParameters {
let queryItems: [URLQueryItem] let queryItems: [URLQueryItem]
init(url: URL?) { init(url: URL?) {
queryItems = URLComponents(string: url?.absoluteString ?? "")?.queryItems ?? [] queryItems = URLComponents(string: url?.absoluteString ?? "")?.queryItems ?? []
print(queryItems)
} }
subscript(name: String) -> String? { subscript(name: String) -> String? {
return queryItems.first(where: { $0.name == name })?.value return queryItems.first(where: { $0.name == name })?.value

66
RSwitch/Swift/exportPopupViewController.swift

@ -33,41 +33,29 @@ class exportPopupViewController: NSViewController {
func loadWebView(urlIn: String) { func loadWebView(urlIn: String) {
urlPath = urlIn // 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
// 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 let url = URL(string: urlPath) { // if (url.path.starts(with: "/export")) {
//
NSLog("URL path: \(url.path)") // let savePanel = NSSavePanel()
//
if (url.path.starts(with: "/export")) { // savePanel.canCreateDirectories = true
// savePanel.nameFieldStringValue = url.queryParameters["name"]!
NSLog(" Name: " + url.queryParameters["name"]!) // savePanel.beginSheetModal(for:self.view.window!) { (response) in
// if (response == NSApplication.ModalResponse.OK) {
let savePanel = NSSavePanel() // download_from_studio_server(fromRS: url.absoluteString, toFS: savePanel.url!.absoluteString)
// }
savePanel.canCreateDirectories = true // savePanel.close()
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()
}
}
}
} }
@ -88,13 +76,9 @@ extension exportPopupViewController: WKUIDelegate {
extension exportPopupViewController: WKNavigationDelegate { extension exportPopupViewController: WKNavigationDelegate {
open func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { open func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { }
print("Export DID START \(String(describing: webView.url))")
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { }
print("Export DID FINISH \(String(describing: webView.url))")
}
} }

34
RSwitch/Swift/plotPopupViewController.swift

@ -33,25 +33,13 @@ class plotPopupViewController: NSViewController {
urlPath = urlIn 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) { if let url = URL(string: urlPath) {
let urlRequest = URLRequest(url: url) let urlRequest = URLRequest(url: url)
NSLog("URL path: " + url.path)
if (url.path.starts(with: "/export")) { if (url.path.starts(with: "/export")) {
NSLog(" Name: " + url.queryParameters["name"]!)
DispatchQueue.main.async {
self.webView.removeFromSuperview()
}
} else { } else {
webView.load(urlRequest) webView.load(urlRequest)
@ -75,20 +63,6 @@ extension plotPopupViewController: WKUIDelegate {
func webView(_ webView: WKWebView, runOpenPanelWith parameters: WKOpenPanelParameters, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping ([URL]?) -> Void) { 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 { extension plotPopupViewController: WKNavigationDelegate {
open func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { open func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {}
print("DID START")
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { }
print("DID FINISH")
}
} }

64
guide/_site/index.html

@ -1,11 +1,10 @@
<!DOCTYPE html> <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="pandoc" /> <meta name="generator" content="pandoc" />
<meta http-equiv="X-UA-Compatible" content="IE=EDGE" /> <meta http-equiv="X-UA-Compatible" content="IE=EDGE" />
@ -14,6 +13,7 @@
<title>Using RSwitch</title> <title>Using RSwitch</title>
<script src="site_libs/header-attrs-2.1/header-attrs.js"></script>
<script src="site_libs/jquery-1.11.3/jquery.min.js"></script> <script src="site_libs/jquery-1.11.3/jquery.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="site_libs/bootstrap-3.3.5/css/darkly.min.css" rel="stylesheet" /> <link href="site_libs/bootstrap-3.3.5/css/darkly.min.css" rel="stylesheet" />
@ -87,7 +87,6 @@ code {
} }
img { img {
max-width:100%; max-width:100%;
height: auto;
} }
.tabbed-pane { .tabbed-pane {
padding-top: 12px; padding-top: 12px;
@ -236,6 +235,7 @@ $(document).ready(function () {
border: none; border: none;
display: inline-block; display: inline-block;
border-radius: 4px; border-radius: 4px;
background-color: transparent;
} }
.tabset-dropdown > .nav-tabs.nav-tabs-open > li { .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 { .toc-content {
padding-left: 30px; padding-left: 30px;
@ -376,8 +382,9 @@ div.tocify {
<h2>Credits</h2> <h2>Credits</h2>
<p>Many thanks to the following folks for their contributions to the project to help make RSwitch better for everyone:</p> <p>Many thanks to the following folks for their contributions to the project to help make RSwitch better for everyone:</p>
<ul> <ul>
<li><a href="https://github.com/guiastrennec">Benjamin Guiastrennec</a> for suggesting improvements to the documentation regarding how to use the installer packages from the <a href="https://mac.r-project.org/">R for macOS Developer’s Page</a> without clobbering existing R Framework installs.</li> <li><a href="https://github.com/guiastrennec">Benjamin Guiastrennec</a> for suggesting improvements to the documentation regarding how to use the installer packages from the <a href="https://mac.r-project.org/">R for macOS Developer’s Page</a> without clobbering existing R Framework installs and also for encouraging support for RStudio Sever file uploads and exports.</li>
<li><a href="https://github.com/xvrdm">Xavier Adam</a> for <a href="https://github.com/hrbrmstr/RSwitch/pull/4">adding books to the RSwitch library</a>.</li> <li><a href="https://github.com/xvrdm">Xavier Adam</a> for <a href="https://github.com/hrbrmstr/RSwitch/pull/4">adding books to the RSwitch library</a>.</li>
<li><a href="https://github.com/pat-s">Patrick Schratz</a> for encourging the development of a command-line switcher to make it easier to use in automation (and sans mouse).</li>
</ul> </ul>
</div> </div>
<div id="basiccore-usage" class="section level2"> <div id="basiccore-usage" class="section level2">
@ -391,6 +398,8 @@ div.tocify {
├── 3.5 ├── 3.5
├── 3.6 ├── 3.6
├── 3.7 ├── 3.7
├── 4.0
├── 4.1
└── Current</code></pre> └── Current</code></pre>
<p>The “R Framework” is, well, <em>R</em> 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 <code>3.5</code> version of the R Framework:</p> <p>The “R Framework” is, well, <em>R</em> 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 <code>3.5</code> version of the R Framework:</p>
<pre class="r"><code>fs::dir_tree(path = &quot;/Library/Frameworks/R.framework/Versions/3.5&quot;, recurse = 1)</code></pre> <pre class="r"><code>fs::dir_tree(path = &quot;/Library/Frameworks/R.framework/Versions/3.5&quot;, recurse = 1)</code></pre>
@ -456,17 +465,16 @@ div.tocify {
<li><code>Resources@ -&gt; Versions/Current/Resources</code></li> <li><code>Resources@ -&gt; Versions/Current/Resources</code></li>
<li><code>Versions/</code></li> <li><code>Versions/</code></li>
</ul> </ul>
<p>For the most control, you can install a coexisting version of R <strong>oldrel</strong>-1, <strong>oldrel</strong> (as of the date this document was created those would be R 3.4 and R 3.5), current <strong>release</strong> (R 3.6) and <strong>devel</strong> (3.7) by hand by going to the <a href="https://mac.r-project.org/">R for macOS Developer’s Page</a> and downloading the <code>tar.gz</code> version of those distributions:</p> <p>For the most control, you can install a coexisting version of R <strong>oldrel</strong>-1, <strong>oldrel</strong> (as of the date this document was created those would be R 3.5 and R 3.6), current <strong>release</strong> (R 4.0) and <strong>devel</strong> (4.1) by hand by going to <a href="https://mac.r-project.org/">R for macOS</a> and downloading the <code>tar.gz</code> version of those distributions:</p>
<p><img src="r-macos-downloads.png" /></p> <p><img src="r-macos-downloads.png" /></p>
<p>Here are direct <code>https</code> links to the tarballs:</p> <p>Here are direct <code>https</code> links to the tarballs:</p>
<ul> <ul>
<li><a href="https://mac.r-project.org/mavericks/R-3.4-branch/R-3.4-branch-mavericks-sa-x86_64.tar.gz">R 3.4</a> (oldrel-1)</li> <li><a href="https://mac.r-project.org/el-capitan/R-3.6-branch/R-3.6-branch-el-capitan-sa-x86_64.tar.gz">R 3.6</a> (oldrel)</li>
<li><a href="https://mac.r-project.org/el-capitan/R-3.5-branch/R-3.5-branch-el-capitan-sa-x86_64.tar.gz">R 3.5</a> (oldrel)</li> <li><a href="https://mac.r-project.org/high-sierra/R-4.0-branch/x86_64/R-4.0-branch.tar.gz">R 4.0</a> (current)</li>
<li><a href="https://mac.r-project.org/el-capitan/R-3.6-branch/R-3.6-branch-el-capitan-sa-x86_64.tar.gz">R 3.6</a> (current)</li> <li><a href="https://mac.r-project.org/high-sierra/R-devel/x86_64/R-devel.tar.gz">R 4.1</a> (devel)</li>
<li><a href="https://mac.r-project.org/el-capitan/R-devel/R-devel-el-capitan-sa-x86_64.tar.gz">R 3.7</a> (devel)</li>
</ul> </ul>
<p>Once downloaded, you can fire up a terminal prompt, head to the root directory (i.e. <code>cd /</code>) and run <code>tar -xvzf path-to-thing-you-just-downloaded</code> to lay out the contents of the tarball onto the filesystem. You can also use the <code>.pkg</code> 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 <code>.pkg</code> format by heading over to the command line and using <code>pkgutil --forget</code> to prevent said clobbering behavior (as noted in <a href="https://cran.rstudio.org/doc/manuals/R-admin.html#Uninstalling-under-macOS">Section 4.2</a> of <em>R Installation and Administration</em>. For example:</p> <p>Once downloaded, you can fire up a terminal prompt, head to the root directory (i.e. <code>cd /</code>) and run <code>tar -xvzf path-to-thing-you-just-downloaded</code> to lay out the contents of the tarball onto the filesystem. You can also use the <code>.pkg</code> 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 <code>.pkg</code> format by heading over to the command line and using <code>pkgutil --forget</code> to prevent said clobbering behavior (as noted in <a href="https://cran.rstudio.org/doc/manuals/R-admin.html#Uninstalling-under-macOS">Section 4.2</a> of <em>R Installation and Administration</em>. For example:</p>
<pre class="bash"><code>sudo pkgutil --forget org.r-project.R.el-capitan.fw.pkg \ <pre class="bash"><code>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.tcltk.x11 \
--forget org.r-project.x86_64.texinfo \ --forget org.r-project.x86_64.texinfo \
--forget org.r-project.R.el-capitan.GUI.pkg</code></pre> --forget org.r-project.R.el-capitan.GUI.pkg</code></pre>
@ -491,7 +499,7 @@ div.tocify {
<div id="getting-help-or-resources-from-the-internet" class="section level2"> <div id="getting-help-or-resources-from-the-internet" class="section level2">
<h2>Getting Help or Resources from the Internet</h2> <h2>Getting Help or Resources from the Internet</h2>
<p>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:</p> <p>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:</p>
<p><img src="rswitch-1.5.0-resources-reorg.png" /></p> <p><img src="web-resources.png" /></p>
<p>and each item will open up in your default web browser. (File an issue if you’d like more links added)</p> <p>and each item will open up in your default web browser. (File an issue if you’d like more links added)</p>
</div> </div>
<div id="even-moar-switching" class="section level2"> <div id="even-moar-switching" class="section level2">
@ -518,18 +526,46 @@ div.tocify {
<p><img src="rswitch-1.5.0-rstudio-server-new.png" /></p> <p><img src="rswitch-1.5.0-rstudio-server-new.png" /></p>
<p>and you can then launch a task-specific browser for each instance you have defined:</p> <p>and you can then launch a task-specific browser for each instance you have defined:</p>
<p><img src="rswitch-1.5.0-rstudio-example.png" /></p> <p><img src="rswitch-1.5.0-rstudio-example.png" /></p>
<p>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 &amp; position are preserved across launches, too.</p> <p>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 &amp; 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.</p>
<p>File uploads and downloads (“exports”) are also now supported.</p>
</div> </div>
<div id="have-it-your-way" class="section level2"> <div id="have-it-your-way" class="section level2">
<h2>Have It Your Way</h2> <h2>Have It Your Way</h2>
<p>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:</p> <p>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.</p>
<p><img src="rswitch-1.5.0-prefs.png" /></p> <p><img src="rswitch-prefs.png" /></p>
<p>Another (new) preference is “Ensure RStudio opens R/Rmd files”. Xcode and other developer-oriented programs seem to love to takeover either <code>.R</code> and <code>.Rmd</code> (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.</p>
</div> </div>
<div id="always-on" class="section level2"> <div id="always-on" class="section level2">
<h2>Always On</h2> <h2>Always On</h2>
<p>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 &amp; Groups” pane of “System Preferences”</p> <p>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 &amp; Groups” pane of “System Preferences”</p>
<p><img src="users-n-grps.png" /></p> <p><img src="users-n-grps.png" /></p>
</div> </div>
<div id="taking-commandline" class="section level2">
<h2>Taking Command(line)</h2>
<p>There’s a new command-line switcher for folks who would rather not interact with a menu to change R versions. <code>RSwitch.app</code> comes with <code>rswitch-cmd</code> tucked into <code>/Applications/RSwitch.app/Contents/Resources/</code>. You can make it easier to type by making a symbolic link in <code>/usr/local/bin/</code> (or your preferred path that’s on <code>$PATH</code>):</p>
<pre class="shell"><code>$ ln -s /Applications/RSwitch.app/Contents/Resources/rswitch-cmd /usr/local/bin/rswitch</code></pre>
<p>Firing off just <code>rswitch</code> will bring up a list of available R installs with an asterisk signifying which one is active:</p>
<pre class="shell"><code>$ rswitch
2.14 (incomplete)
3.5
3.6
3.7
4.0 *
4.1</code></pre>
<p>Just call it with the version you want to switch to and you are ready to go (you can also use <code>--list</code> or <code>-l</code> if you like typing more than you need to):</p>
<pre class="shell"><code>$ rswitch 4.1
$ rswitch --list
2.14 (incomplete)
3.5
3.6
3.7
4.0
4.1 *</code></pre>
<p>You’ll receive an error message if the version specified cannot be found:</p>
<pre class="shell"><code>$ rswitch 4.4
R version 4.4 not found.</code></pre>
<p>All non-successful operations will set a non-zero exit code in the event you are using the command-line utility in scripts.</p>
</div>
<div id="getting-help" class="section level2"> <div id="getting-help" class="section level2">
<h2>Getting Help</h2> <h2>Getting Help</h2>
<p>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:</p> <p>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:</p>

BIN
guide/_site/r-macos-downloads.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

After

Width:  |  Height:  |  Size: 346 KiB

BIN
guide/_site/rswitch-prefs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

12
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);
}
});

2
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 // create a collapsable div to wrap the code in
var div = $('<div class="collapse r-code-collapse"></div>'); var div = $('<div class="collapse r-code-collapse"></div>');
if (show) if (show || $(this)[0].classList.contains('fold-show'))
div.addClass('in'); div.addClass('in');
var id = 'rcode-643E0F36' + currentIndex++; var id = 'rcode-643E0F36' + currentIndex++;
div.attr('id', id); div.attr('id', id);

BIN
guide/_site/web-resources.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 KiB

65
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: 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). - [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 ## 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: 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 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/el-capitan/R-3.6-branch/R-4.0-branch-el-capitan-sa-x86_64.tar.gz) (current) - [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/el-capitan/R-devel/R-devel-el-capitan-sa-x86_64.tar.gz) (devel) - [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: 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} ```{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.tcltk.x11 \
--forget org.r-project.x86_64.texinfo \ --forget org.r-project.x86_64.texinfo \
--forget org.r-project.R.el-capitan.GUI.pkg --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: 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) 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) ![](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 ## 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 ## 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) ![](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 ## 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: 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:

BIN
guide/rswitch-1.5.0-prefs.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 355 KiB

BIN
guide/rswitch-1.5.0-resources-reorg.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 690 KiB

BIN
guide/rswitch-prefs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

BIN
guide/web-resources.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 KiB

BIN
releases/RSwitch-1.7.0.app.zip

Binary file not shown.

1
rswitch-cmd/main.swift

@ -49,6 +49,7 @@ struct RSwitch: ParsableCommand {
if (!versions.contains(rversion!)) { if (!versions.contains(rversion!)) {
print("R version " + rversion! + " not found.", to: &outputStream) print("R version " + rversion! + " not found.", to: &outputStream)
Darwin.exit(3)
} else { } else {
if (rversion! == targetPath) { if (rversion! == targetPath) {
print("Current R version already points to " + targetPath) print("Current R version already points to " + targetPath)

Loading…
Cancel
Save