A small menubar app that allows you to switch between R versions quickly (if you have multiple versions of R framework installed). https://rud.is/rswitch
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

150 lines
4.6 KiB

2 years ago
import Cocoa
2 years ago
// Show an informational alert
public func infoAlert(_ message: String, _ extra: String? = nil, style: NSAlert.Style = NSAlert.Style.informational) {
let alert = NSAlert()
alert.messageText = message
if extra != nil { alert.informativeText = extra! }
alert.alertStyle = style
alert.runModal()
}
2 years ago
2 years ago
// Show an informational alert and then quit
public func quitAlert(_ message: String, _ extra: String? = nil) {
infoAlert(message, "The application will now quit.", style: NSAlert.Style.critical)
NSApp.terminate(nil)
}
2 years ago
2 years ago
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
// Where the official R installs go
let macos_r_framework_dir = "/Library/Frameworks/R.framework/Versions"
// Get the bar setup
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
let statusMenu = NSMenu()
let quitItem = NSMenuItem(title: NSLocalizedString("Quit", comment: "Quit menu item"), action: #selector(NSApp.terminate), keyEquivalent: "q")
override init() {
super.init()
statusMenu.delegate = self
// dial by IconMark from the Noun Project
statusItem.button?.image = #imageLiteral(resourceName: "RSwitch")
statusItem.menu = statusMenu
}
2 years ago
func applicationDidFinishLaunching(_ aNotification: Notification) {
2 years ago
// Insert code here to initialize app
2 years ago
}
2 years ago
2 years ago
func applicationWillTerminate(_ aNotification: Notification) {
2 years ago
// Insert code here to tear down app
2 years ago
}
2 years ago
// The core worker function. Receives the basename of the selected directory
// then removes the current alias and creates the new one.
@objc func handleSwitch(_ sender: NSMenuItem?) {
let fm = FileManager.default;
let title = sender?.title
do {
try fm.removeItem(atPath: macos_r_framework_dir + "/" + "Current")
} catch {
infoAlert("Failed to remove 'Current' alias", macos_r_framework_dir + "/" + "Current")
}
do {
try fm.createSymbolicLink(
at: NSURL(fileURLWithPath: macos_r_framework_dir + "/" + "Current") as URL,
withDestinationURL: NSURL(fileURLWithPath: macos_r_framework_dir + "/" + title!) as URL
)
} catch {
infoAlert("Failed to create alias for " + macos_r_framework_dir + "/" + title!)
}
}
// Show the framework dir in a new Finder window
@objc func openFrameworksDir(_ sender: NSMenuItem?) {
NSWorkspace.shared.openFile(macos_r_framework_dir, withApplication: "Finder")
}
2 years ago
}
2 years ago
extension AppDelegate: NSMenuDelegate {
func menuWillOpen(_ menu: NSMenu) {
if (menu != self.statusMenu) { return }
// clear the menu
menu.removeAllItems()
// add selection to open frameworks dir in Finder
menu.addItem(NSMenuItem(title: "Open R Frameworks Directory", action: #selector(openFrameworksDir), keyEquivalent: "" ))
menu.addItem(NSMenuItem.separator())
// populate installed versions
let fm = FileManager.default
var targetPath:String? = nil
do {
// gets a directory listing
let entries = try fm.contentsOfDirectory(atPath: macos_r_framework_dir)
// retrieves all versions (excludes hidden files and the Current alias
let versions = entries.sorted().filter { !($0.hasPrefix(".")) && !($0 == "Current") }
// if there was a Current alias (prbly shld alert if not)
if ((entries.filter { $0 == "Current" })[0] == "Current") {
// get where Current points to
let furl = NSURL(fileURLWithPath: macos_r_framework_dir + "/" + "Current")
if (furl.fileReferenceURL() != nil) {
do {
let fdat = try NSURL(resolvingAliasFileAt: furl as URL, options: [])
targetPath = fdat.lastPathComponent!
} catch {
targetPath = furl.path
}
}
// populate menu items with all installed R versions, ensuring we
// put a checkbox next to the one that is Current
for version in versions {
let item = NSMenuItem(title: version, action: #selector(handleSwitch), keyEquivalent: "")
item.isEnabled = true
if (version == targetPath) { item.state = NSControl.StateValue.on }
item.representedObject = version
menu.addItem(item)
}
}
} catch {
quitAlert("Failed to list contents of R framework directory. You either do not have R installed or have incorrect permissions set on " + macos_r_framework_dir)
}
// Add a Quit item
menu.addItem(NSMenuItem.separator())
menu.addItem(quitItem)
}
}