Browse Source

v1.4.1

tags/v1.4.1 v1.4.1
boB Rudis 5 years ago
parent
commit
e6de796402
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 8
      Pods/Pods.xcodeproj/project.pbxproj
  2. 42
      RSwitch.xcodeproj/project.pbxproj
  3. 14
      RSwitch/Base.lproj/Main.storyboard
  4. 0
      RSwitch/Swift/AboutViewController.swift
  5. 0
      RSwitch/Swift/AppAlerts/AppAlerts.swift
  6. 0
      RSwitch/Swift/AppDelegate.swift
  7. 4
      RSwitch/Swift/Downloaders/DownloadRStudio.swift
  8. 8
      RSwitch/Swift/Downloaders/DownloadTarball.swift
  9. 17
      RSwitch/Swift/HandleRSwitch.swift
  10. 0
      RSwitch/Swift/HandleSwitchTo.swift
  11. 0
      RSwitch/Swift/HandleUpdate.swift
  12. 2
      RSwitch/Swift/Menu.swift
  13. 8
      RSwitch/Swift/MenuActions/BrowseMenuAction.swift
  14. 0
      RSwitch/Swift/Notify.swift
  15. 0
      RSwitch/Swift/String+Version/Bundle.swift
  16. 0
      RSwitch/Swift/String+Version/String+Version.swift
  17. 0
      RSwitch/Swift/Utils/Globals.swift
  18. 0
      RSwitch/Swift/Utils/Launch.swift
  19. 90
      RSwitch/Swift/Utils/RVersions.swift
  20. 56
      RSwitch/Swift/Utils/Running.swift
  21. 0
      RSwitch/Swift/ViewController.swift
  22. 106
      RSwitch/swift/Utils/Versions+RunningUtils.swift

8
Pods/Pods.xcodeproj/project.pbxproj

@ -525,6 +525,7 @@
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
@ -548,6 +549,7 @@
PODS_ROOT = "$(SRCROOT)"; PODS_ROOT = "$(SRCROOT)";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx; SDKROOT = macosx;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
@ -565,6 +567,7 @@
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
@ -585,6 +588,7 @@
MODULEMAP_FILE = "Target Support Files/SwiftSoup/SwiftSoup.modulemap"; MODULEMAP_FILE = "Target Support Files/SwiftSoup/SwiftSoup.modulemap";
PRODUCT_MODULE_NAME = SwiftSoup; PRODUCT_MODULE_NAME = SwiftSoup;
PRODUCT_NAME = SwiftSoup; PRODUCT_NAME = SwiftSoup;
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx; SDKROOT = macosx;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
@ -728,6 +732,7 @@
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
@ -748,6 +753,7 @@
MODULEMAP_FILE = "Target Support Files/SwiftSoup/SwiftSoup.modulemap"; MODULEMAP_FILE = "Target Support Files/SwiftSoup/SwiftSoup.modulemap";
PRODUCT_MODULE_NAME = SwiftSoup; PRODUCT_MODULE_NAME = SwiftSoup;
PRODUCT_NAME = SwiftSoup; PRODUCT_NAME = SwiftSoup;
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx; SDKROOT = macosx;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
@ -768,6 +774,7 @@
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
@ -791,6 +798,7 @@
PODS_ROOT = "$(SRCROOT)"; PODS_ROOT = "$(SRCROOT)";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx; SDKROOT = macosx;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";

42
RSwitch.xcodeproj/project.pbxproj

@ -8,7 +8,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
01073F0F2311AE2E007162C9 /* String+Version.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F0E2311AE2E007162C9 /* String+Version.swift */; }; 01073F0F2311AE2E007162C9 /* String+Version.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F0E2311AE2E007162C9 /* String+Version.swift */; };
01073F132311E1CF007162C9 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F122311E1CF007162C9 /* Utils.swift */; }; 01073F132311E1CF007162C9 /* Globals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F122311E1CF007162C9 /* Globals.swift */; };
01073F152311E370007162C9 /* Notify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F142311E370007162C9 /* Notify.swift */; }; 01073F152311E370007162C9 /* Notify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F142311E370007162C9 /* Notify.swift */; };
01073F172311E397007162C9 /* Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F162311E397007162C9 /* Menu.swift */; }; 01073F172311E397007162C9 /* Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F162311E397007162C9 /* Menu.swift */; };
01073F192311E3B8007162C9 /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F182311E3B8007162C9 /* Bundle.swift */; }; 01073F192311E3B8007162C9 /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F182311E3B8007162C9 /* Bundle.swift */; };
@ -20,10 +20,11 @@
018A8C3B2312C7BC0006E87D /* libprocInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 018A8C3A2312C7BC0006E87D /* libprocInfo.a */; }; 018A8C3B2312C7BC0006E87D /* libprocInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 018A8C3A2312C7BC0006E87D /* libprocInfo.a */; };
018A8C3F2312CB480006E87D /* procHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 018A8C3E2312CB480006E87D /* procHelper.m */; }; 018A8C3F2312CB480006E87D /* procHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 018A8C3E2312CB480006E87D /* procHelper.m */; };
018A8C412312F4940006E87D /* HandleSwitchTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 018A8C402312F4940006E87D /* HandleSwitchTo.swift */; }; 018A8C412312F4940006E87D /* HandleSwitchTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 018A8C402312F4940006E87D /* HandleSwitchTo.swift */; };
0197554A231BD919003FAD7B /* RVersions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01975549231BD919003FAD7B /* RVersions.swift */; };
0198B99E23196689003F7578 /* BrowseMenuAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198B99D23196689003F7578 /* BrowseMenuAction.swift */; }; 0198B99E23196689003F7578 /* BrowseMenuAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198B99D23196689003F7578 /* BrowseMenuAction.swift */; };
0198B9A0231970ED003F7578 /* AppAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198B99F231970ED003F7578 /* AppAlerts.swift */; }; 0198B9A0231970ED003F7578 /* AppAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198B99F231970ED003F7578 /* AppAlerts.swift */; };
0198B9A823197CBA003F7578 /* LaunchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198B9A723197CBA003F7578 /* LaunchUtils.swift */; }; 0198B9A823197CBA003F7578 /* Launch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198B9A723197CBA003F7578 /* Launch.swift */; };
0198B9AA23197D3A003F7578 /* Versions+RunningUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198B9A923197D3A003F7578 /* Versions+RunningUtils.swift */; }; 0198B9AA23197D3A003F7578 /* Running.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198B9A923197D3A003F7578 /* Running.swift */; };
01F3EF0C230E635300DF5DF9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F3EF0B230E635300DF5DF9 /* AppDelegate.swift */; }; 01F3EF0C230E635300DF5DF9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F3EF0B230E635300DF5DF9 /* AppDelegate.swift */; };
01F3EF0E230E635300DF5DF9 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F3EF0D230E635300DF5DF9 /* ViewController.swift */; }; 01F3EF0E230E635300DF5DF9 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F3EF0D230E635300DF5DF9 /* ViewController.swift */; };
01F3EF10230E635500DF5DF9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 01F3EF0F230E635500DF5DF9 /* Assets.xcassets */; }; 01F3EF10230E635500DF5DF9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 01F3EF0F230E635500DF5DF9 /* Assets.xcassets */; };
@ -33,7 +34,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
01073F0E2311AE2E007162C9 /* String+Version.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Version.swift"; sourceTree = "<group>"; }; 01073F0E2311AE2E007162C9 /* String+Version.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Version.swift"; sourceTree = "<group>"; };
01073F122311E1CF007162C9 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; }; 01073F122311E1CF007162C9 /* Globals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Globals.swift; sourceTree = "<group>"; };
01073F142311E370007162C9 /* Notify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notify.swift; sourceTree = "<group>"; }; 01073F142311E370007162C9 /* Notify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notify.swift; sourceTree = "<group>"; };
01073F162311E397007162C9 /* Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menu.swift; sourceTree = "<group>"; }; 01073F162311E397007162C9 /* Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menu.swift; sourceTree = "<group>"; };
01073F182311E3B8007162C9 /* Bundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = "<group>"; }; 01073F182311E3B8007162C9 /* Bundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = "<group>"; };
@ -49,10 +50,11 @@
018A8C3D2312CB480006E87D /* procHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = procHelper.h; sourceTree = "<group>"; }; 018A8C3D2312CB480006E87D /* procHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = procHelper.h; sourceTree = "<group>"; };
018A8C3E2312CB480006E87D /* procHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = procHelper.m; sourceTree = "<group>"; }; 018A8C3E2312CB480006E87D /* procHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = procHelper.m; sourceTree = "<group>"; };
018A8C402312F4940006E87D /* HandleSwitchTo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandleSwitchTo.swift; sourceTree = "<group>"; }; 018A8C402312F4940006E87D /* HandleSwitchTo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandleSwitchTo.swift; sourceTree = "<group>"; };
01975549231BD919003FAD7B /* RVersions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RVersions.swift; sourceTree = "<group>"; };
0198B99D23196689003F7578 /* BrowseMenuAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowseMenuAction.swift; sourceTree = "<group>"; }; 0198B99D23196689003F7578 /* BrowseMenuAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowseMenuAction.swift; sourceTree = "<group>"; };
0198B99F231970ED003F7578 /* AppAlerts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAlerts.swift; sourceTree = "<group>"; }; 0198B99F231970ED003F7578 /* AppAlerts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAlerts.swift; sourceTree = "<group>"; };
0198B9A723197CBA003F7578 /* LaunchUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchUtils.swift; sourceTree = "<group>"; }; 0198B9A723197CBA003F7578 /* Launch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Launch.swift; sourceTree = "<group>"; };
0198B9A923197D3A003F7578 /* Versions+RunningUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Versions+RunningUtils.swift"; sourceTree = "<group>"; }; 0198B9A923197D3A003F7578 /* Running.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Running.swift; sourceTree = "<group>"; };
01F3EF08230E635300DF5DF9 /* RSwitch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RSwitch.app; sourceTree = BUILT_PRODUCTS_DIR; }; 01F3EF08230E635300DF5DF9 /* RSwitch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RSwitch.app; sourceTree = BUILT_PRODUCTS_DIR; };
01F3EF0B230E635300DF5DF9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 01F3EF0B230E635300DF5DF9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
01F3EF0D230E635300DF5DF9 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; }; 01F3EF0D230E635300DF5DF9 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
@ -77,7 +79,7 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
01073F232311E859007162C9 /* swift */ = { 01073F232311E859007162C9 /* Swift */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
0198B9A1231970F5003F7578 /* AppAlerts */, 0198B9A1231970F5003F7578 /* AppAlerts */,
@ -94,7 +96,7 @@
01073F142311E370007162C9 /* Notify.swift */, 01073F142311E370007162C9 /* Notify.swift */,
01F3EF0D230E635300DF5DF9 /* ViewController.swift */, 01F3EF0D230E635300DF5DF9 /* ViewController.swift */,
); );
path = swift; path = Swift;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
018A8C342312C6510006E87D /* ObjC */ = { 018A8C342312C6510006E87D /* ObjC */ = {
@ -154,9 +156,10 @@
0198B9A623197C8E003F7578 /* Utils */ = { 0198B9A623197C8E003F7578 /* Utils */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
01073F122311E1CF007162C9 /* Utils.swift */, 01073F122311E1CF007162C9 /* Globals.swift */,
0198B9A723197CBA003F7578 /* LaunchUtils.swift */, 0198B9A723197CBA003F7578 /* Launch.swift */,
0198B9A923197D3A003F7578 /* Versions+RunningUtils.swift */, 01975549231BD919003FAD7B /* RVersions.swift */,
0198B9A923197D3A003F7578 /* Running.swift */,
); );
path = Utils; path = Utils;
sourceTree = "<group>"; sourceTree = "<group>";
@ -184,7 +187,7 @@
children = ( children = (
016750FB2319A7A4009E2FD6 /* RSwitch.entitlements */, 016750FB2319A7A4009E2FD6 /* RSwitch.entitlements */,
018A8C342312C6510006E87D /* ObjC */, 018A8C342312C6510006E87D /* ObjC */,
01073F232311E859007162C9 /* swift */, 01073F232311E859007162C9 /* Swift */,
01F3EF0F230E635500DF5DF9 /* Assets.xcassets */, 01F3EF0F230E635500DF5DF9 /* Assets.xcassets */,
01F3EF11230E635500DF5DF9 /* Main.storyboard */, 01F3EF11230E635500DF5DF9 /* Main.storyboard */,
01F3EF14230E635500DF5DF9 /* Info.plist */, 01F3EF14230E635500DF5DF9 /* Info.plist */,
@ -330,18 +333,19 @@
01073F1F2311E67D007162C9 /* HandleUpdate.swift in Sources */, 01073F1F2311E67D007162C9 /* HandleUpdate.swift in Sources */,
01073F1B2311E613007162C9 /* DownloadTarball.swift in Sources */, 01073F1B2311E613007162C9 /* DownloadTarball.swift in Sources */,
018A8C412312F4940006E87D /* HandleSwitchTo.swift in Sources */, 018A8C412312F4940006E87D /* HandleSwitchTo.swift in Sources */,
0198B9AA23197D3A003F7578 /* Versions+RunningUtils.swift in Sources */, 0198B9AA23197D3A003F7578 /* Running.swift in Sources */,
0178970D230ED25100F8F5BC /* AboutViewController.swift in Sources */, 0178970D230ED25100F8F5BC /* AboutViewController.swift in Sources */,
01073F192311E3B8007162C9 /* Bundle.swift in Sources */, 01073F192311E3B8007162C9 /* Bundle.swift in Sources */,
0197554A231BD919003FAD7B /* RVersions.swift in Sources */,
01073F152311E370007162C9 /* Notify.swift in Sources */, 01073F152311E370007162C9 /* Notify.swift in Sources */,
01073F1D2311E64E007162C9 /* DownloadRStudio.swift in Sources */, 01073F1D2311E64E007162C9 /* DownloadRStudio.swift in Sources */,
01073F172311E397007162C9 /* Menu.swift in Sources */, 01073F172311E397007162C9 /* Menu.swift in Sources */,
01F3EF0E230E635300DF5DF9 /* ViewController.swift in Sources */, 01F3EF0E230E635300DF5DF9 /* ViewController.swift in Sources */,
01F3EF0C230E635300DF5DF9 /* AppDelegate.swift in Sources */, 01F3EF0C230E635300DF5DF9 /* AppDelegate.swift in Sources */,
01073F0F2311AE2E007162C9 /* String+Version.swift in Sources */, 01073F0F2311AE2E007162C9 /* String+Version.swift in Sources */,
0198B9A823197CBA003F7578 /* LaunchUtils.swift in Sources */, 0198B9A823197CBA003F7578 /* Launch.swift in Sources */,
0198B99E23196689003F7578 /* BrowseMenuAction.swift in Sources */, 0198B99E23196689003F7578 /* BrowseMenuAction.swift in Sources */,
01073F132311E1CF007162C9 /* Utils.swift in Sources */, 01073F132311E1CF007162C9 /* Globals.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -498,12 +502,12 @@
"$(PROJECT_DIR)/RSwitch/ObjC/ProcInfo", "$(PROJECT_DIR)/RSwitch/ObjC/ProcInfo",
); );
MACOSX_DEPLOYMENT_TARGET = 10.14; MACOSX_DEPLOYMENT_TARGET = 10.14;
MARKETING_VERSION = 1.4.0; MARKETING_VERSION = 1.4.1;
PRODUCT_BUNDLE_IDENTIFIER = is.rud.bob.RSwitch; PRODUCT_BUNDLE_IDENTIFIER = is.rud.bob.RSwitch;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "RSwitch/ObjC/RSwitch-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "RSwitch/ObjC/RSwitch-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
}; };
name = Debug; name = Debug;
@ -531,12 +535,12 @@
"$(PROJECT_DIR)/RSwitch/ObjC/ProcInfo", "$(PROJECT_DIR)/RSwitch/ObjC/ProcInfo",
); );
MACOSX_DEPLOYMENT_TARGET = 10.14; MACOSX_DEPLOYMENT_TARGET = 10.14;
MARKETING_VERSION = 1.4.0; MARKETING_VERSION = 1.4.1;
PRODUCT_BUNDLE_IDENTIFIER = is.rud.bob.RSwitch; PRODUCT_BUNDLE_IDENTIFIER = is.rud.bob.RSwitch;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "RSwitch/ObjC/RSwitch-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "RSwitch/ObjC/RSwitch-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
}; };
name = Release; name = Release;

14
RSwitch/Base.lproj/Main.storyboard

@ -719,7 +719,7 @@
<!--About View Controller--> <!--About View Controller-->
<scene sceneID="lbz-cy-h0Y"> <scene sceneID="lbz-cy-h0Y">
<objects> <objects>
<viewController storyboardIdentifier="about2" id="KlD-6a-3Gc" customClass="AboutViewController" sceneMemberID="viewController"> <viewController storyboardIdentifier="about2" id="KlD-6a-3Gc" customClass="AboutViewController" customModule="RSwitch" sceneMemberID="viewController">
<view key="view" id="SgY-wa-ilj"> <view key="view" id="SgY-wa-ilj">
<rect key="frame" x="0.0" y="0.0" width="480" height="272"/> <rect key="frame" x="0.0" y="0.0" width="480" height="272"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
@ -734,14 +734,14 @@
<textView ambiguous="YES" editable="NO" drawsBackground="NO" importsGraphics="NO" verticallyResizable="YES" smartInsertDelete="YES" id="kWH-Et-k6l"> <textView ambiguous="YES" editable="NO" drawsBackground="NO" importsGraphics="NO" verticallyResizable="YES" smartInsertDelete="YES" id="kWH-Et-k6l">
<rect key="frame" x="0.0" y="0.0" width="463" height="247"/> <rect key="frame" x="0.0" y="0.0" width="463" height="247"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/> <color key="textColor" name="systemBlueColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="alternatingContentBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="alternatingContentBackgroundColor" catalog="System" colorSpace="catalog"/>
<size key="minSize" width="463" height="247"/> <size key="minSize" width="463" height="247"/>
<size key="maxSize" width="463" height="10000000"/> <size key="maxSize" width="463" height="10000000"/>
<attributedString key="textStorage"> <attributedString key="textStorage">
<fragment> <fragment>
<string key="content"> <string key="content">
RSwitch v1.4.0 RSwitch v1.4.1
Copyright © 2019 Bob Rudis Copyright © 2019 Bob Rudis
@ -749,14 +749,14 @@ MIT Licensed
</string> </string>
<attributes> <attributes>
<color key="NSColor" name="textColor" catalog="System" colorSpace="catalog"/> <color key="NSColor" name="systemBlueColor" catalog="System" colorSpace="catalog"/>
<font key="NSFont" metaFont="label" size="17"/> <font key="NSFont" metaFont="label" size="17"/>
<paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/> <paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
</attributes> </attributes>
</fragment> </fragment>
<fragment content="https://rud.is/rswitch/"> <fragment content="https://rud.is/rswitch/">
<attributes> <attributes>
<color key="NSColor" name="textColor" catalog="System" colorSpace="catalog"/> <color key="NSColor" name="systemBlueColor" catalog="System" colorSpace="catalog"/>
<font key="NSFont" metaFont="label" size="17"/> <font key="NSFont" metaFont="label" size="17"/>
<url key="NSLink" string="https://rud.is/rswitch/"/> <url key="NSLink" string="https://rud.is/rswitch/"/>
<paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/> <paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
@ -767,7 +767,7 @@ MIT Licensed
Cgo Cgo
</string> </string>
<attributes> <attributes>
<color key="NSColor" name="textColor" catalog="System" colorSpace="catalog"/> <color key="NSColor" name="systemBlueColor" catalog="System" colorSpace="catalog"/>
<font key="NSFont" metaFont="label" size="17"/> <font key="NSFont" metaFont="label" size="17"/>
<paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/> <paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
</attributes> </attributes>
@ -777,7 +777,7 @@ Cgo
String+Version by DragonCherry String+Version by DragonCherry
ProcInfo by Patrick Wardle </string> ProcInfo by Patrick Wardle </string>
<attributes> <attributes>
<color key="NSColor" name="textColor" catalog="System" colorSpace="catalog"/> <color key="NSColor" name="systemBlueColor" catalog="System" colorSpace="catalog"/>
<font key="NSFont" size="11" name="HelveticaNeue"/> <font key="NSFont" size="11" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/> <paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
</attributes> </attributes>

0
RSwitch/swift/AboutViewController.swift → RSwitch/Swift/AboutViewController.swift

0
RSwitch/swift/AppAlerts/AppAlerts.swift → RSwitch/Swift/AppAlerts/AppAlerts.swift

0
RSwitch/swift/AppDelegate.swift → RSwitch/Swift/AppDelegate.swift

4
RSwitch/swift/Downloaders/DownloadRStudio.swift → RSwitch/Swift/Downloaders/DownloadRStudio.swift

@ -32,8 +32,6 @@ extension AppDelegate {
dlfile.appendPathComponent(dlurl.lastPathComponent) dlfile.appendPathComponent(dlurl.lastPathComponent)
print("RStudio href: " + href)
if (FileManager.default.fileExists(atPath: dlfile.relativePath)) { if (FileManager.default.fileExists(atPath: dlfile.relativePath)) {
self.notifyUser(title: "Action required", subtitle: "RStudio Download", text: "A local copy of the latest RStudio daily already exists. Please remove or rename it if you wish to re-download it.") self.notifyUser(title: "Action required", subtitle: "RStudio Download", text: "A local copy of the latest RStudio daily already exists. Please remove or rename it if you wish to re-download it.")
@ -45,8 +43,6 @@ extension AppDelegate {
} else { } else {
print("Timeout value: ", URLSession.shared.configuration.timeoutIntervalForRequest)
let task = URLSession.shared.downloadTask(with: dlurl) { let task = URLSession.shared.downloadTask(with: dlurl) {
tempURL, response, error in tempURL, response, error in

8
RSwitch/swift/Downloaders/DownloadTarball.swift → RSwitch/Swift/Downloaders/DownloadTarball.swift

@ -9,6 +9,9 @@
import Foundation import Foundation
import Cocoa import Cocoa
let tarballURL = "https://mac.r-project.org/el-capitan/R-devel/R-devel-el-capitan-sa-x86_64.tar.gz"
let tarballFile = NSString(string: tarballURL).lastPathComponent as String
extension AppDelegate { extension AppDelegate {
// Download latest r-devel tarball // Download latest r-devel tarball
@ -16,11 +19,11 @@ extension AppDelegate {
self.rdevel_enabled = false self.rdevel_enabled = false
let dlurl = URL(string: "https://mac.r-project.org/el-capitan/R-devel/R-devel-el-capitan-sa-x86_64.tar.gz")! let dlurl = URL(string: tarballURL)!
let dldir = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first! let dldir = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first!
var dlfile = dldir var dlfile = dldir
dlfile.appendPathComponent("R-devel-el-capitan-sa-x86_64.tar.gz") dlfile.appendPathComponent(tarballFile)
if (FileManager.default.fileExists(atPath: dlfile.relativePath)) { if (FileManager.default.fileExists(atPath: dlfile.relativePath)) {
@ -30,6 +33,7 @@ extension AppDelegate {
NSWorkspace.shared.activateFileViewerSelecting([dlfile]) NSWorkspace.shared.activateFileViewerSelecting([dlfile])
self.rdevel_enabled = true self.rdevel_enabled = true
} else { } else {
let task = URLSession.shared.downloadTask(with: dlurl) { let task = URLSession.shared.downloadTask(with: dlurl) {

17
RSwitch/swift/HandleRSwitch.swift → RSwitch/Swift/HandleRSwitch.swift

@ -11,31 +11,28 @@ import Cocoa
extension AppDelegate { extension AppDelegate {
struct app_dirs {
static let macos_r_framework = "/Library/Frameworks/R.framework/Versions" // Where the official R installs go
}
// The core worker function. Receives the basename of the selected directory // The core worker function. Receives the basename of the selected directory
// then removes the current alias and creates the new one. // then removes the current alias and creates the new one.
@objc func handleRSwitch(_ sender: NSMenuItem?) { @objc func handleRSwitch(_ sender: NSMenuItem?) {
let fm = FileManager.default; let fm = FileManager.default;
let title = sender?.title let title = sender?.title
let rm_link = (RVersions.macos_r_framework) + "/" + "Current"
do { do {
try fm.removeItem(atPath: app_dirs.macos_r_framework + "/" + "Current") try fm.removeItem(atPath: rm_link)
} catch { } catch {
self.notifyUser(title: "Action failed", text: "Failed to remove 'Current' alias" + app_dirs.macos_r_framework + "/" + "Current") self.notifyUser(title: "Action failed", text: "Failed to remove 'Current' alias" + rm_link)
} }
do { do {
try fm.createSymbolicLink( try fm.createSymbolicLink(
at: NSURL(fileURLWithPath: app_dirs.macos_r_framework + "/" + "Current") as URL, at: NSURL(fileURLWithPath: RVersions.macos_r_framework + "/" + "Current") as URL,
withDestinationURL: NSURL(fileURLWithPath: app_dirs.macos_r_framework + "/" + title!) as URL withDestinationURL: NSURL(fileURLWithPath: RVersions.macos_r_framework + "/" + title!) as URL
) )
self.notifyUser(title: "Success", text: "Current R version switched to " + title!) self.notifyUser(title: "Success", text: "Current R version switched to " + title!)
} catch { } catch {
self.notifyUser(title: "Action failed", text: "Failed to create alias for " + app_dirs.macos_r_framework + "/" + title! + " (\(error))") self.notifyUser(title: "Action failed", text: "Failed to create alias for " + RVersions.macos_r_framework + "/" + title! + " (\(error))")
} }
} }

0
RSwitch/swift/HandleSwitchTo.swift → RSwitch/Swift/HandleSwitchTo.swift

0
RSwitch/swift/HandleUpdate.swift → RSwitch/Swift/HandleUpdate.swift

2
RSwitch/swift/Menu.swift → RSwitch/Swift/Menu.swift

@ -25,7 +25,7 @@ extension AppDelegate: NSMenuDelegate {
menu.addItem(NSMenuItem(title: "Current R Version:", action: nil, keyEquivalent: "")) menu.addItem(NSMenuItem(title: "Current R Version:", action: nil, keyEquivalent: ""))
// populate installed versions // populate installed versions
populateRVersionsMenu(menu: menu) RVersions.populateRVersionsMenu(menu: menu, handler: #selector(handleRSwitch))
// Add items to download latest r-devel tarball and latest macOS daily // Add items to download latest r-devel tarball and latest macOS daily
menu.addItem(NSMenuItem.separator()) menu.addItem(NSMenuItem.separator())

8
RSwitch/swift/MenuActions/BrowseMenuAction.swift → RSwitch/Swift/MenuActions/BrowseMenuAction.swift

@ -30,13 +30,18 @@ class BrowseMenuAction {
BrowseMenuAction(title: "R for macOS CRAN…", url: "https://cran.rstudio.org/bin/macosx/"), BrowseMenuAction(title: "R for macOS CRAN…", url: "https://cran.rstudio.org/bin/macosx/"),
BrowseMenuAction(title: "R-SIG-Mac Archives…", url: "https://stat.ethz.ch/pipermail/r-sig-mac/"), BrowseMenuAction(title: "R-SIG-Mac Archives…", url: "https://stat.ethz.ch/pipermail/r-sig-mac/"),
BrowseMenuAction(title: "R-devel News…", url: "https://developer.r-project.org/blosxom.cgi/R-devel/NEWS"), BrowseMenuAction(title: "R-devel News…", url: "https://developer.r-project.org/blosxom.cgi/R-devel/NEWS"),
BrowseMenuAction(title: "R-Forge macOS Subversion…", url: "http://svn.rforge.net/osx/trunk/"),
BrowseMenuAction(title: "R Installation/Admin macOS Section…", url: "https://cran.rstudio.org/doc/manuals/R-admin.html#Installing-R-under-macOS"), BrowseMenuAction(title: "R Installation/Admin macOS Section…", url: "https://cran.rstudio.org/doc/manuals/R-admin.html#Installing-R-under-macOS"),
] ]
private static let webItemsExt = [ private static let webItemsExt = [
BrowseMenuAction(title: "RStudio macOS Dailies…", url: "https://dailies.rstudio.com/rstudio/oss/mac/"), BrowseMenuAction(title: "RStudio macOS Dailies…", url: "https://dailies.rstudio.com/rstudio/oss/mac/"),
BrowseMenuAction(title: "R StackOverflow…", url: "https://stackoverflow.com/questions/tagged/r"), BrowseMenuAction(title: "R StackOverflow…", url: "https://stackoverflow.com/questions/tagged/r"),
BrowseMenuAction(title: "RStudio Community…", url: "https://community.rstudio.com/") BrowseMenuAction(title: "RStudio Community…", url: "https://community.rstudio.com/"),
BrowseMenuAction(title: "Unofficial R-O GitHub CRAN Mirror…", url: "https://github.com/cran"),
BrowseMenuAction(title: "XQuartz (X11 for macOS)…", url: "https://www.xquartz.org/"),
BrowseMenuAction(title: "Homebrew (macOS Package Manager)…", url: "https://brew.sh/"),
BrowseMenuAction(title: "Apple Developer Portal…", url: "https://developer.apple.com/")
] ]
init(title: String, url: String, selector: String = "browseFromMenu", keyEquivalent: String = "") { init(title: String, url: String, selector: String = "browseFromMenu", keyEquivalent: String = "") {
@ -44,7 +49,6 @@ class BrowseMenuAction {
self.url = URL(string: url)! self.url = URL(string: url)!
self.selector = Selector((selector+":")) self.selector = Selector((selector+":"))
self.keyEquivalent = keyEquivalent self.keyEquivalent = keyEquivalent
print(self.selector)
} }
public func asMenuItem() -> NSMenuItem { public func asMenuItem() -> NSMenuItem {

0
RSwitch/swift/Notify.swift → RSwitch/Swift/Notify.swift

0
RSwitch/swift/String+Version/Bundle.swift → RSwitch/Swift/String+Version/Bundle.swift

0
RSwitch/swift/String+Version/String+Version.swift → RSwitch/Swift/String+Version/String+Version.swift

0
RSwitch/swift/Utils/Utils.swift → RSwitch/Swift/Utils/Globals.swift

0
RSwitch/swift/Utils/LaunchUtils.swift → RSwitch/Swift/Utils/Launch.swift

90
RSwitch/Swift/Utils/RVersions.swift

@ -0,0 +1,90 @@
//
// RUtils.swift
// RSwitch
//
// Created by hrbrmstr on 9/1/19.
// Copyright © 2019 Bob Rudis. All rights reserved.
//
import Foundation
import Cocoa
struct versionInfo {
var path : String
var current: Bool
}
class RVersions {
static let macos_r_framework = "/Library/Frameworks/R.framework/Versions" // Where the official R installs go
static func currentVersionTarget() -> String {
// get where Current points to
let furl = NSURL(fileURLWithPath: RVersions.macos_r_framework + "/" + "Current")
if (furl.fileReferenceURL() != nil) {
do {
let fdat = try NSURL(resolvingAliasFileAt: furl as URL, options: [])
return(fdat.lastPathComponent!)
} catch {
return(furl.path!)
}
} else {
return("")
}
}
static func hasRBinary(versionPath : String) -> Bool {
return(
FileManager.default.fileExists(
atPath: (versionPath.starts(with: "/") ? "" : RVersions.macos_r_framework + "/" ) +
versionPath + "/Resources/bin/R"
)
)
}
static func reloadVersions() throws -> [String] {
// gets a directory listing
let entries = try FileManager.default.contentsOfDirectory(atPath: RVersions.macos_r_framework)
// retrieves all versions (excludes hidden files and the Current alias
return(entries.sorted().filter { !($0.hasPrefix(".")) && !($0 == "Current") })
}
static func populateRVersionsMenu(menu : NSMenu, handler : Selector) {
do {
let targetPath = RVersions.currentVersionTarget()
let versions = try RVersions.reloadVersions()
// populate menu items with all installed R versions, ensuring we
// put a checkbox next to the one that is Current
var i = 1
for version in versions {
let complete = RVersions.hasRBinary(versionPath: version)
let keynum = (i < 10) ? String(i) : ""
let item = NSMenuItem(
title: complete ? version : version + " (incomplete)",
action: complete ? handler : nil,
keyEquivalent: complete ? keynum : ""
)
item.isEnabled = complete
if (version == targetPath) { item.state = NSControl.StateValue.on }
item.representedObject = version
menu.addItem(item)
i = complete ? i + 1 : i
}
} catch {
AppAlerts.quitAlert("Failed to list contents of R framework directory. You either do not have R installed or have incorrect permissions set on " + RVersions.macos_r_framework)
}
}
}

56
RSwitch/Swift/Utils/Running.swift

@ -0,0 +1,56 @@
//
// VersionsUtils.swift
// RSwitch
//
// Created by hrbrmstr on 8/30/19.
// Copyright © 2019 Bob Rudis. All rights reserved.
//
import Foundation
import Cocoa
extension AppDelegate {
// Show the framework dir in a new Finder window
@objc func openFrameworksDir(_ sender: NSMenuItem?) {
NSWorkspace.shared.openFile(RVersions.macos_r_framework, withApplication: "Finder")
}
func populateRunningApps(menu : NSMenu) {
// gather running RStudio instances
let running_rstudios = NSWorkspace.shared.runningApplications.filter {
$0.bundleIdentifier == bundleIds.rstudio
}
// gather running R GUI instances
let running_rapps = NSWorkspace.shared.runningApplications.filter {
$0.bundleIdentifier == bundleIds.r_base
}
// if we have any running instances of anything
if ((running_rstudios.count) + (running_rapps.count) > 0) {
menu.addItem(NSMenuItem.separator())
let switchToDropdown = NSMenuItem(title: "Switch to", action: nil, keyEquivalent: "")
let switchToSub = NSMenu()
menu.addItem(switchToDropdown)
menu.setSubmenu(switchToSub, for: switchToDropdown)
// populate RStudio first (it'll be in launch order) then R GUI
for app in running_rstudios + running_rapps {
let args = getArgs(app.processIdentifier)!
let title = app.localizedName! + (args.count > 1 ? " : " + (args[1] as! NSString).lastPathComponent.replacingOccurrences(of: ".Rproj", with: "") : "")
let mi = NSMenuItem(title: title, action: #selector(switch_to), keyEquivalent: "")
mi.representedObject = app
switchToSub.addItem(mi)
}
}
}
}

0
RSwitch/swift/ViewController.swift → RSwitch/Swift/ViewController.swift

106
RSwitch/swift/Utils/Versions+RunningUtils.swift

@ -1,106 +0,0 @@
//
// VersionsUtils.swift
// RSwitch
//
// Created by hrbrmstr on 8/30/19.
// Copyright © 2019 Bob Rudis. All rights reserved.
//
import Foundation
import Cocoa
extension AppDelegate {
// Show the framework dir in a new Finder window
@objc func openFrameworksDir(_ sender: NSMenuItem?) {
NSWorkspace.shared.openFile(app_dirs.macos_r_framework, withApplication: "Finder")
}
func populateRVersionsMenu(menu : NSMenu) {
let fm = FileManager.default
var targetPath:String? = nil
do {
// gets a directory listing
let entries = try fm.contentsOfDirectory(atPath: app_dirs.macos_r_framework)
// retrieves all versions (excludes hidden files and the Current alias
let versions = entries.sorted().filter { !($0.hasPrefix(".")) && !($0 == "Current") }
let hasCurrent = entries.filter { $0 == "Current" }
// if there was a Current alias (prbly shld alert if not)
if (hasCurrent.count > 0) {
// get where Current points to
let furl = NSURL(fileURLWithPath: app_dirs.macos_r_framework + "/" + "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
var i = 1
for version in versions {
let keynum = (i < 10) ? String(i) : ""
let item = NSMenuItem(title: version, action: #selector(handleRSwitch), keyEquivalent: keynum)
item.isEnabled = true
if (version == targetPath) { item.state = NSControl.StateValue.on }
item.representedObject = version
menu.addItem(item)
i = i + 1
}
}
} catch {
AppAlerts.quitAlert("Failed to list contents of R framework directory. You either do not have R installed or have incorrect permissions set on " + app_dirs.macos_r_framework)
}
}
func populateRunningApps(menu : NSMenu) {
// gather running RStudio instances
let running_rstudios = NSWorkspace.shared.runningApplications.filter {
$0.bundleIdentifier == bundleIds.rstudio
}
// gather running R GUI instances
let running_rapps = NSWorkspace.shared.runningApplications.filter {
$0.bundleIdentifier == bundleIds.r_base
}
// if we have any running instances of anything
if ((running_rstudios.count) + (running_rapps.count) > 0) {
menu.addItem(NSMenuItem.separator())
let switchToDropdown = NSMenuItem(title: "Switch to", action: nil, keyEquivalent: "")
let switchToSub = NSMenu()
menu.addItem(switchToDropdown)
menu.setSubmenu(switchToSub, for: switchToDropdown)
// populate RStudio first (it'll be in launch order) then R GUI
for app in running_rstudios + running_rapps {
let args = getArgs(app.processIdentifier)!
let title = app.localizedName! + (args.count > 1 ? " : " + (args[1] as! NSString).lastPathComponent.replacingOccurrences(of: ".Rproj", with: "") : "")
let mi = NSMenuItem(title: title, action: #selector(switch_to), keyEquivalent: "")
mi.representedObject = app
switchToSub.addItem(mi)
}
}
}
}
Loading…
Cancel
Save