├── .gitignore
├── LICENSE.md
├── NewTerm.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── NewTermMarzipan
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
├── External
│ ├── CompactConstraint
│ │ ├── CompactConstraint.h
│ │ ├── LICENSE
│ │ ├── NSLayoutConstraint+CompactConstraint.h
│ │ ├── NSLayoutConstraint+CompactConstraint.m
│ │ ├── UIView+CompactConstraint.h
│ │ └── UIView+CompactConstraint.m
│ ├── UIColor+HBAdditions.h
│ ├── UIColor+HBAdditions.m
│ └── ncurses
│ │ ├── ncurses.h
│ │ ├── ncurses_dll.h
│ │ └── term.h
├── FontMetrics.h
├── FontMetrics.m
├── Fonts.plist
├── HBNTAppDelegate.h
├── HBNTAppDelegate.m
├── HBNTHUDView.h
├── HBNTHUDView.m
├── HBNTKeyboardButton.h
├── HBNTKeyboardButton.m
├── HBNTKeyboardToolbar.h
├── HBNTKeyboardToolbar.m
├── HBNTPTY.h
├── HBNTPTY.m
├── HBNTPreferences.h
├── HBNTPreferences.m
├── HBNTPreferencesRootController.h
├── HBNTPreferencesRootController.m
├── HBNTRootViewController.h
├── HBNTRootViewController.m
├── HBNTSubProcess.h
├── HBNTSubProcess.m
├── HBNTTabCollectionViewCell.h
├── HBNTTabCollectionViewCell.m
├── HBNTTabToolbar.h
├── HBNTTabToolbar.m
├── HBNTTerminalController.h
├── HBNTTerminalController.m
├── HBNTTerminalKeyInput.h
├── HBNTTerminalKeyInput.m
├── HBNTTerminalSessionViewController.h
├── HBNTTerminalSessionViewController.m
├── HBNTTerminalTextView.h
├── HBNTTerminalTextView.m
├── HBNTTextInputBase.h
├── HBNTTextInputBase.m
├── Info.plist
├── Main.storyboard
├── Main.storyboardc
│ ├── Info.plist
│ ├── U5R-jr-i31-view-bFg-2Y-cSI.nib
│ └── UINavigationController-a88-9D-dcr.nib
├── NSCharacterSet+iTerm.h
├── NSCharacterSet+iTerm.m
├── NSStringITerm.h
├── NSStringITerm.m
├── NewTermMarzipan.entitlements
├── ScreenChar.h
├── ScreenChar.m
├── Themes.plist
├── VT100.h
├── VT100.m
├── VT100ColorMap.h
├── VT100ColorMap.m
├── VT100Screen.h
├── VT100Screen.m
├── VT100StringSupplier.h
├── VT100StringSupplier.m
├── VT100Terminal.h
├── VT100Terminal.m
├── VT100Token.h
├── VT100Token.m
├── VT100Types.h
├── bell-hud.png
├── bell-hud@2x.png
├── bell-hud@3x.png
├── charmaps.h
├── colortest.txt
├── en.lproj
│ ├── InfoPlist.strings
│ └── Localizable.strings
├── iTermParser.h
├── main.m
├── settings.png
├── settings@2x.png
└── settings@3x.png
├── README.md
└── UIKit
└── PUT_PATCHED_HEADERS_HERE
/.gitignore:
--------------------------------------------------------------------------------
1 | # Crap
2 | .DS_Store
3 |
4 | # Xcode
5 | *.pbxuser
6 | !default.pbxuser
7 | xcuserdata
8 | *.xccheckout
9 | *.xcuserstate
10 |
11 | # Carthage
12 | Carthage/
13 |
14 | # Theos
15 | .theos
16 | packages/
17 |
18 | # Repo specific
19 | UIKit/*.h
20 | UIKit/*.apinotes
21 |
--------------------------------------------------------------------------------
/NewTerm.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/NewTerm.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/NewTermMarzipan/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "size" : "16x16",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "size" : "16x16",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "size" : "32x32",
16 | "scale" : "1x"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "size" : "32x32",
21 | "scale" : "2x"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "size" : "128x128",
26 | "scale" : "1x"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "size" : "128x128",
31 | "scale" : "2x"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "size" : "256x256",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "size" : "256x256",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "size" : "512x512",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "size" : "512x512",
51 | "scale" : "2x"
52 | }
53 | ],
54 | "info" : {
55 | "version" : 1,
56 | "author" : "xcode"
57 | }
58 | }
--------------------------------------------------------------------------------
/NewTermMarzipan/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/NewTermMarzipan/External/CompactConstraint/CompactConstraint.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Marco Arment on 2014-04-06.
3 | // Copyright (c) 2014 Marco Arment. See included LICENSE file.
4 | //
5 |
6 | #import "NSLayoutConstraint+CompactConstraint.h"
7 | #import "UIView+CompactConstraint.h"
8 |
--------------------------------------------------------------------------------
/NewTermMarzipan/External/CompactConstraint/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 marcoarment
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/NewTermMarzipan/External/CompactConstraint/NSLayoutConstraint+CompactConstraint.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Marco Arment on 2014-04-06.
3 | // Copyright (c) 2014 Marco Arment. See included LICENSE file.
4 | //
5 |
6 | #import "TargetConditionals.h"
7 |
8 | //#if TARGET_OS_IPHONE
9 | #import
10 | //#else
11 | //#import
12 | //#endif
13 |
14 | @interface NSLayoutConstraint (CompactConstraint)
15 |
16 | + (instancetype)compactConstraint:(NSString *)relationship metrics:(NSDictionary *)metrics views:(NSDictionary *)views self:(id)selfView;
17 | + (NSArray *)compactConstraints:(NSArray *)relationshipStrings metrics:(NSDictionary *)metrics views:(NSDictionary *)views self:(id)selfView;
18 |
19 | // And a convenient shortcut for creating constraints with the visualFormat string as the identifier
20 | + (NSArray *)identifiedConstraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary *)metrics views:(NSDictionary *)views;
21 |
22 | // Deprecated, will be removed shortly:
23 | + (instancetype)compactConstraint:(NSString *)relationship metrics:(NSDictionary *)metrics views:(NSDictionary *)views __attribute__ ((deprecated));
24 | + (NSArray *)compactConstraints:(NSArray *)relationshipStrings metrics:(NSDictionary *)metrics views:(NSDictionary *)views __attribute__ ((deprecated));
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/NewTermMarzipan/External/CompactConstraint/UIView+CompactConstraint.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Marco Arment on 2014-04-06.
3 | // Copyright (c) 2014 Marco Arment. See included LICENSE file.
4 | //
5 |
6 | #import "NSLayoutConstraint+CompactConstraint.h"
7 |
8 | //#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
9 | #define CCView UIView
10 | //#elif TARGET_OS_MAC
11 | // #define CCView NSView
12 | //#endif
13 |
14 | @interface CCView (CompactConstraint)
15 |
16 | // Add a single constraint with the compact syntax
17 | - (NSLayoutConstraint *)addCompactConstraint:(NSString *)relationship metrics:(NSDictionary *)metrics views:(NSDictionary *)views;
18 |
19 | // Add any number of constraints. Can also mix in Visual Format Language strings.
20 | - (NSArray *)addCompactConstraints:(NSArray *)relationshipStrings metrics:(NSDictionary *)metrics views:(NSDictionary *)views;
21 |
22 | // And a convenient shortcut for what we always end up doing with the visualFormat call.
23 | - (void)addConstraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary *)metrics views:(NSDictionary *)views;
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/NewTermMarzipan/External/CompactConstraint/UIView+CompactConstraint.m:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Marco Arment on 2014-04-06.
3 | // Copyright (c) 2014 Marco Arment. See included LICENSE file.
4 | //
5 |
6 | #import "UIView+CompactConstraint.h"
7 |
8 | @implementation CCView (CompactConstraint)
9 |
10 | - (NSLayoutConstraint *)addCompactConstraint:(NSString *)relationship metrics:(NSDictionary *)metrics views:(NSDictionary *)views
11 | {
12 | NSLayoutConstraint *constraint = [NSLayoutConstraint compactConstraint:relationship metrics:metrics views:views self:self];
13 | [self addConstraint:constraint];
14 | return constraint;
15 | }
16 |
17 | - (NSArray *)addCompactConstraints:(NSArray *)relationshipStrings metrics:(NSDictionary *)metrics views:(NSDictionary *)views;
18 | {
19 | NSMutableArray *mConstraints = [NSMutableArray arrayWithCapacity:relationshipStrings.count];
20 | for (NSString *relationship in relationshipStrings) {
21 | if ([relationship hasPrefix:@"H:"] || [relationship hasPrefix:@"V:"] || [relationship hasPrefix:@"|"] || [relationship hasPrefix:@"["]) {
22 | [mConstraints addObjectsFromArray:[NSLayoutConstraint identifiedConstraintsWithVisualFormat:relationship options:0 metrics:metrics views:views]];
23 | } else {
24 | [mConstraints addObject:[NSLayoutConstraint compactConstraint:relationship metrics:metrics views:views self:self]];
25 | }
26 | }
27 | NSArray *constraints = [mConstraints copy];
28 | [self addConstraints:constraints];
29 | return constraints;
30 | }
31 |
32 | - (void)addConstraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary *)metrics views:(NSDictionary *)views
33 | {
34 | [self addConstraints:[NSLayoutConstraint identifiedConstraintsWithVisualFormat:format options:opts metrics:metrics views:views]];
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/NewTermMarzipan/External/UIColor+HBAdditions.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | NS_ASSUME_NONNULL_BEGIN
5 |
6 | /// UIColor (HBAdditions) is a class category in `Cephei` that provides some convenience methods.
7 | @interface UIColor (HBAdditions)
8 |
9 | /// Creates and returns a color object using data from the specified object.
10 | ///
11 | /// The value is expected to either be an array of 3 or 4 integer RGB or RGBA color components
12 | /// (respectively), with values between 0 and 255, or a CSS hexadecimal color code string.
13 | ///
14 | /// @param value The object to retrieve data from. See the discussion for the supported object
15 | /// types.
16 | /// @returns The color object. The color information represented by this object is in the device RGB
17 | /// colorspace.
18 | + (instancetype)hb_colorWithPropertyListValue:(id)value;
19 |
20 | /// Initializes and returns a color object using data from the specified object.
21 | ///
22 | /// The value is expected to either be an array of 3 or 4 integer RGB or RGBA color components
23 | /// (respectively), with values between 0 and 255, or a CSS hexadecimal color code string.
24 | ///
25 | /// @param value The object to retrieve data from. See the discussion for the supported object
26 | /// types.
27 | /// @returns An initialized color object. The color information represented by this object is in the
28 | /// device RGB colorspace.
29 | - (instancetype)hb_initWithPropertyListValue:(id)value;
30 |
31 | @end
32 |
33 | NS_ASSUME_NONNULL_END
34 |
--------------------------------------------------------------------------------
/NewTermMarzipan/External/UIColor+HBAdditions.m:
--------------------------------------------------------------------------------
1 | #import "UIColor+HBAdditions.h"
2 |
3 | @implementation UIColor (HBAdditions)
4 |
5 | + (instancetype)hb_colorWithPropertyListValue:(id)value {
6 | return [[self alloc] hb_initWithPropertyListValue:value];
7 | }
8 |
9 | - (instancetype)hb_initWithPropertyListValue:(id)value {
10 | if (!value) {
11 | return nil;
12 | } else if ([value isKindOfClass:NSArray.class] && ((NSArray *)value).count == 3) {
13 | NSArray *array = value;
14 | return [UIColor colorWithRed:((NSNumber *)array[0]).integerValue / 255.f green:((NSNumber *)array[1]).integerValue / 255.f blue:((NSNumber *)array[2]).integerValue / 255.f alpha:1];
15 | } else if ([value isKindOfClass:NSString.class] && [((NSString *)value) hasPrefix:@"#"] && ((NSString *)value).length == 7) {
16 | unsigned int hexInteger = 0;
17 | NSScanner *scanner = [NSScanner scannerWithString:value];
18 | scanner.charactersToBeSkipped = [NSCharacterSet characterSetWithCharactersInString:@"#"];
19 | [scanner scanHexInt:&hexInteger];
20 |
21 | return [UIColor colorWithRed:((hexInteger & 0xFF0000) >> 16) / 255.f green:((hexInteger & 0xFF00) >> 8) / 255.f blue:(hexInteger & 0xFF) / 255.f alpha:1];
22 | } else {
23 | return nil;
24 | }
25 | }
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/NewTermMarzipan/External/ncurses/ncurses.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | * Copyright (c) 1998-2006,2007 Free Software Foundation, Inc. *
3 | * *
4 | * Permission is hereby granted, free of charge, to any person obtaining a *
5 | * copy of this software and associated documentation files (the *
6 | * "Software"), to deal in the Software without restriction, including *
7 | * without limitation the rights to use, copy, modify, merge, publish, *
8 | * distribute, distribute with modifications, sublicense, and/or sell *
9 | * copies of the Software, and to permit persons to whom the Software is *
10 | * furnished to do so, subject to the following conditions: *
11 | * *
12 | * The above copyright notice and this permission notice shall be included *
13 | * in all copies or substantial portions of the Software. *
14 | * *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
22 | * *
23 | * Except as contained in this notice, the name(s) of the above copyright *
24 | * holders shall not be used in advertising or otherwise to promote the *
25 | * sale, use or other dealings in this Software without prior written *
26 | * authorization. *
27 | ****************************************************************************/
28 | /* $Id: ncurses_dll.h,v 1.6 2007/03/10 19:21:49 tom Exp $ */
29 |
30 | #ifndef NCURSES_DLL_H_incl
31 | #define NCURSES_DLL_H_incl 1
32 |
33 | /* no longer needed on cygwin or mingw, thanks to auto-import */
34 | /* but this structure may be useful at some point for an MSVC build */
35 | /* so, for now unconditionally define the important flags */
36 | /* "the right way" for proper static and dll+auto-import behavior */
37 | #undef NCURSES_DLL
38 | #define NCURSES_STATIC
39 |
40 | #if defined(__CYGWIN__)
41 | # if defined(NCURSES_DLL)
42 | # if defined(NCURSES_STATIC)
43 | # undef NCURSES_STATIC
44 | # endif
45 | # endif
46 | # undef NCURSES_IMPEXP
47 | # undef NCURSES_API
48 | # undef NCURSES_EXPORT
49 | # undef NCURSES_EXPORT_VAR
50 | # if defined(NCURSES_DLL)
51 | /* building a DLL */
52 | # define NCURSES_IMPEXP __declspec(dllexport)
53 | # elif defined(NCURSES_STATIC)
54 | /* building or linking to a static library */
55 | # define NCURSES_IMPEXP /* nothing */
56 | # else
57 | /* linking to the DLL */
58 | # define NCURSES_IMPEXP __declspec(dllimport)
59 | # endif
60 | # define NCURSES_API __cdecl
61 | # define NCURSES_EXPORT(type) NCURSES_IMPEXP type NCURSES_API
62 | # define NCURSES_EXPORT_VAR(type) NCURSES_IMPEXP type
63 | #endif
64 |
65 | /* Take care of non-cygwin platforms */
66 | #if !defined(NCURSES_IMPEXP)
67 | # define NCURSES_IMPEXP /* nothing */
68 | #endif
69 | #if !defined(NCURSES_API)
70 | # define NCURSES_API /* nothing */
71 | #endif
72 | #if !defined(NCURSES_EXPORT)
73 | # define NCURSES_EXPORT(type) NCURSES_IMPEXP type NCURSES_API
74 | #endif
75 | #if !defined(NCURSES_EXPORT_VAR)
76 | # define NCURSES_EXPORT_VAR(type) NCURSES_IMPEXP type
77 | #endif
78 |
79 | /*
80 | * For reentrant code, we map the various global variables into SCREEN by
81 | * using functions to access them.
82 | */
83 | #define NCURSES_PUBLIC_VAR(name) _nc_##name
84 | #define NCURSES_WRAPPED_VAR(type,name) extern type NCURSES_PUBLIC_VAR(name)(void)
85 |
86 | #endif /* NCURSES_DLL_H_incl */
87 |
--------------------------------------------------------------------------------
/NewTermMarzipan/External/ncurses/ncurses_dll.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | * Copyright (c) 1998-2006,2007 Free Software Foundation, Inc. *
3 | * *
4 | * Permission is hereby granted, free of charge, to any person obtaining a *
5 | * copy of this software and associated documentation files (the *
6 | * "Software"), to deal in the Software without restriction, including *
7 | * without limitation the rights to use, copy, modify, merge, publish, *
8 | * distribute, distribute with modifications, sublicense, and/or sell *
9 | * copies of the Software, and to permit persons to whom the Software is *
10 | * furnished to do so, subject to the following conditions: *
11 | * *
12 | * The above copyright notice and this permission notice shall be included *
13 | * in all copies or substantial portions of the Software. *
14 | * *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
22 | * *
23 | * Except as contained in this notice, the name(s) of the above copyright *
24 | * holders shall not be used in advertising or otherwise to promote the *
25 | * sale, use or other dealings in this Software without prior written *
26 | * authorization. *
27 | ****************************************************************************/
28 | /* $Id: ncurses_dll.h,v 1.6 2007/03/10 19:21:49 tom Exp $ */
29 |
30 | #ifndef NCURSES_DLL_H_incl
31 | #define NCURSES_DLL_H_incl 1
32 |
33 | /* no longer needed on cygwin or mingw, thanks to auto-import */
34 | /* but this structure may be useful at some point for an MSVC build */
35 | /* so, for now unconditionally define the important flags */
36 | /* "the right way" for proper static and dll+auto-import behavior */
37 | #undef NCURSES_DLL
38 | #define NCURSES_STATIC
39 |
40 | #if defined(__CYGWIN__)
41 | # if defined(NCURSES_DLL)
42 | # if defined(NCURSES_STATIC)
43 | # undef NCURSES_STATIC
44 | # endif
45 | # endif
46 | # undef NCURSES_IMPEXP
47 | # undef NCURSES_API
48 | # undef NCURSES_EXPORT
49 | # undef NCURSES_EXPORT_VAR
50 | # if defined(NCURSES_DLL)
51 | /* building a DLL */
52 | # define NCURSES_IMPEXP __declspec(dllexport)
53 | # elif defined(NCURSES_STATIC)
54 | /* building or linking to a static library */
55 | # define NCURSES_IMPEXP /* nothing */
56 | # else
57 | /* linking to the DLL */
58 | # define NCURSES_IMPEXP __declspec(dllimport)
59 | # endif
60 | # define NCURSES_API __cdecl
61 | # define NCURSES_EXPORT(type) NCURSES_IMPEXP type NCURSES_API
62 | # define NCURSES_EXPORT_VAR(type) NCURSES_IMPEXP type
63 | #endif
64 |
65 | /* Take care of non-cygwin platforms */
66 | #if !defined(NCURSES_IMPEXP)
67 | # define NCURSES_IMPEXP /* nothing */
68 | #endif
69 | #if !defined(NCURSES_API)
70 | # define NCURSES_API /* nothing */
71 | #endif
72 | #if !defined(NCURSES_EXPORT)
73 | # define NCURSES_EXPORT(type) NCURSES_IMPEXP type NCURSES_API
74 | #endif
75 | #if !defined(NCURSES_EXPORT_VAR)
76 | # define NCURSES_EXPORT_VAR(type) NCURSES_IMPEXP type
77 | #endif
78 |
79 | /*
80 | * For reentrant code, we map the various global variables into SCREEN by
81 | * using functions to access them.
82 | */
83 | #define NCURSES_PUBLIC_VAR(name) _nc_##name
84 | #define NCURSES_WRAPPED_VAR(type,name) extern type NCURSES_PUBLIC_VAR(name)(void)
85 |
86 | #endif /* NCURSES_DLL_H_incl */
87 |
--------------------------------------------------------------------------------
/NewTermMarzipan/FontMetrics.h:
--------------------------------------------------------------------------------
1 | // FontMetrics.h
2 | // MobileTerminal
3 | //
4 | //
5 |
6 | #import
7 | @import CoreText;
8 |
9 | @interface FontMetrics : NSObject
10 |
11 | - (instancetype)initWithFont:(UIFont *)font boldFont:(UIFont *)boldFont;
12 |
13 | @property (nonatomic, strong, readonly) UIFont *regularFont;
14 | @property (nonatomic, strong, readonly) UIFont *boldFont;
15 |
16 | // The dimensions of a single glyph on the screen
17 | @property (nonatomic, readonly) CGSize boundingBox;
18 | @property (nonatomic, readonly) CGFloat descent;
19 | @property (nonatomic, readonly) CGFloat ascent;
20 | @property (nonatomic, readonly) CGFloat leading;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/NewTermMarzipan/FontMetrics.m:
--------------------------------------------------------------------------------
1 | // FontMetrics.m
2 | // MobileTerminal
3 |
4 | #import "FontMetrics.h"
5 |
6 | @implementation FontMetrics
7 |
8 | - (instancetype)initWithFont:(UIFont *)uiFont boldFont:(UIFont *)boldUIFont {
9 | self = [super init];
10 |
11 | if (self) {
12 | _regularFont = uiFont;
13 | _boldFont = boldUIFont;
14 |
15 | CTFontRef ctFont = (__bridge CTFontRef)_regularFont;
16 | NSAssert(ctFont != NULL, @"Error in CTFontCreateWithName");
17 |
18 | // This creates a CoreText line that isn't drawn, but used to get the
19 | // size of a single character. This will probably fail miserably if used
20 | // with a non-monospaced font.
21 | CFStringRef string = CFSTR("A");
22 | CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
23 | CFAttributedStringReplaceString(attrString, CFRangeMake(0, 0), string);
24 | CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFStringGetLength(string)), kCTFontAttributeName, ctFont);
25 | CTLineRef line = CTLineCreateWithAttributedString(attrString);
26 |
27 | CGFloat width = CTLineGetTypographicBounds(line, &_ascent, &_descent, &_leading);
28 |
29 | CFRelease(line);
30 | CFRelease(attrString);
31 | CFRelease(ctFont);
32 |
33 | _boundingBox = CGSizeMake(width, _ascent + _descent + _leading);
34 | }
35 |
36 | return self;
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/NewTermMarzipan/Fonts.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Courier
6 |
7 | Regular
8 | Courier
9 | Bold
10 | Courier-Bold
11 |
12 | Courier New
13 |
14 | Regular
15 | CourierNewPSMT
16 | Bold
17 | CourierNew-BoldMT
18 |
19 | Fira Code
20 |
21 | Regular
22 | FiraCode-Retina
23 | Bold
24 | FiraCode-Bold
25 |
26 | Hack
27 |
28 | Regular
29 | Hack-Regular
30 | Bold
31 | Hack-Bold
32 |
33 | Menlo
34 |
35 | Regular
36 | Menlo-Regular
37 | Bold
38 | Menlo-Bold
39 |
40 | Source Code Pro
41 |
42 | Regular
43 | SourceCodePro-Regular
44 | Bold
45 | SourceCodePro-Bold
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTAppDelegate.h
3 | // NewTerm
4 | //
5 | // Created by Adam D on 20/07/2014.
6 | // Copyright (c) 2014 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface HBNTAppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTAppDelegate.m
3 | // NewTerm
4 | //
5 | // Created by Adam D on 20/07/2014.
6 | // Copyright (c) 2014 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import "HBNTAppDelegate.h"
10 | #import "HBNTRootViewController.h"
11 |
12 | @implementation HBNTAppDelegate
13 |
14 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
15 | // UIColor *textColor = [UIColor whiteColor];
16 | // UIColor *tintColor = [UIColor colorWithRed:76.f / 255.f green:161.f / 255.f blue:1 alpha:1];
17 | // UIColor *backgroundColor = [UIColor colorWithWhite:26.f / 255.f alpha:1];
18 | // UIColor *lightTintColor = [UIColor colorWithWhite:60.f / 255.f alpha:1];
19 | //
20 | // [UINavigationBar appearance].barStyle = UIBarStyleBlack;
21 | // [UIToolbar appearance].barStyle = UIBarStyleBlack;
22 | //
23 | // [UITableView appearance].backgroundColor = backgroundColor;
24 | // [UITableViewCell appearance].backgroundColor = backgroundColor;
25 | //#pragma clang diagnostic push
26 | //#pragma clang diagnostic ignored "-Wdeprecated-declarations"
27 | // // this is deprecated but apple doesn’t exactly provide an easy, supported way to do this
28 | // [UITableViewCell appearance].textColor = textColor;
29 | //#pragma clang diagnostic pop
30 | //
31 | // [UINavigationBar appearance].titleTextAttributes = @{ NSForegroundColorAttributeName: textColor };
32 | // [UITextField appearance].textColor = textColor;
33 | //
34 | // [UITableView appearance].separatorColor = lightTintColor;
35 | // [UITextField appearance].keyboardAppearance = UIKeyboardAppearanceAlert;
36 | //
37 | // if ([UIScrollView instancesRespondToSelector:@selector(setKeyboardDismissMode:)]) {
38 | // [UIScrollView appearance].keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
39 | // }
40 |
41 | _window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
42 |
43 | // if ([_window respondsToSelector:@selector(setTintColor:)]) {
44 | // _window.tintColor = tintColor;
45 | // }
46 |
47 | _window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[HBNTRootViewController alloc] init]];
48 | [_window makeKeyAndVisible];
49 |
50 | return YES;
51 | }
52 |
53 | @end
54 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTHUDView.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @interface HBNTHUDView : UIView
4 |
5 | - (instancetype)initWithImage:(UIImage *)image;
6 |
7 | - (void)animate;
8 |
9 | @end
10 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTHUDView.m:
--------------------------------------------------------------------------------
1 | #import "HBNTHUDView.h"
2 |
3 | @implementation HBNTHUDView {
4 | UIImageView *_imageView;
5 | UIVisualEffectView *_backdropView;
6 | }
7 |
8 | - (instancetype)initWithImage:(UIImage *)image {
9 | self = [super initWithFrame:(CGRect){ CGPointZero, self.intrinsicContentSize }];
10 |
11 | if (self) {
12 | self.alpha = 0;
13 | self.clipsToBounds = YES;
14 | self.layer.cornerRadius = 16;
15 |
16 | _backdropView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
17 | _backdropView.frame = self.bounds;
18 | _backdropView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
19 | [self addSubview:_backdropView];
20 |
21 | _imageView = [[UIImageView alloc] initWithImage:image];
22 | _imageView.center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
23 | _imageView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin;
24 | [self addSubview:_imageView];
25 | }
26 |
27 | return self;
28 | }
29 |
30 | - (CGSize)intrinsicContentSize {
31 | return CGSizeMake(54.f, 54.f);
32 | }
33 |
34 | - (void)animate {
35 | // if our alpha is non-zero, we’re already visible. maybe we should extend the visible duration
36 | // but eh. just do nothing
37 | if (self.alpha != 0) {
38 | return;
39 | }
40 |
41 | // display for 1.5 secs, fade out in 0.3 secs, then remove from superview
42 | self.alpha = 1;
43 |
44 | [UIView animateWithDuration:0.3f delay:0.75f options:kNilOptions animations:^{
45 | self.alpha = 0;
46 | } completion:nil];
47 | }
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTKeyboardButton.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @interface HBNTKeyboardButton : UIButton
4 |
5 | + (instancetype)buttonWithTitle:(NSString *)title;
6 | + (instancetype)buttonWithTitle:(NSString *)title target:(id)target action:(SEL)action;
7 |
8 | @end
9 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTKeyboardButton.m:
--------------------------------------------------------------------------------
1 | #import "HBNTKeyboardButton.h"
2 |
3 | @implementation HBNTKeyboardButton
4 |
5 | + (instancetype)buttonWithTitle:(NSString *)title {
6 | HBNTKeyboardButton *button = [[self alloc] initWithFrame:CGRectZero];
7 | [button setTitle:title forState:UIControlStateNormal];
8 | return button;
9 | }
10 |
11 | + (instancetype)buttonWithTitle:(NSString *)title target:(id)target action:(SEL)action {
12 | HBNTKeyboardButton *button = [[self alloc] initWithFrame:CGRectZero];
13 | [button setTitle:title forState:UIControlStateNormal];
14 | [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
15 | return button;
16 | }
17 |
18 | - (instancetype)initWithFrame:(CGRect)frame {
19 | self = [super initWithFrame:frame];
20 |
21 | if (self) {
22 | self.titleLabel.font = [UIFont systemFontOfSize:IS_IPAD ? 18.f : 15.f];
23 | [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
24 | [self setTitleColor:[UIColor blackColor] forState:UIControlStateSelected];
25 | [self setBackgroundImage:[self _imageWithColor:[UIColor colorWithWhite:0.3529411765f alpha:1]] forState:UIControlStateNormal];
26 | [self setBackgroundImage:[self _imageWithColor:[UIColor colorWithWhite:0.2078431373f alpha:1]] forState:UIControlStateHighlighted];
27 | [self setBackgroundImage:[self _imageWithColor:[UIColor colorWithWhite:0.6784313725f alpha:1]] forState:UIControlStateSelected];
28 | self.layer.cornerRadius = IS_IPAD ? 6.f : 4.f;
29 | self.clipsToBounds = YES;
30 |
31 | // make a click when tapped
32 | [self addTarget:[UIDevice currentDevice] action:@selector(playInputClick) forControlEvents:UIControlEventTouchUpInside];
33 | }
34 |
35 | return self;
36 | }
37 |
38 | - (CGSize)intrinsicContentSize {
39 | CGSize contentSize = [super intrinsicContentSize];
40 | contentSize.width += 16.f;
41 | contentSize.height = IS_IPAD ? 40.f : UIViewNoIntrinsicMetric;
42 | return contentSize;
43 | }
44 |
45 | - (UIImage *)_imageWithColor:(UIColor *)color {
46 | // https://stackoverflow.com/a/14525049/709376
47 | CGRect rect = CGRectMake(0, 0, 1.f, 1.f);
48 | UIGraphicsBeginImageContext(rect.size);
49 | CGContextRef context = UIGraphicsGetCurrentContext();
50 |
51 | CGContextSetFillColorWithColor(context, color.CGColor);
52 | CGContextFillRect(context, rect);
53 |
54 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
55 | UIGraphicsEndImageContext();
56 |
57 | return image;
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTKeyboardToolbar.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @class HBNTKeyboardButton;
4 |
5 | @interface HBNTKeyboardToolbar : UIToolbar
6 |
7 | @property (nonatomic, strong) HBNTKeyboardButton *ctrlKey, *metaKey, *tabKey;
8 | @property (nonatomic, strong) HBNTKeyboardButton *upKey, *downKey, *leftKey, *rightKey;
9 |
10 | @end
11 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTKeyboardToolbar.m:
--------------------------------------------------------------------------------
1 | #import "HBNTKeyboardToolbar.h"
2 | #import "HBNTKeyboardButton.h"
3 | #import "UIView+CompactConstraint.h"
4 |
5 | @interface HBNTKeyboardToolbar ()
6 |
7 | @end
8 |
9 | @implementation HBNTKeyboardToolbar
10 |
11 | - (instancetype)init {
12 | self = [super init];
13 |
14 | if (self) {
15 | _ctrlKey = [HBNTKeyboardButton buttonWithTitle:@"Ctrl"];
16 | _metaKey = [HBNTKeyboardButton buttonWithTitle:@"Esc"];
17 | _tabKey = [HBNTKeyboardButton buttonWithTitle:@"Tab"];
18 |
19 | UIView *spacerView = [[UIView alloc] init];
20 |
21 | _upKey = [HBNTKeyboardButton buttonWithTitle:@"▲"];
22 | _downKey = [HBNTKeyboardButton buttonWithTitle:@"▼"];
23 | _leftKey = [HBNTKeyboardButton buttonWithTitle:@"◀"];
24 | _rightKey = [HBNTKeyboardButton buttonWithTitle:@"▶"];
25 |
26 | for (UIView *view in @[ _ctrlKey, _metaKey, _tabKey, spacerView, _upKey, _downKey, _leftKey, _rightKey ]) {
27 | view.translatesAutoresizingMaskIntoConstraints = NO;
28 | [self addSubview:view];
29 |
30 | [self addConstraintsWithVisualFormat:@"V:|-margin-[key]-margin-|" options:kNilOptions metrics:@{
31 | @"margin": self._isSmallDevice ? @2.f : @4.f
32 | } views:@{
33 | @"key": view
34 | }];
35 | }
36 |
37 | [self addConstraintsWithVisualFormat:@"H:|-outerMargin-[ctrlKey]-margin-[metaKey]-margin-[tabKey][spacerView(>=margin)][_upKey]-margin-[_downKey]-margin-[_leftKey]-margin-[_rightKey]-outerMargin-|" options:kNilOptions metrics:@{
38 | @"outerMargin": @3.f,
39 | @"margin": @6.f
40 | } views:@{
41 | @"ctrlKey": _ctrlKey,
42 | @"metaKey": _metaKey,
43 | @"tabKey": _tabKey,
44 | @"spacerView": spacerView,
45 | @"_upKey": _upKey,
46 | @"_downKey": _downKey,
47 | @"_leftKey": _leftKey,
48 | @"_rightKey": _rightKey,
49 | }];
50 | }
51 |
52 | return self;
53 | }
54 |
55 | - (BOOL)enableInputClicksWhenVisible {
56 | // conforming to allows the buttons to make the click sound when tapped
57 | return YES;
58 | }
59 |
60 | - (BOOL)_isSmallDevice {
61 | return [UIScreen mainScreen].bounds.size.height < 600.f;
62 | }
63 |
64 | - (CGSize)intrinsicContentSize {
65 | CGSize size = [super intrinsicContentSize];
66 | size.height = self._isSmallDevice ? 32.f : 44.f;
67 | return size;
68 | }
69 |
70 | @end
71 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTPTY.h:
--------------------------------------------------------------------------------
1 | @import Foundation;
2 |
3 | // PTY.h
4 | // MobileTerminal
5 |
6 | // Controls settings on PTY, currently just width and height.
7 | @interface HBNTPTY : NSObject
8 |
9 | - (instancetype)initWithFileHandle:(NSFileHandle *)fileHandle;
10 |
11 | // Adjust the height and width of the subprocess terminal.
12 | - (void)setWidth:(int)terminalWidth withHeight:(int)terminalHeight;
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTPTY.m:
--------------------------------------------------------------------------------
1 | // PTY.m
2 | // MobileTerminal
3 |
4 | #import "HBNTPTY.h"
5 |
6 | #include
7 | #include
8 |
9 | @implementation HBNTPTY {
10 | NSFileHandle *_handle;
11 | int _width;
12 | int _height;
13 | }
14 |
15 | - (instancetype)init {
16 | return [self initWithFileHandle:nil];
17 | }
18 |
19 | - (instancetype)initWithFileHandle:(NSFileHandle *)fileHandle {
20 | self = [super init];
21 |
22 | if (self) {
23 | _handle = fileHandle;
24 |
25 | // Initialize with the current window size
26 | struct winsize window_size;
27 |
28 | if (ioctl(_handle.fileDescriptor, TIOCGWINSZ, &window_size) == -1) {
29 | [NSException raise:@"IOException" format:@"Unable to read the terminal size: (%d: %s)", errno, strerror(errno)];
30 | }
31 |
32 | _width = window_size.ws_col;
33 | _height = window_size.ws_row;
34 | }
35 |
36 | return self;
37 | }
38 |
39 | - (void)setWidth:(int)terminalWidth withHeight:(int)terminalHeight {
40 | if (_width == terminalWidth && _height == terminalHeight) {
41 | // Nothing changed
42 | return;
43 | }
44 |
45 | _width = terminalWidth;
46 | _height = terminalHeight;
47 |
48 | // Update the window size of the forked pty
49 | struct winsize window_size;
50 | window_size.ws_col = _width;
51 | window_size.ws_row = _height;
52 |
53 | if (ioctl(_handle.fileDescriptor, TIOCSWINSZ, &window_size) == -1) {
54 | [NSException raise:@"IOException" format:@"Unable to write the terminal size (%d: %s)", errno, strerror(errno)];
55 | }
56 | }
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTPreferences.h:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTPreferences.h
3 | // NewTerm
4 | //
5 | // Created by Adam Demasi on 21/11/2015.
6 | // Copyright (c) 2015 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | @import Foundation;
10 | //#import
11 |
12 | @class FontMetrics, VT100ColorMap;
13 |
14 | @interface HBNTPreferences : NSObject
15 |
16 | + (instancetype)sharedInstance;
17 |
18 | @property (strong, nonatomic, readonly) FontMetrics *fontMetrics;
19 | @property (strong, nonatomic, readonly) VT100ColorMap *colorMap;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTPreferences.m:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTPreferences.m
3 | // NewTerm
4 | //
5 | // Created by Adam Demasi on 21/11/2015.
6 | // Copyright (c) 2015 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import "HBNTPreferences.h"
10 | #import "FontMetrics.h"
11 | #import "VT100ColorMap.h"
12 |
13 | @implementation HBNTPreferences {
14 | // HBPreferences *_preferences;
15 | NSMutableDictionary *_preferences;
16 |
17 | NSDictionary *_fontsPlist;
18 | NSDictionary *_themesPlist;
19 |
20 | NSString *_fontName;
21 | CGFloat _fontSize;
22 | NSString *_themeName;
23 | }
24 |
25 | + (instancetype)sharedInstance {
26 | static HBNTPreferences *sharedInstance;
27 | static dispatch_once_t onceToken;
28 | dispatch_once(&onceToken, ^{
29 | sharedInstance = [[self alloc] init];
30 | });
31 |
32 | return sharedInstance;
33 | }
34 |
35 | - (instancetype)init {
36 | self = [super init];
37 |
38 | if (self) {
39 | // _preferences = [[HBPreferences alloc] initWithIdentifier:@"ws.hbang.Terminal"];
40 | //
41 | // [_preferences registerObject:&_fontName default:@"Fira Code" forKey:@"fontName"];
42 | // [_preferences registerFloat:&_fontSize default:13.f forKey:IS_IPAD ? @"fontSizePad" : @"fontSizePhone"];
43 | // [_preferences registerObject:&_themeName default:@"kirb" forKey:@"theme"];
44 |
45 | _preferences = [@{
46 | @"fontName": @"Menlo",
47 | @"fontSizePad": @13.f,
48 | @"fontSizePhone": @13.f,
49 | @"themeName": @"VSCode"
50 | } mutableCopy];
51 | _fontName = @"Menlo";
52 | _fontSize = 13.f;
53 | _themeName = @"VSCode";
54 |
55 | _fontsPlist = @{
56 | @"Menlo": @{
57 | @"Regular": @"Menlo-Regular",
58 | @"Bold": @"Menlo-Bold",
59 | }
60 | };
61 | // _fontsPlist = [NSDictionary dictionaryWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"Fonts" withExtension:@"plist"]];
62 | _themesPlist = [NSDictionary dictionaryWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"Themes" withExtension:@"plist"]];
63 |
64 | // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(preferencesUpdated) name:HBPreferencesDidChangeNotification object:nil];
65 | [self preferencesUpdated];
66 | }
67 |
68 | return self;
69 | }
70 |
71 | #pragma mark - Callbacks
72 |
73 | - (void)preferencesUpdated {
74 | [self _fontMetricsChanged];
75 | [self _colorMapChanged];
76 | }
77 |
78 | #pragma mark - Create model objects from preferences
79 |
80 | - (void)_fontMetricsChanged {
81 | NSDictionary *family = _fontsPlist[_fontName];
82 | UIFont *regularFont, *boldFont;
83 |
84 | if (family) {
85 | // if we have the font name as a known family, use its regular and bold names
86 | regularFont = [UIFont fontWithName:family[@"Regular"] size:_fontSize];
87 | boldFont = [UIFont fontWithName:family[@"Bold"] size:_fontSize];
88 | } else {
89 | // fallback for older style: raw font name stored in preferences. bold not supported
90 | regularFont = [UIFont fontWithName:_fontName size:_fontSize];
91 | boldFont = [UIFont fontWithName:_fontName size:_fontSize];
92 | }
93 |
94 | if (!regularFont || !boldFont) {
95 | NSLog(@"font %@ size %f could not be initialised", _fontName, _fontSize);
96 | regularFont = [UIFont fontWithName:@"Courier" size:13.f];
97 | boldFont = [UIFont fontWithName:@"Courier-Bold" size:13.f];
98 | }
99 |
100 | _fontMetrics = [[FontMetrics alloc] initWithFont:regularFont boldFont:boldFont];
101 | }
102 |
103 | - (void)_colorMapChanged {
104 | // if the theme doesn’t exist… how did we get here? force it to the default, which will call this
105 | // method again
106 | if (!_themesPlist[_themeName]) {
107 | _preferences[@"theme"] = @"kirb";
108 | return;
109 | }
110 |
111 | _colorMap = [[VT100ColorMap alloc] initWithDictionary:_themesPlist[_themeName]];
112 | }
113 |
114 | @end
115 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTPreferencesRootController.h:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTPreferencesRootController.h
3 | // NewTerm
4 | //
5 | // Created by Adam Demasi on 30/10/2015.
6 | // Copyright (c) 2015 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface HBNTPreferencesRootController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTPreferencesRootController.m:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTPreferencesRootController.m
3 | // NewTerm
4 | //
5 | // Created by Adam Demasi on 30/10/2015.
6 | // Copyright (c) 2015 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import "HBNTPreferencesRootController.h"
10 | //#import "../prefs/HBNTPreferencesRootListController.h"
11 | //#import
12 | //#include
13 |
14 | @implementation HBNTPreferencesRootController
15 |
16 | #pragma mark - UIViewController
17 |
18 | - (void)loadView {
19 | [super loadView];
20 |
21 | self.title = @"Preferences!";
22 | }
23 |
24 | - (UIStatusBarStyle)preferredStatusBarStyle {
25 | return UIStatusBarStyleLightContent;
26 | }
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTRootViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTRootViewController.h
3 | // NewTerm
4 | //
5 | // Created by Adam D on 26/01/2015.
6 | // Copyright (c) 2015 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class HBNTTerminalSessionViewController;
12 |
13 | @interface HBNTRootViewController : UIViewController
14 |
15 | - (void)addTerminal;
16 | - (void)removeTerminal:(HBNTTerminalSessionViewController *)viewController;
17 |
18 | @property (nonatomic, assign) NSUInteger selectedTabIndex;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTRootViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTRootViewController.m
3 | // NewTerm
4 | //
5 | // Created by Adam D on 26/01/2015.
6 | // Copyright (c) 2015 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import "HBNTRootViewController.h"
10 | #import "HBNTPreferencesRootController.h"
11 | #import "HBNTTerminalSessionViewController.h"
12 | #import "HBNTTabToolbar.h"
13 | #import "HBNTTabCollectionViewCell.h"
14 | //#import
15 |
16 | @interface HBNTRootViewController ()
17 |
18 | @end
19 |
20 | @implementation HBNTRootViewController {
21 | NSMutableArray *_terminals;
22 | NSUInteger _selectedTabIndex;
23 |
24 | HBNTTabToolbar *_tabToolbar;
25 | UIToolbar *_bottomToolbar;
26 | UICollectionView *_tabsCollectionView;
27 | }
28 |
29 | - (void)loadView {
30 | [super loadView];
31 |
32 | self.navigationController.navigationBarHidden = YES;
33 |
34 | _terminals = [NSMutableArray array];
35 |
36 | _tabToolbar = [[HBNTTabToolbar alloc] init];
37 | _tabToolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
38 | [_tabToolbar.addButton addTarget:self action:@selector(addTerminal) forControlEvents:UIControlEventTouchUpInside];
39 |
40 | _tabsCollectionView = _tabToolbar.tabsCollectionView;
41 | _tabsCollectionView.dataSource = self;
42 | _tabsCollectionView.delegate = self;
43 |
44 | [self.view addSubview:_tabToolbar];
45 |
46 | _bottomToolbar = [[UIToolbar alloc] init];
47 | _bottomToolbar.items = @[
48 | [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"settings"] style:UIBarButtonItemStylePlain target:self action:@selector(showSettings:)],
49 | [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
50 | [[UIBarButtonItem alloc] initWithTitle:@"▲" style:UIBarButtonItemStylePlain target:self action:@selector(showKeyboard)]
51 | ];
52 | [self.view addSubview:_bottomToolbar];
53 |
54 | [self addTerminal];
55 | }
56 |
57 | - (void)viewWillLayoutSubviews {
58 | [super viewWillLayoutSubviews];
59 |
60 | CGFloat barHeight = [UIScreen mainScreen].bounds.size.height < 600.f ? 32.f : 40.f;
61 | CGFloat statusBarHeight = /*IS_IOS_OR_NEWER(iOS_7_0) ? [UIApplication sharedApplication].statusBarFrame.size.height : */22.f;
62 | CGFloat statusBarOffset = /*IS_IOS_OR_NEWER(iOS_7_0) ? 0 : -[UIApplication sharedApplication].statusBarFrame.size.height*/-22.f;
63 |
64 | _tabToolbar.frame = CGRectMake(0, 0, self.view.frame.size.width, statusBarHeight + barHeight);
65 | _bottomToolbar.frame = CGRectMake(0, self.view.frame.size.height - barHeight, self.view.frame.size.width, barHeight);
66 |
67 | UIEdgeInsets barInsets = UIEdgeInsetsMake(_tabToolbar.frame.size.height + statusBarOffset, 0, _bottomToolbar.frame.size.height, 0);
68 |
69 | for (HBNTTerminalSessionViewController *viewController in _terminals) {
70 | viewController.barInsets = barInsets;
71 | }
72 | }
73 |
74 | #pragma mark - Tab management
75 |
76 | - (void)addTerminal {
77 | HBNTTerminalSessionViewController *terminalViewController = [[HBNTTerminalSessionViewController alloc] init];
78 |
79 | [self addChildViewController:terminalViewController];
80 | [terminalViewController willMoveToParentViewController:self];
81 | [self.view insertSubview:terminalViewController.view belowSubview:_tabToolbar];
82 | [terminalViewController didMoveToParentViewController:self];
83 |
84 | [_terminals addObject:terminalViewController];
85 |
86 | [_tabsCollectionView reloadData];
87 | [_tabsCollectionView layoutIfNeeded];
88 | self.selectedTabIndex = _terminals.count - 1;
89 | [_tabsCollectionView reloadData];
90 | }
91 |
92 | - (void)removeTerminalAtIndex:(NSUInteger)index {
93 | HBNTTerminalSessionViewController *terminalViewController = _terminals[index];
94 |
95 | [terminalViewController removeFromParentViewController];
96 | [terminalViewController.view removeFromSuperview];
97 |
98 | [_terminals removeObjectAtIndex:index];
99 |
100 | // if this was the last tab, make a new tab. otherwise select the closest tab we have available
101 | if (_terminals.count == 0) {
102 | [self addTerminal];
103 | } else {
104 | [_tabsCollectionView reloadData];
105 | [_tabsCollectionView layoutIfNeeded];
106 | self.selectedTabIndex = index >= _terminals.count ? index - 1 : index;
107 | }
108 | }
109 |
110 | - (void)removeTerminal:(HBNTTerminalSessionViewController *)viewController {
111 | NSUInteger index = [_terminals indexOfObject:viewController];
112 |
113 | if (index == NSNotFound) {
114 | NSLog(@"asked to remove terminal that doesn’t exist? %@", viewController);
115 | } else {
116 | [self removeTerminalAtIndex:index];
117 | }
118 | }
119 |
120 | - (void)removeTerminalButtonTapped:(UIButton *)button {
121 | [self removeTerminalAtIndex:button.tag];
122 | }
123 |
124 | - (NSUInteger)selectedTabIndex {
125 | return _selectedTabIndex;
126 | }
127 |
128 | - (void)setSelectedTabIndex:(NSUInteger)selectedTabIndex {
129 | // if this is what’s already selected, just select it again and return
130 | if (selectedTabIndex == _selectedTabIndex) {
131 | [_tabsCollectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:_selectedTabIndex inSection:0] animated:YES scrollPosition:UICollectionViewScrollPositionCenteredVertically];
132 | return;
133 | }
134 |
135 | NSUInteger oldSelectedTabIndex = _selectedTabIndex < _terminals.count ? _selectedTabIndex : NSUIntegerMax;
136 |
137 | // if the previous index is now out of bounds, just use nil as our previous. the tab and view
138 | // controller were removed so we don’t need to do anything
139 | HBNTTerminalSessionViewController *previousViewController = _selectedTabIndex < _terminals.count ? _terminals[_selectedTabIndex] : nil;
140 | HBNTTerminalSessionViewController *newViewController = _terminals[selectedTabIndex];
141 |
142 | _selectedTabIndex = selectedTabIndex;
143 |
144 | // call the appropriate view controller lifecycle methods on the previous and new view controllers
145 | [previousViewController viewWillDisappear:NO];
146 | previousViewController.view.hidden = YES;
147 | [previousViewController viewDidDisappear:NO];
148 |
149 | [newViewController viewWillAppear:NO];
150 | newViewController.view.hidden = NO;
151 | [newViewController viewDidAppear:NO];
152 |
153 | [_tabsCollectionView performBatchUpdates:^{
154 | if (oldSelectedTabIndex != NSUIntegerMax) {
155 | [_tabsCollectionView deselectItemAtIndexPath:[NSIndexPath indexPathForItem:oldSelectedTabIndex inSection:0] animated:NO];
156 | }
157 |
158 | [_tabsCollectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:selectedTabIndex inSection:0] animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
159 | } completion:^(BOOL finished) {
160 | // TODO: hack because the previous tab doesn’t deselect for some reason and ugh i hate this
161 | [_tabsCollectionView reloadData];
162 | }];
163 | }
164 |
165 | #pragma mark - Callbacks
166 |
167 | - (void)showSettings:(UIBarButtonItem *)sender {
168 | HBNTPreferencesRootController *rootController = [[HBNTPreferencesRootController alloc] init];// initWithTitle:NSLocalizedString(@"SETTINGS", @"Title of Settings page.") identifier:[NSBundle mainBundle].infoDictionary[@"CFBundleIdentifier"]];
169 | rootController.modalPresentationStyle = UIModalPresentationFormSheet;
170 | [self.navigationController presentViewController:rootController animated:YES completion:nil];
171 | }
172 |
173 | - (void)showKeyboard {
174 | // HBNTTerminalSessionViewController *viewController = _terminals[_selectedTabIndex];
175 | // [viewController becomeFirstResponder];
176 | }
177 |
178 | #pragma mark - Collection view
179 |
180 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
181 | return _terminals.count;
182 | }
183 |
184 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
185 | HBNTTerminalSessionViewController *terminalViewController = _terminals[indexPath.row];
186 |
187 | HBNTTabCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TabCell" forIndexPath:indexPath];
188 | cell.textLabel.text = terminalViewController.title;
189 | cell.selected = _selectedTabIndex == indexPath.row;
190 | cell.closeButton.tag = indexPath.row;
191 | [cell.closeButton addTarget:self action:@selector(removeTerminalButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
192 | return cell;
193 | }
194 |
195 | - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
196 | self.selectedTabIndex = indexPath.row;
197 | }
198 |
199 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
200 | // hardcode a width for now, just so we work on ios 6. to be worked on…
201 | return CGSizeMake(100, _tabsCollectionView.frame.size.height);
202 | }
203 |
204 | @end
205 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTSubProcess.h:
--------------------------------------------------------------------------------
1 | // SubProcess.h
2 | // MobileTerminal
3 |
4 | #import "HBNTPTY.h"
5 |
6 | // Forks a terminal subprocess.
7 | @interface HBNTSubProcess : NSObject
8 |
9 | // Forks a terminal subprocess and initializes the fileHandle for communication.
10 | - (void)start;
11 |
12 | // Kills the forked subprocess, blocking until it ends.
13 | - (void)stop;
14 |
15 | // Communication channel with the terminal subprocess. Only valid after the
16 | // sub process is started.
17 | @property (strong, nonatomic, readonly) NSFileHandle *fileHandle;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTSubProcess.m:
--------------------------------------------------------------------------------
1 | // SubProcess.m
2 | // MobileTerminal
3 |
4 | #import "HBNTSubProcess.h"
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | // These are simply used to initialize the terminal and are probably thrown
11 | // away immediately after startup.
12 | static const int kDefaultWidth = 80;
13 | static const int kDefaultHeight = 25;
14 |
15 | // Default username if we can't tell from the environment
16 | static const char kDefaultUsername[] = "mobile";
17 |
18 | @implementation HBNTSubProcess {
19 | pid_t _childPID;
20 | int _fileDescriptor;
21 | }
22 |
23 | - (void)dealloc {
24 | if (_childPID != 0) {
25 | [NSException raise:@"IllegalStateException" format:@"SubProcess was deallocated while running"];
26 | }
27 | }
28 |
29 | #pragma mark - Start/stop
30 |
31 | - (void)start {
32 | if (_childPID != 0) {
33 | [NSException raise:@"IllegalStateException" format:@"SubProcess was already started"];
34 | return;
35 | }
36 |
37 | const char *username = getenv("USER");
38 |
39 | if (username == NULL) {
40 | username = kDefaultUsername;
41 | }
42 |
43 | struct winsize window_size;
44 | window_size.ws_col = kDefaultWidth;
45 | window_size.ws_row = kDefaultHeight;
46 | pid_t pid = forkpty(&_fileDescriptor, NULL, NULL, &window_size);
47 |
48 | if (pid == -1) {
49 | if (errno == EPERM) {
50 | [NSException raise:@"ForkException" format:@"Not allowed to fork from inside Sandbox"];
51 | } else {
52 | [NSException raise:@"ForkException" format:@"Failed to fork child process (%d: %s)", errno, strerror(errno)];
53 | }
54 | } else if (pid == 0) {
55 | // Handle the child subprocess
56 | // First try to use /bin/login since its a little nicer. Fall back to
57 | // /bin/sh if that is available.
58 | char *login_args[] = { "login", "-fp", (char *)username, NULL };
59 | char *sh_args[] = { "sh", NULL };
60 |
61 | // TODO: these should be configurable
62 | char *env[] = {
63 | "TERM=xterm-color",
64 | "LANG=en_US.UTF-8",
65 | NULL
66 | };
67 |
68 | // NOTE: These should never return if successful
69 | [self _startProcess:@"/usr/bin/login" arguments:login_args environment:env];
70 | [self _startProcess:@"/bin/login" arguments:login_args environment:env];
71 | [self _startProcess:@"/bin/sh" arguments:sh_args environment:env];
72 | [self _startProcess:@"/bootstrap/bin/bash" arguments:sh_args environment:env];
73 | } else {
74 | NSLog(@"process forked: %d", pid);
75 | _childPID = pid;
76 |
77 | // We're the parent process (still).
78 | _fileHandle = [[NSFileHandle alloc] initWithFileDescriptor:_fileDescriptor closeOnDealloc:YES];
79 | }
80 | }
81 |
82 | - (void)stop {
83 | if (_childPID == 0) {
84 | [NSException raise:@"IllegalStateException" format:@"SubProcess was never started"];
85 | return;
86 | }
87 |
88 | kill(_childPID, SIGKILL);
89 | int stat;
90 | waitpid(_childPID, &stat, WUNTRACED);
91 |
92 | _fileDescriptor = 0;
93 | _childPID = 0;
94 | }
95 |
96 | - (int)_startProcess:(NSString *)path arguments:(char *const[])args environment:(char *const[])env {
97 | NSFileManager *fileManager = [NSFileManager defaultManager];
98 |
99 | if (![fileManager fileExistsAtPath:path]) {
100 | return -1;
101 | }
102 |
103 | // Notably, we don't test group or other bits so this still might not always
104 | // notice if the binary is not executable by us.
105 | if (![fileManager isExecutableFileAtPath:path]) {
106 | return -1;
107 | }
108 |
109 | if (execve(path.UTF8String, args, env) == -1) {
110 | NSLog(@"%@: exec failed: %s", path, strerror(errno));
111 | return -1;
112 | }
113 |
114 | // execve never returns if successful
115 | return 0;
116 | }
117 |
118 | @end
119 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTabCollectionViewCell.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @interface HBNTTabCollectionViewCell : UICollectionViewCell
4 |
5 | @property (nonatomic, strong) UILabel *textLabel;
6 | @property (nonatomic, strong) UIButton *closeButton;
7 |
8 | @end
9 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTabCollectionViewCell.m:
--------------------------------------------------------------------------------
1 | #import "HBNTTabCollectionViewCell.h"
2 | #import "UIView+CompactConstraint.h"
3 |
4 | @implementation HBNTTabCollectionViewCell
5 |
6 | - (instancetype)initWithFrame:(CGRect)frame {
7 | self = [super initWithFrame:frame];
8 |
9 | if (self) {
10 | // self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
11 |
12 | self.selectedBackgroundView = [[UIView alloc] init];
13 | self.selectedBackgroundView.backgroundColor = [UIColor colorWithWhite:85.f / 255.f alpha:0.7f];
14 |
15 | _textLabel = [[UILabel alloc] init];
16 | _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
17 | _textLabel.font = [UIFont systemFontOfSize:16.f];
18 | _textLabel.textColor = [UIColor whiteColor];
19 | _textLabel.backgroundColor = [UIColor clearColor];
20 | [self.contentView addSubview:_textLabel];
21 |
22 | _closeButton = [[UIButton alloc] init];
23 | _closeButton.translatesAutoresizingMaskIntoConstraints = NO;
24 | _closeButton.accessibilityLabel = NSLocalizedString(@"CLOSE_TAB", @"VoiceOver label for the close tab button.");
25 | _closeButton.titleLabel.font = [UIFont systemFontOfSize:16.f];
26 | [_closeButton setTitle:@"×" forState:UIControlStateNormal];
27 | [self.contentView addSubview:_closeButton];
28 |
29 | [self.contentView addCompactConstraints:@[
30 | @"textLabel.centerY = contentView.centerY",
31 | @"textLabel.left = contentView.left + 6",
32 | @"closeButton.width = 24",
33 | @"closeButton.height = contentView.height",
34 | @"closeButton.left = textLabel.right",
35 | @"closeButton.right = contentView.right"
36 | ] metrics:@{} views:@{
37 | @"contentView": self.contentView,
38 | @"textLabel": _textLabel,
39 | @"closeButton": _closeButton
40 | }];
41 | }
42 |
43 | return self;
44 | }
45 |
46 | - (CGSize)intrinsicContentSize {
47 | CGSize size = [super intrinsicContentSize];
48 | size.height = [UIScreen mainScreen].bounds.size.height < 600 ? 32.f : 40.f;
49 | return size;
50 | }
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTabToolbar.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @interface HBNTTabToolbar : UIToolbar
4 |
5 | @property (nonatomic, strong) UICollectionView *tabsCollectionView;
6 | @property (nonatomic, strong) UIButton *addButton;
7 |
8 | @end
9 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTabToolbar.m:
--------------------------------------------------------------------------------
1 | #import "HBNTTabToolbar.h"
2 | #import "HBNTTabCollectionViewCell.h"
3 | //#import
4 |
5 | @implementation HBNTTabToolbar
6 |
7 | - (instancetype)init {
8 | self = [super init];
9 |
10 | if (self) {
11 | UICollectionViewFlowLayout *collectionViewLayout = [[UICollectionViewFlowLayout alloc] init];
12 | collectionViewLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
13 | collectionViewLayout.minimumInteritemSpacing = 0;
14 | collectionViewLayout.minimumLineSpacing = 0;
15 |
16 | // the weird frame is to appease ios 6 UICollectionView
17 | _tabsCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) collectionViewLayout:collectionViewLayout];
18 | _tabsCollectionView.backgroundColor = nil;
19 | _tabsCollectionView.showsVerticalScrollIndicator = NO;
20 | _tabsCollectionView.showsHorizontalScrollIndicator = NO;
21 | // _tabsCollectionView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
22 | _tabsCollectionView.allowsMultipleSelection = NO;
23 | [self addSubview:_tabsCollectionView];
24 |
25 | [_tabsCollectionView registerClass:HBNTTabCollectionViewCell.class forCellWithReuseIdentifier:@"TabCell"];
26 |
27 | // TODO: maybe this should be moved to the toolbar as a UIBarButtonItem to appease iOS 6
28 | _addButton = [UIButton buttonWithType:/*IS_IOS_OR_NEWER(iOS_7_0) ?*/ UIButtonTypeSystem /*: UIButtonTypeCustom*/];
29 | _addButton.titleLabel.font = [UIFont systemFontOfSize:18.f];
30 | [_addButton setTitle:@"+" forState:UIControlStateNormal];
31 | _addButton.accessibilityLabel = NSLocalizedString(@"NEW_TAB", @"VoiceOver label for the new tab button.");
32 | [self addSubview:_addButton];
33 |
34 | CGFloat shadowHeight = 1 / [UIScreen mainScreen].scale;
35 | UIView *shadowView = [[UIView alloc] initWithFrame:CGRectMake(0, self.frame.size.height - shadowHeight, self.frame.size.width, shadowHeight)];
36 | shadowView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
37 | shadowView.backgroundColor = [UIColor colorWithWhite:64.f / 255.f alpha:1];
38 | [self addSubview:shadowView];
39 | }
40 |
41 | return self;
42 | }
43 |
44 | - (void)layoutSubviews {
45 | [super layoutSubviews];
46 |
47 | CGFloat statusBarHeight = /*IS_IOS_OR_NEWER(iOS_7_0) ? [UIApplication sharedApplication].statusBarFrame.size.height : */22.f;
48 | CGFloat addButtonWidth = 44.f;
49 |
50 | _addButton.frame = CGRectMake(self.frame.size.width - addButtonWidth, statusBarHeight, addButtonWidth, self.frame.size.height - statusBarHeight);
51 | _tabsCollectionView.frame = CGRectMake(0, statusBarHeight, _addButton.frame.origin.x, _addButton.frame.size.height);
52 |
53 | CGFloat newButtonSize = _addButton.frame.size.height < 44.f ? 18.f : 24.f;
54 |
55 | if (_addButton.titleLabel.font.pointSize != newButtonSize) {
56 | _addButton.titleLabel.font = [UIFont systemFontOfSize:newButtonSize];
57 | }
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTerminalController.h:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTTerminalController.h
3 | // NewTerm
4 | //
5 | // Created by Adam D on 22/01/2015.
6 | // Copyright (c) 2015 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import "HBNTTerminalKeyInput.h"
10 | #import "VT100Types.h"
11 |
12 | @class HBNTTerminalSessionViewController, VT100ColorMap, FontMetrics;
13 |
14 | @protocol HBNTTerminalControllerDelegate
15 |
16 | @required
17 | - (void)refreshWithAttributedString:(NSAttributedString *)attributedString backgroundColor:(UIColor *)backgroundColor;
18 | - (void)activateBell;
19 | - (void)close;
20 |
21 | @end
22 |
23 | @interface HBNTTerminalController : NSObject
24 |
25 | - (void)startSubProcess;
26 | - (void)stopSubProcess;
27 |
28 | @property (nonatomic, strong) HBNTTerminalSessionViewController *viewController;
29 | @property (nonatomic) ScreenSize screenSize;
30 | @property (nonatomic, strong, readonly) VT100ColorMap *colorMap;
31 | @property (nonatomic, strong, readonly) FontMetrics *fontMetrics;
32 | @property (nonatomic, readonly) int scrollbackLines;
33 |
34 | @property (nonatomic, weak) id delegate;
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTerminalController.m:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTTerminalController.m
3 | // NewTerm
4 | //
5 | // Created by Adam D on 22/01/2015.
6 | // Copyright (c) 2015 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import "HBNTTerminalController.h"
10 | #import "HBNTTerminalSessionViewController.h"
11 | #import "HBNTSubProcess.h"
12 | #import "HBNTPTY.h"
13 | #import "HBNTPreferences.h"
14 | #import "VT100.h"
15 | #import "VT100StringSupplier.h"
16 | #import "VT100ColorMap.h"
17 | #import "FontMetrics.h"
18 |
19 | @interface HBNTTerminalController ()
20 |
21 | @end
22 |
23 | @implementation HBNTTerminalController {
24 | VT100 *_buffer;
25 | VT100StringSupplier *_stringSupplier;
26 | dispatch_queue_t _updateQueue;
27 |
28 | HBNTSubProcess *_subProcess;
29 | HBNTPTY *_pty;
30 |
31 | BOOL _processEnded;
32 | }
33 |
34 | - (instancetype)init {
35 | self = [super init];
36 |
37 | if (self) {
38 | // create a serial background queue for updating the text view, using the address of self to
39 | // make the name unique
40 | _updateQueue = dispatch_queue_create([NSString stringWithFormat:@"ws.hbang.Terminal.update-queue-%p", self].UTF8String, DISPATCH_QUEUE_SERIAL);
41 |
42 | _buffer = [[VT100 alloc] init];
43 | _buffer.refreshDelegate = self;
44 |
45 | _stringSupplier = [[VT100StringSupplier alloc] init];
46 | _stringSupplier.screenBuffer = _buffer;
47 |
48 | // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(preferencesUpdated) name:HBPreferencesDidChangeNotification object:nil];
49 | [self preferencesUpdated];
50 | }
51 |
52 | return self;
53 | }
54 |
55 | #pragma mark - Screen Buffer
56 |
57 | // TODO: this is pretty ugly. maybe we should just be a VT100 subclass?
58 |
59 | - (id )refreshDelegate {
60 | return _buffer.refreshDelegate;
61 | }
62 |
63 | - (void)setRefreshDelegate:(id )refreshDelegate {
64 | _buffer.refreshDelegate = refreshDelegate;
65 | }
66 |
67 | - (ScreenSize)screenSize {
68 | return _buffer.screenSize;
69 | }
70 |
71 | - (void)setScreenSize:(ScreenSize)screenSize {
72 | // Send the terminal the actual size of our vt100 view. This should be called any time we change
73 | // the size of the view. This should be a no-op if the size has not changed since the last time we
74 | // called it.
75 | _buffer.screenSize = screenSize;
76 | [_pty setWidth:screenSize.width withHeight:screenSize.height];
77 | }
78 |
79 | - (void)readInputStream:(NSData *)data {
80 | // Simply forward the input stream down the VT100 processor. When it notices
81 | // changes to the screen, it should invoke our refresh delegate below.
82 | [_buffer readInputStream:data];
83 | }
84 |
85 | - (void)clearScreen {
86 | [_buffer clearScreen];
87 | }
88 |
89 | - (int)scrollbackLines {
90 | return _buffer.scrollbackLines;
91 | }
92 |
93 | - (VT100ColorMap *)colorMap {
94 | return _stringSupplier.colorMap;
95 | }
96 |
97 | - (FontMetrics *)fontMetrics {
98 | return _stringSupplier.fontMetrics;
99 | }
100 |
101 | #pragma mark - Screen Buffer Delegate
102 |
103 | - (void)refresh {
104 | // TODO: we should handle the scrollback separately so it only appears if the user scrolls
105 | dispatch_async(_updateQueue, ^{
106 | NSAttributedString *attributedString = _stringSupplier.attributedString;
107 | UIColor *backgroundColor = _stringSupplier.colorMap.background;
108 |
109 | dispatch_async(dispatch_get_main_queue(), ^{
110 | [_delegate refreshWithAttributedString:attributedString backgroundColor:backgroundColor];
111 | });
112 | });
113 | }
114 |
115 | - (void)activateBell {
116 | [_delegate activateBell];
117 | }
118 |
119 | #pragma mark - Sub Process
120 |
121 | - (void)startSubProcess {
122 | _processEnded = NO;
123 |
124 | _subProcess = [[HBNTSubProcess alloc] init];
125 | [_subProcess start];
126 |
127 | // The PTY will be sized correctly on the first call to layoutSubViews
128 | _pty = [[HBNTPTY alloc] initWithFileHandle:_subProcess.fileHandle];
129 |
130 | // Schedule an async read of the subprocess. Invokes our callback when data becomes available.
131 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dataAvailable:) name:NSFileHandleReadCompletionNotification object:_subProcess.fileHandle];
132 | [_subProcess.fileHandle readInBackgroundAndNotify];
133 | }
134 |
135 | - (void)dataAvailable:(NSNotification *)notification {
136 | NSData *data = notification.userInfo[NSFileHandleNotificationDataItem];
137 |
138 | if (data.length == 0) {
139 | // zero-length data is an indicator of EOF. this can happen if the user exits the terminal by
140 | // typing `exit`, or if there’s a catastrophic failure (e.g. /bin/login is broken). we print a
141 | // message to the terminal saying the process ended, and then when the user presses any key, the
142 | // tab will close
143 | NSString *message = [NSString stringWithFormat:@"[%@]\r\n%@\r\n", NSLocalizedString(@"PROCESS_COMPLETED_TITLE", @"Title displayed when the terminal’s process has ended."), NSLocalizedString(@"PROCESS_COMPLETED_MESSAGE", @"Message indicating the user can press any key to close the tab.")];
144 | [self readInputStream:[message dataUsingEncoding:NSUTF8StringEncoding]];
145 |
146 | _processEnded = YES;
147 | [_subProcess stop];
148 | } else {
149 | // Forward the subprocess data into the terminal character handler
150 | [self readInputStream:data];
151 |
152 | // Queue another read
153 | [_subProcess.fileHandle readInBackgroundAndNotify];
154 | }
155 | }
156 |
157 | - (void)stopSubProcess {
158 | _processEnded = YES;
159 | [_subProcess stop];
160 | }
161 |
162 | - (void)receiveKeyboardInput:(NSData *)data {
163 | if (_processEnded) {
164 | // The sub process previously exited, close it at the users request.
165 | [_viewController close];
166 | } else {
167 | // Forward the data from the keyboard directly to the subprocess
168 | [_subProcess.fileHandle writeData:data];
169 | }
170 | }
171 |
172 | #pragma mark - Preferences
173 |
174 | - (void)preferencesUpdated {
175 | HBNTPreferences *preferences = [HBNTPreferences sharedInstance];
176 | _stringSupplier.colorMap = preferences.colorMap;
177 | _stringSupplier.fontMetrics = preferences.fontMetrics;
178 |
179 | [self refresh];
180 | }
181 |
182 | #pragma mark - NSObject
183 |
184 | - (void)dealloc {
185 | [[NSNotificationCenter defaultCenter] removeObserver:self];
186 | }
187 |
188 | @end
189 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTerminalKeyInput.h:
--------------------------------------------------------------------------------
1 | #import "HBNTTextInputBase.h"
2 |
3 | // Protocol implemented by listener of keyboard events
4 | @protocol HBNTTerminalInputProtocol
5 |
6 | @required
7 | - (void)receiveKeyboardInput:(NSData *)data;
8 |
9 | @end
10 |
11 | @protocol HBNTTerminalKeyboardProtocol
12 |
13 | @end
14 |
15 | @interface HBNTTerminalKeyInput : HBNTTextInputBase
16 |
17 | @property (nonatomic, strong) UITextView *textView;
18 |
19 | // TODO: i think this should be weak?
20 | @property (nonatomic, strong) id terminalInputDelegate;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTerminalKeyInput.m:
--------------------------------------------------------------------------------
1 | #import "HBNTTerminalKeyInput.h"
2 | #import "HBNTKeyboardButton.h"
3 | #import "HBNTKeyboardToolbar.h"
4 |
5 | @implementation HBNTTerminalKeyInput {
6 | HBNTKeyboardToolbar *_toolbar;
7 | HBNTKeyboardButton *_ctrlKey, *_metaKey;
8 | BOOL _ctrlDown, _metaDown;
9 |
10 | NSData *_backspaceData, *_tabKeyData, *_upKeyData, *_downKeyData, *_leftKeyData, *_rightKeyData;
11 | }
12 |
13 | - (instancetype)init {
14 | self = [super init];
15 |
16 | if (self) {
17 | self.autocapitalizationType = UITextAutocapitalizationTypeNone;
18 | self.autocorrectionType = UITextAutocorrectionTypeNo;
19 | self.spellCheckingType = UITextSpellCheckingTypeNo;
20 |
21 | if (@available(iOS 11.0, *)) {
22 | self.smartQuotesType = UITextSmartQuotesTypeNo;
23 | self.smartDashesType = UITextSmartDashesTypeNo;
24 | self.smartInsertDeleteType = UITextSmartInsertDeleteTypeNo;
25 | }
26 |
27 | // TODO: this should be themable
28 | self.keyboardAppearance = UIKeyboardAppearanceDark;
29 |
30 | // TODO: this is kinda ugly and causes duped code for these buttons
31 | if (IS_IPAD && [self respondsToSelector:@selector(inputAssistantItem)]) {
32 | _ctrlKey = [HBNTKeyboardButton buttonWithTitle:@"Ctrl" target:self action:@selector(ctrlKeyPressed:)];
33 | _metaKey = [HBNTKeyboardButton buttonWithTitle:@"Esc" target:self action:@selector(metaKeyPressed:)];
34 |
35 | self.inputAssistantItem.allowsHidingShortcuts = NO;
36 | self.inputAssistantItem.leadingBarButtonGroups = [self.inputAssistantItem.leadingBarButtonGroups arrayByAddingObject:
37 | [[UIBarButtonItemGroup alloc] initWithBarButtonItems:@[
38 | [[UIBarButtonItem alloc] initWithCustomView:_ctrlKey],
39 | [[UIBarButtonItem alloc] initWithCustomView:_metaKey],
40 | [[UIBarButtonItem alloc] initWithCustomView:[HBNTKeyboardButton buttonWithTitle:@"Tab" target:self action:@selector(tabKeyPressed:)]]
41 | ] representativeItem:nil]];
42 | self.inputAssistantItem.trailingBarButtonGroups = [self.inputAssistantItem.trailingBarButtonGroups arrayByAddingObject:
43 | [[UIBarButtonItemGroup alloc] initWithBarButtonItems:@[
44 | [[UIBarButtonItem alloc] initWithCustomView:[HBNTKeyboardButton buttonWithTitle:@"▲" target:self action:@selector(upKeyPressed:)]],
45 | [[UIBarButtonItem alloc] initWithCustomView:[HBNTKeyboardButton buttonWithTitle:@"▼" target:self action:@selector(downKeyPressed:)]],
46 | [[UIBarButtonItem alloc] initWithCustomView:[HBNTKeyboardButton buttonWithTitle:@"◀" target:self action:@selector(leftKeyPressed:)]],
47 | [[UIBarButtonItem alloc] initWithCustomView:[HBNTKeyboardButton buttonWithTitle:@"▶" target:self action:@selector(rightKeyPressed:)]]
48 | ] representativeItem:nil]];
49 | } else {
50 | _toolbar = [[HBNTKeyboardToolbar alloc] init];
51 | _toolbar.translatesAutoresizingMaskIntoConstraints = NO;
52 | [_toolbar.ctrlKey addTarget:self action:@selector(ctrlKeyPressed:) forControlEvents:UIControlEventTouchUpInside];
53 | [_toolbar.metaKey addTarget:self action:@selector(metaKeyPressed:) forControlEvents:UIControlEventTouchUpInside];
54 | [_toolbar.tabKey addTarget:self action:@selector(tabKeyPressed:) forControlEvents:UIControlEventTouchUpInside];
55 | [_toolbar.upKey addTarget:self action:@selector(upKeyPressed:) forControlEvents:UIControlEventTouchUpInside];
56 | [_toolbar.downKey addTarget:self action:@selector(downKeyPressed:) forControlEvents:UIControlEventTouchUpInside];
57 | [_toolbar.leftKey addTarget:self action:@selector(leftKeyPressed:) forControlEvents:UIControlEventTouchUpInside];
58 | [_toolbar.rightKey addTarget:self action:@selector(rightKeyPressed:) forControlEvents:UIControlEventTouchUpInside];
59 |
60 | _ctrlKey = _toolbar.ctrlKey;
61 | _metaKey = _toolbar.metaKey;
62 | }
63 |
64 | _backspaceData = [NSData dataWithBytes:"\x7F" length:1];
65 | _tabKeyData = [NSData dataWithBytes:"\t" length:1];
66 | _upKeyData = [NSData dataWithBytes:"\e[A" length:3];
67 | _downKeyData = [NSData dataWithBytes:"\e[B" length:3];
68 | _leftKeyData = [NSData dataWithBytes:"\e[D" length:3];
69 | _rightKeyData = [NSData dataWithBytes:"\e[C" length:3];
70 | }
71 |
72 | return self;
73 | }
74 |
75 | - (UIView *)inputAccessoryView {
76 | return _toolbar;
77 | }
78 |
79 | #pragma mark - Callbacks
80 |
81 | - (void)ctrlKeyPressed:(UIButton *)button {
82 | _ctrlDown = !_ctrlDown;
83 | button.selected = _ctrlDown;
84 | }
85 |
86 | - (void)metaKeyPressed:(UIButton *)button {
87 | _metaDown = !_metaDown;
88 | button.selected = _metaDown;
89 | }
90 |
91 | - (void)tabKeyPressed:(UIButton *)button {
92 | [_terminalInputDelegate receiveKeyboardInput:_tabKeyData];
93 | }
94 |
95 | - (void)upKeyPressed:(UIButton *)button {
96 | [_terminalInputDelegate receiveKeyboardInput:_upKeyData];
97 | }
98 |
99 | - (void)downKeyPressed:(UIButton *)button {
100 | [_terminalInputDelegate receiveKeyboardInput:_downKeyData];
101 | }
102 |
103 | - (void)leftKeyPressed:(UIButton *)button {
104 | [_terminalInputDelegate receiveKeyboardInput:_leftKeyData];
105 | }
106 |
107 | - (void)rightKeyPressed:(UIButton *)button {
108 | [_terminalInputDelegate receiveKeyboardInput:_rightKeyData];
109 | }
110 |
111 | #pragma mark - UITextInput
112 |
113 | - (BOOL)hasText {
114 | return YES;
115 | }
116 |
117 | - (void)insertText:(NSString *)input {
118 | // mobile terminal used to use the bullet key • as a ctrl equivalent. continue to support that
119 | // TODO: is this just a nuisance? what if you actually want to type a bullet?
120 | if ([input characterAtIndex:0] == 0x2022) {
121 | _ctrlDown = YES;
122 | _ctrlKey.selected = YES;
123 | return;
124 | }
125 |
126 | NSMutableData *data = [NSMutableData data];
127 |
128 | unichar characters[input.length];
129 | [input getCharacters:characters range:NSMakeRange(0, input.length)];
130 |
131 | for (int i = 0; i < input.length; i++) {
132 | unichar character = characters[i];
133 |
134 | if (_ctrlDown) {
135 | // translate capital to lowercase
136 | if (character >= 'A' && character <= 'Z') {
137 | character += 'a' - 'A';
138 | }
139 |
140 | // convert to the matching control character
141 | if (character >= 'a' && character <= 'z') {
142 | character -= 'a' - 1;
143 | }
144 | } else if (_metaDown) {
145 | // prepend the escape character
146 | [data appendBytes:"\e" length:1];
147 | }
148 |
149 | if (character == 0x0a) {
150 | // Convert newline to a carraige return
151 | character = 0x0d;
152 | }
153 |
154 | // Re-encode as UTF8
155 | [data appendBytes:&character length:1];
156 | }
157 |
158 | [_terminalInputDelegate receiveKeyboardInput:data];
159 |
160 | if (_ctrlDown) {
161 | _ctrlDown = NO;
162 | _ctrlKey.selected = NO;
163 | }
164 |
165 | if (_metaDown) {
166 | _metaDown = NO;
167 | _metaKey.selected = NO;
168 | }
169 | }
170 |
171 | - (void)deleteBackward {
172 | [_terminalInputDelegate receiveKeyboardInput:_backspaceData];
173 | }
174 |
175 | #pragma mark - UIResponder
176 |
177 | - (BOOL)becomeFirstResponder {
178 | [super becomeFirstResponder];
179 | return YES;
180 | }
181 |
182 | - (BOOL)canBecomeFirstResponder {
183 | return YES;
184 | }
185 |
186 | - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
187 | if (action == @selector(paste:)) {
188 | // Only paste if the board contains plain text
189 | return [[UIPasteboard generalPasteboard] containsPasteboardTypes:UIPasteboardTypeListString];
190 | } else if (action == @selector(cut:)) {
191 | // ensure cut is never allowed
192 | return NO;
193 | } else if (action == @selector(copy) || action == @selector(select:) || action == @selector(selectAll:)) {
194 | // allow copy, select, select all based on what the text view feels like doing
195 | return [_textView canPerformAction:action withSender:sender];
196 | }
197 |
198 | // consult the super implementation’s opinion
199 | return [super canPerformAction:action withSender:sender];
200 | }
201 |
202 | - (void)copy:(id)sender {
203 | // forward the operation to the text view
204 | [_textView copy:sender];
205 | }
206 |
207 | - (void)select:(id)sender {
208 | [_textView select:sender];
209 | }
210 |
211 | - (void)selectAll:(id)sender {
212 | [_textView selectAll:sender];
213 | }
214 |
215 | - (void)paste:(id)sender {
216 | UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
217 |
218 | if (![pasteboard containsPasteboardTypes:UIPasteboardTypeListString]) {
219 | return;
220 | }
221 |
222 | [_terminalInputDelegate receiveKeyboardInput:[pasteboard.string dataUsingEncoding:NSUTF8StringEncoding]];
223 | }
224 |
225 | @end
226 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTerminalSessionViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTTerminalSessionViewController.h
3 | // NewTerm
4 | //
5 | // Created by Adam D on 12/12/2014.
6 | // Copyright (c) 2014 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "VT100Types.h"
12 | #import "HBNTTerminalController.h"
13 |
14 | @class VT100ColorMap;
15 |
16 | @interface HBNTTerminalSessionViewController : UIViewController
17 |
18 | @property (nonatomic, strong, readonly) UITextView *textView;
19 | @property (nonatomic) UIEdgeInsets barInsets;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTerminalSessionViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTTerminalSessionViewController.m
3 | // NewTerm
4 | //
5 | // Created by Adam D on 12/12/2014.
6 | // Copyright (c) 2014 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import "HBNTTerminalSessionViewController.h"
10 | #import "HBNTTerminalController.h"
11 | #import "HBNTTerminalKeyInput.h"
12 | #import "HBNTTerminalTextView.h"
13 | #import "HBNTHUDView.h"
14 | #import "HBNTPreferences.h"
15 | #import "HBNTRootViewController.h"
16 | #import "VT100ColorMap.h"
17 | #import "FontMetrics.h"
18 | #import "UIView+CompactConstraint.h"
19 |
20 | @implementation HBNTTerminalSessionViewController {
21 | HBNTTerminalController *_terminalController;
22 | HBNTTerminalKeyInput *_keyInput;
23 | HBNTTerminalTextView *_textView;
24 | HBNTHUDView *_bellHUDView;
25 |
26 | NSException *_failureException;
27 |
28 | BOOL _hasAppeared;
29 | BOOL _hasStarted;
30 | CGFloat _keyboardHeight;
31 | CGPoint _lastAutomaticScrollOffset;
32 | }
33 |
34 | - (instancetype)init {
35 | self = [super init];
36 |
37 | if (self) {
38 | _terminalController = [[HBNTTerminalController alloc] init];
39 | _terminalController.viewController = self;
40 | _terminalController.delegate = self;
41 |
42 | @try {
43 | [_terminalController startSubProcess];
44 | _hasStarted = YES;
45 | } @catch (NSException *exception) {
46 | _failureException = exception;
47 | }
48 | }
49 |
50 | return self;
51 | }
52 |
53 | - (void)loadView {
54 | [super loadView];
55 |
56 | self.title = NSLocalizedString(@"TERMINAL", @"Generic title displayed before the terminal sets a proper title.");
57 |
58 | _textView = [[HBNTTerminalTextView alloc] initWithFrame:self.view.bounds];
59 | _textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
60 | _textView.showsVerticalScrollIndicator = NO;
61 | _textView.showsHorizontalScrollIndicator = NO;
62 | // TODO: this breaks stuff sorta
63 | // [_textView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTextViewTap:)]];
64 | [self.view addSubview:_textView];
65 |
66 | _keyInput = [[HBNTTerminalKeyInput alloc] init];
67 | _keyInput.textView = _textView;
68 | _keyInput.terminalInputDelegate = _terminalController;
69 | [self.view addSubview:_keyInput];
70 | }
71 |
72 | - (void)viewWillAppear:(BOOL)animated {
73 | [super viewWillAppear:animated];
74 |
75 | // [self registerForKeyboardNotifications];
76 | // [self becomeFirstResponder];
77 | }
78 |
79 | - (void)viewWillDisappear:(BOOL)animated {
80 | [super viewWillDisappear:animated];
81 |
82 | // [self unregisterForKeyboardNotifications];
83 | // [self resignFirstResponder];
84 | }
85 |
86 | - (void)viewWillLayoutSubviews {
87 | [super viewWillLayoutSubviews];
88 | [self updateScreenSize];
89 | }
90 |
91 | - (void)viewDidAppear:(BOOL)animated {
92 | [super viewDidAppear:animated];
93 |
94 | if (_failureException) {
95 | NSString *ok = NSLocalizedStringFromTableInBundle(@"OK", @"Localizable", [NSBundle bundleForClass:UIView.class], nil);
96 |
97 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"TERMINAL_LAUNCH_FAILED", @"Alert title displayed when a terminal could not be launched.") message:_failureException.reason preferredStyle:UIAlertControllerStyleAlert];
98 | [alertController addAction:[UIAlertAction actionWithTitle:ok style:UIAlertActionStyleCancel handler:nil]];
99 | [self presentViewController:alertController animated:YES completion:nil];
100 | }
101 | }
102 |
103 | - (void)removeFromParentViewController {
104 | if (_hasStarted) {
105 | // TODO: for some reason this always throws “subprocess was never started”? groannnn
106 | // [_terminalController stopSubProcess];
107 | }
108 |
109 | [super removeFromParentViewController];
110 | }
111 |
112 | #pragma mark - Screen
113 |
114 | - (void)updateScreenSize {
115 | // update the text view insets. if the keyboard height is non-zero, keyboard is visible and that’s
116 | // our bottom inset. else, it’s not and the bottom toolbar height is the bottom inset
117 | UIEdgeInsets barInsets = _barInsets;
118 | barInsets.bottom = _keyboardHeight ?: barInsets.bottom;
119 |
120 | _textView.contentInset = barInsets;
121 | _textView.scrollIndicatorInsets = _textView.contentInset;
122 |
123 | CGSize glyphSize = _terminalController.fontMetrics.boundingBox;
124 |
125 | // Determine the screen size based on the font size
126 | CGFloat width = _textView.frame.size.width;
127 | CGFloat height = _textView.frame.size.height - barInsets.top - barInsets.bottom;
128 |
129 | ScreenSize size;
130 | size.width = floorf(width / glyphSize.width);
131 | size.height = floorf(height / glyphSize.height);
132 |
133 | // The font size should not be too small that it overflows the glyph buffers. It is not worth the
134 | // effort to fail gracefully (increasing the buffer size would be better).
135 | NSParameterAssert(size.width < kMaxRowBufferSize);
136 |
137 | if (size.width != _terminalController.screenSize.width || size.height != _terminalController.screenSize.height) {
138 | _terminalController.screenSize = size;
139 | }
140 | }
141 |
142 | - (void)refreshWithAttributedString:(NSAttributedString *)attributedString backgroundColor:(UIColor *)backgroundColor {
143 | _textView.attributedText = attributedString;
144 |
145 | if (backgroundColor != _textView.backgroundColor) {
146 | _textView.backgroundColor = backgroundColor;
147 | }
148 |
149 | // TODO: not sure why this is needed all of a sudden? what did i break?
150 | dispatch_async(dispatch_get_main_queue(), ^{
151 | [self scrollToBottom];
152 | });
153 | }
154 |
155 | - (void)activateBell {
156 | // display the bell HUD, lazily initialising it if it hasn’t been yet
157 | if (!_bellHUDView) {
158 | _bellHUDView = [[HBNTHUDView alloc] initWithImage:[UIImage imageNamed:@"bell-hud"]];
159 | _bellHUDView.translatesAutoresizingMaskIntoConstraints = NO;
160 | [self.view addSubview:_bellHUDView];
161 | [self.view addCompactConstraints:@[
162 | @"hudView.centerX = self.centerX",
163 | @"hudView.top = self.top + 100"
164 | ] metrics:nil views:@{
165 | @"self": self.view,
166 | @"hudView": _bellHUDView
167 | }];
168 | }
169 |
170 | [_bellHUDView animate];
171 | }
172 |
173 | - (void)close {
174 | // TODO: i guess this is kind of the wrong spot
175 | if (self.parentViewController && self.parentViewController.class == HBNTRootViewController.class) {
176 | [(HBNTRootViewController *)self.parentViewController removeTerminal:self];
177 | }
178 | }
179 |
180 | - (void)scrollToBottom {
181 | // if the user has scrolled up far enough on their own, don’t rudely scroll them back to the
182 | // bottom. when they scroll back, the automatic scrolling will continue
183 | // TODO: buggy
184 | // if (_textView.contentOffset.y < _lastAutomaticScrollOffset.y - 20) {
185 | // return;
186 | // }
187 |
188 | // if there is no scrollback, use the top of the scroll view. if there is, calculate the bottom
189 | UIEdgeInsets insets = _textView.scrollIndicatorInsets;
190 | CGPoint offset = _textView.contentOffset;
191 | CGFloat bottom = _keyboardHeight ?: insets.bottom;
192 | offset.y = _terminalController.scrollbackLines == 0 ? -insets.top : bottom + _textView.contentSize.height - _textView.frame.size.height;
193 |
194 | // if the offset has changed, update it and our lastAutomaticScrollOffset
195 | if (_textView.contentOffset.y != offset.y) {
196 | _textView.contentOffset = offset;
197 | _lastAutomaticScrollOffset = offset;
198 | }
199 | }
200 |
201 | #pragma mark - Keyboard management
202 |
203 | - (void)registerForKeyboardNotifications {
204 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardVisibilityChanged:) name:UIKeyboardWillShowNotification object:nil];
205 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardVisibilityChanged:) name:UIKeyboardWillHideNotification object:nil];
206 | }
207 |
208 | - (void)unregisterForKeyboardNotifications {
209 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
210 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
211 | }
212 |
213 | - (void)keyboardVisibilityChanged:(NSNotification *)notification {
214 | // we do this to avoid the scroll indicator from appearing as soon as the terminal appears. we
215 | // only want to see it after the keyboard has appeared
216 | if (!_hasAppeared) {
217 | _hasAppeared = YES;
218 | // _textView.showsVerticalScrollIndicator = YES;
219 | }
220 |
221 | // YES when showing, NO when hiding
222 | BOOL direction = [notification.name isEqualToString:UIKeyboardWillShowNotification];
223 |
224 | CGFloat animationDuration = ((NSNumber *)notification.userInfo[UIKeyboardAnimationDurationUserInfoKey]).doubleValue;
225 |
226 | // determine the final keyboard height. we still get a height if hiding, so force it to 0 if this
227 | // isn’t a show notification
228 | CGRect keyboardFrame = ((NSValue *)notification.userInfo[UIKeyboardFrameEndUserInfoKey]).CGRectValue;
229 | _keyboardHeight = direction ? keyboardFrame.size.height : 0;
230 |
231 | // we call updateScreenSize in an animation block to force it to be animated with the exact
232 | // parameters given to us in the notification
233 | [UIView animateWithDuration:animationDuration animations:^{
234 | [self updateScreenSize];
235 | }];
236 | }
237 |
238 | - (BOOL)becomeFirstResponder {
239 | return NO;
240 | // return [_keyInput becomeFirstResponder];
241 | }
242 |
243 | - (BOOL)resignFirstResponder {
244 | return NO;
245 | // return [_keyInput resignFirstResponder];
246 | }
247 |
248 | - (BOOL)isFirstResponder {
249 | return _keyInput.isFirstResponder;
250 | }
251 |
252 | - (void)toggleKeyboard:(id)sender {
253 | if (self.isFirstResponder) {
254 | [self resignFirstResponder];
255 | } else {
256 | [self becomeFirstResponder];
257 | }
258 | }
259 |
260 | - (void)handleTextViewTap:(UITapGestureRecognizer *)gestureRecognizer {
261 | if (gestureRecognizer.state == UIGestureRecognizerStateEnded && !self.isFirstResponder) {
262 | [self becomeFirstResponder];
263 | }
264 | }
265 |
266 | @end
267 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTerminalTextView.h:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTTerminalTextView.h
3 | // NewTerm
4 | //
5 | // Created by Adam D on 26/01/2015.
6 | // Copyright (c) 2015 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface HBNTTerminalTextView : UITextView
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTerminalTextView.m:
--------------------------------------------------------------------------------
1 | //
2 | // HBNTTerminalTextView.m
3 | // NewTerm
4 | //
5 | // Created by Adam D on 26/01/2015.
6 | // Copyright (c) 2015 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import "HBNTTerminalTextView.h"
10 |
11 | @implementation HBNTTerminalTextView
12 |
13 | - (instancetype)initWithFrame:(CGRect)frame textContainer:(NSTextContainer *)textContainer {
14 | self = [super initWithFrame:frame textContainer:textContainer];
15 |
16 | if (self) {
17 | [self _commonInit];
18 | }
19 |
20 | return self;
21 | }
22 |
23 | - (instancetype)initWithFrame:(CGRect)frame {
24 | self = [super initWithFrame:frame];
25 |
26 | if (self) {
27 | [self _commonInit];
28 | }
29 |
30 | return self;
31 | }
32 |
33 | - (void)_commonInit {
34 | self.backgroundColor = [UIColor blackColor];
35 | self.indicatorStyle = UIScrollViewIndicatorStyleWhite;
36 | self.showsHorizontalScrollIndicator = NO;
37 | self.showsVerticalScrollIndicator = NO;
38 | // self.dataDetectorTypes = UIDataDetectorTypeLink;
39 | self.editable = NO;
40 |
41 | if ([self respondsToSelector:@selector(setLinkTextAttributes:)]) {
42 | self.linkTextAttributes = @{
43 | NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)
44 | };
45 | }
46 |
47 | if ([self respondsToSelector:@selector(textContainer)]) {
48 | self.textContainerInset = UIEdgeInsetsZero;
49 | self.textContainer.lineFragmentPadding = 0;
50 | }
51 | }
52 |
53 | #pragma mark - UIResponder
54 |
55 | - (BOOL)becomeFirstResponder {
56 | // we aren’t meant to ever become first responder. that’s the job of HBNTTerminalKeyInput
57 | return NO;
58 | }
59 |
60 | #pragma mark - UITextInput
61 |
62 | - (CGRect)caretRectForPosition:(UITextPosition *)position {
63 | // TODO: should we take advantage of this?
64 | return CGRectZero;
65 | }
66 |
67 | @end
68 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTextInputBase.h:
--------------------------------------------------------------------------------
1 | // UITextInputBase.h
2 | // MobileTerminal
3 | //
4 | // This file contains a base view for implementing keyboard handling routines
5 | // via the UITextInput protocol. That protocol is a grab bag of other protocols
6 | // that are mostly unused by the terminal keyboard handling code.
7 |
8 | #import
9 |
10 | #ifndef __IPHONE_11_0
11 | #define UITextSmartQuotesType NSInteger
12 | #define UITextSmartDashesType NSInteger
13 | #define UITextSmartInsertDeleteType NSInteger
14 | #define UITextSmartQuotesTypeNo 1
15 | #define UITextSmartDashesTypeNo 1
16 | #define UITextSmartInsertDeleteTypeNo 1
17 | #endif
18 |
19 | @interface HBNTTextPosition : UITextPosition
20 |
21 | @property (nonatomic, strong) NSNumber *position;
22 |
23 | @end
24 |
25 | @interface HBNTTextInputBase : UIView
26 |
27 | // UIKeyInput
28 | - (BOOL)hasText;
29 | - (void)insertText:(NSString *)text;
30 | - (void)deleteBackward;
31 |
32 |
33 | /* Methods for manipulating text. */
34 | - (NSString *)textInRange:(UITextRange *)range;
35 | - (void)replaceRange:(UITextRange *)range withText:(NSString *)text;
36 |
37 | /* Text may have a selection, either zero-length (a caret) or ranged. Editing operations are
38 | * always performed on the text from this selection. nil corresponds to no selection. */
39 |
40 | @property (readwrite, copy) UITextRange *selectedTextRange;
41 |
42 | /* If text can be selected, it can be marked. Marked text represents provisionally
43 | * inserted text that has yet to be confirmed by the user. It requires unique visual
44 | * treatment in its display. If there is any marked text, the selection, whether a
45 | * caret or an extended range, always resides witihin.
46 | *
47 | * Setting marked text either replaces the existing marked text or, if none is present,
48 | * inserts it from the current selection. */
49 |
50 | @property (nonatomic, readonly) UITextRange *markedTextRange; // Nil if no marked text.
51 | @property (nonatomic, copy) NSDictionary *markedTextStyle; // Describes how the marked text should be drawn.
52 | - (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange; // selectedRange is a range within the markedText
53 | - (void)unmarkText;
54 |
55 | /* The end and beginning of the the text document. */
56 | @property (nonatomic, readonly) UITextPosition *beginningOfDocument;
57 | @property (nonatomic, readonly) UITextPosition *endOfDocument;
58 |
59 | /* Methods for creating ranges and positions. */
60 | - (UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition;
61 | - (UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset;
62 | - (UITextPosition *)positionFromPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction offset:(NSInteger)offset;
63 |
64 | /* Simple evaluation of positions */
65 | - (NSComparisonResult)comparePosition:(UITextPosition *)position toPosition:(UITextPosition *)other;
66 | - (NSInteger)offsetFromPosition:(UITextPosition *)from toPosition:(UITextPosition *)toPosition;
67 |
68 | /* A system-provied input delegate is assigned when the system is interested in input changes. */
69 | @property (nonatomic, assign) id inputDelegate;
70 |
71 | /* A tokenizer must be provided to inform the text input system about text units of varying granularity. */
72 | @property (nonatomic, readonly) id tokenizer;
73 |
74 | /* Layout questions. */
75 | - (UITextPosition *)positionWithinRange:(UITextRange *)range farthestInDirection:(UITextLayoutDirection)direction;
76 | - (UITextRange *)characterRangeByExtendingPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction;
77 |
78 | /* Writing direction */
79 | - (UITextWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction;
80 | - (void)setBaseWritingDirection:(UITextWritingDirection)writingDirection forRange:(UITextRange *)range;
81 |
82 | /* Geometry used to provide, for example, a correction rect. */
83 | - (CGRect)firstRectForRange:(UITextRange *)range;
84 | - (CGRect)caretRectForPosition:(UITextPosition *)position;
85 | - (NSArray *)selectionRectsForRange:(UITextRange *)range;
86 |
87 | /* Hit testing. */
88 | - (UITextPosition *)closestPositionToPoint:(CGPoint)point;
89 | - (UITextPosition *)closestPositionToPoint:(CGPoint)point withinRange:(UITextRange *)range;
90 | - (UITextRange *)characterRangeAtPoint:(CGPoint)point;
91 |
92 | /* Text styling information can affect, for example, the appearance of a correction rect. */
93 | - (NSDictionary *)textStylingAtPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction;
94 |
95 | /* To be implemented if there is not a one-to-one correspondence between text positions within range and character offsets into the associated string. */
96 | - (UITextPosition *)positionWithinRange:(UITextRange *)range atCharacterOffset:(NSInteger)offset;
97 | - (NSInteger)characterOffsetOfPosition:(UITextPosition *)position withinRange:(UITextRange *)range;
98 |
99 | /* An affiliated view that provides a coordinate system for all geometric values in this protocol.
100 | * If unimplmeented, the first view in the responder chain will be selected. */
101 | @property (nonatomic, readonly) UIView *textInputView;
102 |
103 | /* Selection affinity determines whether, for example, the insertion point appears after the last
104 | * character on a line or before the first character on the following line in cases where text
105 | * wraps across line boundaries. */
106 | @property (nonatomic) UITextStorageDirection selectionAffinity;
107 |
108 | // traits:
109 |
110 | @property (nonatomic) UITextAutocapitalizationType autocapitalizationType; // default is UITextAutocapitalizationTypeSentences
111 | @property (nonatomic) UITextAutocorrectionType autocorrectionType; // default is UITextAutocorrectionTypeDefault
112 | @property (nonatomic) UITextSpellCheckingType spellCheckingType; // default is UITextSpellCheckingTypeDefault
113 | @property (nonatomic) UITextSmartQuotesType smartQuotesType /*NS_AVAILABLE_IOS(11_0)*/; // default is UITextSmartQuotesTypeDefault
114 | @property (nonatomic) UITextSmartDashesType smartDashesType /*NS_AVAILABLE_IOS(11_0)*/; // default is UITextSmartDashesTypeDefault
115 | @property (nonatomic) UITextSmartInsertDeleteType smartInsertDeleteType /*NS_AVAILABLE_IOS(11_0)*/; // default is UITextSmartInsertDeleteTypeDefault
116 | @property (nonatomic) UIKeyboardType keyboardType; // default is UIKeyboardTypeDefault
117 | @property (nonatomic) UIKeyboardAppearance keyboardAppearance; // default is UIKeyboardAppearanceDefault
118 | @property (nonatomic) UIReturnKeyType returnKeyType; // default is UIReturnKeyDefault
119 |
120 | @end
121 |
--------------------------------------------------------------------------------
/NewTermMarzipan/HBNTTextInputBase.m:
--------------------------------------------------------------------------------
1 | // UITextInputBase.m
2 | // MobileTerminal
3 |
4 | #import "HBNTTextInputBase.h"
5 |
6 | @implementation HBNTTextPosition
7 |
8 | @end
9 |
10 | @implementation HBNTTextInputBase
11 |
12 | - (BOOL)hasText {
13 | return NO;
14 | }
15 |
16 | - (void)insertText:(NSString *)text {}
17 |
18 | - (void)deleteBackward {}
19 |
20 | - (NSString *)textInRange:(UITextRange *)range {
21 | return nil;
22 | }
23 |
24 | - (void)replaceRange:(UITextRange *)range withText:(NSString *)text {}
25 |
26 | - (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange {}
27 |
28 | - (void)unmarkText {}
29 |
30 | /* Methods for creating ranges and positions. */
31 | - (UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition {
32 | return nil;
33 | }
34 |
35 | - (UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset {
36 | return nil;
37 | }
38 |
39 | - (UITextPosition *)positionFromPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction offset:(NSInteger)offset {
40 | return nil;
41 | }
42 |
43 | - (NSComparisonResult)comparePosition:(UITextPosition *)position toPosition:(UITextPosition *)other {
44 | return [((HBNTTextPosition *)position).position compare:((HBNTTextPosition *)other).position];
45 | }
46 |
47 | - (NSInteger)offsetFromPosition:(UITextPosition *)from toPosition:(UITextPosition *)toPosition {
48 | return 0;
49 | }
50 |
51 | - (UITextPosition *)positionWithinRange:(UITextRange *)range farthestInDirection:(UITextLayoutDirection)direction {
52 | return nil;
53 | }
54 |
55 | - (UITextRange *)characterRangeByExtendingPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction {
56 | return nil;
57 | }
58 |
59 | - (UITextWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction {
60 | return UITextWritingDirectionNatural;
61 | }
62 |
63 | - (void)setBaseWritingDirection:(UITextWritingDirection)writingDirection forRange:(UITextRange *)range {}
64 |
65 | - (CGRect)firstRectForRange:(UITextRange *)range {
66 | return CGRectZero;
67 | }
68 |
69 | - (CGRect)caretRectForPosition:(UITextPosition *)position {
70 | return CGRectZero;
71 | }
72 |
73 | - (NSArray *)selectionRectsForRange:(UITextRange *)range {
74 | return nil;
75 | }
76 |
77 | - (UITextPosition *)closestPositionToPoint:(CGPoint)point {
78 | HBNTTextPosition *position = [[HBNTTextPosition alloc] init];
79 | position.position = @(point.x);
80 | return position;
81 | }
82 |
83 | - (UITextPosition *)closestPositionToPoint:(CGPoint)point withinRange:(UITextRange *)range {
84 | HBNTTextPosition *position = [[HBNTTextPosition alloc] init];
85 | position.position = @(point.x);
86 | return position;
87 | }
88 |
89 | - (UITextRange *)characterRangeAtPoint:(CGPoint)point {
90 | return nil;
91 | }
92 |
93 | - (NSDictionary *)textStylingAtPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction {
94 | return nil;
95 | }
96 |
97 | /* To be implemented if there is not a one-to-one correspondence between text positions within range and character offsets into the associated string. */
98 | - (UITextPosition *)positionWithinRange:(UITextRange *)range atCharacterOffset:(NSInteger)offset {
99 | return nil;
100 | }
101 |
102 | - (NSInteger)characterOffsetOfPosition:(UITextPosition *)position withinRange:(UITextRange *)range {
103 | return 0;
104 | }
105 |
106 | @end
107 |
--------------------------------------------------------------------------------
/NewTermMarzipan/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 | NSHumanReadableCopyright
26 | Copyright © 2018 HASHBANG Productions. All rights reserved.
27 |
28 |
29 |
--------------------------------------------------------------------------------
/NewTermMarzipan/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/NewTermMarzipan/Main.storyboardc/Info.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kirb/iOSMac-Demo/742c528fb3280dcdb01b1e71ffe2aceb09245468/NewTermMarzipan/Main.storyboardc/Info.plist
--------------------------------------------------------------------------------
/NewTermMarzipan/Main.storyboardc/U5R-jr-i31-view-bFg-2Y-cSI.nib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kirb/iOSMac-Demo/742c528fb3280dcdb01b1e71ffe2aceb09245468/NewTermMarzipan/Main.storyboardc/U5R-jr-i31-view-bFg-2Y-cSI.nib
--------------------------------------------------------------------------------
/NewTermMarzipan/Main.storyboardc/UINavigationController-a88-9D-dcr.nib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kirb/iOSMac-Demo/742c528fb3280dcdb01b1e71ffe2aceb09245468/NewTermMarzipan/Main.storyboardc/UINavigationController-a88-9D-dcr.nib
--------------------------------------------------------------------------------
/NewTermMarzipan/NSCharacterSet+iTerm.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSCharacterSet+iTerm.h
3 | // iTerm2
4 | //
5 | // Created by George Nachman on 3/29/15.
6 | //
7 | //
8 |
9 | @import Foundation;
10 |
11 | @interface NSCharacterSet (iTerm)
12 |
13 | + (instancetype)fullWidthCharacterSetForUnicodeVersion:(NSInteger)version;
14 | + (instancetype)ambiguousWidthCharacterSetForUnicodeVersion:(NSInteger)version;
15 | + (instancetype)zeroWidthSpaceCharacterSet;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/NewTermMarzipan/NSStringITerm.h:
--------------------------------------------------------------------------------
1 | // $Id: NSStringITerm.h,v 1.2 2006-11-13 06:57:47 yfabian Exp $
2 | //
3 | // NSStringJTerminal.h
4 | //
5 | // Additional function to NSString Class by Category
6 | // 2001.11.13 by Y.Hanahara
7 | // 2002.05.18 by Kiichi Kusama
8 | /*
9 | ** NSStringIterm.h
10 | **
11 | ** Copyright (c) 2002, 2003
12 | **
13 | ** Author: Fabian
14 | ** Initial code by Kiichi Kusama
15 | **
16 | ** Project: iTerm
17 | **
18 | ** Description: Implements NSString extensions.
19 | **
20 | ** This program is free software; you can redistribute it and/or modify
21 | ** it under the terms of the GNU General Public License as published by
22 | ** the Free Software Foundation; either version 2 of the License, or
23 | ** (at your option) any later version.
24 | **
25 | ** This program is distributed in the hope that it will be useful,
26 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of
27 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 | ** GNU General Public License for more details.
29 | **
30 | ** You should have received a copy of the GNU General Public License
31 | ** along with this program; if not, write to the Free Software
32 | ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 | */
34 |
35 | @import Foundation;
36 |
37 | // This is the standard unicode replacement character for when input couldn't
38 | // be parsed properly but we need to render something there.
39 | #define UNICODE_REPLACEMENT_CHAR 0xfffd
40 |
41 | @interface NSString (iTerm)
42 |
43 | + (BOOL)isDoubleWidthCharacter:(int)unicode
44 | ambiguousIsDoubleWidth:(BOOL)ambiguousIsDoubleWidth
45 | unicodeVersion:(NSInteger)version;
46 |
47 | // Call |block| for each composed character in the string. If it is a single base character or a
48 | // high surrogate, then |simple| will be valid and |complex| will be nil. Otherwise, |complex| will
49 | // be non-nil.
50 | - (void)enumerateComposedCharacters:(void (^)(NSRange range,
51 | unichar simple,
52 | NSString *complexString,
53 | BOOL *stop))block;
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/NewTermMarzipan/NSStringITerm.m:
--------------------------------------------------------------------------------
1 | /*
2 | ** NSStringIterm.m
3 | **
4 | ** Copyright (c) 2002, 2003
5 | **
6 | ** Author: Fabian
7 | ** Initial code by Kiichi Kusama
8 | **
9 | ** Project: iTerm
10 | **
11 | ** Description: Implements NSString extensions.
12 | **
13 | ** This program is free software; you can redistribute it and/or modify
14 | ** it under the terms of the GNU General Public License as published by
15 | ** the Free Software Foundation; either version 2 of the License, or
16 | ** (at your option) any later version.
17 | **
18 | ** This program is distributed in the hope that it will be useful,
19 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | ** GNU General Public License for more details.
22 | **
23 | ** You should have received a copy of the GNU General Public License
24 | ** along with this program; if not, write to the Free Software
25 | ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 | */
27 |
28 | #import "NSStringITerm.h"
29 | #import "NSCharacterSet+iTerm.h"
30 |
31 | @implementation NSString (iTerm)
32 |
33 | + (BOOL)isDoubleWidthCharacter:(int)unicode
34 | ambiguousIsDoubleWidth:(BOOL)ambiguousIsDoubleWidth
35 | unicodeVersion:(NSInteger)version {
36 | if (unicode <= 0xa0 ||
37 | (unicode > 0x452 && unicode < 0x1100)) {
38 | // Quickly cover the common cases.
39 | return NO;
40 | }
41 |
42 | if ([[NSCharacterSet fullWidthCharacterSetForUnicodeVersion:version] longCharacterIsMember:unicode]) {
43 | return YES;
44 | }
45 | if (ambiguousIsDoubleWidth &&
46 | [[NSCharacterSet ambiguousWidthCharacterSetForUnicodeVersion:version] longCharacterIsMember:unicode]) {
47 | return YES;
48 | }
49 | return NO;
50 | }
51 |
52 | - (void)enumerateComposedCharacters:(void (^)(NSRange, unichar, NSString *, BOOL *))block {
53 | if (self.length == 0) {
54 | return;
55 | }
56 | static dispatch_once_t onceToken;
57 | static NSCharacterSet *exceptions;
58 | dispatch_once(&onceToken, ^{
59 | // These characters are forced to be base characters.
60 | exceptions = [NSCharacterSet characterSetWithCharactersInString:@"\uff9e\uff9f"];
61 | });
62 | CFIndex index = 0;
63 | NSInteger minimumLocation = 0;
64 | NSRange range;
65 | do {
66 | CFRange tempRange = CFStringGetRangeOfComposedCharactersAtIndex((CFStringRef)self, index);
67 | if (tempRange.location < minimumLocation) {
68 | NSInteger diff = minimumLocation - tempRange.location;
69 | tempRange.location += diff;
70 | if (diff > tempRange.length) {
71 | tempRange.length = 0;
72 | } else {
73 | tempRange.length -= diff;
74 | }
75 | }
76 | range = NSMakeRange(tempRange.location, tempRange.length);
77 | if (range.length > 0) {
78 | // CFStringGetRangeOfComposedCharactersAtIndex thinks that U+FF9E and U+FF9F are
79 | // combining marks. Terminal.app and the person in issue 6048 disagree. Prevent them
80 | // from combining.
81 | NSRange rangeOfFirstException = [self rangeOfCharacterFromSet:exceptions
82 | options:NSLiteralSearch
83 | range:range];
84 | if (rangeOfFirstException.location != NSNotFound &&
85 | rangeOfFirstException.location > range.location) {
86 | range.length = rangeOfFirstException.location - range.location;
87 | minimumLocation = NSMaxRange(range);
88 | }
89 |
90 | unichar simple = range.length == 1 ? [self characterAtIndex:range.location] : 0;
91 | NSString *complexString = range.length == 1 ? nil : [self substringWithRange:range];
92 | BOOL stop = NO;
93 | block(range, simple, complexString, &stop);
94 | if (stop) {
95 | return;
96 | }
97 | }
98 | index = NSMaxRange(range);
99 | } while (NSMaxRange(range) < self.length);
100 | }
101 |
102 | @end
103 |
--------------------------------------------------------------------------------
/NewTermMarzipan/NewTermMarzipan.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.private.iosmac
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/NewTermMarzipan/Themes.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Basic
6 |
7 | Background
8 | #ffffff
9 | BoldText
10 | #000000
11 | Cursor
12 | #7f7f7f
13 | IsDark
14 |
15 | Text
16 | #000000
17 |
18 | Grass
19 |
20 | Background
21 | #13773d
22 | BoldText
23 | #ffb03b
24 | Cursor
25 | #8e2800
26 | IsDark
27 |
28 | Text
29 | #fff0a5
30 |
31 | Homebrew
32 |
33 | Background
34 | #000000
35 | BoldText
36 | #00ff00
37 | Cursor
38 | #38fe27
39 | IsDark
40 |
41 | Text
42 | #13773d
43 |
44 | kirb
45 |
46 | Background
47 | #0f0f0f
48 | BoldText
49 | #ffffff
50 | Cursor
51 | #00d900
52 | IsDark
53 |
54 | Text
55 | #f2f2f2
56 |
57 | Man Page
58 |
59 | Background
60 | #fef49c
61 | BoldText
62 | #000000
63 | Cursor
64 | #7f7f7f
65 | IsDark
66 |
67 | Text
68 | #000000
69 |
70 | Novel
71 |
72 | Background
73 | #dfdbc3
74 | BoldText
75 | #7f2a19
76 | Cursor
77 | #3a2322
78 | IsDark
79 |
80 | Text
81 | #3b2322
82 |
83 | Ocean
84 |
85 | Background
86 | #224fbc
87 | BoldText
88 | #ffffff
89 | Cursor
90 | #7f7f7f
91 | IsDark
92 |
93 | Text
94 | #ffffff
95 |
96 | Pro
97 |
98 | Background
99 | #000000
100 | BoldText
101 | #ffffff
102 | Cursor
103 | #4d4d4d
104 | IsDark
105 |
106 | Text
107 | #f2f2f2
108 |
109 | Red Sands
110 |
111 | Background
112 | #7a251e
113 | BoldText
114 | #dfbd22
115 | Cursor
116 | #ffffff
117 | IsDark
118 |
119 | Text
120 | #d7c9a7
121 |
122 | Silver Aerogel
123 |
124 | Background
125 | #808080
126 | BoldText
127 | #ffffff
128 | Cursor
129 | #d9d9d9
130 | IsDark
131 |
132 | Text
133 | #000000
134 |
135 | VSCode
136 |
137 | Background
138 | #1e1e1e
139 | BoldText
140 | #cccccc
141 | ColorTable
142 |
143 | #000000
144 | #cd3131
145 | #0dbc79
146 | #e5e510
147 | #2472c8
148 | #bc3fbc
149 | #11a8cd
150 | #e5e5e5
151 | #666666
152 | #f14c4c
153 | #23d18b
154 | #f5f543
155 | #3b8eea
156 | #d670d6
157 | #29b8db
158 | #e5e5e5
159 |
160 | Cursor
161 | #0dbc79
162 | IsDark
163 |
164 | Text
165 | #ffffff
166 |
167 |
168 |
169 |
--------------------------------------------------------------------------------
/NewTermMarzipan/VT100.h:
--------------------------------------------------------------------------------
1 | // VT100.h
2 | // MobileTerminal
3 | //
4 | // This file contains the bridge between the higher level text drawing
5 | // controls and the lower level terminal state pieces (screen and terminal).
6 | // The VT100 interface should be the only access from those components to the
7 | // VT100 subsystem. This layer mostly exists to keep the complexity/mess of
8 | // the VT100Terminal and VT100 screen away from everything else.
9 |
10 | #import "VT100Types.h"
11 |
12 | // Forward declarations
13 | @class VT100Terminal;
14 | @class VT100Screen;
15 |
16 | // VT100 is the public interface that combines the terminal subcomponents. The
17 | // caller is expected to provide the raw terminal data into the VT100 object
18 | // via calls to handleInputStream. VT100 exposes the contents of the screen by
19 | // implementing the ScreenBuffer protocol.
20 | @interface VT100 : NSObject
21 |
22 | @property (nonatomic, retain) id refreshDelegate;
23 |
24 | // Initialize a VT100
25 | - (instancetype)init;
26 |
27 | // Reads raw character data into the terminal character processor. This will
28 | // almost certainly cause updates to the screen buffer.
29 | - (void)readInputStream:(NSData *)data;
30 |
31 | // ScreenBuffer methods for obtaining information about the characters
32 | // currently on the screen.
33 | @property (nonatomic) ScreenSize screenSize;
34 |
35 | // The row specified here also includes the scrollback buffer.
36 | - (screen_char_t*)bufferForRow:(int)row;
37 | - (int)numberOfRows;
38 | - (unsigned)scrollbackLines;
39 |
40 | - (ScreenPosition)cursorPosition;
41 |
42 | - (void)clearScreen;
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/NewTermMarzipan/VT100.m:
--------------------------------------------------------------------------------
1 | // VT100.m
2 | // MobileTerminal
3 |
4 | #import "VT100.h"
5 |
6 | #import "VT100Terminal.h"
7 | #import "VT100Screen.h"
8 |
9 | // The default width and height are basically thrown away as soon as the text view is initialized
10 | // and determines the right height and width for the current font.
11 | static const int kDefaultWidth = 80;
12 | static const int kDefaultHeight = 25;
13 |
14 | @implementation VT100 {
15 | VT100Terminal *_terminal;
16 | }
17 |
18 | - (instancetype)init {
19 | self = [super init];
20 |
21 | if (self) {
22 | _terminal = [[VT100Terminal alloc] init];
23 | _terminal.encoding = NSUTF8StringEncoding;
24 |
25 | _terminal.primaryScreen.refreshDelegate = self;
26 | _terminal.alternateScreen.refreshDelegate = self;
27 | [_terminal.primaryScreen resizeWidth:kDefaultWidth height:kDefaultHeight];
28 | [_terminal.alternateScreen resizeWidth:kDefaultWidth height:kDefaultHeight];
29 | }
30 |
31 | return self;
32 | }
33 |
34 | // This object itself is the refresh delegate for the screen. When we're
35 | // invoked, invoke our refresh delegate and then reset the dirty bits on the
36 | // screen since we should have now refreshed the screen.
37 | - (void)refresh {
38 | [_refreshDelegate refresh];
39 | [_terminal.currentScreen resetDirty];
40 | }
41 |
42 | - (void)activateBell {
43 | // tell the refresh delegate to activate the bell
44 | [_refreshDelegate activateBell];
45 | }
46 |
47 | - (void)readInputStream:(NSData *)data {
48 | // Push the input stream into the terminal, then parse the stream back out as
49 | // a series of tokens and feed them back to the screen
50 | [_terminal putStreamData:data];
51 | VT100Token *token;
52 | while((token = [_terminal getNextToken]),
53 | token.type != VT100_WAIT && token.type != VT100CC_NULL) {
54 | // process token
55 | if (token.type != VT100_SKIP) {
56 | if (token.type == VT100_NOTSUPPORT) {
57 | NSLog(@"not support token");
58 | } else {
59 | [_terminal.currentScreen putToken:token];
60 | }
61 | } else {
62 | NSLog(@"skip token");
63 | }
64 | }
65 | // Cause the text display to determine if it should re-draw anything
66 | [_refreshDelegate refresh];
67 | }
68 |
69 | - (ScreenSize)screenSize {
70 | ScreenSize size;
71 | size.width = _terminal.currentScreen.width;
72 | size.height = _terminal.currentScreen.height;
73 | return size;
74 | }
75 |
76 | - (void)setScreenSize:(ScreenSize)size {
77 | [_terminal.primaryScreen resizeWidth:size.width height:size.height];
78 | [_terminal.alternateScreen resizeWidth:size.width height:size.height];
79 | }
80 |
81 | - (ScreenPosition)cursorPosition {
82 | ScreenPosition position;
83 | position.x = _terminal.currentScreen.cursorX;
84 | position.y = _terminal.currentScreen.cursorY;
85 | return position;
86 | }
87 |
88 | - (screen_char_t*)bufferForRow:(int)row {
89 | return [_terminal.currentScreen getLineAtIndex:row];
90 | }
91 |
92 | - (void)clearScreen {
93 | // Clears both the screen and scrollback buffer
94 | [_terminal.currentScreen clearBuffer];
95 | }
96 |
97 | - (int)numberOfRows {
98 | return [_terminal.currentScreen numberOfLines];
99 | }
100 |
101 | - (unsigned)scrollbackLines {
102 | return [_terminal.currentScreen numberOfScrollbackLines];
103 | }
104 |
105 | @end
106 |
--------------------------------------------------------------------------------
/NewTermMarzipan/VT100ColorMap.h:
--------------------------------------------------------------------------------
1 | // ColorMap.h
2 | // MobileTerminal
3 |
4 | #import
5 |
6 | // 16 terminal color slots available
7 | #define COLOR_MAP_MAX_COLORS 16
8 |
9 | @interface VT100ColorMap : NSObject
10 |
11 | @property (nonatomic, retain, readonly) UIColor *background;
12 | @property (nonatomic, retain, readonly) UIColor *foreground;
13 | @property (nonatomic, retain, readonly) UIColor *foregroundBold;
14 | @property (nonatomic, retain, readonly) UIColor *foregroundCursor;
15 | @property (nonatomic, retain, readonly) UIColor *backgroundCursor;
16 |
17 | @property (nonatomic, readonly) BOOL isDark;
18 |
19 | - (instancetype)init;
20 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary;
21 |
22 | // Terminal color index
23 | - (UIColor *)colorAtIndex:(unsigned)index;
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/NewTermMarzipan/VT100ColorMap.m:
--------------------------------------------------------------------------------
1 | // ColorMap.m
2 | // MobileTerminal
3 |
4 | #import "VT100ColorMap.h"
5 | #import "VT100Terminal.h"
6 | #import "UIColor+HBAdditions.h"
7 |
8 | @interface VT100ColorMap () {
9 | UIColor *_table[COLOR_MAP_MAX_COLORS];
10 | }
11 |
12 | @end
13 |
14 | @implementation VT100ColorMap
15 |
16 | - (instancetype)init {
17 | self = [super init];
18 |
19 | if (self) {
20 | _background = [UIColor colorWithWhite:0.f alpha:1.f];
21 | _foreground = [UIColor colorWithWhite:0.95f alpha:1.f];
22 | _foregroundBold = [UIColor colorWithWhite:1.f alpha:1.f];
23 | _foregroundCursor = [UIColor colorWithWhite:0.95f alpha:1.f];
24 | _backgroundCursor = [UIColor colorWithWhite:0.4f alpha:1.f];
25 | _isDark = YES;
26 |
27 | // System 7.5 colors, why not?
28 | _table[kiTermScreenCharAnsiColorBlack] = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:1.f];
29 | _table[kiTermScreenCharAnsiColorRed] = [UIColor colorWithRed:0.6f green:0.0f blue:0.0f alpha:1.f];
30 | _table[kiTermScreenCharAnsiColorGreen] = [UIColor colorWithRed:0.0f green:0.6f blue:0.0f alpha:1.f];
31 | _table[kiTermScreenCharAnsiColorYellow] = [UIColor colorWithRed:0.6f green:0.4f blue:0.0f alpha:1.f];
32 | _table[kiTermScreenCharAnsiColorBlue] = [UIColor colorWithRed:0.0f green:0.0f blue:0.6f alpha:1.f];
33 | _table[kiTermScreenCharAnsiColorMagenta] = [UIColor colorWithRed:0.6f green:0.0f blue:0.6f alpha:1.f];
34 | _table[kiTermScreenCharAnsiColorCyan] = [UIColor colorWithRed:0.0f green:0.6f blue:0.6f alpha:1.f];
35 | _table[kiTermScreenCharAnsiColorWhite] = [UIColor colorWithRed:0.6f green:0.6f blue:0.6f alpha:1.f];
36 | _table[kiTermScreenCharAnsiColorBrightBlack] = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:1.f];
37 | _table[kiTermScreenCharAnsiColorBrightRed] = [UIColor colorWithRed:1.0f green:0.0f blue:0.0f alpha:1.f];
38 | _table[kiTermScreenCharAnsiColorBrightGreen] = [UIColor colorWithRed:0.0f green:1.0f blue:0.0f alpha:1.f];
39 | _table[kiTermScreenCharAnsiColorBrightYellow] = [UIColor colorWithRed:1.0f green:1.0f blue:0.0f alpha:1.f];
40 | _table[kiTermScreenCharAnsiColorBrightBlue] = [UIColor colorWithRed:0.0f green:0.0f blue:1.0f alpha:1.f];
41 | _table[kiTermScreenCharAnsiColorBrightMagenta] = [UIColor colorWithRed:1.0f green:0.0f blue:1.0f alpha:1.f];
42 | _table[kiTermScreenCharAnsiColorBrightCyan] = [UIColor colorWithRed:0.0f green:1.0f blue:1.0f alpha:1.f];
43 | _table[kiTermScreenCharAnsiColorBrightWhite] = [UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.f];
44 | }
45 |
46 | return self;
47 | }
48 |
49 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary {
50 | self = [self init];
51 |
52 | if (self) {
53 | if (dictionary[@"Background"]) {
54 | _background = [UIColor hb_colorWithPropertyListValue:dictionary[@"Background"]];
55 | }
56 |
57 | if (dictionary[@"Text"]) {
58 | _foreground = [UIColor hb_colorWithPropertyListValue:dictionary[@"Text"]];
59 | }
60 |
61 | if (dictionary[@"BoldText"]) {
62 | _foregroundBold = [UIColor hb_colorWithPropertyListValue:dictionary[@"BoldText"]];
63 | }
64 |
65 | if (dictionary[@"Cursor"]) {
66 | _foregroundCursor = [UIColor hb_colorWithPropertyListValue:dictionary[@"Cursor"]];
67 | _backgroundCursor = [UIColor hb_colorWithPropertyListValue:dictionary[@"Cursor"]];
68 | }
69 |
70 | if (dictionary[@"IsDark"]) {
71 | _isDark = ((NSNumber *)dictionary[@"IsDark"]).boolValue;
72 | }
73 |
74 | if (dictionary[@"ColorTable"] && [dictionary[@"ColorTable"] isKindOfClass:NSArray.class] && ((NSDictionary *)dictionary[@"ColorTable"]).count == COLOR_MAP_MAX_COLORS) {
75 | NSArray *colors = dictionary[@"ColorTable"];
76 | for (int i = 0; i < colors.count; i++) {
77 | _table[i] = [UIColor hb_colorWithPropertyListValue:colors[i]];
78 | }
79 | }
80 | }
81 |
82 | return self;
83 | }
84 |
85 | - (UIColor *)colorAtIndex:(unsigned int)index {
86 | // TODO(allen): The logic here is pretty ad hoc and could use some some helpful comments
87 | // describing whats its doing. It seems to work?
88 | if (index == -1) {
89 | return [UIColor clearColor];
90 | } else if (index & COLOR_CODE_MASK) {
91 | switch (index) {
92 | case CURSOR_TEXT:
93 | return _foregroundCursor;
94 | case CURSOR_BG:
95 | return _backgroundCursor;
96 | case BG_COLOR_CODE:
97 | return [UIColor clearColor];
98 | default:
99 | if (index & BOLD_MASK) {
100 | if (index - BOLD_MASK == BG_COLOR_CODE) {
101 | return [UIColor clearColor];
102 | } else {
103 | return _foregroundBold;
104 | }
105 | } else {
106 | return _foreground;
107 | }
108 | }
109 | } else {
110 | index &= 0xff;
111 | if (index < 16) {
112 | // predefined color
113 | return _table[index];
114 | } else if (index < 232) {
115 | // 256-color
116 | index -= 16;
117 | CGFloat components[] = {
118 | (index / 36) ? ((index / 36) * 40 + 55) / 255.0 : 0.0,
119 | (index % 36) / 6 ? (((index % 36) / 6) * 40 + 55) / 255.0 : 0.0,
120 | (index % 6) ? ((index % 6) * 40 + 55) / 255.0 : 0.0,
121 | 1.0
122 | };
123 | return [UIColor colorWithRed:components[0] green:components[1] blue:components[2] alpha:1.0f];
124 | } else if (index < 256) {
125 | // grayscale
126 | index -= 232;
127 | CGFloat gray = (index * 10 + 8) / 255.0;
128 | return [UIColor colorWithWhite:gray alpha:1.0f];
129 | } else {
130 | return _foreground;
131 | }
132 | }
133 | }
134 |
135 | @end
136 |
--------------------------------------------------------------------------------
/NewTermMarzipan/VT100Screen.h:
--------------------------------------------------------------------------------
1 | // -*- mode:objc -*-
2 | /*
3 | ** VT100Screen.h
4 | **
5 | ** Copyright (c) 2002, 2003, 2007
6 | **
7 | ** Author: Fabian, Ujwal S. Setlur
8 | ** Initial code by Kiichi Kusama
9 | ** Ported to MobileTerminal (from iTerm) by Allen Porter
10 | **
11 | ** This program is free software; you can redistribute it and/or modify
12 | ** it under the terms of the GNU General Public License as published by
13 | ** the Free Software Foundation; either version 2 of the License, or
14 | ** (at your option) any later version.
15 | **
16 | ** This program is distributed in the hope that it will be useful,
17 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | ** GNU General Public License for more details.
20 | **
21 | ** You should have received a copy of the GNU General Public License
22 | ** along with this program; if not, write to the Free Software
23 | ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 | */
25 |
26 | #import "VT100Terminal.h"
27 | #import "VT100Types.h"
28 |
29 | //_______________________________________________________________________________
30 | //_______________________________________________________________________________
31 |
32 | #define TABWINDOW 300
33 |
34 | @interface VT100Screen : NSObject
35 |
36 | @property (nonatomic, strong) VT100Terminal *terminal;
37 | @property (nonatomic, weak) id refreshDelegate;
38 |
39 | @property (nonatomic) int width, height;
40 |
41 | - (void)resizeWidth:(int)width height:(int)height;
42 | - (void)reset;
43 | - (void)setWidth:(int)width height:(int)height;
44 |
45 | @property (nonatomic) unsigned int maxScrollbackLines;
46 |
47 | @property (nonatomic) BOOL cursorVisible;
48 | @property (nonatomic) BOOL blinkingCursor;
49 |
50 | // line access
51 | - (screen_char_t *)getLineAtIndex:(int)theIndex;
52 | - (screen_char_t *)getLineAtScreenIndex:(int)theIndex;
53 |
54 | // edit screen buffer
55 | - (void)putToken:(VT100Token *)token;
56 | - (void)clearBuffer;
57 | - (void)clearScrollbackBuffer;
58 |
59 | // internal
60 | - (void)setString:(NSString *)s ascii:(BOOL)ascii;
61 | - (void)setNewLine;
62 | - (void)deleteCharacters:(int)n;
63 | - (void)backSpace;
64 | - (void)setTab;
65 | - (void)clearTabStop;
66 | - (void)clearScreen;
67 | - (void)eraseInDisplay:(VT100Token *)token;
68 | - (void)eraseInLine:(VT100Token *)token;
69 | - (void)selectGraphicRendition:(VT100Token *)token;
70 | - (void)cursorLeft:(int)n;
71 | - (void)cursorRight:(int)n;
72 | - (void)cursorUp:(int)n;
73 | - (void)cursorDown:(int)n;
74 | - (void)cursorToX:(int)x;
75 | - (void)cursorToX:(int)x Y:(int)y;
76 | - (void)saveCursorPosition;
77 | - (void)restoreCursorPosition;
78 | - (void)setTopBottom:(VT100Token *)token;
79 | - (void)scrollUp;
80 | - (void)scrollDown;
81 | - (void)activateBell;
82 | - (void)insertBlank:(int)n;
83 | - (void)insertLines:(int)n;
84 | - (void)deleteLines:(int)n;
85 |
86 | @property (nonatomic, readonly) int cursorX, cursorY;
87 |
88 | - (void)resetDirty;
89 | - (void)setDirty;
90 |
91 | - (int)numberOfLines;
92 | - (unsigned int)numberOfScrollbackLines;
93 |
94 | // print to ansi...
95 | @property (nonatomic) BOOL printToAnsi;
96 |
97 | - (void)printStringToAnsi:(NSString *)aString;
98 |
99 | // UI stuff
100 | @property (nonatomic, readonly) int newWidth, newHeight;
101 | @property (nonatomic, readonly) int scrollUpLines;
102 |
103 | - (void)resetScrollUpLines;
104 |
105 | @end
106 |
107 | /* vim: set syntax=objc sw=4 ts=4 sts=4 expandtab textwidth=80 ff=unix: */
108 |
--------------------------------------------------------------------------------
/NewTermMarzipan/VT100StringSupplier.h:
--------------------------------------------------------------------------------
1 | // VT100RowStringSupplier.h
2 | // MobileTerminal
3 |
4 | #import "VT100Types.h"
5 |
6 | @class VT100ColorMap, FontMetrics;
7 |
8 | @interface VT100StringSupplier : NSObject
9 |
10 | @property (nonatomic, weak) id screenBuffer;
11 | @property (nonatomic, strong) VT100ColorMap *colorMap;
12 | @property (nonatomic, strong) FontMetrics *fontMetrics;
13 |
14 | - (int)rowCount;
15 |
16 | - (NSString *)stringForLine:(int)rowIndex;
17 | - (NSMutableAttributedString *)attributedString;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/NewTermMarzipan/VT100StringSupplier.m:
--------------------------------------------------------------------------------
1 | // VT100RowStringSupplier.m
2 | // MobileTerminal
3 |
4 | #import "VT100StringSupplier.h"
5 | #import "VT100ColorMap.h"
6 | #import "VT100Types.h"
7 | #import "FontMetrics.h"
8 |
9 | @implementation VT100StringSupplier
10 |
11 | - (int)rowCount {
12 | return _screenBuffer.numberOfRows;
13 | }
14 |
15 | - (int)columnCount {
16 | return _screenBuffer.screenSize.width;
17 | }
18 |
19 | - (NSString *)stringForLine:(int)rowIndex {
20 | // Buffer of characters to draw on the screen, holds up to one row
21 | unichar unicharBuffer[kMaxRowBufferSize];
22 |
23 | // TODO(aporter): Make the screen object itself return an attributed string?
24 | int width = self.columnCount;
25 | screen_char_t *row = [_screenBuffer bufferForRow:rowIndex];
26 |
27 | for (int j = 0; j < width; ++j) {
28 | if (row[j].code == '\0') {
29 | unicharBuffer[j] = ' ';
30 | } else {
31 | unicharBuffer[j] = row[j].code;
32 | }
33 | }
34 |
35 | // UITextView won’t render a massive line of spaces (e.g. an empty nano screen), so add a newline
36 | // if the line ends with a space
37 | if (rowIndex != self.rowCount - 1 && unicharBuffer[width - 1] == ' ') {
38 | unicharBuffer[width - 1] = '\n';
39 | }
40 |
41 | return [[NSString alloc] initWithCharacters:unicharBuffer length:width];
42 | }
43 |
44 | - (NSMutableAttributedString *)attributedString {
45 | NSParameterAssert(_fontMetrics);
46 | NSParameterAssert(_fontMetrics.regularFont);
47 | NSParameterAssert(_fontMetrics.boldFont);
48 | NSParameterAssert(_screenBuffer);
49 | NSParameterAssert(_colorMap);
50 |
51 | int width = self.columnCount;
52 | ScreenPosition cursorPosition = _screenBuffer.cursorPosition;
53 |
54 | // The cursor is initially relative to the screen, not the position in the
55 | // scrollback buffer.
56 | if (_screenBuffer.numberOfRows > _screenBuffer.screenSize.height) {
57 | cursorPosition.y += _screenBuffer.numberOfRows - _screenBuffer.screenSize.height;
58 | }
59 |
60 | NSMutableString *allLines = [NSMutableString string];
61 |
62 | for (int i = 0; i < self.rowCount; i++) {
63 | [allLines appendString:[self stringForLine:i]];
64 | }
65 |
66 | NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
67 | paragraphStyle.alignment = NSTextAlignmentLeft;
68 | paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
69 |
70 | NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:allLines attributes:@{
71 | NSFontAttributeName: _fontMetrics.regularFont,
72 | NSParagraphStyleAttributeName: paragraphStyle
73 | }];
74 |
75 | NSUInteger startOffset = 0;
76 |
77 | for (int i = 0; i < self.rowCount; i++) {
78 | // Update the string with background/foreground color attributes. This loop compares the colors
79 | // of characters and sets the attribute when it runs into a character of a different color. It
80 | // runs one extra time to set the attribute for the run of characters at the end of the line.
81 | NSUInteger lastColorIndex = NSUIntegerMax;
82 | UIColor *lastColor = nil;
83 | screen_char_t *row = [_screenBuffer bufferForRow:i];
84 |
85 | // TODO(aporter): This looks a lot more complicated than it needs to be. Try
86 | // this again with fewer lines of code.
87 | for (int j = 0; j <= width; ++j) {
88 | BOOL eol = (j == width); // reached end of line
89 | UIColor *color = nil;
90 |
91 | if (!eol) {
92 | color = [_colorMap colorAtIndex:row[j].backgroundColor];
93 |
94 | if (cursorPosition.x == j && cursorPosition.y == i) {
95 | color = _colorMap.backgroundCursor;
96 | }
97 | }
98 |
99 | if (eol || ![color isEqual:lastColor]) {
100 | int length = j - lastColorIndex;
101 |
102 | // TODO: the less than length check shouldn’t really be here, there’s clearly a bug
103 | // elsewhere in this logic
104 | if (lastColorIndex != NSUIntegerMax && startOffset + lastColorIndex + length <= attributedString.string.length) {
105 | [attributedString addAttribute:NSBackgroundColorAttributeName value:lastColor range:NSMakeRange(startOffset + lastColorIndex, length)];
106 | }
107 |
108 | if (!eol) {
109 | lastColorIndex = j;
110 | lastColor = color;
111 | }
112 | }
113 | }
114 |
115 | // Same thing again for foreground color
116 | lastColorIndex = NSUIntegerMax;
117 | lastColor = nil;
118 |
119 | for (int j = 0; j <= width; ++j) {
120 | BOOL eol = (j == width); // reached end of line
121 | UIColor *color = nil;
122 |
123 | if (!eol) {
124 | color = [_colorMap colorAtIndex:row[j].foregroundColor];
125 |
126 | if (cursorPosition.x == j && cursorPosition.y == i) {
127 | color = _colorMap.foregroundCursor;
128 | }
129 | }
130 |
131 | if (eol || ![color isEqual:lastColor]) {
132 | int length = j - lastColorIndex;
133 |
134 | // TODO: the less than length check shouldn’t really be here, there’s clearly a bug
135 | // elsewhere in this logic
136 | if (lastColorIndex != NSUIntegerMax && startOffset + lastColorIndex + length <= attributedString.string.length) {
137 | [attributedString addAttribute:NSForegroundColorAttributeName value:lastColor range:NSMakeRange(startOffset + lastColorIndex, length)];
138 | }
139 |
140 | if (!eol) {
141 | lastColorIndex = j;
142 | lastColor = color;
143 | }
144 | }
145 | }
146 |
147 | startOffset += width;
148 | }
149 |
150 | return attributedString;
151 | }
152 |
153 | @end
154 |
--------------------------------------------------------------------------------
/NewTermMarzipan/VT100Terminal.h:
--------------------------------------------------------------------------------
1 | // VT100Terminal.h
2 | // MobileTeterminal
3 | //
4 | // This header file originally came from the iTerm project, but has been
5 | // modified heavily for use in MobileTerminal. See the original copyright
6 | // below.
7 | //
8 | // VT100Terminal contains the logic for parsing streams of character data and
9 | // modifying the current state of the VT100Screen. This low-level component
10 | // should have no direct dependencies on other parts of the VT100 system.
11 | //
12 | // The VT100Terminal is wrapped by the VT100 class which provides a simpler
13 | // interface to use by the higher level text drawing components.
14 | /*`
15 | ** VT100Terminal.h
16 | **
17 | ** Copyright (c) 2002, 2003, 2007
18 | **
19 | ** Author: Fabian, Ujwal S. Setlur
20 | ** Initial code by Kiichi Kusama
21 | **
22 | ** This program is free software; you can redistribute it and/or modify
23 | ** it under the terms of the GNU General Public License as published by
24 | ** the Free Software Foundation; either version 2 of the License, or
25 | ** (at your option) any later version.
26 | **
27 | ** This program is distributed in the hope that it will be useful,
28 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of
29 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 | ** GNU General Public License for more details.
31 | **
32 | ** You should have received a copy of the GNU General Public License
33 | ** along with this program; if not, write to the Free Software
34 | ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 | */
36 |
37 | #import "VT100Types.h"
38 | #import "VT100Token.h"
39 |
40 | #define VT100CSIPARAM_MAX 16
41 |
42 | @class VT100Screen;
43 |
44 | // character attributes
45 | #define VT100CHARATTR_ALLOFF 0
46 | #define VT100CHARATTR_BOLD 1
47 | #define VT100CHARATTR_UNDER 4
48 | #define VT100CHARATTR_BLINK 5
49 | #define VT100CHARATTR_REVERSE 7
50 |
51 | // xterm additions
52 | #define VT100CHARATTR_NORMAL 22
53 | #define VT100CHARATTR_NOT_UNDER 24
54 | #define VT100CHARATTR_STEADY 25
55 | #define VT100CHARATTR_POSITIVE 27
56 |
57 | typedef enum {
58 | COLORCODE_BLACK=0,
59 | COLORCODE_RED=1,
60 | COLORCODE_GREEN=2,
61 | COLORCODE_YELLOW=3,
62 | COLORCODE_BLUE=4,
63 | COLORCODE_PURPLE=5,
64 | COLORCODE_WATER=6,
65 | COLORCODE_WHITE=7,
66 | COLORCODE_256=8,
67 | COLORS
68 | } colorCode;
69 |
70 | // 8 color support
71 | #define VT100CHARATTR_FG_BASE 30
72 | #define VT100CHARATTR_BG_BASE 40
73 |
74 | #define VT100CHARATTR_FG_BLACK (VT100CHARATTR_FG_BASE + COLORCODE_BLACK)
75 | #define VT100CHARATTR_FG_RED (VT100CHARATTR_FG_BASE + COLORCODE_RED)
76 | #define VT100CHARATTR_FG_GREEN (VT100CHARATTR_FG_BASE + COLORCODE_GREEN)
77 | #define VT100CHARATTR_FG_YELLOW (VT100CHARATTR_FG_BASE + COLORCODE_YELLOW)
78 | #define VT100CHARATTR_FG_BLUE (VT100CHARATTR_FG_BASE + COLORCODE_BLUE)
79 | #define VT100CHARATTR_FG_PURPLE (VT100CHARATTR_FG_BASE + COLORCODE_PURPLE)
80 | #define VT100CHARATTR_FG_WATER (VT100CHARATTR_FG_BASE + COLORCODE_WATER)
81 | #define VT100CHARATTR_FG_WHITE (VT100CHARATTR_FG_BASE + COLORCODE_WHITE)
82 | #define VT100CHARATTR_FG_256 (VT100CHARATTR_FG_BASE + COLORCODE_256)
83 | #define VT100CHARATTR_FG_DEFAULT (VT100CHARATTR_FG_BASE + 9)
84 |
85 | #define VT100CHARATTR_BG_BLACK (VT100CHARATTR_BG_BASE + COLORCODE_BLACK)
86 | #define VT100CHARATTR_BG_RED (VT100CHARATTR_BG_BASE + COLORCODE_RED)
87 | #define VT100CHARATTR_BG_GREEN (VT100CHARATTR_BG_BASE + COLORCODE_GREEN)
88 | #define VT100CHARATTR_BG_YELLOW (VT100CHARATTR_BG_BASE + COLORCODE_YELLOW)
89 | #define VT100CHARATTR_BG_BLUE (VT100CHARATTR_BG_BASE + COLORCODE_BLUE)
90 | #define VT100CHARATTR_BG_PURPLE (VT100CHARATTR_BG_BASE + COLORCODE_PURPLE)
91 | #define VT100CHARATTR_BG_WATER (VT100CHARATTR_BG_BASE + COLORCODE_WATER)
92 | #define VT100CHARATTR_BG_WHITE (VT100CHARATTR_BG_BASE + COLORCODE_WHITE)
93 | #define VT100CHARATTR_BG_256 (VT100CHARATTR_BG_BASE + COLORCODE_256)
94 | #define VT100CHARATTR_BG_DEFAULT (VT100CHARATTR_BG_BASE + 9)
95 |
96 | // 16 color support
97 | #define VT100CHARATTR_FG_HI_BASE 90
98 | #define VT100CHARATTR_BG_HI_BASE 100
99 |
100 | #define VT100CHARATTR_FG_HI_BLACK (VT100CHARATTR_FG_HI_BASE + COLORCODE_BLACK)
101 | #define VT100CHARATTR_FG_HI_RED (VT100CHARATTR_FG_HI_BASE + COLORCODE_RED)
102 | #define VT100CHARATTR_FG_HI_GREEN (VT100CHARATTR_FG_HI_BASE + COLORCODE_GREEN)
103 | #define VT100CHARATTR_FG_HI_YELLOW (VT100CHARATTR_FG_HI_BASE + COLORCODE_YELLOW)
104 | #define VT100CHARATTR_FG_HI_BLUE (VT100CHARATTR_FG_HI_BASE + COLORCODE_BLUE)
105 | #define VT100CHARATTR_FG_HI_PURPLE (VT100CHARATTR_FG_HI_BASE + COLORCODE_PURPLE)
106 | #define VT100CHARATTR_FG_HI_WATER (VT100CHARATTR_FG_HI_BASE + COLORCODE_WATER)
107 | #define VT100CHARATTR_FG_HI_WHITE (VT100CHARATTR_FG_HI_BASE + COLORCODE_WHITE)
108 |
109 | #define VT100CHARATTR_BG_HI_BLACK (VT100CHARATTR_BG_HI_BASE + COLORCODE_BLACK)
110 | #define VT100CHARATTR_BG_HI_RED (VT100CHARATTR_BG_HI_BASE + COLORCODE_RED)
111 | #define VT100CHARATTR_BG_HI_GREEN (VT100CHARATTR_BG_HI_BASE + COLORCODE_GREEN)
112 | #define VT100CHARATTR_BG_HI_YELLOW (VT100CHARATTR_BG_HI_BASE + COLORCODE_YELLOW)
113 | #define VT100CHARATTR_BG_HI_BLUE (VT100CHARATTR_BG_HI_BASE + COLORCODE_BLUE)
114 | #define VT100CHARATTR_BG_HI_PURPLE (VT100CHARATTR_BG_HI_BASE + COLORCODE_PURPLE)
115 | #define VT100CHARATTR_BG_HI_WATER (VT100CHARATTR_BG_HI_BASE + COLORCODE_WATER)
116 | #define VT100CHARATTR_BG_HI_WHITE (VT100CHARATTR_BG_HI_BASE + COLORCODE_WHITE)
117 |
118 | // color codes & masks
119 | #define FG_COLOR_CODE 0x100
120 | #define BG_COLOR_CODE 0x101
121 | #define SELECTED_TEXT 0x102
122 | #define CURSOR_TEXT 0x103
123 | #define CURSOR_BG 0x104
124 |
125 | #define COLOR_CODE_MASK 0x100
126 | #define SELECTION_MASK 0x200
127 | #define BOLD_MASK 0x200
128 | #define BLINK_MASK 0x400
129 | #define UNDER_MASK 0x800
130 |
131 | // terminfo stuff
132 | enum {
133 | TERMINFO_KEY_LEFT, TERMINFO_KEY_RIGHT, TERMINFO_KEY_UP, TERMINFO_KEY_DOWN,
134 | TERMINFO_KEY_HOME, TERMINFO_KEY_END, TERMINFO_KEY_PAGEDOWN, TERMINFO_KEY_PAGEUP,
135 | TERMINFO_KEY_F0, TERMINFO_KEY_F1, TERMINFO_KEY_F2, TERMINFO_KEY_F3, TERMINFO_KEY_F4,
136 | TERMINFO_KEY_F5, TERMINFO_KEY_F6, TERMINFO_KEY_F7, TERMINFO_KEY_F8, TERMINFO_KEY_F9,
137 | TERMINFO_KEY_F10, TERMINFO_KEY_F11, TERMINFO_KEY_F12, TERMINFO_KEY_F13, TERMINFO_KEY_F14,
138 | TERMINFO_KEY_F15, TERMINFO_KEY_F16, TERMINFO_KEY_F17, TERMINFO_KEY_F18, TERMINFO_KEY_F19,
139 | TERMINFO_KEY_F20, TERMINFO_KEY_F21, TERMINFO_KEY_F22, TERMINFO_KEY_F23, TERMINFO_KEY_F24,
140 | TERMINFO_KEY_F25, TERMINFO_KEY_F26, TERMINFO_KEY_F27, TERMINFO_KEY_F28, TERMINFO_KEY_F29,
141 | TERMINFO_KEY_F30, TERMINFO_KEY_F31, TERMINFO_KEY_F32, TERMINFO_KEY_F33, TERMINFO_KEY_F34,
142 | TERMINFO_KEY_F35,
143 | TERMINFO_KEY_BACKSPACE, TERMINFO_KEY_BACK_TAB,
144 | TERMINFO_KEY_TAB,
145 | TERMINFO_KEY_DEL, TERMINFO_KEY_INS,
146 | TERMINFO_KEY_HELP,
147 | TERMINFO_KEYS
148 | };
149 |
150 | typedef enum {
151 | MOUSE_REPORTING_NONE = -1,
152 | MOUSE_REPORTING_NORMAL = 0,
153 | MOUSE_REPORTING_HILITE,
154 | MOUSE_REPORTING_BUTTON_MOTION,
155 | MOUSE_REPORTING_ALL_MOTION,
156 | } mouseMode;
157 |
158 | @interface VT100Terminal : NSObject
159 |
160 | - (instancetype)init;
161 |
162 | @property (nonatomic, strong) NSString *termType;
163 | @property (nonatomic) BOOL trace;
164 | @property (nonatomic) BOOL strictAnsiMode;
165 | @property (nonatomic) BOOL allowColumnMode;
166 | @property (nonatomic) NSStringEncoding encoding;
167 |
168 | @property (nonatomic, weak) VT100Screen *currentScreen;
169 | @property (nonatomic, strong) VT100Screen *primaryScreen;
170 | @property (nonatomic, strong) VT100Screen *alternateScreen;
171 |
172 | - (void)setMode:(VT100Token *)token;
173 | - (void)setCharAttr:(VT100Token *)token;
174 |
175 | - (void)cleanStream;
176 | - (void)putStreamData:(NSData *)data;
177 | - (VT100Token *)getNextToken;
178 |
179 | - (void)reset;
180 |
181 | - (NSData *)keyArrowUp:(unsigned int)modflag;
182 | - (NSData *)keyArrowDown:(unsigned int)modflag;
183 | - (NSData *)keyArrowLeft:(unsigned int)modflag;
184 | - (NSData *)keyArrowRight:(unsigned int)modflag;
185 | - (NSData *)keyHome:(unsigned int)modflag;
186 | - (NSData *)keyEnd:(unsigned int)modflag;
187 | - (NSData *)keyInsert;
188 | - (NSData *)keyDelete;
189 | - (NSData *)keyBackspace;
190 | - (NSData *)keyPageUp;
191 | - (NSData *)keyPageDown;
192 | - (NSData *)keyFunction:(int)no;
193 | - (NSData *)keyPFn:(int)n;
194 | - (NSData *)keypadData:(unichar)unicode keystr:(NSString *)keystr;
195 |
196 | @property (nonatomic, readonly) BOOL lineMode; // YES=Newline, NO=Line feed
197 | @property (nonatomic, readonly) BOOL cursorMode; // YES=Application, NO=Cursor
198 | @property (nonatomic, readonly) BOOL ansiMode; // YES=ANSI, NO=VT52
199 | @property (nonatomic, readonly) BOOL columnMode; // YES=132 Column, NO=80 Column
200 | @property (nonatomic, readonly) BOOL scrollMode; // YES=Smooth, NO=Jump
201 | @property (nonatomic, readonly) BOOL screenMode; // YES=Reverse, NO=Normal
202 | @property (nonatomic, readonly) BOOL originMode; // YES=Relative, NO=Absolute
203 | @property (nonatomic, readonly) BOOL wraparoundMode; // YES=On, NO=Off
204 | @property (nonatomic, readonly) BOOL autorepeatMode; // YES=On, NO=Off
205 | @property (nonatomic, readonly) BOOL interlaceMode; // YES=On, NO=Off
206 | @property (nonatomic, readonly) BOOL keypadMode; // YES=Application, NO=Numeric
207 | @property (nonatomic, readonly) BOOL insertMode; // YES=Insert, NO=Replace
208 | @property (nonatomic, readonly) int charset; // G0...G3
209 | @property (nonatomic, readonly) BOOL xon; // YES=_xon, NO=XOFF
210 | @property (nonatomic, readonly) mouseMode mouseMode;
211 |
212 | - (int)foregroundColorCode;
213 | - (int)backgroundColorCode;
214 |
215 | - (NSData *)reportActivePositionWithX:(int)x Y:(int)y;
216 | - (NSData *)reportStatus;
217 | - (NSData *)reportDeviceAttribute;
218 | - (NSData *)reportSecondaryDeviceAttribute;
219 |
220 | @end
221 |
222 | /* vim: set syntax=objc sw=4 ts=4 sts=4 expandtab textwidth=80 ff=unix: */
223 |
--------------------------------------------------------------------------------
/NewTermMarzipan/VT100Token.h:
--------------------------------------------------------------------------------
1 | #import "ScreenChar.h"
2 | #import "iTermParser.h"
3 |
4 | typedef enum {
5 | // Any control character between 0-0x1f inclusive can by a token type. For these, the value
6 | // matters. Make sure to update the -codeName method when changing this enum.
7 | VT100CC_NULL = 0,
8 | VT100CC_SOH = 1, // Not used
9 | VT100CC_STX = 2, // Not used
10 | VT100CC_ETX = 3, // Not used
11 | VT100CC_EOT = 4, // Not used
12 | VT100CC_ENQ = 5, // Transmit ANSWERBACK message
13 | VT100CC_ACK = 6, // Not used
14 | VT100CC_BEL = 7, // Sound bell
15 | VT100CC_BS = 8, // Move cursor to the left
16 | VT100CC_HT = 9, // Move cursor to the next tab stop
17 | VT100CC_LF = 10, // line feed or new line operation
18 | VT100CC_VT = 11, // Same as .
19 | VT100CC_FF = 12, // Same as .
20 | VT100CC_CR = 13, // Move the cursor to the left margin
21 | VT100CC_SO = 14, // Invoke the G1 character set
22 | VT100CC_SI = 15, // Invoke the G0 character set
23 | VT100CC_DLE = 16, // Not used
24 | VT100CC_DC1 = 17, // Causes terminal to resume transmission (XON).
25 | VT100CC_DC2 = 18, // Not used
26 | VT100CC_DC3 = 19, // Causes terminal to stop transmitting all codes except XOFF and XON (XOFF).
27 | VT100CC_DC4 = 20, // Not used
28 | VT100CC_NAK = 21, // Not used
29 | VT100CC_SYN = 22, // Not used
30 | VT100CC_ETB = 23, // Not used
31 | VT100CC_CAN = 24, // Cancel a control sequence
32 | VT100CC_EM = 25, // Not used
33 | VT100CC_SUB = 26, // Same as .
34 | VT100CC_ESC = 27, // Introduces a control sequence.
35 | VT100CC_FS = 28, // Not used
36 | VT100CC_GS = 29, // Not used
37 | VT100CC_RS = 30, // Not used
38 | VT100CC_US = 31, // Not used
39 | VT100CC_DEL = 127, // Backspaces
40 |
41 | VT100_WAIT = 1000,
42 | VT100_NOTSUPPORT,
43 | VT100_SKIP,
44 | VT100_STRING,
45 | VT100_ASCIISTRING,
46 | VT100_UNKNOWNCHAR,
47 | VT100_INVALID_SEQUENCE,
48 | VT100_BINARY_GARBAGE,
49 |
50 | VT100CSI_CPR, // Cursor Position Report
51 | VT100CSI_CUB, // Cursor Backward
52 | VT100CSI_CUD, // Cursor Down
53 | VT100CSI_CUF, // Cursor Forward
54 | VT100CSI_CUP, // Cursor Position
55 | VT100CSI_CUU, // Cursor Up
56 | VT100CSI_CNL, // Cursor Next Line
57 | VT100CSI_CPL, // Cursor Preceding Line
58 | VT100CSI_DA, // Device Attributes
59 | VT100CSI_DA2, // Secondary Device Attributes
60 | VT100CSI_DECALN, // Screen Alignment Display
61 | VT100CSI_DECDHL, // Double Height Line
62 | VT100CSI_DECDWL, // Double Width Line
63 | VT100CSI_DECID, // Identify Terminal
64 | VT100CSI_DECKPAM, // Keypad Application Mode
65 | VT100CSI_DECKPNM, // Keypad Numeric Mode
66 | VT100CSI_DECRC, // Restore Cursor
67 | VT100CSI_DECRST,
68 | VT100CSI_DECSC, // Save Cursor
69 | VT100CSI_DECSET,
70 | VT100CSI_DECSTBM, // Set Top and Bottom Margins
71 | VT100CSI_DSR, // Device Status Report
72 | VT100CSI_ED, // Erase In Display
73 | VT100CSI_EL, // Erase In Line
74 | VT100CSI_HTS, // Horizontal Tabulation Set
75 | VT100CSI_HVP, // Horizontal and Vertical Position
76 | VT100CSI_IND, // Index
77 | VT100CSI_NEL, // Next Line
78 | VT100CSI_RI, // Reverse Index
79 | VT100CSI_RIS, // Reset To Initial State
80 | VT100CSI_RM, // Reset Mode
81 | VT100CSI_SCS,
82 | VT100CSI_SCS0, // Select Character Set 0
83 | VT100CSI_SCS1, // Select Character Set 1
84 | VT100CSI_SCS2, // Select Character Set 2
85 | VT100CSI_SCS3, // Select Character Set 3
86 | VT100CSI_SGR, // Select Graphic Rendition
87 | VT100CSI_SM, // Set Mode
88 | VT100CSI_TBC, // Tabulation Clear
89 | VT100CSI_DECSCUSR, // Select the Style of the Cursor
90 | VT100CSI_DECSTR, // Soft reset
91 | VT100CSI_DECDSR, // Device Status Report (DEC specific)
92 | VT100CSI_SET_MODIFIERS, // CSI > Ps; Pm m (Whether to set modifiers for different kinds of key presses; no official name)
93 | VT100CSI_RESET_MODIFIERS, // CSI > Ps n (Set all modifiers values to -1, disabled)
94 | VT100CSI_DECSLRM, // Set left-right margin
95 | VT100CSI_DECRQCRA, // Request Checksum of Rectangular Area
96 | VT100CSI_REP, // Repeat
97 |
98 | // some xterm extensions
99 | XTERMCC_WIN_TITLE, // Set window title
100 | XTERMCC_ICON_TITLE,
101 | XTERMCC_WINICON_TITLE,
102 | VT100CSI_ICH, // Insert blank
103 | XTERMCC_INSLN, // Insert lines
104 | XTERMCC_DELCH, // delete blank
105 | XTERMCC_DELLN, // delete lines
106 | XTERMCC_WINDOWSIZE, // (8,H,W) NK: added for Vim resizing window
107 | XTERMCC_WINDOWSIZE_PIXEL, // (8,H,W) NK: added for Vim resizing window
108 | XTERMCC_WINDOWPOS, // (3,Y,X) NK: added for Vim positioning window
109 | XTERMCC_ICONIFY,
110 | XTERMCC_DEICONIFY,
111 | XTERMCC_RAISE,
112 | XTERMCC_LOWER,
113 | XTERMCC_SU, // scroll up
114 | XTERMCC_SD, // scroll down
115 | XTERMCC_REPORT_WIN_STATE,
116 | XTERMCC_REPORT_WIN_POS,
117 | XTERMCC_REPORT_WIN_PIX_SIZE,
118 | XTERMCC_REPORT_WIN_SIZE,
119 | XTERMCC_REPORT_SCREEN_SIZE,
120 | XTERMCC_REPORT_ICON_TITLE,
121 | XTERMCC_REPORT_WIN_TITLE,
122 | XTERMCC_PUSH_TITLE,
123 | XTERMCC_POP_TITLE,
124 | XTERMCC_SET_RGB,
125 | // This is not a real xterm code. It is from eTerm, which extended the xterm
126 | // protocol for its own purposes. We don't follow the eTerm protocol,
127 | // but we follow the template it set.
128 | // http://www.eterm.org/docs/view.php?doc=ref#escape
129 | XTERMCC_PROPRIETARY_ETERM_EXT,
130 | XTERMCC_PWD_URL,
131 | XTERMCC_LINK,
132 | XTERMCC_SET_PALETTE,
133 | XTERMCC_SET_KVP,
134 | // OSC 1337;File=(args):(data) gets changed by the parser from XTERMCC_SET_KVP to a
135 | // series of incidental tokens beginning with XTERMCC_MULTITOKEN_HEADER_SET_KVP.
136 | // See comment above XTERMCC_MULTITOKEN_BODY for details.
137 | XTERMCC_MULTITOKEN_HEADER_SET_KVP,
138 | XTERMCC_PASTE64,
139 | XTERMCC_FINAL_TERM,
140 |
141 | // If a sequence is split into mutiple tokens, the first will be one of the above whose name
142 | // includes MULTITOKEN_HEADER, then zero or more of these, and then XTERMCC_MULTITOKEN_END.
143 | XTERMCC_MULTITOKEN_BODY,
144 | XTERMCC_MULTITOKEN_END,
145 |
146 | // Some ansi stuff
147 | ANSICSI_CHA, // Cursor Horizontal Absolute
148 | ANSICSI_VPA, // Vert Position Absolute
149 | ANSICSI_VPR, // Vert Position Relative
150 | ANSICSI_ECH, // Erase Character
151 | ANSICSI_PRINT, // Print to Ansi
152 | ANSICSI_SCP, // Save cursor position
153 | ANSICSI_RCP, // Restore cursor position
154 | ANSICSI_CBT, // Back tab
155 |
156 | ANSI_RIS, // Reset to initial state (there's also a CSI version)
157 |
158 | // DCS
159 | DCS_REQUEST_TERMCAP_TERMINFO, // Request Termcap/Terminfo String
160 |
161 | // Toggle between ansi/vt52
162 | STRICT_ANSI_MODE,
163 |
164 | // iTerm extension
165 | ITERM_GROWL,
166 | DCS_TMUX_HOOK, // Enter tmux mode
167 |
168 | // Wraps an escape code. The escape code is in csi.string.
169 | DCS_TMUX_CODE_WRAP,
170 |
171 | TMUX_LINE, // A line of input from tmux
172 | TMUX_EXIT, // Exit tmux mode
173 |
174 | // Ambiguous codes - disambiguated at execution time.
175 | VT100CSI_DECSLRM_OR_ANSICSI_SCP,
176 |
177 | // ISO-2022 codes for choosing character encoding. There are a bunch of other encodings that
178 | // there are escape codes for but they're really old-fashioned, so only these two are supported
179 | // so far.
180 | ISO2022_SELECT_LATIN_1,
181 | ISO2022_SELECT_UTF_8
182 | } VT100TerminalTokenType;
183 |
184 | // A preinitialized array of screen_char_t. When ASCII data is present, it will have the codes
185 | // populated and all other fields zeroed out.
186 | #define kStaticScreenCharsCount 16
187 | typedef struct {
188 | screen_char_t *buffer;
189 | int length;
190 | screen_char_t staticBuffer[kStaticScreenCharsCount];
191 | } ScreenChars;
192 |
193 | // Tokens with type VT100_ASCIISTRING are stored in |asciiData| with this type.
194 | // |buffer| will point at |staticBuffer| or a malloc()ed buffer, depending on
195 | // |length|.
196 | typedef struct {
197 | char *buffer;
198 | int length;
199 | char staticBuffer[128];
200 | ScreenChars *screenChars;
201 | } AsciiData;
202 |
203 | @interface VT100Token : NSObject {
204 | @public
205 | // data is populated because the current mode uses the raw input. data is
206 | // always set for ascii strings regardless of mode.
207 | BOOL savingData;
208 | }
209 |
210 | @property (nonatomic) VT100TerminalTokenType type;
211 |
212 | @property (nonatomic) unsigned char *position;
213 | @property (nonatomic) int length;
214 |
215 | // For VT100_UNKNOWNCHAR and VT100CSI_SCS0...SCS3.
216 | @property (nonatomic) unsigned char code;
217 |
218 | // For VT100_STRING
219 | @property (nonatomic, retain) NSString *string;
220 |
221 | // For saved data (when copying to clipboard)
222 | @property (nonatomic, retain) NSData *savedData;
223 |
224 | // For XTERMCC_SET_KVP.
225 | @property (nonatomic, retain) NSString *kvpKey;
226 | @property (nonatomic, retain) NSString *kvpValue;
227 |
228 | // For VT100CSI_ codes that take paramters.
229 | @property (nonatomic, readonly) CSIParam *csi;
230 |
231 | // Is this an ascii string?
232 | @property (nonatomic, readonly) BOOL isAscii;
233 |
234 | // Is this a string or ascii string?
235 | @property (nonatomic, readonly) BOOL isStringType;
236 |
237 | // For ascii strings (type==VT100_ASCIISTRING).
238 | @property (nonatomic, readonly) AsciiData *asciiData;
239 |
240 | + (instancetype)token;
241 | + (instancetype)tokenForControlCharacter:(unsigned char)controlCharacter;
242 |
243 | - (void)setAsciiBytes:(char *)bytes length:(int)length;
244 |
245 | // Returns a string for |asciiData|, for convenience (this is slow).
246 | - (NSString *)stringForAsciiData;
247 |
248 | @end
249 |
--------------------------------------------------------------------------------
/NewTermMarzipan/VT100Token.m:
--------------------------------------------------------------------------------
1 | //
2 | // VT100Token.m
3 | // iTerm
4 | //
5 | // Created by George Nachman on 3/3/14.
6 | //
7 | //
8 |
9 | #import "VT100Token.h"
10 | #include
11 |
12 | @interface VT100Token ()
13 | @property(nonatomic, readwrite) CSIParam *csi;
14 | @end
15 |
16 | @implementation VT100Token {
17 | AsciiData _asciiData;
18 | ScreenChars _screenChars;
19 | }
20 |
21 | + (instancetype)token {
22 | return [[self alloc] init];
23 | }
24 |
25 | + (instancetype)tokenForControlCharacter:(unsigned char)controlCharacter {
26 | VT100Token *token = [[self alloc] init];
27 | token.type = controlCharacter;
28 | return token;
29 | }
30 |
31 | - (void)dealloc {
32 | if (_csi) {
33 | free(_csi);
34 | _csi = NULL;
35 | }
36 |
37 | if (_asciiData.buffer != _asciiData.staticBuffer) {
38 | free(_asciiData.buffer);
39 | }
40 | if (_asciiData.screenChars && _asciiData.screenChars->buffer != _asciiData.screenChars->staticBuffer) {
41 | free(_asciiData.screenChars->buffer);
42 | }
43 | _asciiData.buffer = NULL;
44 | _asciiData.length = 0;
45 | _asciiData.screenChars = NULL;
46 |
47 | _type = 0;
48 | _code = 0;
49 | }
50 |
51 | - (NSString *)codeName {
52 | NSDictionary *map = @{@(VT100CC_NULL): @"VT100CC_NULL",
53 | @(VT100CC_SOH): @"VT100CC_SOH",
54 | @(VT100CC_STX): @"VT100CC_STX",
55 | @(VT100CC_ETX): @"VT100CC_ETX",
56 | @(VT100CC_EOT): @"VT100CC_EOT",
57 | @(VT100CC_ENQ): @"VT100CC_ENQ",
58 | @(VT100CC_ACK): @"VT100CC_ACK",
59 | @(VT100CC_BEL): @"VT100CC_BEL",
60 | @(VT100CC_BS): @"VT100CC_BS",
61 | @(VT100CC_HT): @"VT100CC_HT",
62 | @(VT100CC_LF): @"VT100CC_LF",
63 | @(VT100CC_VT): @"VT100CC_VT",
64 | @(VT100CC_FF): @"VT100CC_FF",
65 | @(VT100CC_CR): @"VT100CC_CR",
66 | @(VT100CC_SO): @"VT100CC_SO",
67 | @(VT100CC_SI): @"VT100CC_SI",
68 | @(VT100CC_DLE): @"VT100CC_DLE",
69 | @(VT100CC_DC1): @"VT100CC_DC1",
70 | @(VT100CC_DC2): @"VT100CC_DC2",
71 | @(VT100CC_DC3): @"VT100CC_DC3",
72 | @(VT100CC_DC4): @"VT100CC_DC4",
73 | @(VT100CC_NAK): @"VT100CC_NAK",
74 | @(VT100CC_SYN): @"VT100CC_SYN",
75 | @(VT100CC_ETB): @"VT100CC_ETB",
76 | @(VT100CC_CAN): @"VT100CC_CAN",
77 | @(VT100CC_EM): @"VT100CC_EM",
78 | @(VT100CC_SUB): @"VT100CC_SUB",
79 | @(VT100CC_ESC): @"VT100CC_ESC",
80 | @(VT100CC_FS): @"VT100CC_FS",
81 | @(VT100CC_GS): @"VT100CC_GS",
82 | @(VT100CC_RS): @"VT100CC_RS",
83 | @(VT100CC_US): @"VT100CC_US",
84 | @(VT100CC_DEL): @"VT100CC_DEL",
85 | @(VT100_WAIT): @"VT100_WAIT",
86 | @(VT100_NOTSUPPORT): @"VT100_NOTSUPPORT",
87 | @(VT100_SKIP): @"VT100_SKIP",
88 | @(VT100_STRING): @"VT100_STRING",
89 | @(VT100_ASCIISTRING): @"VT100_ASCIISTRING",
90 | @(VT100_UNKNOWNCHAR): @"VT100_UNKNOWNCHAR",
91 | @(VT100_INVALID_SEQUENCE): @"VT100_INVALID_SEQUENCE",
92 | @(VT100_BINARY_GARBAGE): @"VT100_BINARY_GARBAGE",
93 | @(VT100CSI_CPR): @"VT100CSI_CPR",
94 | @(VT100CSI_CUB): @"VT100CSI_CUB",
95 | @(VT100CSI_CUD): @"VT100CSI_CUD",
96 | @(VT100CSI_CUF): @"VT100CSI_CUF",
97 | @(VT100CSI_CUP): @"VT100CSI_CUP",
98 | @(VT100CSI_CUU): @"VT100CSI_CUU",
99 | @(VT100CSI_DA): @"VT100CSI_DA",
100 | @(VT100CSI_DA2): @"VT100CSI_DA2",
101 | @(VT100CSI_DECALN): @"VT100CSI_DECALN",
102 | @(VT100CSI_DECDHL): @"VT100CSI_DECDHL",
103 | @(VT100CSI_DECDWL): @"VT100CSI_DECDWL",
104 | @(VT100CSI_DECID): @"VT100CSI_DECID",
105 | @(VT100CSI_DECKPAM): @"VT100CSI_DECKPAM",
106 | @(VT100CSI_DECKPNM): @"VT100CSI_DECKPNM",
107 | @(VT100CSI_DECRC): @"VT100CSI_DECRC",
108 | @(VT100CSI_DECRQCRA): @"VT100CSI_DECRQCRA",
109 | @(VT100CSI_DECRST): @"VT100CSI_DECRST",
110 | @(VT100CSI_DECSC): @"VT100CSI_DECSC",
111 | @(VT100CSI_DECSET): @"VT100CSI_DECSET",
112 | @(VT100CSI_DECSTBM): @"VT100CSI_DECSTBM",
113 | @(VT100CSI_DSR): @"VT100CSI_DSR",
114 | @(VT100CSI_ED): @"VT100CSI_ED",
115 | @(VT100CSI_EL): @"VT100CSI_EL",
116 | @(VT100CSI_HTS): @"VT100CSI_HTS",
117 | @(VT100CSI_HVP): @"VT100CSI_HVP",
118 | @(VT100CSI_IND): @"VT100CSI_IND",
119 | @(VT100CSI_NEL): @"VT100CSI_NEL",
120 | @(VT100CSI_RI): @"VT100CSI_RI",
121 | @(VT100CSI_RIS): @"VT100CSI_RIS",
122 | @(VT100CSI_RM): @"VT100CSI_RM",
123 | @(VT100CSI_SCS): @"VT100CSI_SCS",
124 | @(VT100CSI_SCS0): @"VT100CSI_SCS0",
125 | @(VT100CSI_SCS1): @"VT100CSI_SCS1",
126 | @(VT100CSI_SCS2): @"VT100CSI_SCS2",
127 | @(VT100CSI_SCS3): @"VT100CSI_SCS3",
128 | @(VT100CSI_SGR): @"VT100CSI_SGR",
129 | @(VT100CSI_SM): @"VT100CSI_SM",
130 | @(VT100CSI_TBC): @"VT100CSI_TBC",
131 | @(VT100CSI_DECSCUSR): @"VT100CSI_DECSCUSR",
132 | @(VT100CSI_DECSTR): @"VT100CSI_DECSTR",
133 | @(VT100CSI_DECDSR): @"VT100CSI_DECDSR",
134 | @(VT100CSI_SET_MODIFIERS): @"VT100CSI_SET_MODIFIERS",
135 | @(VT100CSI_RESET_MODIFIERS): @"VT100CSI_RESET_MODIFIERS",
136 | @(VT100CSI_REP): @"VT100CSI_REP",
137 | @(VT100CSI_DECSLRM): @"VT100CSI_DECSLRM",
138 | @(XTERMCC_WIN_TITLE): @"XTERMCC_WIN_TITLE",
139 | @(XTERMCC_ICON_TITLE): @"XTERMCC_ICON_TITLE",
140 | @(XTERMCC_WINICON_TITLE): @"XTERMCC_WINICON_TITLE",
141 | @(VT100CSI_ICH): @"VT100CSI_ICH",
142 | @(XTERMCC_INSLN): @"XTERMCC_INSLN",
143 | @(XTERMCC_DELCH): @"XTERMCC_DELCH",
144 | @(XTERMCC_DELLN): @"XTERMCC_DELLN",
145 | @(XTERMCC_WINDOWSIZE): @"XTERMCC_WINDOWSIZE",
146 | @(XTERMCC_WINDOWSIZE_PIXEL): @"XTERMCC_WINDOWSIZE_PIXEL",
147 | @(XTERMCC_WINDOWPOS): @"XTERMCC_WINDOWPOS",
148 | @(XTERMCC_ICONIFY): @"XTERMCC_ICONIFY",
149 | @(XTERMCC_DEICONIFY): @"XTERMCC_DEICONIFY",
150 | @(XTERMCC_RAISE): @"XTERMCC_RAISE",
151 | @(XTERMCC_LOWER): @"XTERMCC_LOWER",
152 | @(XTERMCC_SU): @"XTERMCC_SU",
153 | @(XTERMCC_SD): @"XTERMCC_SD",
154 | @(XTERMCC_REPORT_WIN_STATE): @"XTERMCC_REPORT_WIN_STATE",
155 | @(XTERMCC_REPORT_WIN_POS): @"XTERMCC_REPORT_WIN_POS",
156 | @(XTERMCC_REPORT_WIN_PIX_SIZE): @"XTERMCC_REPORT_WIN_PIX_SIZE",
157 | @(XTERMCC_REPORT_WIN_SIZE): @"XTERMCC_REPORT_WIN_SIZE",
158 | @(XTERMCC_REPORT_SCREEN_SIZE): @"XTERMCC_REPORT_SCREEN_SIZE",
159 | @(XTERMCC_REPORT_ICON_TITLE): @"XTERMCC_REPORT_ICON_TITLE",
160 | @(XTERMCC_REPORT_WIN_TITLE): @"XTERMCC_REPORT_WIN_TITLE",
161 | @(XTERMCC_PUSH_TITLE): @"XTERMCC_PUSH_TITLE",
162 | @(XTERMCC_POP_TITLE): @"XTERMCC_POP_TITLE",
163 | @(XTERMCC_SET_RGB): @"XTERMCC_SET_RGB",
164 | @(XTERMCC_PROPRIETARY_ETERM_EXT): @"XTERMCC_PROPRIETARY_ETERM_EXT",
165 | @(XTERMCC_PWD_URL): @"XTERMCC_PWD_URL",
166 | @(XTERMCC_SET_PALETTE): @"XTERMCC_SET_PALETTE",
167 | @(XTERMCC_SET_KVP): @"XTERMCC_SET_KVP",
168 | @(XTERMCC_MULTITOKEN_HEADER_SET_KVP): @"XTERMCC_MULTITOKEN_HEADER_SET_KVP",
169 | @(XTERMCC_MULTITOKEN_BODY): @"XTERMCC_MULTITOKEN_BODY",
170 | @(XTERMCC_MULTITOKEN_END): @"XTERMCC_MULTITOKEN_END",
171 | @(XTERMCC_PASTE64): @"XTERMCC_PASTE64",
172 | @(XTERMCC_FINAL_TERM): @"XTERMCC_FINAL_TERM",
173 | @(XTERMCC_LINK): @"XTERMCC_LINK",
174 | @(ANSICSI_CHA): @"ANSICSI_CHA",
175 | @(ANSICSI_VPA): @"ANSICSI_VPA",
176 | @(ANSICSI_VPR): @"ANSICSI_VPR",
177 | @(ANSICSI_ECH): @"ANSICSI_ECH",
178 | @(ANSICSI_PRINT): @"ANSICSI_PRINT",
179 | @(ANSICSI_SCP): @"ANSICSI_SCP",
180 | @(ANSICSI_RCP): @"ANSICSI_RCP",
181 | @(ANSICSI_CBT): @"ANSICSI_CBT",
182 | @(ANSI_RIS): @"ANSI_RIS",
183 | @(STRICT_ANSI_MODE): @"STRICT_ANSI_MODE",
184 | @(ITERM_GROWL): @"ITERM_GROWL",
185 | @(DCS_TMUX_HOOK): @"DCS_TMUX_HOOK",
186 | @(TMUX_LINE): @"TMUX_LINE",
187 | @(TMUX_EXIT): @"TMUX_EXIT",
188 | @(DCS_TMUX_CODE_WRAP): @"DCS_TMUX_CODE_WRAP",
189 | @(VT100CSI_DECSLRM_OR_ANSICSI_SCP): @"VT100CSI_DECSLRM_OR_ANSICSI_SCP",
190 | @(DCS_REQUEST_TERMCAP_TERMINFO): @"DCS_REQUEST_TERMCAP_TERMINFO", };
191 | NSString *name = map[@(_type)];
192 | if (name) {
193 | return name;
194 | } else {
195 | return [NSString stringWithFormat:@"%d", _type];
196 | }
197 | }
198 |
199 | - (NSString *)description {
200 | NSMutableString *params = [NSMutableString string];
201 | if (_csi && _csi->count > 0) {
202 | [params appendString:@" params="];
203 | for (int i = 0; i < _csi->count; i++) {
204 | if (_csi->p[i] < 0) {
205 | [params appendFormat:@"[default];"];
206 | } else {
207 | [params appendFormat:@"%d;", _csi->p[i]];
208 | }
209 | }
210 | }
211 | if (_string) {
212 | [params appendFormat:@" string=“%@”", _string];
213 | }
214 | if (_asciiData.length) {
215 | [params appendFormat:@" asciiData=“%.*s”", _asciiData.length, _asciiData.buffer];
216 | }
217 | return [NSString stringWithFormat:@"<%@: %p type=%@%@>", self.class, self, [self codeName], params];
218 | }
219 |
220 | - (CSIParam *)csi {
221 | if (!_csi) {
222 | _csi = calloc(sizeof(*_csi), 1);
223 | }
224 | return _csi;
225 | }
226 |
227 | - (BOOL)isAscii {
228 | return _type == VT100_ASCIISTRING;
229 | }
230 |
231 | - (BOOL)isStringType {
232 | return (_type == VT100_STRING || _type == VT100_ASCIISTRING);
233 | }
234 |
235 | - (void)setAsciiBytes:(char *)bytes length:(int)length {
236 | assert(_asciiData.buffer == NULL);
237 |
238 | _asciiData.length = length;
239 | if (length > sizeof(_asciiData.staticBuffer)) {
240 | _asciiData.buffer = malloc(length);
241 | } else {
242 | _asciiData.buffer = _asciiData.staticBuffer;
243 | }
244 | memcpy(_asciiData.buffer, bytes, length);
245 |
246 | [self preInitializeScreenChars];
247 | }
248 |
249 | - (AsciiData *)asciiData {
250 | return &_asciiData;
251 | }
252 |
253 | - (NSString *)stringForAsciiData {
254 | return [[NSString alloc] initWithBytes:_asciiData.buffer length:_asciiData.length encoding:NSASCIIStringEncoding];
255 | }
256 |
257 | - (ScreenChars *)screenChars {
258 | return &_screenChars;
259 | }
260 |
261 | - (void)preInitializeScreenChars {
262 | // TODO: Expand this beyond just ascii characters.
263 | if (_asciiData.length > kStaticScreenCharsCount) {
264 | _screenChars.buffer = calloc(_asciiData.length, sizeof(screen_char_t));
265 | } else {
266 | _screenChars.buffer = _screenChars.staticBuffer;
267 | memset(_screenChars.buffer, 0, _asciiData.length * sizeof(screen_char_t));
268 | }
269 | for (int i = 0; i < _asciiData.length; i++) {
270 | _screenChars.buffer[i].code = _asciiData.buffer[i];
271 | }
272 | _screenChars.length = _asciiData.length;
273 | _asciiData.screenChars = &_screenChars;
274 | }
275 |
276 | @end
277 |
--------------------------------------------------------------------------------
/NewTermMarzipan/VT100Types.h:
--------------------------------------------------------------------------------
1 | // VT100Types.h
2 | // MobileTerminal
3 | //
4 | // This header file contains types that are used by both the low level VT100
5 | // components and the higher level text view components so they both do not
6 | // have to depend on each other.
7 |
8 | #import "ScreenChar.h"
9 |
10 | @class FontMetrics;
11 |
12 | // Buffer space used to draw any particular row.
13 | static const int kMaxRowBufferSize = 200;
14 |
15 | typedef struct {
16 | int width;
17 | int height;
18 | } ScreenSize;
19 |
20 | typedef struct {
21 | int x;
22 | int y;
23 | } ScreenPosition;
24 |
25 | // The protocol for reading and writing data to the terminal screen
26 | @protocol ScreenBuffer
27 | @required
28 |
29 | // Return the current size of the screen
30 | - (ScreenSize)screenSize;
31 |
32 | // Resize the screen to the specified size. This is a no-op of the new size
33 | // is the same as the existing size.
34 | - (void)setScreenSize:(ScreenSize)size;
35 |
36 | // Return the position of the cursor on the screen
37 | - (ScreenPosition)cursorPosition;
38 |
39 | // Row indexes include scrollback
40 | - (screen_char_t*)bufferForRow:(int)row;
41 | - (int)numberOfRows;
42 |
43 | - (void)readInputStream:(NSData *)data;
44 |
45 | - (void)clearScreen;
46 |
47 | @end
48 |
49 | // A thin protocol for implementing a delegate interface with a single method
50 | // that is invoked when the screen needs to be refreshed because at least some
51 | // portion has become invalidated.
52 | @protocol ScreenBufferRefreshDelegate
53 | @required
54 | - (void)refresh;
55 | - (void)activateBell;
56 | @end
57 |
58 | // Supplies an attributed string for a row of text. In practice this is just
59 | // a string of screen_char_t converted to an attributed string (text color,
60 | // etc). The row index includes space in the scrollback buffer.
61 | @protocol AttributedStringSupplier
62 | - (int)rowCount;
63 | - (NSString *)stringForLine:(int)rowIndex;
64 | - (NSAttributedString *)attributedString;
65 | @end
66 |
--------------------------------------------------------------------------------
/NewTermMarzipan/bell-hud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kirb/iOSMac-Demo/742c528fb3280dcdb01b1e71ffe2aceb09245468/NewTermMarzipan/bell-hud.png
--------------------------------------------------------------------------------
/NewTermMarzipan/bell-hud@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kirb/iOSMac-Demo/742c528fb3280dcdb01b1e71ffe2aceb09245468/NewTermMarzipan/bell-hud@2x.png
--------------------------------------------------------------------------------
/NewTermMarzipan/bell-hud@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kirb/iOSMac-Demo/742c528fb3280dcdb01b1e71ffe2aceb09245468/NewTermMarzipan/bell-hud@3x.png
--------------------------------------------------------------------------------
/NewTermMarzipan/charmaps.h:
--------------------------------------------------------------------------------
1 | /* Derived from linux/drivers/char/consolemap.c, GNU GPL:ed */
2 |
3 | /*
4 | 0 1 2 3 4 5 6 7 8 9 A B C D E F
5 | U+250x ─ ━ │ ┃ ┄ ┅ ┆ ┇ ┈ ┉ ┊ ┋ ┌ ┍ ┎ ┏
6 | U+251x ┐ ┑ ┒ ┓ └ ┕ ┖ ┗ ┘ ┙ ┚ ┛ ├ ┝ ┞ ┟
7 | U+252x ┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯
8 | U+253x ┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻ ┼ ┽ ┾ ┿
9 | U+254x ╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╌ ╍ ╎ ╏
10 | U+255x ═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟
11 | U+256x ╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯
12 | U+257x ╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿
13 | */
14 |
15 | #define iTermBoxDrawingCodeMin 0x2500
16 | #define iTermBoxDrawingCodeMax 0x257f
17 |
18 | typedef NS_ENUM(unichar, iTermBoxDrawingCode) {
19 | iTermBoxDrawingCodeLightHorizontal = 0x2500, // ─
20 | iTermBoxDrawingCodeHeavyHorizontal = 0x2501, // ━
21 |
22 | iTermBoxDrawingCodeLightVertical = 0x2502, // │
23 | iTermBoxDrawingCodeHeavyVertical = 0x2503, // ┃
24 |
25 | iTermBoxDrawingCodeLightTripleDashHorizontal = 0x2504, // ┄
26 | iTermBoxDrawingCodeHeavyTripleDashHorizontal = 0x2505, // ┅
27 |
28 | iTermBoxDrawingCodeLightTripleDashVertical = 0x2506, // ┆
29 | iTermBoxDrawingCodeHeavyTripleDashVertical = 0x2507, // ┇
30 |
31 | iTermBoxDrawingCodeLightQuadrupleDashHorizontal = 0x2508, // ┈
32 | iTermBoxDrawingCodeHeavyQuadrupleDashHorizontal = 0x2509, // ┉
33 |
34 | iTermBoxDrawingCodeLightQuadrupleDashVertical = 0x250A, // ┊
35 | iTermBoxDrawingCodeHeavyQuadrupleDashVertical = 0x250B, // ┋
36 |
37 | iTermBoxDrawingCodeLightDownAndRight = 0x250C, // ┌
38 | iTermBoxDrawingCodeDownLightAndRightHeavy = 0x250D, // ┍
39 | iTermBoxDrawingCodeDownHeavyAndRightLight = 0x250E, // ┎
40 | iTermBoxDrawingCodeHeavyDownAndRight = 0x250F, // ┏
41 |
42 | iTermBoxDrawingCodeLightDownAndLeft = 0x2510, // ┐
43 | iTermBoxDrawingCodeDownLightAndLeftHeavy = 0x2511, // ┑
44 | iTermBoxDrawingCodeDownHeavyAndLeftLight = 0x2512, // ┒
45 | iTermBoxDrawingCodeHeavyDownAndLeft = 0x2513, // ┓
46 |
47 | iTermBoxDrawingCodeLightUpAndRight = 0x2514, // └
48 | iTermBoxDrawingCodeUpLightAndRightHeavy = 0x2515, // ┕
49 | iTermBoxDrawingCodeUpHeavyAndRightLight = 0x2516, // ┖
50 | iTermBoxDrawingCodeHeavyUpAndRight = 0x2517, // ┗
51 |
52 | iTermBoxDrawingCodeLightUpAndLeft = 0x2518, // ┘
53 | iTermBoxDrawingCodeUpLightAndLeftHeavy = 0x2519, // ┙
54 | iTermBoxDrawingCodeUpHeavyAndLeftLight = 0x251A, // ┚
55 | iTermBoxDrawingCodeHeavyUpAndLeft = 0x251B, // ┛
56 |
57 | iTermBoxDrawingCodeLightVerticalAndRight = 0x251C, // ├
58 | iTermBoxDrawingCodeVerticalLightAndRightHeavy = 0x251D, // ┝
59 | iTermBoxDrawingCodeUpHeavyAndRightDownLight = 0x251E, // ┞
60 | iTermBoxDrawingCodeDownHeavyAndRightUpLight = 0x251F, // ┟
61 | iTermBoxDrawingCodeVerticalHeavyAndRightLight = 0x2520, // ┠
62 | iTermBoxDrawingCodeDownLightAndRightUpHeavy = 0x2521, // ┡
63 | iTermBoxDrawingCodeUpLightAndRightDownHeavy = 0x2522, // ┢
64 | iTermBoxDrawingCodeHeavyVerticalAndRight = 0x2523, // ┣
65 |
66 | iTermBoxDrawingCodeLightVerticalAndLeft = 0x2524, // ┤
67 | iTermBoxDrawingCodeVerticalLightAndLeftHeavy = 0x2525, // ┥
68 | iTermBoxDrawingCodeUpHeavyAndLeftDownLight = 0x2526, // ┦
69 | iTermBoxDrawingCodeDownHeavyAndLeftUpLight = 0x2527, // ┧
70 | iTermBoxDrawingCodeVerticalHeavyAndLeftLight = 0x2528, // ┨
71 | iTermBoxDrawingCodeDownLightAndLeftUpHeavy = 0x2529, // ┩
72 | iTermBoxDrawingCodeUpLightAndLeftDownHeavy = 0x252A, // ┪
73 | iTermBoxDrawingCodeHeavyVerticalAndLeft = 0x252B, // ┫
74 |
75 | iTermBoxDrawingCodeLightDownAndHorizontal = 0x252C, // ┬
76 | iTermBoxDrawingCodeLeftHeavyAndRightDownLight = 0x252D, // ┭
77 | iTermBoxDrawingCodeRightHeavyAndLeftDownLight = 0x252E, // ┮
78 | iTermBoxDrawingCodeDownLightAndHorizontalHeavy = 0x252F, // ┯
79 | iTermBoxDrawingCodeDownHeavyAndHorizontalLight = 0x2530, // ┰
80 | iTermBoxDrawingCodeRightLightAndLeftDownHeavy = 0x2531, // ┱
81 | iTermBoxDrawingCodeLeftLightAndRightDownHeavy = 0x2532, // ┲
82 | iTermBoxDrawingCodeHeavyDownAndHorizontal = 0x2533, // ┳
83 |
84 | iTermBoxDrawingCodeLightUpAndHorizontal = 0x2534, // ┴
85 | iTermBoxDrawingCodeLeftHeavyAndRightUpLight = 0x2535, // ┵
86 | iTermBoxDrawingCodeRightHeavyAndLeftUpLight = 0x2536, // ┶
87 | iTermBoxDrawingCodeUpLightAndHorizontalHeavy = 0x2537, // ┷
88 | iTermBoxDrawingCodeUpHeavyAndHorizontalLight = 0x2538, // ┸
89 | iTermBoxDrawingCodeRightLightAndLeftUpHeavy = 0x2539, // ┹
90 | iTermBoxDrawingCodeLeftLightAndRightUpHeavy = 0x253A, // ┺
91 | iTermBoxDrawingCodeHeavyUpAndHorizontal = 0x253B, // ┻
92 |
93 | iTermBoxDrawingCodeLightVerticalAndHorizontal = 0x253C, // ┼
94 | iTermBoxDrawingCodeLeftHeavyAndRightVerticalLight = 0x253D, // ┽
95 | iTermBoxDrawingCodeRightHeavyAndLeftVerticalLight = 0x253E, // ┾
96 | iTermBoxDrawingCodeVerticalLightAndHorizontalHeavy = 0x253F, // ┿
97 | iTermBoxDrawingCodeUpHeavyAndDownHorizontalLight = 0x2540, // ╀
98 | iTermBoxDrawingCodeDownHeavyAndUpHorizontalLight = 0x2541, // ╁
99 | iTermBoxDrawingCodeVerticalHeavyAndHorizontalLight = 0x2542, // ╂
100 | iTermBoxDrawingCodeLeftUpHeavyAndRightDownLight = 0x2543, // ╃
101 | iTermBoxDrawingCodeRightUpHeavyAndLeftDownLight = 0x2544, // ╄
102 | iTermBoxDrawingCodeLeftDownHeavyAndRightUpLight = 0x2545, // ╅
103 | iTermBoxDrawingCodeRightDownHeavyAndLeftUpLight = 0x2546, // ╆
104 | iTermBoxDrawingCodeDownLightAndUpHorizontalHeavy = 0x2547, // ╇
105 | iTermBoxDrawingCodeUpLightAndDownHorizontalHeavy = 0x2548, // ╈
106 | iTermBoxDrawingCodeRightLightAndLeftVerticalHeavy = 0x2549, // ╉
107 | iTermBoxDrawingCodeLeftLightAndRightVerticalHeavy = 0x254A, // ╊
108 | iTermBoxDrawingCodeHeavyVerticalAndHorizontal = 0x254B, // ╋
109 |
110 | iTermBoxDrawingCodeLightDoubleDashHorizontal = 0x254C, // ╌
111 | iTermBoxDrawingCodeHeavyDoubleDashHorizontal = 0x254D, // ╍
112 |
113 | iTermBoxDrawingCodeLightDoubleDashVertical = 0x254E, // ╎
114 | iTermBoxDrawingCodeHeavyDoubleDashVertical = 0x254F, // ╏
115 |
116 | iTermBoxDrawingCodeDoubleHorizontal = 0x2550, // ═
117 |
118 | iTermBoxDrawingCodeDoubleVertical = 0x2551, // ║
119 |
120 | iTermBoxDrawingCodeDownSingleAndRightDouble = 0x2552, // ╒
121 | iTermBoxDrawingCodeDownDoubleAndRightSingle = 0x2553, // ╓
122 | iTermBoxDrawingCodeDoubleDownAndRight = 0x2554, // ╔
123 |
124 | iTermBoxDrawingCodeDownSingleAndLeftDouble = 0x2555, // ╕
125 | iTermBoxDrawingCodeDownDoubleAndLeftSingle = 0x2556, // ╖
126 | iTermBoxDrawingCodeDoubleDownAndLeft = 0x2557, // ╗
127 |
128 | iTermBoxDrawingCodeUpSingleAndRightDouble = 0x2558, // ╘
129 | iTermBoxDrawingCodeUpDoubleAndRightSingle = 0x2559, // ╙
130 | iTermBoxDrawingCodeDoubleUpAndRight = 0x255A, // ╚
131 |
132 | iTermBoxDrawingCodeUpSingleAndLeftDouble = 0x255B, // ╛
133 | iTermBoxDrawingCodeUpDoubleAndLeftSingle = 0x255C, // ╜
134 | iTermBoxDrawingCodeDoubleUpAndLeft = 0x255D, // ╝
135 |
136 | iTermBoxDrawingCodeVerticalSingleAndRightDouble = 0x255E, // ╞
137 | iTermBoxDrawingCodeVerticalDoubleAndRightSingle = 0x255F, // ╟
138 | iTermBoxDrawingCodeDoubleVerticalAndRight = 0x2560, // ╠
139 |
140 | iTermBoxDrawingCodeVerticalSingleAndLeftDouble = 0x2561, // ╡
141 | iTermBoxDrawingCodeVerticalDoubleAndLeftSingle = 0x2562, // ╢
142 | iTermBoxDrawingCodeDoubleVerticalAndLeft = 0x2563, // ╣
143 |
144 | iTermBoxDrawingCodeDownSingleAndHorizontalDouble = 0x2564, // ╤
145 | iTermBoxDrawingCodeDownDoubleAndHorizontalSingle = 0x2565, // ╥
146 | iTermBoxDrawingCodeDoubleDownAndHorizontal = 0x2566, // ╦
147 |
148 | iTermBoxDrawingCodeUpSingleAndHorizontalDouble = 0x2567, // ╧
149 | iTermBoxDrawingCodeUpDoubleAndHorizontalSingle = 0x2568, // ╨
150 | iTermBoxDrawingCodeDoubleUpAndHorizontal = 0x2569, // ╩
151 |
152 | iTermBoxDrawingCodeVerticalSingleAndHorizontalDouble = 0x256A, // ╪
153 | iTermBoxDrawingCodeVerticalDoubleAndHorizontalSingle = 0x256B, // ╫
154 | iTermBoxDrawingCodeDoubleVerticalAndHorizontal = 0x256C, // ╬
155 |
156 | iTermBoxDrawingCodeLightArcDownAndRight = 0x256D, // ╭
157 | iTermBoxDrawingCodeLightArcDownAndLeft = 0x256E, // ╮
158 | iTermBoxDrawingCodeLightArcUpAndLeft = 0x256F, // ╯
159 | iTermBoxDrawingCodeLightArcUpAndRight = 0x2570, // ╰
160 |
161 | iTermBoxDrawingCodeLightDiagonalUpperRightToLowerLeft = 0x2571, // ╱
162 |
163 | iTermBoxDrawingCodeLightDiagonalUpperLeftToLowerRight = 0x2572, // ╲
164 |
165 | iTermBoxDrawingCodeLightDiagonalCross = 0x2573, // ╳
166 |
167 | iTermBoxDrawingCodeLightLeft = 0x2574, // ╴
168 |
169 | iTermBoxDrawingCodeLightUp = 0x2575, // ╵
170 |
171 | iTermBoxDrawingCodeLightRight = 0x2576, // ╶
172 |
173 | iTermBoxDrawingCodeLightDown = 0x2577, // ╷
174 |
175 | iTermBoxDrawingCodeHeavyLeft = 0x2578, // ╸
176 |
177 | iTermBoxDrawingCodeHeavyUp = 0x2579, // ╹
178 |
179 | iTermBoxDrawingCodeHeavyRight = 0x257A, // ╺
180 |
181 | iTermBoxDrawingCodeHeavyDown = 0x257B, // ╻
182 |
183 | iTermBoxDrawingCodeLightLeftAndHeavyRight = 0x257C, // ╼
184 |
185 | iTermBoxDrawingCodeLightUpAndHeavyDown = 0x257D, // ╽
186 |
187 | iTermBoxDrawingCodeHeavyLeftAndLightRight = 0x257E, // ╾
188 |
189 | iTermBoxDrawingCodeHeavyUpAndLightDown = 0x257F, // ╿
190 | };
191 |
192 | // Defines a mapping from ascii characters to their Unicode graphical equivalent. Used in line-
193 | // drawing mode.
194 | static const unichar charmap[256]={
195 | 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
196 | 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
197 | 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
198 | 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
199 | 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
200 | 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
201 | 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
202 | 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
203 | 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
204 | 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
205 | 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
206 | 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
207 | 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
208 | 0x2424, 0x240b,
209 | iTermBoxDrawingCodeLightUpAndLeft,
210 | iTermBoxDrawingCodeLightDownAndLeft,
211 | iTermBoxDrawingCodeLightDownAndRight,
212 | iTermBoxDrawingCodeLightUpAndRight,
213 | iTermBoxDrawingCodeLightVerticalAndHorizontal,
214 | 0x23ba, 0x23bb,
215 | iTermBoxDrawingCodeLightHorizontal,
216 | 0x23bc, 0x23bd,
217 | iTermBoxDrawingCodeLightVerticalAndRight,
218 | iTermBoxDrawingCodeLightVerticalAndLeft,
219 | iTermBoxDrawingCodeLightUpAndHorizontal,
220 | iTermBoxDrawingCodeLightDownAndHorizontal,
221 | iTermBoxDrawingCodeLightVertical,
222 | 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
223 | 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
224 | 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
225 | 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
226 | 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
227 | 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
228 | 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
229 | 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
230 | 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
231 | 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
232 | 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
233 | 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
234 | 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
235 | 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
236 | 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
237 | 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
238 | 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
239 | };
240 |
241 |
--------------------------------------------------------------------------------
/NewTermMarzipan/colortest.txt:
--------------------------------------------------------------------------------
1 | iPhone:/System/Library mobile$ ls --color CoreServices | head -5
2 | [0m[01;32mAppleIDAuthAgent[0m*
3 | [01;34mAssistiveTouch.app[0m/
4 | [01;36mAuthBrokerAgent[0m@
5 | [01;36mCFNetworkAgent[0m@
6 | [01;32mCacheDeleteAppContainerCaches[0m*
7 |
8 | System colors:
9 | [48;5;0m[38;5;15m [0m[0m[48;5;1m[38;5;15m [0m[0m[48;5;2m[38;5;15m [0m[0m[48;5;3m[38;5;15m [0m[0m[48;5;4m[38;5;15m [0m[0m[48;5;5m[38;5;15m [0m[0m[48;5;6m[38;5;15m [0m[0m[48;5;7m[38;5;15m [0m[0m
10 | [48;5;8m[38;5;0m [0m[0m[48;5;9m[38;5;0m [0m[0m[48;5;10m[38;5;0m [0m[0m[48;5;11m[38;5;0m [0m[0m[48;5;12m[38;5;0m [0m[0m[48;5;13m[38;5;0m [0m[0m[48;5;14m[38;5;0m [0m[0m[48;5;15m[38;5;0m [0m[0m
11 |
12 | 6x6x6 color cube:
13 | [48;5;16m[38;5;15m [0m[0m[48;5;17m[38;5;15m [0m[0m[48;5;18m[38;5;15m [0m[0m[48;5;19m[38;5;15m [0m[0m[48;5;20m[38;5;15m [0m[0m[48;5;21m[38;5;15m [0m[0m [48;5;88m[38;5;15m [0m[0m[48;5;89m[38;5;15m [0m[0m[48;5;90m[38;5;15m [0m[0m[48;5;91m[38;5;15m [0m[0m[48;5;92m[38;5;15m [0m[0m[48;5;93m[38;5;15m [0m[0m [48;5;160m[38;5;0m [0m[0m[48;5;161m[38;5;0m [0m[0m[48;5;162m[38;5;0m [0m[0m[48;5;163m[38;5;0m [0m[0m[48;5;164m[38;5;0m [0m[0m[48;5;165m[38;5;0m [0m[0m
14 | [48;5;22m[38;5;15m [0m[0m[48;5;23m[38;5;15m [0m[0m[48;5;24m[38;5;15m [0m[0m[48;5;25m[38;5;15m [0m[0m[48;5;26m[38;5;15m [0m[0m[48;5;27m[38;5;15m [0m[0m [48;5;94m[38;5;15m [0m[0m[48;5;95m[38;5;15m [0m[0m[48;5;96m[38;5;15m [0m[0m[48;5;97m[38;5;15m [0m[0m[48;5;98m[38;5;15m [0m[0m[48;5;99m[38;5;15m [0m[0m [48;5;166m[38;5;0m [0m[0m[48;5;167m[38;5;0m [0m[0m[48;5;168m[38;5;0m [0m[0m[48;5;169m[38;5;0m [0m[0m[48;5;170m[38;5;0m [0m[0m[48;5;171m[38;5;0m [0m[0m
15 | [48;5;28m[38;5;15m [0m[0m[48;5;29m[38;5;15m [0m[0m[48;5;30m[38;5;15m [0m[0m[48;5;31m[38;5;15m [0m[0m[48;5;32m[38;5;15m [0m[0m[48;5;33m[38;5;15m [0m[0m [48;5;100m[38;5;15m [0m[0m[48;5;101m[38;5;15m [0m[0m[48;5;102m[38;5;15m [0m[0m[48;5;103m[38;5;15m [0m[0m[48;5;104m[38;5;15m [0m[0m[48;5;105m[38;5;15m [0m[0m [48;5;172m[38;5;0m [0m[0m[48;5;173m[38;5;0m [0m[0m[48;5;174m[38;5;0m [0m[0m[48;5;175m[38;5;0m [0m[0m[48;5;176m[38;5;0m [0m[0m[48;5;177m[38;5;0m [0m[0m
16 | [48;5;34m[38;5;15m [0m[0m[48;5;35m[38;5;15m [0m[0m[48;5;36m[38;5;15m [0m[0m[48;5;37m[38;5;15m [0m[0m[48;5;38m[38;5;15m [0m[0m[48;5;39m[38;5;15m [0m[0m [48;5;106m[38;5;15m [0m[0m[48;5;107m[38;5;15m [0m[0m[48;5;108m[38;5;15m [0m[0m[48;5;109m[38;5;15m [0m[0m[48;5;110m[38;5;15m [0m[0m[48;5;111m[38;5;15m [0m[0m [48;5;178m[38;5;0m [0m[0m[48;5;179m[38;5;0m [0m[0m[48;5;180m[38;5;0m [0m[0m[48;5;181m[38;5;0m [0m[0m[48;5;182m[38;5;0m [0m[0m[48;5;183m[38;5;0m [0m[0m
17 | [48;5;40m[38;5;15m [0m[0m[48;5;41m[38;5;15m [0m[0m[48;5;42m[38;5;15m [0m[0m[48;5;43m[38;5;15m [0m[0m[48;5;44m[38;5;15m [0m[0m[48;5;45m[38;5;15m [0m[0m [48;5;112m[38;5;15m [0m[0m[48;5;113m[38;5;15m [0m[0m[48;5;114m[38;5;15m [0m[0m[48;5;115m[38;5;15m [0m[0m[48;5;116m[38;5;15m [0m[0m[48;5;117m[38;5;15m [0m[0m [48;5;184m[38;5;0m [0m[0m[48;5;185m[38;5;0m [0m[0m[48;5;186m[38;5;0m [0m[0m[48;5;187m[38;5;0m [0m[0m[48;5;188m[38;5;0m [0m[0m[48;5;189m[38;5;0m [0m[0m
18 | [48;5;46m[38;5;15m [0m[0m[48;5;47m[38;5;15m [0m[0m[48;5;48m[38;5;15m [0m[0m[48;5;49m[38;5;15m [0m[0m[48;5;50m[38;5;15m [0m[0m[48;5;51m[38;5;15m [0m[0m [48;5;118m[38;5;15m [0m[0m[48;5;119m[38;5;15m [0m[0m[48;5;120m[38;5;15m [0m[0m[48;5;121m[38;5;15m [0m[0m[48;5;122m[38;5;15m [0m[0m[48;5;123m[38;5;15m [0m[0m [48;5;190m[38;5;0m [0m[0m[48;5;191m[38;5;0m [0m[0m[48;5;192m[38;5;0m [0m[0m[48;5;193m[38;5;0m [0m[0m[48;5;194m[38;5;0m [0m[0m[48;5;195m[38;5;0m [0m[0m
19 | [48;5;82m[38;5;15m [0m[0m[48;5;83m[38;5;15m [0m[0m[48;5;84m[38;5;15m [0m[0m[48;5;85m[38;5;15m [0m[0m[48;5;86m[38;5;15m [0m[0m[48;5;87m[38;5;15m [0m[0m [48;5;154m[38;5;0m [0m[0m[48;5;155m[38;5;0m [0m[0m[48;5;156m[38;5;0m [0m[0m[48;5;157m[38;5;0m [0m[0m[48;5;158m[38;5;0m [0m[0m[48;5;159m[38;5;0m [0m[0m [48;5;226m[38;5;0m [0m[0m[48;5;227m[38;5;0m [0m[0m[48;5;228m[38;5;0m [0m[0m[48;5;229m[38;5;0m [0m[0m[48;5;230m[38;5;0m [0m[0m[48;5;231m[38;5;0m [0m[0m
20 | [48;5;76m[38;5;15m [0m[0m[48;5;77m[38;5;15m [0m[0m[48;5;78m[38;5;15m [0m[0m[48;5;79m[38;5;15m [0m[0m[48;5;80m[38;5;15m [0m[0m[48;5;81m[38;5;15m [0m[0m [48;5;148m[38;5;0m [0m[0m[48;5;149m[38;5;0m [0m[0m[48;5;150m[38;5;0m [0m[0m[48;5;151m[38;5;0m [0m[0m[48;5;152m[38;5;0m [0m[0m[48;5;153m[38;5;0m [0m[0m [48;5;220m[38;5;0m [0m[0m[48;5;221m[38;5;0m [0m[0m[48;5;222m[38;5;0m [0m[0m[48;5;223m[38;5;0m [0m[0m[48;5;224m[38;5;0m [0m[0m[48;5;225m[38;5;0m [0m[0m
21 | [48;5;70m[38;5;15m [0m[0m[48;5;71m[38;5;15m [0m[0m[48;5;72m[38;5;15m [0m[0m[48;5;73m[38;5;15m [0m[0m[48;5;74m[38;5;15m [0m[0m[48;5;75m[38;5;15m [0m[0m [48;5;142m[38;5;0m [0m[0m[48;5;143m[38;5;0m [0m[0m[48;5;144m[38;5;0m [0m[0m[48;5;145m[38;5;0m [0m[0m[48;5;146m[38;5;0m [0m[0m[48;5;147m[38;5;0m [0m[0m [48;5;214m[38;5;0m [0m[0m[48;5;215m[38;5;0m [0m[0m[48;5;216m[38;5;0m [0m[0m[48;5;217m[38;5;0m [0m[0m[48;5;218m[38;5;0m [0m[0m[48;5;219m[38;5;0m [0m[0m
22 | [48;5;64m[38;5;15m [0m[0m[48;5;65m[38;5;15m [0m[0m[48;5;66m[38;5;15m [0m[0m[48;5;67m[38;5;15m [0m[0m[48;5;68m[38;5;15m [0m[0m[48;5;69m[38;5;15m [0m[0m [48;5;136m[38;5;0m [0m[0m[48;5;137m[38;5;0m [0m[0m[48;5;138m[38;5;0m [0m[0m[48;5;139m[38;5;0m [0m[0m[48;5;140m[38;5;0m [0m[0m[48;5;141m[38;5;0m [0m[0m [48;5;208m[38;5;0m [0m[0m[48;5;209m[38;5;0m [0m[0m[48;5;210m[38;5;0m [0m[0m[48;5;211m[38;5;0m [0m[0m[48;5;212m[38;5;0m [0m[0m[48;5;213m[38;5;0m [0m[0m
23 | [48;5;58m[38;5;15m [0m[0m[48;5;59m[38;5;15m [0m[0m[48;5;60m[38;5;15m [0m[0m[48;5;61m[38;5;15m [0m[0m[48;5;62m[38;5;15m [0m[0m[48;5;63m[38;5;15m [0m[0m [48;5;130m[38;5;0m [0m[0m[48;5;131m[38;5;0m [0m[0m[48;5;132m[38;5;0m [0m[0m[48;5;133m[38;5;0m [0m[0m[48;5;134m[38;5;0m [0m[0m[48;5;135m[38;5;0m [0m[0m [48;5;202m[38;5;0m [0m[0m[48;5;203m[38;5;0m [0m[0m[48;5;204m[38;5;0m [0m[0m[48;5;205m[38;5;0m [0m[0m[48;5;206m[38;5;0m [0m[0m[48;5;207m[38;5;0m [0m[0m
24 | [48;5;52m[38;5;15m [0m[0m[48;5;53m[38;5;15m [0m[0m[48;5;54m[38;5;15m [0m[0m[48;5;55m[38;5;15m [0m[0m[48;5;56m[38;5;15m [0m[0m[48;5;57m[38;5;15m [0m[0m [48;5;124m[38;5;0m [0m[0m[48;5;125m[38;5;0m [0m[0m[48;5;126m[38;5;0m [0m[0m[48;5;127m[38;5;0m [0m[0m[48;5;128m[38;5;0m [0m[0m[48;5;129m[38;5;0m [0m[0m [48;5;196m[38;5;0m [0m[0m[48;5;197m[38;5;0m [0m[0m[48;5;198m[38;5;0m [0m[0m[48;5;199m[38;5;0m [0m[0m[48;5;200m[38;5;0m [0m[0m[48;5;201m[38;5;0m [0m[0m
25 |
26 | Greyscale ramp:
27 | [48;5;232m[38;5;15m [0m[0m[48;5;233m[38;5;15m [0m[0m[48;5;234m[38;5;15m [0m[0m[48;5;235m[38;5;15m [0m[0m[48;5;236m[38;5;15m [0m[0m[48;5;237m[38;5;15m [0m[0m[48;5;238m[38;5;15m [0m[0m[48;5;239m[38;5;15m [0m[0m[48;5;240m[38;5;15m [0m[0m[48;5;241m[38;5;15m [0m[0m[48;5;242m[38;5;15m [0m[0m[48;5;243m[38;5;15m [0m[0m
28 | [48;5;244m[38;5;0m [0m[0m[48;5;245m[38;5;0m [0m[0m[48;5;246m[38;5;0m [0m[0m[48;5;247m[38;5;0m [0m[0m[48;5;248m[38;5;0m [0m[0m[48;5;249m[38;5;0m [0m[0m[48;5;250m[38;5;0m [0m[0m[48;5;251m[38;5;0m [0m[0m[48;5;252m[38;5;0m [0m[0m[48;5;253m[38;5;0m [0m[0m[48;5;254m[38;5;0m [0m[0m[48;5;255m[38;5;0m [0m[0m
29 |
--------------------------------------------------------------------------------
/NewTermMarzipan/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/NewTermMarzipan/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | TERMINAL
7 | Terminal
8 |
9 |
10 | SETTINGS
11 | Settings
12 |
13 |
14 | TERMINAL_LAUNCH_FAILED
15 | Couldn’t start the terminal subprocess because an error occurred.
16 |
17 |
18 | PROCESS_COMPLETED_TITLE
19 | Process completed
20 |
21 |
22 | PROCESS_COMPLETED_MESSAGE
23 | Press any key to close the tab.
24 |
25 |
26 | NEW_TAB
27 | New Tab
28 |
29 |
30 | CLOSE_TAB
31 | Close Tab
32 |
33 |
34 |
--------------------------------------------------------------------------------
/NewTermMarzipan/iTermParser.h:
--------------------------------------------------------------------------------
1 | //
2 | // iTermParser.h
3 | // iTerm2
4 | //
5 | // Created by George Nachman on 1/5/15.
6 | //
7 | // Utilities for parsing escape codes.
8 |
9 | typedef struct {
10 | // Pointer to next character to read.
11 | unsigned char *datap;
12 | // Number of valid bytes starting at datap.
13 | int datalen;
14 | // Number of bytes already consumed. Subtract this from datap to get the original value of datap.
15 | int rmlen;
16 | } iTermParserContext;
17 |
18 | NS_INLINE iTermParserContext iTermParserContextMake(unsigned char *datap, int length) {
19 | iTermParserContext context = {
20 | .datap = datap,
21 | .datalen = length,
22 | .rmlen = 0
23 | };
24 | return context;
25 | }
26 |
27 | NS_INLINE BOOL iTermParserCanAdvance(iTermParserContext *context) {
28 | return context->datalen > 0;
29 | }
30 |
31 | NS_INLINE unsigned char iTermParserPeek(iTermParserContext *context) {
32 | return context->datap[0];
33 | }
34 |
35 | NS_INLINE BOOL iTermParserTryPeek(iTermParserContext *context, unsigned char *c) {
36 | if (iTermParserCanAdvance(context)) {
37 | *c = iTermParserPeek(context);
38 | return YES;
39 | } else {
40 | return NO;
41 | }
42 | }
43 |
44 | NS_INLINE void iTermParserAdvance(iTermParserContext *context) {
45 | context->datap++;
46 | context->datalen--;
47 | context->rmlen++;
48 | }
49 |
50 | NS_INLINE void iTermParserAdvanceMultiple(iTermParserContext *context, int n) {
51 | assert(context->datalen >= n);
52 | context->datap += n;
53 | context->datalen -= n;
54 | context->rmlen += n;
55 | }
56 |
57 | NS_INLINE BOOL iTermParserTryAdvance(iTermParserContext *context) {
58 | if (!iTermParserCanAdvance(context)) {
59 | return NO;
60 | }
61 | iTermParserAdvance(context);
62 | return YES;
63 | }
64 |
65 | NS_INLINE NSInteger iTermParserNumberOfBytesConsumed(iTermParserContext *context) {
66 | return context->rmlen;
67 | }
68 |
69 | // Only safe to call if iTermParserCanAdvance returns YES.
70 | NS_INLINE unsigned char iTermParserConsume(iTermParserContext *context) {
71 | unsigned char c = context->datap[0];
72 | iTermParserAdvance(context);
73 | return c;
74 | }
75 |
76 | NS_INLINE BOOL iTermParserTryConsume(iTermParserContext *context, unsigned char *c) {
77 | if (!iTermParserCanAdvance(context)) {
78 | return NO;
79 | }
80 | *c = iTermParserConsume(context);
81 | return YES;
82 | }
83 |
84 | NS_INLINE void iTermParserConsumeOrDie(iTermParserContext *context, unsigned char expected) {
85 | unsigned char actual;
86 | BOOL consumedOk = iTermParserTryConsume(context, &actual);
87 |
88 | assert(consumedOk);
89 | assert(actual == expected);
90 | }
91 |
92 | NS_INLINE void iTermParserBacktrackBy(iTermParserContext *context, int n) {
93 | context->datap -= n;
94 | context->datalen += n;
95 | context->rmlen -= n;
96 | }
97 |
98 | NS_INLINE void iTermParserBacktrack(iTermParserContext *context) {
99 | iTermParserBacktrackBy(context, context->rmlen);
100 | }
101 |
102 | NS_INLINE int iTermParserNumberOfBytesUntilCharacter(iTermParserContext *context, char c) {
103 | unsigned char *pointer = memchr(context->datap, '\n', context->datalen);
104 | if (!pointer) {
105 | return -1;
106 | } else {
107 | return (int)(pointer - context->datap);
108 | }
109 | }
110 |
111 | NS_INLINE int iTermParserLength(iTermParserContext *context) {
112 | return context->datalen;
113 | }
114 |
115 | NS_INLINE unsigned char *iTermParserPeekRawBytes(iTermParserContext *context, int length) {
116 | if (context->datalen < length) {
117 | return NULL;
118 | } else {
119 | return context->datap;
120 | }
121 | }
122 |
123 | // Returns YES if any digits were found, NO if the first character was not a digit. |n| must be a
124 | // valid pointer. It will be filled in with the integer at the start of the context and the context
125 | // will be advanced to the end of the integer.
126 | NS_INLINE BOOL iTermParserConsumeInteger(iTermParserContext *context, int *n) {
127 | int numDigits = 0;
128 | *n = 0;
129 | unsigned char c;
130 | while (iTermParserCanAdvance(context) &&
131 | isdigit((c = iTermParserPeek(context)))) {
132 | ++numDigits;
133 | *n *= 10;
134 | *n += (c - '0');
135 | iTermParserAdvance(context);
136 | }
137 |
138 | return numDigits > 0;
139 | }
140 |
141 | #pragma mark - CSI
142 |
143 | #define VT100CSIPARAM_MAX 16 // Maximum number of CSI parameters in VT100Token.csi->p.
144 | #define VT100CSISUBPARAM_MAX 16 // Maximum number of CSI sub-parameters in VT100Token.csi->p.
145 |
146 | typedef struct {
147 | // Integer parameters. The first |count| elements are valid. -1 means the value is unset; set
148 | // values are always nonnegative.
149 | int p[VT100CSIPARAM_MAX];
150 |
151 | // Number of defined values in |p|.
152 | int count;
153 |
154 | // An integer that holds a packed representation of the prefix byte, intermediate byte, and
155 | // final byte.
156 | int32_t cmd;
157 |
158 | BOOL question;
159 | int modifier;
160 |
161 | // Sub-parameters.
162 | int sub[VT100CSIPARAM_MAX][VT100CSISUBPARAM_MAX];
163 |
164 | // Number of subparameters for each parameter.
165 | int subCount[VT100CSIPARAM_MAX];
166 | } CSIParam;
167 |
168 | // If the n'th parameter has a negative (default) value, replace it with |value|.
169 | // CSI parameter values are all initialized to -1 before parsing, so this has the effect of setting
170 | // a value iff it hasn't already been set.
171 | // If there aren't yet n+1 parameters, increase the count to n+1.
172 | NS_INLINE void iTermParserSetCSIParameterIfDefault(CSIParam *csiParam, int n, int value) {
173 | csiParam->p[n] = csiParam->p[n] < 0 ? value : csiParam->p[n];
174 | csiParam->count = MAX(csiParam->count, n + 1);
175 | }
176 |
--------------------------------------------------------------------------------
/NewTermMarzipan/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // NewTerm
4 | //
5 | // Created by Adam D on 20/07/2014.
6 | // Copyright (c) 2014 HASHBANG Productions. All rights reserved.
7 | //
8 |
9 | #import "HBNTAppDelegate.h"
10 |
11 | int main(int argc, char * argv[]) {
12 | @autoreleasepool {
13 | return UIApplicationMain(argc, argv, nil, NSStringFromClass(HBNTAppDelegate.class));
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/NewTermMarzipan/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kirb/iOSMac-Demo/742c528fb3280dcdb01b1e71ffe2aceb09245468/NewTermMarzipan/settings.png
--------------------------------------------------------------------------------
/NewTermMarzipan/settings@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kirb/iOSMac-Demo/742c528fb3280dcdb01b1e71ffe2aceb09245468/NewTermMarzipan/settings@2x.png
--------------------------------------------------------------------------------
/NewTermMarzipan/settings@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kirb/iOSMac-Demo/742c528fb3280dcdb01b1e71ffe2aceb09245468/NewTermMarzipan/settings@3x.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Experimenting with iOSMac (Marzipan)
2 | This repo accompanies my blog post [**A quick look at UIKit on macOS**](https://kirb.me/2018/06/07/iosmac-research.html), where I investigate the iOSMac (aka UIKit on Mac, aka Marzipan) system included with macOS Mojave. This is a proof-of-concept of my iOS app [NewTerm](https://github.com/hbang/NewTerm) (somewhat) running on macOS using iOSMac. This repo is very messy and iOSMac is very crashy, but it serves as a proof-of-concept that an app really can be ported from iOS to macOS.
3 |
4 | ## Building
5 | Most importantly, you need to be on macOS Mojave (the current developer beta release) with Xcode 10 (also beta), disable System Integrity Protection (Google for a guide), as well as AppleMobileFileIntegrity (AMFI) using `sudo nvram boot-args='amfi_get_out_of_my_way=0x1'`. This is of course disabling a lot of macOS’s security functionality and you should only do this on a test installation of macOS (you’re not running a beta OS as your daily driver, right‽), and re-enable it all once you’re done. Keep in mind NVRAM is global and affects all installations of macOS on the computer, and SIP configuration is kept in NVRAM.
6 |
7 | I haven’t included UIKit headers, so you’ll need to take them from the iOS SDK and patch them to shut up availability warnings:
8 |
9 | ```shell
10 | cp -r /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/UIKit.framework/Headers/*.h ~/Downloads/iOSMac-Demo/UIKit/
11 | cd ~/Downloads/iOSMac-Demo/UIKit/
12 |
13 | for i in *.h; do
14 | sed -Ei s/'NS_(|CLASS_|ENUM_)AVAILABLE_IOS\([0-9]+_[0-9]\)'//g "$i"
15 | done
16 | ```
17 |
18 | Open NewTerm.xcodeproj, select the NewTerm project file at the top of the file list, and ensure the signing team is set to yourself (a free developer account works). Then click Run and have fun!
19 |
20 | **Keep in mind** iOSMac is very likely to crash or hang the window server. This project currently causes a hang immediately after. You should enable SSH in the macOS Sharing Preferences so you can SSH in from another machine and run `killall UIKitSystemApp` if you’re in trouble. If you forget or can’t, just hold the power button. There’s no permanent damage — iOSMac is just very unstable right now.
21 |
22 | ## License
23 | This is based on the [NewTerm](https://github.com/hbang/NewTerm) project, licensed under the GNU General Public License, version 2.0. Refer to [LICENSE.md](LICENSE.md).
24 |
--------------------------------------------------------------------------------
/UIKit/PUT_PATCHED_HEADERS_HERE:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kirb/iOSMac-Demo/742c528fb3280dcdb01b1e71ffe2aceb09245468/UIKit/PUT_PATCHED_HEADERS_HERE
--------------------------------------------------------------------------------