Compare commits

...

6 Commits

  1. 2
      Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/Just.xcscheme
  2. 2
      Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/Pods-RSwitch.xcscheme
  3. 11
      Pods/Target Support Files/Just/Just.debug.xcconfig
  4. 11
      Pods/Target Support Files/Just/Just.release.xcconfig
  5. 219
      RSwitch.xcodeproj/project.pbxproj
  6. 78
      RSwitch.xcodeproj/xcshareddata/xcschemes/RSwitch.xcscheme
  7. 13
      RSwitch.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/xcschememanagement.plist
  8. 16
      RSwitch.xcworkspace/xcshareddata/swiftpm/Package.resolved
  9. BIN
      RSwitch.xcworkspace/xcuserdata/hrbrmstr.xcuserdatad/UserInterfaceState.xcuserstate
  10. 74
      RSwitch/Base.lproj/Main.storyboard
  11. 5
      RSwitch/Swift/AppDelegate.swift
  12. 63
      RSwitch/Swift/Downloaders/DownloadFromRStudioServer.swift
  13. 22
      RSwitch/Swift/ExportWebViewController.swift
  14. 1
      RSwitch/Swift/HandleRSwitch.swift
  15. 18
      RSwitch/Swift/Menu.swift
  16. 16
      RSwitch/Swift/MenuActions/BrowseMenuAction.swift
  17. 4
      RSwitch/Swift/MenuActions/RStudioServerAction.swift
  18. 5
      RSwitch/Swift/Notify.swift
  19. 84
      RSwitch/Swift/RStudioServerSessionWebViewController.swift
  20. 4
      RSwitch/Swift/Utils/Associations.swift
  21. 12
      RSwitch/Swift/Utils/Preferences.swift
  22. 26
      RSwitch/Swift/Utils/urls.swift
  23. 100
      RSwitch/Swift/exportPopupViewController.swift
  24. 19
      RSwitch/Swift/plotPopupViewController.swift
  25. 7
      guide/index.Rmd
  26. BIN
      guide/r-macos-downloads.png
  27. 22
      rswitch-cmd/Info.plist
  28. 90
      rswitch-cmd/main.swift

2
Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/Just.xcscheme

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1130"
LastUpgradeVersion = "1150"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

2
Pods/Pods.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/Pods-RSwitch.xcscheme

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1130"
LastUpgradeVersion = "1150"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

11
Pods/Target Support Files/Just/Just.debug.xcconfig

@ -0,0 +1,11 @@
CODE_SIGN_IDENTITY =
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Just
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/Just
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

11
Pods/Target Support Files/Just/Just.release.xcconfig

@ -0,0 +1,11 @@
CODE_SIGN_IDENTITY =
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Just
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/Just
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

219
RSwitch.xcodeproj/project.pbxproj

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objectVersion = 52;
objects = {
/* Begin PBXBuildFile section */
@ -19,6 +19,11 @@
010A1C1423215B0900E32A9A /* SessionWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 010A1C1323215B0900E32A9A /* SessionWindowController.swift */; };
0117C9E0232270F0004BC889 /* RStudioUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0117C9DF232270F0004BC889 /* RStudioUtils.swift */; };
011951B4231F00A000B62C3A /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011951B3231F00A000B62C3A /* Preferences.swift */; };
01575A37245443D7004A5715 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01575A36245443D7004A5715 /* main.swift */; };
01575A3B245445B2004A5715 /* rswitch-cmd in Resources */ = {isa = PBXBuildFile; fileRef = 01575A34245443D7004A5715 /* rswitch-cmd */; };
01575A4024544892004A5715 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 01575A3F24544892004A5715 /* ArgumentParser */; };
01575A4324544DA6004A5715 /* RVersions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01975549231BD919003FAD7B /* RVersions.swift */; };
01575A4424544F49004A5715 /* AppAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198B99F231970ED003F7578 /* AppAlerts.swift */; };
0178970D230ED25100F8F5BC /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0178970C230ED25100F8F5BC /* AboutViewController.swift */; };
018A8C3B2312C7BC0006E87D /* libprocInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 018A8C3A2312C7BC0006E87D /* libprocInfo.a */; };
018A8C3F2312CB480006E87D /* procHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 018A8C3E2312CB480006E87D /* procHelper.m */; };
@ -42,10 +47,36 @@
01FC5D02232874F600771CD7 /* ToolbarWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FC5CFE232874F600771CD7 /* ToolbarWebViewController.swift */; };
01FC5D03232874F600771CD7 /* RStudioServerSessionWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FC5CFF232874F600771CD7 /* RStudioServerSessionWebViewController.swift */; };
01FC5D04232874F600771CD7 /* PlotWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FC5D00232874F600771CD7 /* PlotWebViewController.swift */; };
01FC6E97247B0AB60091AC87 /* exportPopupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6E96247B0AB60091AC87 /* exportPopupViewController.swift */; };
01FC6E99247B0AF80091AC87 /* urls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6E98247B0AF80091AC87 /* urls.swift */; };
01FC6E9B247B0B370091AC87 /* ExportWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6E9A247B0B370091AC87 /* ExportWebViewController.swift */; };
01FC6E9D247B2FF80091AC87 /* DownloadFromRStudioServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6E9C247B2FF80091AC87 /* DownloadFromRStudioServer.swift */; };
52B8A14237DA712A6A2ABDE0 /* Pods_RSwitch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E2F8556B6C8EF8ED93F7E99 /* Pods_RSwitch.framework */; };
C4290DD6231F190F00AA5955 /* AppMenuActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4290DD5231F190E00AA5955 /* AppMenuActions.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
01575A3C24544613004A5715 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 01F3EF00230E635300DF5DF9 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 01575A33245443D7004A5715;
remoteInfo = "rswitch-cmd";
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
01575A32245443D7004A5715 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
01073F0E2311AE2E007162C9 /* String+Version.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Version.swift"; sourceTree = "<group>"; };
01073F122311E1CF007162C9 /* Globals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Globals.swift; sourceTree = "<group>"; };
@ -59,6 +90,8 @@
010A1C1323215B0900E32A9A /* SessionWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionWindowController.swift; sourceTree = "<group>"; };
0117C9DF232270F0004BC889 /* RStudioUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RStudioUtils.swift; sourceTree = "<group>"; };
011951B3231F00A000B62C3A /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
01575A34245443D7004A5715 /* rswitch-cmd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "rswitch-cmd"; sourceTree = BUILT_PRODUCTS_DIR; };
01575A36245443D7004A5715 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
016750FB2319A7A4009E2FD6 /* RSwitch.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RSwitch.entitlements; sourceTree = "<group>"; };
0178970C230ED25100F8F5BC /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
018A8C392312C7BC0006E87D /* procInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = procInfo.h; sourceTree = "<group>"; };
@ -74,6 +107,7 @@
01A4F40923F3084E005B88C2 /* Reachable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reachable.swift; sourceTree = "<group>"; };
01A4F40B23F30DB4005B88C2 /* Associations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Associations.swift; sourceTree = "<group>"; };
01B611EB232176A200432807 /* NewSessionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewSessionViewController.swift; sourceTree = "<group>"; };
01BDA1A5245482CD005DC733 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
01D3E439232119DD00E3BC02 /* WebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = "<group>"; };
01D3E43B23211B4C00E3BC02 /* RStudioServerAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RStudioServerAction.swift; sourceTree = "<group>"; };
01D3E43E2321315900E3BC02 /* RStudioServerSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RStudioServerSession.swift; sourceTree = "<group>"; };
@ -88,6 +122,10 @@
01FC5CFE232874F600771CD7 /* ToolbarWebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolbarWebViewController.swift; sourceTree = "<group>"; };
01FC5CFF232874F600771CD7 /* RStudioServerSessionWebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RStudioServerSessionWebViewController.swift; sourceTree = "<group>"; };
01FC5D00232874F600771CD7 /* PlotWebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlotWebViewController.swift; sourceTree = "<group>"; };
01FC6E96247B0AB60091AC87 /* exportPopupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = exportPopupViewController.swift; sourceTree = "<group>"; };
01FC6E98247B0AF80091AC87 /* urls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = urls.swift; sourceTree = "<group>"; };
01FC6E9A247B0B370091AC87 /* ExportWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportWebViewController.swift; sourceTree = "<group>"; };
01FC6E9C247B2FF80091AC87 /* DownloadFromRStudioServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadFromRStudioServer.swift; sourceTree = "<group>"; };
0E2F8556B6C8EF8ED93F7E99 /* Pods_RSwitch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RSwitch.framework; sourceTree = BUILT_PRODUCTS_DIR; };
53FF56D90FA7100C1726A4F7 /* Pods-RSwitch.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RSwitch.debug.xcconfig"; path = "Target Support Files/Pods-RSwitch/Pods-RSwitch.debug.xcconfig"; sourceTree = "<group>"; };
574911021B3B7938E36AB013 /* Pods-RSwitch.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RSwitch.release.xcconfig"; path = "Target Support Files/Pods-RSwitch/Pods-RSwitch.release.xcconfig"; sourceTree = "<group>"; };
@ -95,6 +133,14 @@
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
01575A31245443D7004A5715 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
01575A4024544892004A5715 /* ArgumentParser in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
01F3EF05230E635300DF5DF9 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -120,6 +166,8 @@
0178970C230ED25100F8F5BC /* AboutViewController.swift */,
01FC5CFD232874F500771CD7 /* plotPopupViewController.swift */,
01FC5D00232874F600771CD7 /* PlotWebViewController.swift */,
01FC6E96247B0AB60091AC87 /* exportPopupViewController.swift */,
01FC6E9A247B0B370091AC87 /* ExportWebViewController.swift */,
01FC5CFF232874F600771CD7 /* RStudioServerSessionWebViewController.swift */,
01FC5CFE232874F600771CD7 /* ToolbarWebViewController.swift */,
01073F202311E6BD007162C9 /* HandleRSwitch.swift */,
@ -135,6 +183,15 @@
path = Swift;
sourceTree = "<group>";
};
01575A35245443D7004A5715 /* rswitch-cmd */ = {
isa = PBXGroup;
children = (
01BDA1A5245482CD005DC733 /* Info.plist */,
01575A36245443D7004A5715 /* main.swift */,
);
path = "rswitch-cmd";
sourceTree = "<group>";
};
018A8C342312C6510006E87D /* ObjC */ = {
isa = PBXGroup;
children = (
@ -186,6 +243,7 @@
children = (
01073F1A2311E613007162C9 /* DownloadTarball.swift */,
01073F1C2311E64E007162C9 /* DownloadRStudio.swift */,
01FC6E9C247B2FF80091AC87 /* DownloadFromRStudioServer.swift */,
);
path = Downloaders;
sourceTree = "<group>";
@ -195,6 +253,7 @@
children = (
01073F182311E3B8007162C9 /* Bundle.swift */,
01073F122311E1CF007162C9 /* Globals.swift */,
01FC6E98247B0AF80091AC87 /* urls.swift */,
0117C9DF232270F0004BC889 /* RStudioUtils.swift */,
01975549231BD919003FAD7B /* RVersions.swift */,
0198B9A923197D3A003F7578 /* Running.swift */,
@ -218,16 +277,20 @@
isa = PBXGroup;
children = (
01F3EF0A230E635300DF5DF9 /* RSwitch */,
01575A35245443D7004A5715 /* rswitch-cmd */,
01F3EF09230E635300DF5DF9 /* Products */,
6E9DFB632C8DAEE9C1D64321 /* Pods */,
08E99D67B1A9A0A9D2CF3F66 /* Frameworks */,
);
indentWidth = 2;
sourceTree = "<group>";
tabWidth = 2;
};
01F3EF09230E635300DF5DF9 /* Products */ = {
isa = PBXGroup;
children = (
01F3EF08230E635300DF5DF9 /* RSwitch.app */,
01575A34245443D7004A5715 /* rswitch-cmd */,
);
name = Products;
sourceTree = "<group>";
@ -264,7 +327,38 @@
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
01BDA1A624548938005DC733 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
01575A33245443D7004A5715 /* rswitch-cmd */ = {
isa = PBXNativeTarget;
buildConfigurationList = 01575A38245443D7004A5715 /* Build configuration list for PBXNativeTarget "rswitch-cmd" */;
buildPhases = (
01BDA1A624548938005DC733 /* Headers */,
01575A30245443D7004A5715 /* Sources */,
01575A31245443D7004A5715 /* Frameworks */,
01575A32245443D7004A5715 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = "rswitch-cmd";
packageProductDependencies = (
01575A3F24544892004A5715 /* ArgumentParser */,
);
productName = "rswitch-cmd";
productReference = 01575A34245443D7004A5715 /* rswitch-cmd */;
productType = "com.apple.product-type.tool";
};
01F3EF07230E635300DF5DF9 /* RSwitch */ = {
isa = PBXNativeTarget;
buildConfigurationList = 01F3EF18230E635500DF5DF9 /* Build configuration list for PBXNativeTarget "RSwitch" */;
@ -278,6 +372,7 @@
buildRules = (
);
dependencies = (
01575A3D24544613004A5715 /* PBXTargetDependency */,
);
name = RSwitch;
productName = RSwitch;
@ -290,10 +385,13 @@
01F3EF00230E635300DF5DF9 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1100;
LastUpgradeCheck = 1130;
LastSwiftUpdateCheck = 1140;
LastUpgradeCheck = 1150;
ORGANIZATIONNAME = "Bob Rudis";
TargetAttributes = {
01575A33245443D7004A5715 = {
CreatedOnToolsVersion = 11.4;
};
01F3EF07230E635300DF5DF9 = {
CreatedOnToolsVersion = 11.0;
LastSwiftMigration = 1100;
@ -301,7 +399,7 @@
};
};
buildConfigurationList = 01F3EF03230E635300DF5DF9 /* Build configuration list for PBXProject "RSwitch" */;
compatibilityVersion = "Xcode 9.3";
compatibilityVersion = "Xcode 11.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@ -309,11 +407,15 @@
Base,
);
mainGroup = 01F3EEFF230E635300DF5DF9;
packageReferences = (
01575A3E24544892004A5715 /* XCRemoteSwiftPackageReference "swift-argument-parser" */,
);
productRefGroup = 01F3EF09230E635300DF5DF9 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
01F3EF07230E635300DF5DF9 /* RSwitch */,
01575A33245443D7004A5715 /* rswitch-cmd */,
);
};
/* End PBXProject section */
@ -323,6 +425,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
01575A3B245445B2004A5715 /* rswitch-cmd in Resources */,
01F3EF10230E635500DF5DF9 /* Assets.xcassets in Resources */,
01F3EF13230E635500DF5DF9 /* Main.storyboard in Resources */,
);
@ -373,6 +476,16 @@
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
01575A30245443D7004A5715 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
01575A4424544F49004A5715 /* AppAlerts.swift in Sources */,
01575A4324544DA6004A5715 /* RVersions.swift in Sources */,
01575A37245443D7004A5715 /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
01F3EF04230E635300DF5DF9 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -397,16 +510,20 @@
01073F152311E370007162C9 /* Notify.swift in Sources */,
C4290DD6231F190F00AA5955 /* AppMenuActions.swift in Sources */,
01FC5D03232874F600771CD7 /* RStudioServerSessionWebViewController.swift in Sources */,
01FC6E9D247B2FF80091AC87 /* DownloadFromRStudioServer.swift in Sources */,
01073F1D2311E64E007162C9 /* DownloadRStudio.swift in Sources */,
01073F172311E397007162C9 /* Menu.swift in Sources */,
01F3EF0E230E635300DF5DF9 /* ViewController.swift in Sources */,
01FC6E97247B0AB60091AC87 /* exportPopupViewController.swift in Sources */,
01FC5D04232874F600771CD7 /* PlotWebViewController.swift in Sources */,
01A4F40C23F30DB4005B88C2 /* Associations.swift in Sources */,
01F3EF0C230E635300DF5DF9 /* AppDelegate.swift in Sources */,
01FC6E9B247B0B370091AC87 /* ExportWebViewController.swift in Sources */,
01FC5D01232874F600771CD7 /* plotPopupViewController.swift in Sources */,
01D3E441232131F300E3BC02 /* RStudioServerSessionManager.swift in Sources */,
01B611EC232176A200432807 /* NewSessionViewController.swift in Sources */,
01073F0F2311AE2E007162C9 /* String+Version.swift in Sources */,
01FC6E99247B0AF80091AC87 /* urls.swift in Sources */,
0198B99E23196689003F7578 /* BrowseMenuAction.swift in Sources */,
01FC5D02232874F600771CD7 /* ToolbarWebViewController.swift in Sources */,
01073F132311E1CF007162C9 /* Globals.swift in Sources */,
@ -415,6 +532,14 @@
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
01575A3D24544613004A5715 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 01575A33245443D7004A5715 /* rswitch-cmd */;
targetProxy = 01575A3C24544613004A5715 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
01F3EF11230E635500DF5DF9 /* Main.storyboard */ = {
isa = PBXVariantGroup;
@ -427,6 +552,50 @@
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
01575A39245443D7004A5715 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = CBY22P58G8;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "$(SRCROOT)/rswitch-cmd/Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = "is.rud.rswitch-cmd";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
STRIP_INSTALLED_PRODUCT = YES;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
01575A3A245443D7004A5715 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "Developer ID Application";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = CBY22P58G8;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "$(SRCROOT)/rswitch-cmd/Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = "is.rud.rswitch-cmd";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
STRIP_INSTALLED_PRODUCT = YES;
SWIFT_VERSION = 5.0;
};
name = Release;
};
01F3EF16230E635500DF5DF9 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -459,7 +628,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@ -478,11 +647,12 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INSTALL_PATH = /Users/hrbrmstr/Desktop;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
STRIP_INSTALLED_PRODUCT = NO;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
@ -520,7 +690,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@ -533,11 +703,12 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INSTALL_PATH = /Users/hrbrmstr/Desktop;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = NO;
SDKROOT = macosx;
STRIP_INSTALLED_PRODUCT = NO;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
@ -570,6 +741,8 @@
PRODUCT_BUNDLE_IDENTIFIER = is.rud.bob.RSwitch;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "rswitch-1+";
SKIP_INSTALL = NO;
STRIP_INSTALLED_PRODUCT = YES;
SWIFT_OBJC_BRIDGING_HEADER = "RSwitch/ObjC/RSwitch-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
@ -603,6 +776,8 @@
PRODUCT_BUNDLE_IDENTIFIER = is.rud.bob.RSwitch;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "rswitch-1+";
SKIP_INSTALL = NO;
STRIP_INSTALLED_PRODUCT = YES;
SWIFT_OBJC_BRIDGING_HEADER = "RSwitch/ObjC/RSwitch-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
@ -612,6 +787,15 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
01575A38245443D7004A5715 /* Build configuration list for PBXNativeTarget "rswitch-cmd" */ = {
isa = XCConfigurationList;
buildConfigurations = (
01575A39245443D7004A5715 /* Debug */,
01575A3A245443D7004A5715 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
01F3EF03230E635300DF5DF9 /* Build configuration list for PBXProject "RSwitch" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@ -631,6 +815,25 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
01575A3E24544892004A5715 /* XCRemoteSwiftPackageReference "swift-argument-parser" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "git@github.com:apple/swift-argument-parser.git";
requirement = {
branch = master;
kind = branch;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
01575A3F24544892004A5715 /* ArgumentParser */ = {
isa = XCSwiftPackageProductDependency;
package = 01575A3E24544892004A5715 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
productName = ArgumentParser;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 01F3EF00230E635300DF5DF9 /* Project object */;
}

78
RSwitch.xcodeproj/xcshareddata/xcschemes/RSwitch.xcscheme

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1150"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "01F3EF07230E635300DF5DF9"
BuildableName = "RSwitch.app"
BlueprintName = "RSwitch"
ReferencedContainer = "container:RSwitch.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "01F3EF07230E635300DF5DF9"
BuildableName = "RSwitch.app"
BlueprintName = "RSwitch"
ReferencedContainer = "container:RSwitch.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "01F3EF07230E635300DF5DF9"
BuildableName = "RSwitch.app"
BlueprintName = "RSwitch"
ReferencedContainer = "container:RSwitch.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

13
RSwitch.xcodeproj/xcuserdata/hrbrmstr.xcuserdatad/xcschemes/xcschememanagement.plist

@ -9,6 +9,19 @@
<key>orderHint</key>
<integer>2</integer>
</dict>
<key>rswitch-cmd.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>01F3EF07230E635300DF5DF9</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

16
RSwitch.xcworkspace/xcshareddata/swiftpm/Package.resolved

@ -0,0 +1,16 @@
{
"object": {
"pins": [
{
"package": "swift-argument-parser",
"repositoryURL": "git@github.com:apple/swift-argument-parser.git",
"state": {
"branch": "master",
"revision": "1081d08b1d716e6a68a9cbc258bb309359fbae1e",
"version": null
}
}
]
},
"version": 1
}

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

Binary file not shown.

74
RSwitch/Base.lproj/Main.storyboard

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="15505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15505"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="16097"/>
<capability name="System colors introduced in macOS 10.14" minToolsVersion="10.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@ -832,11 +832,11 @@ DQ
<scrollView appearanceType="aqua" fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" hasVerticalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rEB-nx-gFw">
<rect key="frame" x="9" y="11" width="463" height="247"/>
<autoresizingMask key="autoresizingMask"/>
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="iCP-uh-CRl">
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="iCP-uh-CRl">
<rect key="frame" x="0.0" y="0.0" width="463" height="247"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView ambiguous="YES" editable="NO" drawsBackground="NO" importsGraphics="NO" verticallyResizable="YES" smartInsertDelete="YES" id="kWH-Et-k6l">
<textView 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"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
@ -845,31 +845,13 @@ DQ
<size key="maxSize" width="463" height="10000000"/>
<attributedString key="textStorage">
<fragment>
<string key="content" base64-UTF8="YES">
Cg
</string>
<attributes>
<color key="NSColor" name="textColor" catalog="System" colorSpace="catalog"/>
<font key="NSFont" metaFont="label" size="17"/>
<paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
</attributes>
</fragment>
<fragment>
<string key="content">RSwitch v1.6.0
<string key="content">
RSwitch v1.7.0
Copyright © 2019 Bob Rudis
Copyright © 2020 Bob Rudis
MIT Licensed
</string>
<attributes>
<color key="NSColor" red="0.0" green="0.56031829119999998" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<font key="NSFont" metaFont="label" size="17"/>
<paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
</attributes>
</fragment>
<fragment>
<string key="content" base64-UTF8="YES">
Cg
</string>
<attributes>
<color key="NSColor" name="textColor" catalog="System" colorSpace="catalog"/>
@ -901,7 +883,7 @@ String+Version by DragonCherry
ProcInfo by Patrick Wardle
Just by Daniel Duan</string>
<attributes>
<color key="NSColor" red="0.0" green="0.56031829119999998" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="NSColor" name="textColor" catalog="System" colorSpace="catalog"/>
<font key="NSFont" size="11" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="center" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
</attributes>
@ -911,11 +893,11 @@ Just by Daniel Duan</string>
</textView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="1Xi-yD-fAs">
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="1Xi-yD-fAs">
<rect key="frame" x="-100" y="-100" width="225" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="S8X-5h-pQ6">
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="S8X-5h-pQ6">
<rect key="frame" x="-100" y="-100" width="15" height="223"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
@ -961,6 +943,40 @@ Just by Daniel Duan</string>
</objects>
<point key="canvasLocation" x="1543" y="1669"/>
</scene>
<!--Window Controller-->
<scene sceneID="EW7-BM-Jxb">
<objects>
<windowController storyboardIdentifier="exportPopupPanel" id="VkT-PO-mgW" customClass="ExportWebViewController" customModule="RSwitch" customModuleProvider="target" sceneMemberID="viewController">
<window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="jld-Yw-4I9" customClass="NSPanel">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="425" y="470" width="480" height="270"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1440"/>
<connections>
<outlet property="delegate" destination="VkT-PO-mgW" id="Kk8-u6-crK"/>
</connections>
</window>
<connections>
<segue destination="Emi-lu-BKC" kind="relationship" relationship="window.shadowedContentViewController" id="Zko-qD-0ow"/>
</connections>
</windowController>
<customObject id="ewW-uJ-OlL" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2423" y="406"/>
</scene>
<!--Export Popup View Controller-->
<scene sceneID="2dv-Ig-duI">
<objects>
<viewController id="Emi-lu-BKC" customClass="exportPopupViewController" customModule="RSwitch" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="ta8-41-7dT">
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
<autoresizingMask key="autoresizingMask"/>
</view>
</viewController>
<customObject id="RCl-OA-PEF" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2382" y="1492"/>
</scene>
<!--Rstudio Server Session Web View Controller-->
<scene sceneID="g2O-De-dmv">
<objects>

5
RSwitch/Swift/AppDelegate.swift

@ -38,6 +38,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSToolbarDelegate {
@objc func performTimer(_ sender: Timer) {
if (Preferences.hourlyRStudioCheck) { performRStudioCheck(sender) }
if (Preferences.ensureFileHandlers) { FileAssociationUtils.setHandlers() }
}
var mainStoryboard: NSStoryboard!
@ -92,9 +93,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSToolbarDelegate {
sess = RStudioServerSessionManager()
FileAssociationUtils.getHandlers();
FileAssociationUtils.setHandlers();
FileAssociationUtils.getHandlers();
if (Preferences.ensureFileHandlers) { FileAssociationUtils.setHandlers() }
timer = Timer.scheduledTimer(
timeInterval: 3600,

63
RSwitch/Swift/Downloaders/DownloadFromRStudioServer.swift

@ -0,0 +1,63 @@
//
// DownloadFromRStudioServer.swift
// RSwitch
//
// Created by hrbrmstr on 8/24/19.
// Copyright © 2019 Bob Rudis. All rights reserved.
//
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)!
if (FileManager.default.fileExists(atPath: fsURL.path)) {
NSLog("Deleting old file")
do {
try FileManager.default.removeItem(at: fsURL)
} catch {
NSLog("error deleting old file")
}
}
let task = URLSession.shared.downloadTask(with: rsURL) {
localURL, urlResponse, error in
if (error != nil) {
NSLog("dler \(String(describing: error))")
} else {
if let localURL = localURL {
NSLog("We've got the data");
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.activateFileViewerSelecting([fsURL])
} catch {
NSLog("Move Error \(error)")
}
}
}
}
task.resume()
}

22
RSwitch/Swift/ExportWebViewController.swift

@ -0,0 +1,22 @@
//
// ExportWebViewController.swift
// RSwitch
//
// Created by hrbrmstr on 5/24/20.
// Copyright © 2020 Bob Rudis. All rights reserved.
//
import Cocoa
class ExportWebViewController: NSWindowController {
override func windowDidLoad() {
shouldCascadeWindows = false
window?.setFrameAutosaveName(window!.title)
super.windowDidLoad()
}
}

1
RSwitch/Swift/HandleRSwitch.swift

@ -33,6 +33,7 @@ extension AppDelegate {
withDestinationURL: NSURL(fileURLWithPath: title_link) as URL
)
self.notifyUser(title: "Success", text: "Current R version switched to " + title!)
// self.notifyUserWithDL(title: "Success", subtitle: "Subtitle", text: "Current R version switched to " + title!)
} catch {
self.notifyUser(title: "Action failed", text: "Failed to create alias for " + title_link + " (\(error))")
}

18
RSwitch/Swift/Menu.swift

@ -34,6 +34,18 @@ extension AppDelegate: NSMenuDelegate {
}
}
@objc func toggle_ensure_file_handlers(_ sender: NSMenuItem) {
Preferences.ensureFileHandlers = !Preferences.ensureFileHandlers
if (Preferences.ensureFileHandlers) { FileAssociationUtils.setHandlers() }
if let menu = statusItem.menu, let item = menu.item(withTag: 98) {
item.state = Preferences.ensureFileHandlers.stateValue
}
}
@objc func subscribeToMailingList(_ sender: NSMenuItem) {
NSWorkspace.shared.open(URL(string: "https://lists.sr.ht/~hrbrmstr/rswitch")!)
@ -115,6 +127,12 @@ extension AppDelegate: NSMenuDelegate {
rstudioCheckItem.state = Preferences.hourlyRStudioCheck.stateValue
prefSub.addItem(rstudioCheckItem)
let fileHandlersCheckItem = NSMenuItem(title: "Ensure RStudio opens R/Rmd files", action: #selector(toggle_ensure_file_handlers), keyEquivalent: "")
fileHandlersCheckItem.tag = 97
fileHandlersCheckItem.target = self
fileHandlersCheckItem.state = Preferences.ensureFileHandlers.stateValue
prefSub.addItem(fileHandlersCheckItem)
menu.addItem(NSMenuItem(title: "Check for update…", action: #selector(checkForUpdate), keyEquivalent: ""))
menu.addItem(NSMenuItem(title: "Subscribe to mailing list…", action: #selector(subscribeToMailingList), keyEquivalent: ""))
menu.addItem(NSMenuItem(title: "About RSwitch…", action: #selector(showAbout), keyEquivalent: ""))

16
RSwitch/Swift/MenuActions/BrowseMenuAction.swift

@ -30,7 +30,7 @@ class BrowseMenuAction {
public var url : URL
private static let webItemsR = [
BrowseMenuAction(title: "R for macOS Developer's", url: "https://mac.r-project.org/"),
BrowseMenuAction(title: "R for macOS…", url: "https://mac.r-project.org/"),
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-devel News…", url: "https://developer.r-project.org/blosxom.cgi/R-devel/NEWS"),
@ -41,7 +41,7 @@ class BrowseMenuAction {
private static let webItemsExt = [
BrowseMenuAction(title: "R Package Documentation (rdrr.io)…", url: "https://rdrr.io/"),
BrowseMenuAction(title: "R Compiler Tools for RCpp on macOS…", url: "https://thecoatlessprofessor.com/programming/cpp/r-compiler-tools-for-rcpp-on-macos/"),
BrowseMenuAction(title: "R Compiler Tools for Rcpp on macOS…", url: "https://thecoatlessprofessor.com/programming/cpp/r-compiler-tools-for-rcpp-on-macos/"),
BrowseMenuAction(title: "Rseek…", url: "https://rseek.org"),
BrowseMenuAction(title: "R StackOverflow…", url: "https://stackoverflow.com/questions/tagged/r"),
BrowseMenuAction(title: "ROpenSci Discuss…", url: "https://discuss.ropensci.org/"),
@ -54,12 +54,12 @@ class BrowseMenuAction {
]
private static let webItemsMan = [
BrowseMenuAction(title: "An Introduction to R…", url: "file:///Library/Frameworks/R.framework/Versions/3.6/Resources/doc/manual/R-intro.html"),
BrowseMenuAction(title: "R Data Import/Export…", url: "file:///Library/Frameworks/R.framework/Versions/3.6/Resources/doc/manual/R-data.html"),
BrowseMenuAction(title: "R Installation and Administration…", url: "file:///Library/Frameworks/R.framework/Versions/3.6/Resources/doc/manual/R-admin.html"),
BrowseMenuAction(title: "Writing R Extensions…", url: "file:///Library/Frameworks/R.framework/Versions/3.6/Resources/doc/manual/"),
BrowseMenuAction(title: "The R language definition…", url: "file:///Library/Frameworks/R.framework/Versions/3.6/Resources/doc/manual/R-exts.html"),
BrowseMenuAction(title: "R Internals…", url: "file:///Library/Frameworks/R.framework/Versions/3.6/Resources/doc/manual/R-ints.html")
BrowseMenuAction(title: "An Introduction to R…", url: "file:///Library/Frameworks/R.framework/Resources/doc/manual/R-intro.html"),
BrowseMenuAction(title: "R Data Import/Export…", url: "file:///Library/Frameworks/R.framework/Resources/doc/manual/R-data.html"),
BrowseMenuAction(title: "R Installation and Administration…", url: "file:///Library/Frameworks/R.framework/Resources/doc/manual/R-admin.html"),
BrowseMenuAction(title: "Writing R Extensions…", url: "file:///Library/Frameworks/R.framework/Resources/doc/manual/"),
BrowseMenuAction(title: "The R language definition…", url: "file:///Library/Frameworks/R.framework/Resources/doc/manual/R-exts.html"),
BrowseMenuAction(title: "R Internals…", url: "file:///Library/Frameworks/R.framework/Resources/doc/manual/R-ints.html")
]
private static let webItemsBook = [

4
RSwitch/Swift/MenuActions/RStudioServerAction.swift

@ -36,14 +36,14 @@ class RStudioServerMenuAction {
menu.addItem(rsDropdown)
menu.setSubmenu(rsSub, for: rsDropdown)
let newRStudioSessItem = NSMenuItem(title: "New RStudio Server Connection…", action: Selector(("newRstudioServerSession:")), keyEquivalent: "")
let newRStudioSessItem = NSMenuItem(title: "New RStudio Server Connection…", action: #selector(AppDelegate.newRstudioServerSession(_:)), keyEquivalent: "")
rsSub.addItem(newRStudioSessItem)
rsSub.addItem(NSMenuItem.separator())
for sess in manager.sessions! {
let sessItem = NSMenuItem(title: sess.menuTitle, action: Selector(("activateServerSession:")), keyEquivalent: "")
let sessItem = NSMenuItem(title: sess.menuTitle, action: #selector(AppDelegate.activateServerSession(_:)), keyEquivalent: "")
sessItem.representedObject = sess
rsSub.addItem(sessItem)

5
RSwitch/Swift/Notify.swift

@ -16,10 +16,12 @@ extension AppDelegate : NSUserNotificationCenterDelegate {
let notification = NSUserNotification()
// notification.identifier = "RSwitch"
notification.title = title
notification.subtitle = subtitle
notification.informativeText = text
notification.hasActionButton = true
notification.otherButtonTitle = "Dismiss"
notification.actionButtonTitle = "Download"
notification.soundName = NSUserNotificationDefaultSoundName
@ -34,6 +36,7 @@ extension AppDelegate : NSUserNotificationCenterDelegate {
let notification = NSUserNotification()
// notification.identifier = "RSwitch"
notification.title = title
notification.subtitle = subtitle
notification.informativeText = text
@ -46,10 +49,12 @@ 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)
}

84
RSwitch/Swift/RStudioServerSessionWebViewController.swift

@ -55,7 +55,6 @@ extension RstudioServerSessionWebViewController: WKUIDelegate {
NSLog("PANELING!")
print("PANELING!")
let openPanel = NSOpenPanel()
openPanel.canChooseFiles = true
@ -77,15 +76,82 @@ extension RstudioServerSessionWebViewController: WKUIDelegate {
if navigationAction.targetFrame == nil {
let plotWindowController = NSStoryboard(name: "Main", bundle: nil).instantiateController(withIdentifier: "plotPopupPanel") as! PlotWebViewController
let plotWV = (plotWindowController.contentViewController as! plotPopupViewController)
plotWV.view.window?.title = navigationAction.request.url!.absoluteString
plotWV.setupWebView(configuration: configuration)
plotWindowController.showWindow(self)
plotWV.loadWebView(urlIn: navigationAction.request.url!.absoluteString)
let u = URL(string: navigationAction.request.url!.absoluteString)!
return(plotWV.webView)
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)
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) {
download_from_studio_server(fromRS: url.absoluteString, toFS: savePanel.url!.absoluteString)
} else {
NSLog("Don't do anything!")
}
savePanel.close()
}
}
}
return(exportWV.webView)
} else {
let plotWindowController = NSStoryboard(name: "Main", bundle: nil).instantiateController(withIdentifier: "plotPopupPanel") as! PlotWebViewController
let plotWV = (plotWindowController.contentViewController as! plotPopupViewController)
plotWV.view.window?.title = navigationAction.request.url!.absoluteString
plotWV.setupWebView(configuration: configuration)
plotWindowController.showWindow(self)
plotWV.loadWebView(urlIn: navigationAction.request.url!.absoluteString)
return(plotWV.webView)
}
}

4
RSwitch/Swift/Utils/Associations.swift

@ -45,12 +45,12 @@ class FileAssociationUtils {
public static func setHandlers() {
let setResR : String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, "R" as CFString, nil)?.takeRetainedValue() as String? ?? "";
NSLog("UTI of .R extension: " + setResR);
//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);
//NSLog("UTI of .Rmd extension: " + setResRmd);
LSSetDefaultRoleHandlerForContentType(setResRmd as CFString, LSRolesMask.all, "org.rstudio.RStudio" as CFString);

12
RSwitch/Swift/Utils/Preferences.swift

@ -21,6 +21,7 @@ extension UserDefaults {
enum Key: String {
case showDockIcon = "showDockIcon"
case hourlyRStudioCheck = "hourlyRStudioCheck"
case ensureFileHandlers = "ensureFileHandlers"
case firstRunGone = "firstRunGone"
case lastVersionNotified = ""
}
@ -86,10 +87,19 @@ struct Preferences {
defaults.synchronize()
}
}
static var ensureFileHandlers: Bool {
get { return(defaults.bool(forKey: .ensureFileHandlers)) }
set {
defaults.set(newValue, forKey: .ensureFileHandlers)
defaults.synchronize()
}
}
static func restore() {
Preferences.showDockIcon = false
Preferences.hourlyRStudioCheck = false
Preferences.ensureFileHandlers = false
Preferences.lastVersionNotified = ""
}

26
RSwitch/Swift/Utils/urls.swift

@ -0,0 +1,26 @@
//
// urls.swift
// RSwitch
//
// Created by hrbrmstr on 5/24/20.
// Copyright © 2020 Bob Rudis. All rights reserved.
//
import Foundation
import Cocoa
import WebKit
extension URL {
var queryParameters: QueryParameters { return QueryParameters(url: self) }
}
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
}
}

100
RSwitch/Swift/exportPopupViewController.swift

@ -0,0 +1,100 @@
//
// exportPopupViewController.swift
// RSwitch
//
// Created by hrbrmstr on 5/24/20.
// Copyright © 2020 Bob Rudis. All rights reserved.
//
import Cocoa
import WebKit
// EXPORT
class exportPopupViewController: NSViewController {
var webView: WKWebView!
var urlPath: String = ""
open override func viewDidLoad() {
super.viewDidLoad()
}
func setupWebView(configuration: WKWebViewConfiguration) {
webView = WKWebView(frame: view.bounds, configuration: configuration)
webView.autoresizingMask = [.width, .height]
webView.uiDelegate = self
webView.navigationDelegate = self
view.addSubview(webView)
}
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()
}
}
}
}
override func viewDidAppear() {
super.viewDidAppear()
}
}
extension exportPopupViewController: WKUIDelegate {
func webViewDidClose(_ webView: WKWebView) {
self.view.window?.close()
}
}
extension exportPopupViewController: WKNavigationDelegate {
open func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print("Export DID START \(String(describing: webView.url))")
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("Export DID FINISH \(String(describing: webView.url))")
}
}

19
RSwitch/Swift/plotPopupViewController.swift

@ -29,7 +29,6 @@ class plotPopupViewController: NSViewController {
}
func loadWebView(urlIn: String) {
urlPath = urlIn
@ -40,8 +39,24 @@ class plotPopupViewController: NSViewController {
// 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)
webView.load(urlRequest)
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)
}
}
}

7
guide/index.Rmd

@ -51,16 +51,15 @@ The `Resources` directory (and everything else in `/Library/Frameworks/R.framewo
- `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](https://mac.r-project.org/) 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](https://mac.r-project.org/) and downloading the `tar.gz` version of those distributions:
![](r-macos-downloads.png)
Here are direct `https` links to the tarballs:
- [R 3.4](https://mac.r-project.org/mavericks/R-3.4-branch/R-3.4-branch-mavericks-sa-x86_64.tar.gz) (oldrel-1)
- [R 3.5](https://mac.r-project.org/el-capitan/R-3.5-branch/R-3.5-branch-el-capitan-sa-x86_64.tar.gz) (oldrel)
- [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.7](https://mac.r-project.org/el-capitan/R-devel/R-devel-el-capitan-sa-x86_64.tar.gz) (devel)
- [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)
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:

BIN
guide/r-macos-downloads.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

After

Width:  |  Height:  |  Size: 346 KiB

22
rswitch-cmd/Info.plist

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>is.rud.rswitch-cmd</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>rswitch-cmd</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2020 Bob Rudis. All rights reserved. MIT Licensed</string>
</dict>
</plist>

90
rswitch-cmd/main.swift

@ -0,0 +1,90 @@
//
// main.swift
// rswitch-cmd
//
// Created by boB Rudis on 4/25/20.
// Copyright © 2020 Bob Rudis. All rights reserved.
//
import Foundation
import ArgumentParser
final class StandardErrorOutputStream: TextOutputStream {
func write(_ string: String) {
FileHandle.standardError.write(Data(string.utf8))
}
}
struct RSwitch: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Switch R versions.",
version: "1.0.0"
)
@Flag(name: .shortAndLong, help: "List R versions.")
var list: Bool
@Argument(help: "The R version to switch to.")
var rversion: String?
func run() throws {
var outputStream = StandardErrorOutputStream()
let targetPath = RVersions.currentVersionTarget()
let versions = try RVersions.reloadVersions()
if (list || (rversion == nil)) {
for version in versions {
let complete = RVersions.hasRBinary(versionPath: version)
var v = version
if (version == targetPath) { v = v + " *" }
if (!complete) { v = version + " (incomplete)" }
print(v)
}
} else {
if (!versions.contains(rversion!)) {
print("R version " + rversion! + " not found.", to: &outputStream)
} else {
if (rversion! == targetPath) {
print("Current R version already points to " + targetPath)
} else {
let fm = FileManager.default
let rm_link = (RVersions.macos_r_framework as NSString).appendingPathComponent("Current")
let new_link = (RVersions.macos_r_framework as NSString).appendingPathComponent(rversion!)
do {
try fm.removeItem(atPath: rm_link)
} catch {
print("Failed to remove existing R version symlink. Check file/directory permissions.", to: &outputStream)
Darwin.exit(1)
}
do {
try fm.createSymbolicLink(
at: NSURL(fileURLWithPath: rm_link) as URL,
withDestinationURL: NSURL(fileURLWithPath: new_link) as URL
)
} catch {
print("Failed to create a symlink to the chosen R version. Check file/directory permissions.", to: &outputStream)
Darwin.exit(2)
}
Darwin.exit(0)
}
}
}
}
}
RSwitch.main()
Loading…
Cancel
Save