瀏覽代碼

Add demo code

xcbosa mbp16 2 年之前
父節點
當前提交
cf86e3bad7

+ 1 - 1
Modules/XCTreeLang

@@ -1 +1 @@
-Subproject commit a113d59f5a22d91d2819ee04ddee3bca4c5d9425
+Subproject commit 931f9dd6646cca1d4cbb5adf73464c2b88e32f84

+ 26 - 7
XCTreeLangDemo.xcodeproj/project.pbxproj

@@ -8,10 +8,11 @@
 
 /* Begin PBXBuildFile section */
 		75E262402A82199D00CC55C6 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 75E2623F2A82199D00CC55C6 /* AppDelegate.m */; };
-		75E262462A82199D00CC55C6 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 75E262452A82199D00CC55C6 /* ViewController.m */; };
+		75E262462A82199D00CC55C6 /* RootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 75E262452A82199D00CC55C6 /* RootViewController.m */; };
 		75E2624B2A82199E00CC55C6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 75E2624A2A82199E00CC55C6 /* Assets.xcassets */; };
 		75E2624E2A82199E00CC55C6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 75E2624C2A82199E00CC55C6 /* LaunchScreen.storyboard */; };
 		75E262512A82199E00CC55C6 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 75E262502A82199E00CC55C6 /* main.m */; };
+		75E262582A8220C000CC55C6 /* InitialContent.xct in Resources */ = {isa = PBXBuildFile; fileRef = 75E262572A8220C000CC55C6 /* InitialContent.xct */; };
 		F21117A1C61597F517D248FF /* Pods_XCTreeLangDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F58CB9BF3ADA10A596FA66B /* Pods_XCTreeLangDemo.framework */; };
 /* End PBXBuildFile section */
 
@@ -22,12 +23,14 @@
 		75E2623B2A82199D00CC55C6 /* XCTreeLangDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XCTreeLangDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		75E2623E2A82199D00CC55C6 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
 		75E2623F2A82199D00CC55C6 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
-		75E262442A82199D00CC55C6 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
-		75E262452A82199D00CC55C6 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+		75E262442A82199D00CC55C6 /* RootViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = "<group>"; };
+		75E262452A82199D00CC55C6 /* RootViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = "<group>"; };
 		75E2624A2A82199E00CC55C6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		75E2624D2A82199E00CC55C6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
 		75E2624F2A82199E00CC55C6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		75E262502A82199E00CC55C6 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		75E262572A8220C000CC55C6 /* InitialContent.xct */ = {isa = PBXFileReference; lastKnownFileType = text; path = InitialContent.xct; sourceTree = "<group>"; };
+		75E262592A8220F700CC55C6 /* XCTreeLangDemo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = XCTreeLangDemo.entitlements; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -63,10 +66,12 @@
 		75E2623D2A82199D00CC55C6 /* XCTreeLangDemo */ = {
 			isa = PBXGroup;
 			children = (
+				75E262592A8220F700CC55C6 /* XCTreeLangDemo.entitlements */,
 				75E2623E2A82199D00CC55C6 /* AppDelegate.h */,
 				75E2623F2A82199D00CC55C6 /* AppDelegate.m */,
-				75E262442A82199D00CC55C6 /* ViewController.h */,
-				75E262452A82199D00CC55C6 /* ViewController.m */,
+				75E262442A82199D00CC55C6 /* RootViewController.h */,
+				75E262452A82199D00CC55C6 /* RootViewController.m */,
+				75E262572A8220C000CC55C6 /* InitialContent.xct */,
 				75E2624A2A82199E00CC55C6 /* Assets.xcassets */,
 				75E2624C2A82199E00CC55C6 /* LaunchScreen.storyboard */,
 				75E2624F2A82199E00CC55C6 /* Info.plist */,
@@ -81,7 +86,6 @@
 				45FFC2391B183F4F112909C4 /* Pods-XCTreeLangDemo.debug.xcconfig */,
 				2EFAC6B97CFB0BB3765F7932 /* Pods-XCTreeLangDemo.release.xcconfig */,
 			);
-			name = Pods;
 			path = Pods;
 			sourceTree = "<group>";
 		};
@@ -153,6 +157,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				75E2624E2A82199E00CC55C6 /* LaunchScreen.storyboard in Resources */,
+				75E262582A8220C000CC55C6 /* InitialContent.xct in Resources */,
 				75E2624B2A82199E00CC55C6 /* Assets.xcassets in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -206,7 +211,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				75E262462A82199D00CC55C6 /* ViewController.m in Sources */,
+				75E262462A82199D00CC55C6 /* RootViewController.m in Sources */,
 				75E262402A82199D00CC55C6 /* AppDelegate.m in Sources */,
 				75E262512A82199E00CC55C6 /* main.m in Sources */,
 			);
@@ -348,15 +353,18 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+				CODE_SIGN_ENTITLEMENTS = XCTreeLangDemo/XCTreeLangDemo.entitlements;
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = QM43SUA9CG;
+				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = XCTreeLangDemo/Info.plist;
 				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
 				INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
 				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
 				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
@@ -364,6 +372,10 @@
 				MARKETING_VERSION = 1.0;
 				PRODUCT_BUNDLE_IDENTIFIER = org.forgetive.XCTreeLangDemo;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+				SUPPORTS_MACCATALYST = YES;
+				SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+				SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
 				SWIFT_EMIT_LOC_STRINGS = YES;
 				TARGETED_DEVICE_FAMILY = "1,2";
 			};
@@ -375,15 +387,18 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+				CODE_SIGN_ENTITLEMENTS = XCTreeLangDemo/XCTreeLangDemo.entitlements;
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = QM43SUA9CG;
+				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = XCTreeLangDemo/Info.plist;
 				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
 				INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
 				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
 				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
@@ -391,6 +406,10 @@
 				MARKETING_VERSION = 1.0;
 				PRODUCT_BUNDLE_IDENTIFIER = org.forgetive.XCTreeLangDemo;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+				SUPPORTS_MACCATALYST = YES;
+				SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+				SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
 				SWIFT_EMIT_LOC_STRINGS = YES;
 				TARGETED_DEVICE_FAMILY = "1,2";
 			};

+ 3 - 2
XCTreeLangDemo/AppDelegate.h

@@ -1,14 +1,15 @@
 //
 //  AppDelegate.h
-//  XCTreeLangDemo
+//  TestApp
 //
-//  Created by 邢铖 on 2023/8/8.
+//  Created by 邢铖 on 2023/6/1.
 //
 
 #import <UIKit/UIKit.h>
 
 @interface AppDelegate : UIResponder <UIApplicationDelegate>
 
+@property (nonatomic, strong) UIWindow *window;
 
 @end
 

+ 14 - 19
XCTreeLangDemo/AppDelegate.m

@@ -1,11 +1,13 @@
 //
 //  AppDelegate.m
-//  XCTreeLangDemo
+//  TestApp
 //
-//  Created by 邢铖 on 2023/8/8.
+//  Created by 邢铖 on 2023/6/1.
 //
 
 #import "AppDelegate.h"
+#import "RootViewController.h"
+#import <XCTreeLang/XCTreeLang.h>
 
 @interface AppDelegate ()
 
@@ -13,28 +15,21 @@
 
 @implementation AppDelegate
 
+- (UIWindow *)window {
+    if (!_window) {
+        _window = [UIWindow new];
+        _window.rootViewController = [RootViewController new];
+    }
+    return _window;
+}
+
 
 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
     // Override point for customization after application launch.
+    [XCTLEngine.shared enableAutoEvaluateForViewController];
+    [self.window makeKeyAndVisible];
     return YES;
 }
 
 
-#pragma mark - UISceneSession lifecycle
-
-
-- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
-    // Called when a new scene session is being created.
-    // Use this method to select a configuration to create the new scene with.
-    return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
-}
-
-
-- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
-    // Called when the user discards a scene session.
-    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
-    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
-}
-
-
 @end

+ 43 - 0
XCTreeLangDemo/InitialContent.xct

@@ -0,0 +1,43 @@
+paragraph fib(inArray: array maxInputNumber: max) {
+    array.addObject(0)
+    for i in range(1 max) {
+        switch i {
+            lessthan 2 { nextthan }
+            equalthan 2 {
+                array.addObject(i)
+            }
+            else {
+                set last = array.objectAtIndex(minus(i 1))
+                set prev = array.objectAtIndex(minus(i 2))
+                set newValue = add(last prev)
+                array.addObject(newValue)
+            }
+        }
+    }
+}
+
+paragraph main {
+    NSMutableArray array { }
+    fib(inArray: array maxInputNumber: 10)
+    set id = 0
+    for it in array {
+        switch id {
+            equalthan 0 { continue }
+            else {
+                logn("fib(" id ") =" it)
+            }
+        }
+        set id = add(id 1)
+    }
+    setUpPreview()
+}
+
+paragraph setUpPreview {
+    export previewViewController
+    XCTLViewController previewViewController { } {
+        ^view.backgroundColor = UIColor.cyanColor
+    }
+}
+
+main()
+

+ 14 - 0
XCTreeLangDemo/RootViewController.h

@@ -0,0 +1,14 @@
+//
+//  ViewController.h
+//  TestApp
+//
+//  Created by 邢铖 on 2023/6/1.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface RootViewController : UIViewController
+
+
+@end
+

+ 222 - 0
XCTreeLangDemo/RootViewController.m

@@ -0,0 +1,222 @@
+//
+//  ViewController.m
+//  TestApp
+//
+//  Created by 邢铖 on 2023/6/1.
+//
+
+#import "RootViewController.h"
+#import <XCTreeLang/XCTreeLang.h>
+
+char *kRootViewControllerKVOKey = "kRootViewControllerKVOKey";
+
+@interface RootViewController () <UITextViewDelegate, XCTLStreamDelegate>
+
+@property (nonatomic, strong) UITextView *sourceTextView;
+@property (nonatomic, strong) UITextView *terminalTextView;
+@property (nonatomic, strong) UIButton *runButton;
+@property (nonatomic, strong) UIView *previewViewControllerContext;
+@property (nonatomic, strong) UIViewController *previewViewController;
+@property (nonatomic, copy) NSArray<NSLayoutConstraint *> *previewConstraints;
+
+@property (nonatomic, strong) UIView *testView;
+
+@end
+
+@implementation RootViewController
+
+- (UIView *)testView {
+    if (!_testView) {
+        _testView = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
+    }
+    return _testView;
+}
+
+- (void)viewDidLoad {
+    [self.view addSubview:self.sourceTextView];
+    [self.view addSubview:self.terminalTextView];
+    [self.view addSubview:self.runButton];
+    [self.view addSubview:self.previewViewControllerContext];
+    
+    [self.previewViewControllerContext.rightAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.rightAnchor].active = true;
+    [self.previewViewControllerContext.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = true;
+    [self.previewViewControllerContext.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor].active = true;
+    [self.previewViewControllerContext.widthAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.widthAnchor multiplier:0.3].active = true;
+    
+    [self.sourceTextView.leftAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leftAnchor].active = true;
+    [self.sourceTextView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = true;
+    [self.sourceTextView.rightAnchor constraintEqualToAnchor:self.previewViewControllerContext.leftAnchor].active = true;
+    [self.sourceTextView.heightAnchor constraintEqualToAnchor:self.terminalTextView.heightAnchor multiplier:2].active = true;
+    
+    [self.terminalTextView.topAnchor constraintEqualToAnchor:self.sourceTextView.bottomAnchor].active = true;
+    [self.terminalTextView.leftAnchor constraintEqualToAnchor:self.sourceTextView.leftAnchor].active = true;
+    [self.terminalTextView.rightAnchor constraintEqualToAnchor:self.sourceTextView.rightAnchor].active = true;
+    [self.terminalTextView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor].active = true;
+    
+    [self.runButton.rightAnchor constraintEqualToAnchor:self.sourceTextView.rightAnchor constant:-10].active = true;
+    [self.runButton.bottomAnchor constraintEqualToAnchor:self.sourceTextView.bottomAnchor constant:-10].active = true;
+    [self.runButton.widthAnchor constraintEqualToConstant:108].active = true;
+    [self.runButton.heightAnchor constraintEqualToConstant:38].active = true;
+    
+    [self addObserver:self
+           forKeyPath:@"previewViewController"
+              options:NSKeyValueObservingOptionOld
+              context:kRootViewControllerKVOKey];
+    
+    [self addObserver:self
+           forKeyPath:@"previewViewController"
+              options:NSKeyValueObservingOptionNew
+              context:kRootViewControllerKVOKey];
+    
+    [super viewDidLoad];
+}
+
+- (UITextView *)makeTextView {
+    UITextView *textView = [UITextView new];
+    textView.translatesAutoresizingMaskIntoConstraints = false;
+    textView.font = [UIFont fontWithName:@"Menlo" size:16];
+    textView.backgroundColor = UIColor.systemBackgroundColor;
+    textView.allowsEditingTextAttributes = false;
+    textView.contentMode = UIViewContentModeRedraw;
+    textView.autocorrectionType = UITextAutocorrectionTypeNo;
+    textView.smartQuotesType = UITextSmartQuotesTypeNo;
+    textView.smartDashesType = UITextSmartDashesTypeNo;
+    textView.smartInsertDeleteType = UITextSmartInsertDeleteTypeNo;
+    textView.autocapitalizationType = UITextAutocapitalizationTypeNone;
+    textView.spellCheckingType = UITextSpellCheckingTypeNo;
+    textView.textContentType = nil;
+    textView.tintColor = UIColor.systemOrangeColor;
+    textView.editable = true;
+    return textView;
+}
+
+- (UITextView *)sourceTextView {
+    if (!_sourceTextView) {
+        _sourceTextView = [self makeTextView];
+        _sourceTextView.backgroundColor = UIColor.systemBackgroundColor;
+        NSString *savedCode = [NSUserDefaults.standardUserDefaults stringForKey:@"code"];
+        if (savedCode == nil || savedCode.length == 0) {
+            savedCode = [NSString stringWithContentsOfFile:[NSBundle.mainBundle pathForResource:@"InitialContent" ofType:@"xct"]
+                                                  encoding:NSUTF8StringEncoding
+                                                     error:nil];
+        }
+        _sourceTextView.text = savedCode;
+        _sourceTextView.delegate = self;
+    }
+    return _sourceTextView;
+}
+
+- (UITextView *)terminalTextView {
+    if (!_terminalTextView) {
+        _terminalTextView = [self makeTextView];
+        _terminalTextView.backgroundColor = UIColor.tertiarySystemBackgroundColor;
+        _terminalTextView.editable = false;
+    }
+    return _terminalTextView;
+}
+
+- (UIButton *)runButton {
+    if (!_runButton) {
+        _runButton = [UIButton new];
+        _runButton.translatesAutoresizingMaskIntoConstraints = false;
+        _runButton.layer.cornerRadius = 10;
+        _runButton.backgroundColor = UIColor.systemFillColor;
+        [_runButton setTitleColor:UIColor.systemOrangeColor forState:UIControlStateNormal];
+        [_runButton setTitle:@"Run Code" forState:UIControlStateNormal];
+        [_runButton addTarget:self
+                       action:@selector(runButtonDidTouchUp)
+             forControlEvents:UIControlEventTouchUpInside];
+    }
+    return _runButton;
+}
+
+- (UIView *)previewViewControllerContext {
+    if (!_previewViewControllerContext) {
+        _previewViewControllerContext = [UIView new];
+        _previewViewControllerContext.translatesAutoresizingMaskIntoConstraints = false;
+        _previewViewControllerContext.backgroundColor = UIColor.secondarySystemBackgroundColor;
+    }
+    return _previewViewControllerContext;
+}
+
+- (void)runButtonDidTouchUp {
+    [self clearPreviewWithViewController:self.previewViewController];
+    _previewViewController = nil;
+    
+    self.terminalTextView.text = @"";
+    XCTLAST *program = [XCTLEngine.shared compileWithCode:self.sourceTextView.text];
+    if (program == NULL) {
+        self.terminalTextView.text = [self.terminalTextView.text stringByAppendingString:@"Compile failed, see program log for more details."];
+        return;
+    }
+    program.stdoutDelegate = self;
+    NSError *error;
+    [XCTLEngine.shared evaluateWithAst:program
+                          sourceObject:self
+                                 error:&error];
+    if (error) {
+        self.terminalTextView.text = [self.terminalTextView.text stringByAppendingString:error.localizedDescription];
+        self.terminalTextView.text = [self.terminalTextView.text stringByAppendingFormat:@"\n%@", error.description];
+    }
+}
+
+- (void)updatePreview {
+    if (self.previewViewController) {
+        [self addChildViewController:self.previewViewController];
+        [self.previewViewControllerContext addSubview:self.previewViewController.view];
+        self.previewViewController.view.translatesAutoresizingMaskIntoConstraints = false;
+        self.previewConstraints = @[
+            [self.previewViewController.view.leftAnchor constraintEqualToAnchor:self.previewViewControllerContext.leftAnchor],
+            [self.previewViewController.view.topAnchor constraintEqualToAnchor:self.previewViewControllerContext.topAnchor],
+            [self.previewViewController.view.rightAnchor constraintEqualToAnchor:self.previewViewControllerContext.rightAnchor],
+            [self.previewViewController.view.bottomAnchor constraintEqualToAnchor:self.previewViewControllerContext.bottomAnchor]
+        ];
+        for (NSLayoutConstraint *constraint in self.previewConstraints) {
+            constraint.active = true;
+        }
+    }
+}
+
+- (void)clearPreviewWithViewController:(UIViewController *)viewController {
+    if (self.previewConstraints) {
+        [self.previewViewControllerContext removeConstraints:self.previewConstraints];
+        self.previewConstraints = nil;
+    }
+    if (viewController) {
+        [viewController.view removeFromSuperview];
+        [viewController removeFromParentViewController];
+    }
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
+    if (context == kRootViewControllerKVOKey) {
+        if ([@"previewViewController" isEqualToString:keyPath]) {
+            UIViewController *oldValue = change[NSKeyValueChangeOldKey];
+            if (oldValue) {
+                if ([oldValue isKindOfClass:UIViewController.class]) {
+                    [self clearPreviewWithViewController:oldValue];
+                }
+            } else {
+                [self updatePreview];
+            }
+        }
+    } else {
+        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+    }
+}
+
+- (void)stream:(XCTLStream *)stream appendText:(NSString *)text {
+    self.terminalTextView.text = [self.terminalTextView.text stringByAppendingString:text];
+}
+
+- (void)textViewDidChange:(UITextView *)textView {
+    [NSUserDefaults.standardUserDefaults setValue:textView.text forKey:@"code"];
+}
+
+- (void)dealloc {
+    [self removeObserver:self
+              forKeyPath:@"previewViewController"
+                 context:kRootViewControllerKVOKey];
+}
+
+@end

+ 0 - 14
XCTreeLangDemo/ViewController.h

@@ -1,14 +0,0 @@
-//
-//  ViewController.h
-//  XCTreeLangDemo
-//
-//  Created by 邢铖 on 2023/8/8.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface ViewController : UIViewController
-
-
-@end
-

+ 0 - 22
XCTreeLangDemo/ViewController.m

@@ -1,22 +0,0 @@
-//
-//  ViewController.m
-//  XCTreeLangDemo
-//
-//  Created by 邢铖 on 2023/8/8.
-//
-
-#import "ViewController.h"
-
-@interface ViewController ()
-
-@end
-
-@implementation ViewController
-
-- (void)viewDidLoad {
-    [super viewDidLoad];
-    // Do any additional setup after loading the view.
-}
-
-
-@end

+ 10 - 0
XCTreeLangDemo/XCTreeLangDemo.entitlements

@@ -0,0 +1,10 @@
+<?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>com.apple.security.app-sandbox</key>
+	<true/>
+	<key>com.apple.security.network.client</key>
+	<true/>
+</dict>
+</plist>

+ 2 - 2
XCTreeLangDemo/main.m

@@ -1,8 +1,8 @@
 //
 //  main.m
-//  XCTreeLangDemo
+//  TestApp
 //
-//  Created by 邢铖 on 2023/8/8.
+//  Created by 邢铖 on 2023/6/1.
 //
 
 #import <UIKit/UIKit.h>