Compare commits
1 Commits
v0.2.0
...
507d77a0de
| Author | SHA1 | Date | |
|---|---|---|---|
|
507d77a0de
|
@@ -15,6 +15,7 @@
|
|||||||
187F4B521BFC3BD29ADA79E3 /* HotkeyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEB7FE2BDE5C25B7E599F340 /* HotkeyManager.swift */; };
|
187F4B521BFC3BD29ADA79E3 /* HotkeyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEB7FE2BDE5C25B7E599F340 /* HotkeyManager.swift */; };
|
||||||
1AB4A0F1BE668D3130EFBA93 /* TerminalTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFE9E5BADB0C427903A0D874 /* TerminalTheme.swift */; };
|
1AB4A0F1BE668D3130EFBA93 /* TerminalTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFE9E5BADB0C427903A0D874 /* TerminalTheme.swift */; };
|
||||||
2089566A2BBAA65EA82119B3 /* NotchOrchestratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6D136A0B3FC79DDE12A826 /* NotchOrchestratorTests.swift */; };
|
2089566A2BBAA65EA82119B3 /* NotchOrchestratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6D136A0B3FC79DDE12A826 /* NotchOrchestratorTests.swift */; };
|
||||||
|
21373D6E9C2F34FD63CEC6A5 /* TerminalScrollCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40D9E323185F6D722B360C3C /* TerminalScrollCoordinatorTests.swift */; };
|
||||||
2375B9DA559A0777FE558A8B /* WorkspaceStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FA62DFE9AD003F4C5B55F14 /* WorkspaceStoreTests.swift */; };
|
2375B9DA559A0777FE558A8B /* WorkspaceStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FA62DFE9AD003F4C5B55F14 /* WorkspaceStoreTests.swift */; };
|
||||||
23E2DDCF36D0DAB2EA72C39C /* NotchState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B352301BC9CAD7C9D8B7AA9 /* NotchState.swift */; };
|
23E2DDCF36D0DAB2EA72C39C /* NotchState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B352301BC9CAD7C9D8B7AA9 /* NotchState.swift */; };
|
||||||
26AE379040149CBE05B314BB /* WorkspacesSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70A31EFACF23DD9262A040E /* WorkspacesSettingsView.swift */; };
|
26AE379040149CBE05B314BB /* WorkspacesSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70A31EFACF23DD9262A040E /* WorkspacesSettingsView.swift */; };
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
2DF22798D3A7514E2A9183FC /* WorkspaceSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2BCA543CE54DAB1DB80E43 /* WorkspaceSummary.swift */; };
|
2DF22798D3A7514E2A9183FC /* WorkspaceSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2BCA543CE54DAB1DB80E43 /* WorkspaceSummary.swift */; };
|
||||||
34AF69BF7AF8DC78ADE3774A /* GeneralSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27E7EEEDFBD8D9CEB8FD86A5 /* GeneralSettingsView.swift */; };
|
34AF69BF7AF8DC78ADE3774A /* GeneralSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27E7EEEDFBD8D9CEB8FD86A5 /* GeneralSettingsView.swift */; };
|
||||||
3B69CB3CDEC2E5F2DCE600F9 /* NotchSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 297BA3E5B837FBDDEED9DE66 /* NotchSettings.swift */; };
|
3B69CB3CDEC2E5F2DCE600F9 /* NotchSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 297BA3E5B837FBDDEED9DE66 /* NotchSettings.swift */; };
|
||||||
|
40183737D8C237022D0882FD /* TerminalScrollbackEstimatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77DC2AED643512C786AD70A /* TerminalScrollbackEstimatorTests.swift */; };
|
||||||
4CFA0C79095ACE0A327A2469 /* WorkspaceRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E97758F68FACCFFACA895B7 /* WorkspaceRegistry.swift */; };
|
4CFA0C79095ACE0A327A2469 /* WorkspaceRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E97758F68FACCFFACA895B7 /* WorkspaceRegistry.swift */; };
|
||||||
4D335F67B71F7DD977B6AEF9 /* AppSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6C98C406899F4B242075AF /* AppSettingsStore.swift */; };
|
4D335F67B71F7DD977B6AEF9 /* AppSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6C98C406899F4B242075AF /* AppSettingsStore.swift */; };
|
||||||
4E0AD14B7427532271E485AA /* NotchWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFAC70814C72BAF76D90B9DF /* NotchWindow.swift */; };
|
4E0AD14B7427532271E485AA /* NotchWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFAC70814C72BAF76D90B9DF /* NotchWindow.swift */; };
|
||||||
@@ -56,6 +58,7 @@
|
|||||||
D4CEB4B895F75D91FA892A06 /* PopoutWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB593A2546BF2C0BE8E40387 /* PopoutWindowController.swift */; };
|
D4CEB4B895F75D91FA892A06 /* PopoutWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB593A2546BF2C0BE8E40387 /* PopoutWindowController.swift */; };
|
||||||
DAD3AB4A0DAADA32C02D959E /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3125FD3DC55420122CF85D80 /* SettingsView.swift */; };
|
DAD3AB4A0DAADA32C02D959E /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3125FD3DC55420122CF85D80 /* SettingsView.swift */; };
|
||||||
DCFD5B03E64A46783F46726B /* TerminalCommandArrowBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = F22AA47452CF798A977A6F47 /* TerminalCommandArrowBehavior.swift */; };
|
DCFD5B03E64A46783F46726B /* TerminalCommandArrowBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = F22AA47452CF798A977A6F47 /* TerminalCommandArrowBehavior.swift */; };
|
||||||
|
DD116B0FCC341D66F1534EC4 /* TerminalScrollbackEstimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165DCCD7BB164A6470D49BBF /* TerminalScrollbackEstimator.swift */; };
|
||||||
E63FD5862C0EC54E284F6A0F /* ScreenRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAF23753B5A0CAF04D7566A3 /* ScreenRegistry.swift */; };
|
E63FD5862C0EC54E284F6A0F /* ScreenRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAF23753B5A0CAF04D7566A3 /* ScreenRegistry.swift */; };
|
||||||
E792411FA82E79E810F4B4C3 /* HotkeyRecorderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B81432CECBDB61D21EE4DC3 /* HotkeyRecorderView.swift */; };
|
E792411FA82E79E810F4B4C3 /* HotkeyRecorderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B81432CECBDB61D21EE4DC3 /* HotkeyRecorderView.swift */; };
|
||||||
EE72479BA5A25FF31BACCC50 /* NotchOrchestrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7912AF01E1600B8619AF31 /* NotchOrchestrator.swift */; };
|
EE72479BA5A25FF31BACCC50 /* NotchOrchestrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7912AF01E1600B8619AF31 /* NotchOrchestrator.swift */; };
|
||||||
@@ -82,6 +85,7 @@
|
|||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
0E97758F68FACCFFACA895B7 /* WorkspaceRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceRegistry.swift; sourceTree = "<group>"; };
|
0E97758F68FACCFFACA895B7 /* WorkspaceRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceRegistry.swift; sourceTree = "<group>"; };
|
||||||
|
165DCCD7BB164A6470D49BBF /* TerminalScrollbackEstimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalScrollbackEstimator.swift; sourceTree = "<group>"; };
|
||||||
27E7EEEDFBD8D9CEB8FD86A5 /* GeneralSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsView.swift; sourceTree = "<group>"; };
|
27E7EEEDFBD8D9CEB8FD86A5 /* GeneralSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsView.swift; sourceTree = "<group>"; };
|
||||||
297BA3E5B837FBDDEED9DE66 /* NotchSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotchSettings.swift; sourceTree = "<group>"; };
|
297BA3E5B837FBDDEED9DE66 /* NotchSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotchSettings.swift; sourceTree = "<group>"; };
|
||||||
2B81432CECBDB61D21EE4DC3 /* HotkeyRecorderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HotkeyRecorderView.swift; sourceTree = "<group>"; };
|
2B81432CECBDB61D21EE4DC3 /* HotkeyRecorderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HotkeyRecorderView.swift; sourceTree = "<group>"; };
|
||||||
@@ -91,6 +95,7 @@
|
|||||||
3CB1DFD6FCDF64B4DF24230A /* WorkspaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceController.swift; sourceTree = "<group>"; };
|
3CB1DFD6FCDF64B4DF24230A /* WorkspaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceController.swift; sourceTree = "<group>"; };
|
||||||
3F57837A7115DEEE11E14B40 /* NotchShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotchShape.swift; sourceTree = "<group>"; };
|
3F57837A7115DEEE11E14B40 /* NotchShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotchShape.swift; sourceTree = "<group>"; };
|
||||||
3F5FF5623898FA150C3B70D4 /* AppSettingsControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettingsControllerTests.swift; sourceTree = "<group>"; };
|
3F5FF5623898FA150C3B70D4 /* AppSettingsControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettingsControllerTests.swift; sourceTree = "<group>"; };
|
||||||
|
40D9E323185F6D722B360C3C /* TerminalScrollCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalScrollCoordinatorTests.swift; sourceTree = "<group>"; };
|
||||||
48198AFE5473B0F7AECAB3FB /* AboutSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutSettingsView.swift; sourceTree = "<group>"; };
|
48198AFE5473B0F7AECAB3FB /* AboutSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutSettingsView.swift; sourceTree = "<group>"; };
|
||||||
496267F03E261FEC9EBD5A9D /* CommandNotchUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CommandNotchUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
496267F03E261FEC9EBD5A9D /* CommandNotchUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CommandNotchUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
49E1791BB45E1505500ACC67 /* TerminalSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalSession.swift; sourceTree = "<group>"; };
|
49E1791BB45E1505500ACC67 /* TerminalSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalSession.swift; sourceTree = "<group>"; };
|
||||||
@@ -124,6 +129,7 @@
|
|||||||
CFE9E5BADB0C427903A0D874 /* TerminalTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalTheme.swift; sourceTree = "<group>"; };
|
CFE9E5BADB0C427903A0D874 /* TerminalTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalTheme.swift; sourceTree = "<group>"; };
|
||||||
D03D042117E59DCA9D553844 /* HotkeySettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HotkeySettingsView.swift; sourceTree = "<group>"; };
|
D03D042117E59DCA9D553844 /* HotkeySettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HotkeySettingsView.swift; sourceTree = "<group>"; };
|
||||||
D288132700770C4A625A15F6 /* WindowFrameCalculatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowFrameCalculatorTests.swift; sourceTree = "<group>"; };
|
D288132700770C4A625A15F6 /* WindowFrameCalculatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowFrameCalculatorTests.swift; sourceTree = "<group>"; };
|
||||||
|
D77DC2AED643512C786AD70A /* TerminalScrollbackEstimatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalScrollbackEstimatorTests.swift; sourceTree = "<group>"; };
|
||||||
DC7912AF01E1600B8619AF31 /* NotchOrchestrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotchOrchestrator.swift; sourceTree = "<group>"; };
|
DC7912AF01E1600B8619AF31 /* NotchOrchestrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotchOrchestrator.swift; sourceTree = "<group>"; };
|
||||||
DF0FFBC96F2446687D6474F4 /* WorkspaceSwitcherView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceSwitcherView.swift; sourceTree = "<group>"; };
|
DF0FFBC96F2446687D6474F4 /* WorkspaceSwitcherView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceSwitcherView.swift; sourceTree = "<group>"; };
|
||||||
E37A6DCD9C5DE1FE11C4C1CD /* TerminalSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalSettingsView.swift; sourceTree = "<group>"; };
|
E37A6DCD9C5DE1FE11C4C1CD /* TerminalSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalSettingsView.swift; sourceTree = "<group>"; };
|
||||||
@@ -165,6 +171,7 @@
|
|||||||
7181BB1F3926B457445105E5 /* ScreenContext.swift */,
|
7181BB1F3926B457445105E5 /* ScreenContext.swift */,
|
||||||
AAF23753B5A0CAF04D7566A3 /* ScreenRegistry.swift */,
|
AAF23753B5A0CAF04D7566A3 /* ScreenRegistry.swift */,
|
||||||
567E85A2ED628460CEC760DB /* TerminalManager.swift */,
|
567E85A2ED628460CEC760DB /* TerminalManager.swift */,
|
||||||
|
165DCCD7BB164A6470D49BBF /* TerminalScrollbackEstimator.swift */,
|
||||||
49E1791BB45E1505500ACC67 /* TerminalSession.swift */,
|
49E1791BB45E1505500ACC67 /* TerminalSession.swift */,
|
||||||
CFE9E5BADB0C427903A0D874 /* TerminalTheme.swift */,
|
CFE9E5BADB0C427903A0D874 /* TerminalTheme.swift */,
|
||||||
3CB1DFD6FCDF64B4DF24230A /* WorkspaceController.swift */,
|
3CB1DFD6FCDF64B4DF24230A /* WorkspaceController.swift */,
|
||||||
@@ -218,6 +225,8 @@
|
|||||||
A770A63582CF9834F4E7F058 /* ScreenContextTests.swift */,
|
A770A63582CF9834F4E7F058 /* ScreenContextTests.swift */,
|
||||||
EEC7F7D8D15A1BC4EE43DDDB /* ScreenRegistryTests.swift */,
|
EEC7F7D8D15A1BC4EE43DDDB /* ScreenRegistryTests.swift */,
|
||||||
C0D19729317029008D81F361 /* TerminalCommandArrowBehaviorTests.swift */,
|
C0D19729317029008D81F361 /* TerminalCommandArrowBehaviorTests.swift */,
|
||||||
|
D77DC2AED643512C786AD70A /* TerminalScrollbackEstimatorTests.swift */,
|
||||||
|
40D9E323185F6D722B360C3C /* TerminalScrollCoordinatorTests.swift */,
|
||||||
D288132700770C4A625A15F6 /* WindowFrameCalculatorTests.swift */,
|
D288132700770C4A625A15F6 /* WindowFrameCalculatorTests.swift */,
|
||||||
591FCE91AF83A8A8E44E1625 /* WorkspaceRegistryTests.swift */,
|
591FCE91AF83A8A8E44E1625 /* WorkspaceRegistryTests.swift */,
|
||||||
4FA62DFE9AD003F4C5B55F14 /* WorkspaceStoreTests.swift */,
|
4FA62DFE9AD003F4C5B55F14 /* WorkspaceStoreTests.swift */,
|
||||||
@@ -370,7 +379,6 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = C47A3896770C98F2A3E62B7A /* Build configuration list for PBXProject "CommandNotch" */;
|
buildConfigurationList = C47A3896770C98F2A3E62B7A /* Build configuration list for PBXProject "CommandNotch" */;
|
||||||
compatibilityVersion = "Xcode 14.0";
|
|
||||||
developmentRegion = en;
|
developmentRegion = en;
|
||||||
hasScannedForEncodings = 0;
|
hasScannedForEncodings = 0;
|
||||||
knownRegions = (
|
knownRegions = (
|
||||||
@@ -383,6 +391,7 @@
|
|||||||
28377BE3F9997892D4929B6E /* XCRemoteSwiftPackageReference "SwiftTerm" */,
|
28377BE3F9997892D4929B6E /* XCRemoteSwiftPackageReference "SwiftTerm" */,
|
||||||
);
|
);
|
||||||
preferredProjectObjectVersion = 77;
|
preferredProjectObjectVersion = 77;
|
||||||
|
productRefGroup = B269158E04E8E603B61448F0 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
@@ -423,6 +432,8 @@
|
|||||||
D2468B19D6F0A2C1DFDFE2B7 /* ScreenContextTests.swift in Sources */,
|
D2468B19D6F0A2C1DFDFE2B7 /* ScreenContextTests.swift in Sources */,
|
||||||
8A1B2A4CD61B0D9A4BAB075B /* ScreenRegistryTests.swift in Sources */,
|
8A1B2A4CD61B0D9A4BAB075B /* ScreenRegistryTests.swift in Sources */,
|
||||||
CFBBE994BA6BAD4658AAB9CB /* TerminalCommandArrowBehaviorTests.swift in Sources */,
|
CFBBE994BA6BAD4658AAB9CB /* TerminalCommandArrowBehaviorTests.swift in Sources */,
|
||||||
|
21373D6E9C2F34FD63CEC6A5 /* TerminalScrollCoordinatorTests.swift in Sources */,
|
||||||
|
40183737D8C237022D0882FD /* TerminalScrollbackEstimatorTests.swift in Sources */,
|
||||||
0F133E8A88D2E313D90C32AD /* WindowFrameCalculatorTests.swift in Sources */,
|
0F133E8A88D2E313D90C32AD /* WindowFrameCalculatorTests.swift in Sources */,
|
||||||
154F363D434A26105C5999B5 /* WorkspaceRegistryTests.swift in Sources */,
|
154F363D434A26105C5999B5 /* WorkspaceRegistryTests.swift in Sources */,
|
||||||
2375B9DA559A0777FE558A8B /* WorkspaceStoreTests.swift in Sources */,
|
2375B9DA559A0777FE558A8B /* WorkspaceStoreTests.swift in Sources */,
|
||||||
@@ -465,6 +476,7 @@
|
|||||||
88113BA9B217DA579C36BEBE /* TabBar.swift in Sources */,
|
88113BA9B217DA579C36BEBE /* TabBar.swift in Sources */,
|
||||||
DCFD5B03E64A46783F46726B /* TerminalCommandArrowBehavior.swift in Sources */,
|
DCFD5B03E64A46783F46726B /* TerminalCommandArrowBehavior.swift in Sources */,
|
||||||
6F249EDFA2D654457DF385F1 /* TerminalManager.swift in Sources */,
|
6F249EDFA2D654457DF385F1 /* TerminalManager.swift in Sources */,
|
||||||
|
DD116B0FCC341D66F1534EC4 /* TerminalScrollbackEstimator.swift in Sources */,
|
||||||
7A69B5AAC686174BCA54D0F0 /* TerminalSession.swift in Sources */,
|
7A69B5AAC686174BCA54D0F0 /* TerminalSession.swift in Sources */,
|
||||||
65C7DB7296C6C6A77598A1F4 /* TerminalSettingsView.swift in Sources */,
|
65C7DB7296C6C6A77598A1F4 /* TerminalSettingsView.swift in Sources */,
|
||||||
1AB4A0F1BE668D3130EFBA93 /* TerminalTheme.swift in Sources */,
|
1AB4A0F1BE668D3130EFBA93 /* TerminalTheme.swift in Sources */,
|
||||||
@@ -499,14 +511,20 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = CommandNotch/Resources/CommandNotch.entitlements;
|
CODE_SIGN_ENTITLEMENTS = CommandNotch/Resources/CommandNotch.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
DEVELOPMENT_TEAM = G698BP272N;
|
||||||
INFOPLIST_FILE = CommandNotch/Resources/Info.plist;
|
INFOPLIST_FILE = CommandNotch/Resources/Info.plist;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 0.0.3;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.commandnotch.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.commandnotch.app;
|
||||||
PRODUCT_NAME = CommandNotch;
|
PRODUCT_NAME = CommandNotch;
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
@@ -598,14 +616,20 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = CommandNotch/Resources/CommandNotch.entitlements;
|
CODE_SIGN_ENTITLEMENTS = CommandNotch/Resources/CommandNotch.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
DEVELOPMENT_TEAM = G698BP272N;
|
||||||
INFOPLIST_FILE = CommandNotch/Resources/Info.plist;
|
INFOPLIST_FILE = CommandNotch/Resources/Info.plist;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 0.0.3;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.commandnotch.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.commandnotch.app;
|
||||||
PRODUCT_NAME = CommandNotch;
|
PRODUCT_NAME = CommandNotch;
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
|
|||||||
Binary file not shown.
@@ -5,33 +5,9 @@
|
|||||||
<key>SchemeUserState</key>
|
<key>SchemeUserState</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>CommandNotch.xcscheme_^#shared#^_</key>
|
<key>CommandNotch.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict/>
|
||||||
<key>orderHint</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
<key>CommandNotchTests.xcscheme_^#shared#^_</key>
|
|
||||||
<dict>
|
|
||||||
<key>orderHint</key>
|
|
||||||
<integer>2</integer>
|
|
||||||
</dict>
|
|
||||||
<key>CommandNotchUITests.xcscheme_^#shared#^_</key>
|
|
||||||
<dict>
|
|
||||||
<key>orderHint</key>
|
|
||||||
<integer>2</integer>
|
|
||||||
</dict>
|
|
||||||
<key>Release-CommandNotch.xcscheme_^#shared#^_</key>
|
<key>Release-CommandNotch.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict/>
|
||||||
<key>orderHint</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
<key>SuppressBuildableAutocreation</key>
|
|
||||||
<dict>
|
|
||||||
<key>1485207FA11756EC2DF4F08B</key>
|
|
||||||
<dict>
|
|
||||||
<key>primary</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
observeSizePreferences()
|
observeSizePreferences()
|
||||||
observeFontSizeChanges()
|
observeFontSizeChanges()
|
||||||
observeTerminalThemeChanges()
|
observeTerminalThemeChanges()
|
||||||
|
observeTerminalScrollbackChanges()
|
||||||
applyUITestLaunchBehaviorIfNeeded()
|
applyUITestLaunchBehaviorIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +91,16 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func observeTerminalScrollbackChanges() {
|
||||||
|
settingsController.$settings
|
||||||
|
.map(\.terminal.scrollbackLines)
|
||||||
|
.removeDuplicates()
|
||||||
|
.sink { scrollbackLines in
|
||||||
|
WorkspaceRegistry.shared.updateAllWorkspacesScrollbackLines(scrollbackLines)
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
|
||||||
private var launchArguments: [String] {
|
private var launchArguments: [String] {
|
||||||
ProcessInfo.processInfo.arguments
|
ProcessInfo.processInfo.arguments
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ struct AppSettings: Equatable, Codable {
|
|||||||
fontSize: NotchSettings.Defaults.terminalFontSize,
|
fontSize: NotchSettings.Defaults.terminalFontSize,
|
||||||
shellPath: NotchSettings.Defaults.terminalShell,
|
shellPath: NotchSettings.Defaults.terminalShell,
|
||||||
themeRawValue: NotchSettings.Defaults.terminalTheme,
|
themeRawValue: NotchSettings.Defaults.terminalTheme,
|
||||||
|
scrollbackLines: NotchSettings.Defaults.terminalScrollbackLines,
|
||||||
sizePresetsJSON: NotchSettings.Defaults.terminalSizePresets
|
sizePresetsJSON: NotchSettings.Defaults.terminalSizePresets
|
||||||
),
|
),
|
||||||
hotkeys: HotkeySettings(
|
hotkeys: HotkeySettings(
|
||||||
@@ -106,6 +107,7 @@ extension AppSettings {
|
|||||||
var fontSize: Double
|
var fontSize: Double
|
||||||
var shellPath: String
|
var shellPath: String
|
||||||
var themeRawValue: String
|
var themeRawValue: String
|
||||||
|
var scrollbackLines: Int
|
||||||
var sizePresetsJSON: String
|
var sizePresetsJSON: String
|
||||||
|
|
||||||
var theme: TerminalTheme {
|
var theme: TerminalTheme {
|
||||||
@@ -155,6 +157,7 @@ struct TerminalSessionConfiguration: Equatable {
|
|||||||
var fontSize: CGFloat
|
var fontSize: CGFloat
|
||||||
var theme: TerminalTheme
|
var theme: TerminalTheme
|
||||||
var shellPath: String
|
var shellPath: String
|
||||||
|
var scrollbackLines: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ final class AppSettingsController: ObservableObject, TerminalSessionConfiguratio
|
|||||||
TerminalSessionConfiguration(
|
TerminalSessionConfiguration(
|
||||||
fontSize: CGFloat(settings.terminal.fontSize),
|
fontSize: CGFloat(settings.terminal.fontSize),
|
||||||
theme: settings.terminal.theme,
|
theme: settings.terminal.theme,
|
||||||
shellPath: settings.terminal.shellPath
|
shellPath: settings.terminal.shellPath,
|
||||||
|
scrollbackLines: settings.terminal.scrollbackLines
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ struct UserDefaultsAppSettingsStore: AppSettingsStoreType {
|
|||||||
fontSize: double(NotchSettings.Keys.terminalFontSize, default: NotchSettings.Defaults.terminalFontSize),
|
fontSize: double(NotchSettings.Keys.terminalFontSize, default: NotchSettings.Defaults.terminalFontSize),
|
||||||
shellPath: string(NotchSettings.Keys.terminalShell, default: NotchSettings.Defaults.terminalShell),
|
shellPath: string(NotchSettings.Keys.terminalShell, default: NotchSettings.Defaults.terminalShell),
|
||||||
themeRawValue: string(NotchSettings.Keys.terminalTheme, default: NotchSettings.Defaults.terminalTheme),
|
themeRawValue: string(NotchSettings.Keys.terminalTheme, default: NotchSettings.Defaults.terminalTheme),
|
||||||
|
scrollbackLines: integer(NotchSettings.Keys.terminalScrollbackLines, default: NotchSettings.Defaults.terminalScrollbackLines),
|
||||||
sizePresetsJSON: string(NotchSettings.Keys.terminalSizePresets, default: NotchSettings.Defaults.terminalSizePresets)
|
sizePresetsJSON: string(NotchSettings.Keys.terminalSizePresets, default: NotchSettings.Defaults.terminalSizePresets)
|
||||||
),
|
),
|
||||||
hotkeys: .init(
|
hotkeys: .init(
|
||||||
@@ -101,6 +102,7 @@ struct UserDefaultsAppSettingsStore: AppSettingsStoreType {
|
|||||||
defaults.set(settings.terminal.fontSize, forKey: NotchSettings.Keys.terminalFontSize)
|
defaults.set(settings.terminal.fontSize, forKey: NotchSettings.Keys.terminalFontSize)
|
||||||
defaults.set(settings.terminal.shellPath, forKey: NotchSettings.Keys.terminalShell)
|
defaults.set(settings.terminal.shellPath, forKey: NotchSettings.Keys.terminalShell)
|
||||||
defaults.set(settings.terminal.themeRawValue, forKey: NotchSettings.Keys.terminalTheme)
|
defaults.set(settings.terminal.themeRawValue, forKey: NotchSettings.Keys.terminalTheme)
|
||||||
|
defaults.set(settings.terminal.scrollbackLines, forKey: NotchSettings.Keys.terminalScrollbackLines)
|
||||||
defaults.set(settings.terminal.sizePresetsJSON, forKey: NotchSettings.Keys.terminalSizePresets)
|
defaults.set(settings.terminal.sizePresetsJSON, forKey: NotchSettings.Keys.terminalSizePresets)
|
||||||
|
|
||||||
defaults.set(settings.hotkeys.toggle.toJSON(), forKey: NotchSettings.Keys.hotkeyToggle)
|
defaults.set(settings.hotkeys.toggle.toJSON(), forKey: NotchSettings.Keys.hotkeyToggle)
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ enum NotchSettings {
|
|||||||
static let terminalFontSize = "terminalFontSize"
|
static let terminalFontSize = "terminalFontSize"
|
||||||
static let terminalShell = "terminalShell"
|
static let terminalShell = "terminalShell"
|
||||||
static let terminalTheme = "terminalTheme"
|
static let terminalTheme = "terminalTheme"
|
||||||
|
static let terminalScrollbackLines = "terminalScrollbackLines"
|
||||||
static let terminalSizePresets = "terminalSizePresets"
|
static let terminalSizePresets = "terminalSizePresets"
|
||||||
static let workspaceSummaries = "workspaceSummaries"
|
static let workspaceSummaries = "workspaceSummaries"
|
||||||
static let screenAssignments = "screenAssignments"
|
static let screenAssignments = "screenAssignments"
|
||||||
@@ -98,6 +99,7 @@ enum NotchSettings {
|
|||||||
static let terminalFontSize: Double = 13
|
static let terminalFontSize: Double = 13
|
||||||
static let terminalShell: String = ""
|
static let terminalShell: String = ""
|
||||||
static let terminalTheme: String = TerminalTheme.terminalApp.rawValue
|
static let terminalTheme: String = TerminalTheme.terminalApp.rawValue
|
||||||
|
static let terminalScrollbackLines: Int = 500
|
||||||
static let terminalSizePresets: String = TerminalSizePresetStore.defaultPresetsJSON()
|
static let terminalSizePresets: String = TerminalSizePresetStore.defaultPresetsJSON()
|
||||||
|
|
||||||
// Default hotkey bindings as JSON
|
// Default hotkey bindings as JSON
|
||||||
@@ -148,6 +150,7 @@ enum NotchSettings {
|
|||||||
Keys.terminalFontSize: Defaults.terminalFontSize,
|
Keys.terminalFontSize: Defaults.terminalFontSize,
|
||||||
Keys.terminalShell: Defaults.terminalShell,
|
Keys.terminalShell: Defaults.terminalShell,
|
||||||
Keys.terminalTheme: Defaults.terminalTheme,
|
Keys.terminalTheme: Defaults.terminalTheme,
|
||||||
|
Keys.terminalScrollbackLines: Defaults.terminalScrollbackLines,
|
||||||
Keys.terminalSizePresets: Defaults.terminalSizePresets,
|
Keys.terminalSizePresets: Defaults.terminalSizePresets,
|
||||||
|
|
||||||
Keys.hotkeyToggle: Defaults.hotkeyToggle,
|
Keys.hotkeyToggle: Defaults.hotkeyToggle,
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import AppKit
|
||||||
|
import CoreText
|
||||||
|
import SwiftTerm
|
||||||
|
|
||||||
|
enum TerminalScrollbackEstimator {
|
||||||
|
private static let minimumColumns = 1
|
||||||
|
private static let minimumRows = 1
|
||||||
|
private static let defaultBytesPerLineOverhead = 256
|
||||||
|
|
||||||
|
struct Estimate: Equatable {
|
||||||
|
let bytes: Int
|
||||||
|
let columns: Int
|
||||||
|
let rows: Int
|
||||||
|
|
||||||
|
var formattedBytes: String {
|
||||||
|
ByteCountFormatter.string(fromByteCount: Int64(bytes), countStyle: .memory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func estimate(
|
||||||
|
scrollbackLines: Int,
|
||||||
|
fontSize: Double,
|
||||||
|
openWidth: Double,
|
||||||
|
openHeight: Double
|
||||||
|
) -> Estimate {
|
||||||
|
let safeScrollbackLines = max(0, scrollbackLines)
|
||||||
|
let dimensions = terminalGridDimensions(
|
||||||
|
fontSize: fontSize,
|
||||||
|
openWidth: openWidth,
|
||||||
|
openHeight: openHeight
|
||||||
|
)
|
||||||
|
let totalLines = safeScrollbackLines + dimensions.rows
|
||||||
|
let bytesPerCell = MemoryLayout<CharData>.stride
|
||||||
|
let bytesPerLine = (dimensions.columns * bytesPerCell) + defaultBytesPerLineOverhead
|
||||||
|
let totalBytes = max(0, totalLines * bytesPerLine)
|
||||||
|
|
||||||
|
return Estimate(bytes: totalBytes, columns: dimensions.columns, rows: dimensions.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func terminalGridDimensions(
|
||||||
|
fontSize: Double,
|
||||||
|
openWidth: Double,
|
||||||
|
openHeight: Double
|
||||||
|
) -> (columns: Int, rows: Int) {
|
||||||
|
let font = NSFont.monospacedSystemFont(ofSize: CGFloat(max(1, fontSize)), weight: .regular)
|
||||||
|
let cellWidth = max(1, font.advancement(forGlyph: font.glyph(withName: "W")).width)
|
||||||
|
let cellHeight = max(1, ceil(CTFontGetAscent(font) + CTFontGetDescent(font) + CTFontGetLeading(font)))
|
||||||
|
|
||||||
|
let columns = max(minimumColumns, Int(CGFloat(max(1, openWidth)) / cellWidth))
|
||||||
|
let rows = max(minimumRows, Int(CGFloat(max(1, openHeight)) / cellHeight))
|
||||||
|
|
||||||
|
return (columns, rows)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,58 @@ import AppKit
|
|||||||
import SwiftTerm
|
import SwiftTerm
|
||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
|
/// Tracks whether the terminal viewport should follow live output or preserve
|
||||||
|
/// the user's current scrollback position.
|
||||||
|
final class TerminalScrollCoordinator {
|
||||||
|
private let bottomThreshold: Double
|
||||||
|
private var suppressScrollTracking = false
|
||||||
|
|
||||||
|
private(set) var followsOutput = true
|
||||||
|
private(set) var preservedScrollPosition: Double = 1
|
||||||
|
|
||||||
|
init(bottomThreshold: Double = 0.999) {
|
||||||
|
self.bottomThreshold = bottomThreshold
|
||||||
|
}
|
||||||
|
|
||||||
|
func terminalDidScroll(to position: Double, canScroll: Bool) {
|
||||||
|
guard !suppressScrollTracking else { return }
|
||||||
|
|
||||||
|
guard canScroll else {
|
||||||
|
followsOutput = true
|
||||||
|
preservedScrollPosition = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let clampedPosition = min(max(position, 0), 1)
|
||||||
|
if clampedPosition >= bottomThreshold {
|
||||||
|
followsOutput = true
|
||||||
|
preservedScrollPosition = 1
|
||||||
|
} else {
|
||||||
|
followsOutput = false
|
||||||
|
preservedScrollPosition = clampedPosition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func outputRestorePosition(canScroll: Bool) -> Double? {
|
||||||
|
guard canScroll, !followsOutput else { return nil }
|
||||||
|
return preservedScrollPosition
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
func userDidStartTyping() -> Bool {
|
||||||
|
let shouldJumpToBottom = !followsOutput
|
||||||
|
followsOutput = true
|
||||||
|
preservedScrollPosition = 1
|
||||||
|
return shouldJumpToBottom
|
||||||
|
}
|
||||||
|
|
||||||
|
func suppressTracking<T>(_ body: () -> T) -> T {
|
||||||
|
suppressScrollTracking = true
|
||||||
|
defer { suppressScrollTracking = false }
|
||||||
|
return body()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Wraps a single SwiftTerm TerminalView + LocalProcess pair.
|
/// Wraps a single SwiftTerm TerminalView + LocalProcess pair.
|
||||||
@MainActor
|
@MainActor
|
||||||
class TerminalSession: NSObject, ObservableObject, LocalProcessDelegate, @preconcurrency TerminalViewDelegate {
|
class TerminalSession: NSObject, ObservableObject, LocalProcessDelegate, @preconcurrency TerminalViewDelegate {
|
||||||
@@ -12,7 +64,9 @@ class TerminalSession: NSObject, ObservableObject, LocalProcessDelegate, @precon
|
|||||||
private var keyEventMonitor: Any?
|
private var keyEventMonitor: Any?
|
||||||
private let backgroundColor = NSColor.black
|
private let backgroundColor = NSColor.black
|
||||||
private let configuredShellPath: String
|
private let configuredShellPath: String
|
||||||
|
private var scrollbackLines: Int
|
||||||
private let launchDirectory: String
|
private let launchDirectory: String
|
||||||
|
private let scrollCoordinator = TerminalScrollCoordinator()
|
||||||
|
|
||||||
@Published var title: String = "shell"
|
@Published var title: String = "shell"
|
||||||
@Published var isRunning: Bool = true
|
@Published var isRunning: Bool = true
|
||||||
@@ -22,11 +76,13 @@ class TerminalSession: NSObject, ObservableObject, LocalProcessDelegate, @precon
|
|||||||
fontSize: CGFloat,
|
fontSize: CGFloat,
|
||||||
theme: TerminalTheme,
|
theme: TerminalTheme,
|
||||||
shellPath: String,
|
shellPath: String,
|
||||||
|
scrollbackLines: Int,
|
||||||
initialDirectory: String? = nil,
|
initialDirectory: String? = nil,
|
||||||
startImmediately: Bool = true
|
startImmediately: Bool = true
|
||||||
) {
|
) {
|
||||||
terminalView = TerminalView(frame: NSRect(x: 0, y: 0, width: 600, height: 300))
|
terminalView = TerminalView(frame: NSRect(x: 0, y: 0, width: 600, height: 300))
|
||||||
configuredShellPath = shellPath
|
configuredShellPath = shellPath
|
||||||
|
self.scrollbackLines = max(0, scrollbackLines)
|
||||||
launchDirectory = Self.resolveInitialDirectory(initialDirectory)
|
launchDirectory = Self.resolveInitialDirectory(initialDirectory)
|
||||||
currentDirectory = launchDirectory
|
currentDirectory = launchDirectory
|
||||||
super.init()
|
super.init()
|
||||||
@@ -36,6 +92,7 @@ class TerminalSession: NSObject, ObservableObject, LocalProcessDelegate, @precon
|
|||||||
let font = NSFont.monospacedSystemFont(ofSize: fontSize, weight: .regular)
|
let font = NSFont.monospacedSystemFont(ofSize: fontSize, weight: .regular)
|
||||||
terminalView.font = font
|
terminalView.font = font
|
||||||
applyTheme(theme)
|
applyTheme(theme)
|
||||||
|
updateScrollbackLines(self.scrollbackLines)
|
||||||
installCommandArrowMonitor()
|
installCommandArrowMonitor()
|
||||||
|
|
||||||
if startImmediately {
|
if startImmediately {
|
||||||
@@ -128,6 +185,12 @@ class TerminalSession: NSObject, ObservableObject, LocalProcessDelegate, @precon
|
|||||||
terminalView.installColors(theme.ansiColors)
|
terminalView.installColors(theme.ansiColors)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateScrollbackLines(_ scrollbackLines: Int) {
|
||||||
|
let sanitizedScrollbackLines = max(0, scrollbackLines)
|
||||||
|
self.scrollbackLines = sanitizedScrollbackLines
|
||||||
|
terminalView.getTerminal().changeHistorySize(sanitizedScrollbackLines)
|
||||||
|
}
|
||||||
|
|
||||||
func terminate() {
|
func terminate() {
|
||||||
process?.terminate()
|
process?.terminate()
|
||||||
process = nil
|
process = nil
|
||||||
@@ -142,7 +205,16 @@ class TerminalSession: NSObject, ObservableObject, LocalProcessDelegate, @precon
|
|||||||
|
|
||||||
nonisolated func dataReceived(slice: ArraySlice<UInt8>) {
|
nonisolated func dataReceived(slice: ArraySlice<UInt8>) {
|
||||||
let data = slice
|
let data = slice
|
||||||
Task { @MainActor in self.terminalView.feed(byteArray: data) }
|
Task { @MainActor in
|
||||||
|
if let restorePosition = self.scrollCoordinator.outputRestorePosition(canScroll: self.terminalView.canScroll) {
|
||||||
|
self.scrollCoordinator.suppressTracking {
|
||||||
|
self.terminalView.feed(byteArray: data)
|
||||||
|
self.terminalView.scroll(toPosition: restorePosition)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.terminalView.feed(byteArray: data)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nonisolated func getWindowSize() -> winsize {
|
nonisolated func getWindowSize() -> winsize {
|
||||||
@@ -155,6 +227,9 @@ class TerminalSession: NSObject, ObservableObject, LocalProcessDelegate, @precon
|
|||||||
// MARK: - TerminalViewDelegate
|
// MARK: - TerminalViewDelegate
|
||||||
|
|
||||||
func send(source: TerminalView, data: ArraySlice<UInt8>) {
|
func send(source: TerminalView, data: ArraySlice<UInt8>) {
|
||||||
|
if scrollCoordinator.userDidStartTyping() {
|
||||||
|
terminalView.scroll(toPosition: 1)
|
||||||
|
}
|
||||||
process?.send(data: data)
|
process?.send(data: data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +254,9 @@ class TerminalSession: NSObject, ObservableObject, LocalProcessDelegate, @precon
|
|||||||
currentDirectory = normalizedDirectory
|
currentDirectory = normalizedDirectory
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrolled(source: TerminalView, position: Double) {}
|
func scrolled(source: TerminalView, position: Double) {
|
||||||
|
scrollCoordinator.terminalDidScroll(to: position, canScroll: source.canScroll)
|
||||||
|
}
|
||||||
func rangeChanged(source: TerminalView, startY: Int, endY: Int) {}
|
func rangeChanged(source: TerminalView, startY: Int, endY: Int) {}
|
||||||
|
|
||||||
func clipboardCopy(source: TerminalView, content: Data) {
|
func clipboardCopy(source: TerminalView, content: Data) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ protocol TerminalSessionFactoryType {
|
|||||||
fontSize: CGFloat,
|
fontSize: CGFloat,
|
||||||
theme: TerminalTheme,
|
theme: TerminalTheme,
|
||||||
shellPath: String,
|
shellPath: String,
|
||||||
|
scrollbackLines: Int,
|
||||||
initialDirectory: String?
|
initialDirectory: String?
|
||||||
) -> TerminalSession
|
) -> TerminalSession
|
||||||
}
|
}
|
||||||
@@ -16,12 +17,14 @@ struct LiveTerminalSessionFactory: TerminalSessionFactoryType {
|
|||||||
fontSize: CGFloat,
|
fontSize: CGFloat,
|
||||||
theme: TerminalTheme,
|
theme: TerminalTheme,
|
||||||
shellPath: String,
|
shellPath: String,
|
||||||
|
scrollbackLines: Int,
|
||||||
initialDirectory: String?
|
initialDirectory: String?
|
||||||
) -> TerminalSession {
|
) -> TerminalSession {
|
||||||
TerminalSession(
|
TerminalSession(
|
||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
shellPath: shellPath,
|
shellPath: shellPath,
|
||||||
|
scrollbackLines: scrollbackLines,
|
||||||
initialDirectory: initialDirectory
|
initialDirectory: initialDirectory
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -106,6 +109,7 @@ final class WorkspaceController: ObservableObject {
|
|||||||
fontSize: config.fontSize,
|
fontSize: config.fontSize,
|
||||||
theme: config.theme,
|
theme: config.theme,
|
||||||
shellPath: config.shellPath,
|
shellPath: config.shellPath,
|
||||||
|
scrollbackLines: config.scrollbackLines,
|
||||||
initialDirectory: activeTab?.currentDirectory
|
initialDirectory: activeTab?.currentDirectory
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -187,4 +191,10 @@ final class WorkspaceController: ObservableObject {
|
|||||||
tab.applyTheme(theme)
|
tab.applyTheme(theme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateAllScrollbackLines(_ scrollbackLines: Int) {
|
||||||
|
for tab in tabs {
|
||||||
|
tab.updateScrollbackLines(scrollbackLines)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,6 +157,12 @@ final class WorkspaceRegistry: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateAllWorkspacesScrollbackLines(_ scrollbackLines: Int) {
|
||||||
|
for controller in controllers.values {
|
||||||
|
controller.updateAllScrollbackLines(scrollbackLines)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func resolvedWorkspaceName(from proposedName: String?) -> String {
|
private func resolvedWorkspaceName(from proposedName: String?) -> String {
|
||||||
let trimmed = proposedName?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
let trimmed = proposedName?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
||||||
if !trimmed.isEmpty {
|
if !trimmed.isEmpty {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct TerminalSettingsView: View {
|
struct TerminalSettingsView: View {
|
||||||
|
private static let scrollbackRange = 0...1_000_000
|
||||||
|
|
||||||
@ObservedObject private var settingsController = AppSettingsController.shared
|
@ObservedObject private var settingsController = AppSettingsController.shared
|
||||||
@State private var sizePresets: [TerminalSizePreset] = []
|
@State private var sizePresets: [TerminalSizePreset] = []
|
||||||
|
|
||||||
@@ -40,6 +42,34 @@ struct TerminalSettingsView: View {
|
|||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Section("Scrollback") {
|
||||||
|
HStack {
|
||||||
|
Text("Lines")
|
||||||
|
Spacer()
|
||||||
|
TextField(
|
||||||
|
"Scrollback lines",
|
||||||
|
value: scrollbackBinding,
|
||||||
|
format: .number.grouping(.automatic)
|
||||||
|
)
|
||||||
|
.textFieldStyle(.roundedBorder)
|
||||||
|
.frame(width: 140)
|
||||||
|
}
|
||||||
|
|
||||||
|
Stepper(
|
||||||
|
value: scrollbackBinding,
|
||||||
|
in: Self.scrollbackRange,
|
||||||
|
step: scrollbackStepSize
|
||||||
|
) {
|
||||||
|
Text("\(settingsController.settings.terminal.scrollbackLines.formatted()) lines")
|
||||||
|
.monospacedDigit()
|
||||||
|
}
|
||||||
|
|
||||||
|
let estimate = scrollbackEstimate
|
||||||
|
Text("Based on the current terminal size, this may use ~\(estimate.formattedBytes) of RAM (\(estimate.columns) columns x \(estimate.rows) rows visible).")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
|
||||||
Section("Size Presets") {
|
Section("Size Presets") {
|
||||||
ForEach($sizePresets) { $preset in
|
ForEach($sizePresets) { $preset in
|
||||||
TerminalSizePresetEditor(
|
TerminalSizePresetEditor(
|
||||||
@@ -94,6 +124,39 @@ struct TerminalSettingsView: View {
|
|||||||
sizePresets.removeAll { $0.id == id }
|
sizePresets.removeAll { $0.id == id }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var scrollbackBinding: Binding<Int> {
|
||||||
|
Binding(
|
||||||
|
get: { settingsController.settings.terminal.scrollbackLines },
|
||||||
|
set: { newValue in
|
||||||
|
let clampedValue = min(max(Self.scrollbackRange.lowerBound, newValue), Self.scrollbackRange.upperBound)
|
||||||
|
settingsController.update {
|
||||||
|
$0.terminal.scrollbackLines = clampedValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var scrollbackEstimate: TerminalScrollbackEstimator.Estimate {
|
||||||
|
TerminalScrollbackEstimator.estimate(
|
||||||
|
scrollbackLines: settingsController.settings.terminal.scrollbackLines,
|
||||||
|
fontSize: settingsController.settings.terminal.fontSize,
|
||||||
|
openWidth: settingsController.settings.display.openWidth,
|
||||||
|
openHeight: settingsController.settings.display.openHeight
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var scrollbackStepSize: Int {
|
||||||
|
let lines = settingsController.settings.terminal.scrollbackLines
|
||||||
|
switch lines {
|
||||||
|
case ..<10_000:
|
||||||
|
return 500
|
||||||
|
case ..<100_000:
|
||||||
|
return 5_000
|
||||||
|
default:
|
||||||
|
return 10_000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func applyPreset(_ preset: TerminalSizePreset) {
|
private func applyPreset(_ preset: TerminalSizePreset) {
|
||||||
settingsController.update {
|
settingsController.update {
|
||||||
$0.display.openWidth = preset.width
|
$0.display.openWidth = preset.width
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ final class AppSettingsControllerTests: XCTestCase {
|
|||||||
let store = InMemoryAppSettingsStore()
|
let store = InMemoryAppSettingsStore()
|
||||||
var settings = AppSettings.default
|
var settings = AppSettings.default
|
||||||
settings.terminal.shellPath = "/opt/homebrew/bin/fish"
|
settings.terminal.shellPath = "/opt/homebrew/bin/fish"
|
||||||
|
settings.terminal.scrollbackLines = 12_000
|
||||||
store.storedSettings = settings
|
store.storedSettings = settings
|
||||||
|
|
||||||
let controller = AppSettingsController(store: store)
|
let controller = AppSettingsController(store: store)
|
||||||
|
|
||||||
XCTAssertEqual(controller.terminalSessionConfiguration.shellPath, "/opt/homebrew/bin/fish")
|
XCTAssertEqual(controller.terminalSessionConfiguration.shellPath, "/opt/homebrew/bin/fish")
|
||||||
|
XCTAssertEqual(controller.terminalSessionConfiguration.scrollbackLines, 12_000)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testTerminalSizePresetsDecodeFromTypedSettings() {
|
func testTerminalSizePresetsDecodeFromTypedSettings() {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ final class AppSettingsStoreTests: XCTestCase {
|
|||||||
settings.appearance.blurRadius = 4.5
|
settings.appearance.blurRadius = 4.5
|
||||||
settings.terminal.fontSize = 16
|
settings.terminal.fontSize = 16
|
||||||
settings.terminal.themeRawValue = TerminalTheme.dracula.rawValue
|
settings.terminal.themeRawValue = TerminalTheme.dracula.rawValue
|
||||||
|
settings.terminal.scrollbackLines = 25_000
|
||||||
settings.terminal.sizePresetsJSON = TerminalSizePresetStore.encodePresets([
|
settings.terminal.sizePresetsJSON = TerminalSizePresetStore.encodePresets([
|
||||||
TerminalSizePreset(name: "Wide", width: 960, height: 420, hotkey: .cmdShiftDigit(4))
|
TerminalSizePreset(name: "Wide", width: 960, height: 420, hotkey: .cmdShiftDigit(4))
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -306,7 +306,7 @@ private final class TestAppSettingsStore: AppSettingsStoreType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final class ScreenRegistryTestSettingsProvider: TerminalSessionConfigurationProviding {
|
private final class ScreenRegistryTestSettingsProvider: TerminalSessionConfigurationProviding {
|
||||||
let terminalSessionConfiguration = TerminalSessionConfiguration(fontSize: 13, theme: .terminalApp, shellPath: "")
|
let terminalSessionConfiguration = TerminalSessionConfiguration(fontSize: 13, theme: .terminalApp, shellPath: "", scrollbackLines: 500)
|
||||||
let hotkeySettings = AppSettings.default.hotkeys
|
let hotkeySettings = AppSettings.default.hotkeys
|
||||||
let terminalSizePresets = TerminalSizePresetStore.loadDefaults()
|
let terminalSizePresets = TerminalSizePresetStore.loadDefaults()
|
||||||
}
|
}
|
||||||
@@ -317,6 +317,7 @@ private struct ScreenRegistryUnusedTerminalSessionFactory: TerminalSessionFactor
|
|||||||
fontSize: CGFloat,
|
fontSize: CGFloat,
|
||||||
theme: TerminalTheme,
|
theme: TerminalTheme,
|
||||||
shellPath: String,
|
shellPath: String,
|
||||||
|
scrollbackLines: Int,
|
||||||
initialDirectory: String?
|
initialDirectory: String?
|
||||||
) -> TerminalSession {
|
) -> TerminalSession {
|
||||||
fatalError("ScreenRegistryTests should not create live terminal sessions.")
|
fatalError("ScreenRegistryTests should not create live terminal sessions.")
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import XCTest
|
||||||
|
@testable import CommandNotch
|
||||||
|
|
||||||
|
final class TerminalScrollCoordinatorTests: XCTestCase {
|
||||||
|
func testScrollAwayFromBottomDisablesOutputFollow() {
|
||||||
|
let coordinator = TerminalScrollCoordinator()
|
||||||
|
|
||||||
|
coordinator.terminalDidScroll(to: 0.42, canScroll: true)
|
||||||
|
|
||||||
|
XCTAssertFalse(coordinator.followsOutput)
|
||||||
|
XCTAssertEqual(coordinator.outputRestorePosition(canScroll: true) ?? .nan, 0.42, accuracy: 0.0001)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testTypingReEnablesFollowAndRequestsJumpToBottom() {
|
||||||
|
let coordinator = TerminalScrollCoordinator()
|
||||||
|
coordinator.terminalDidScroll(to: 0.42, canScroll: true)
|
||||||
|
|
||||||
|
let shouldJump = coordinator.userDidStartTyping()
|
||||||
|
|
||||||
|
XCTAssertTrue(shouldJump)
|
||||||
|
XCTAssertTrue(coordinator.followsOutput)
|
||||||
|
XCTAssertNil(coordinator.outputRestorePosition(canScroll: true))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testScrollingBackToBottomReEnablesOutputFollow() {
|
||||||
|
let coordinator = TerminalScrollCoordinator()
|
||||||
|
coordinator.terminalDidScroll(to: 0.42, canScroll: true)
|
||||||
|
|
||||||
|
coordinator.terminalDidScroll(to: 1, canScroll: true)
|
||||||
|
|
||||||
|
XCTAssertTrue(coordinator.followsOutput)
|
||||||
|
XCTAssertNil(coordinator.outputRestorePosition(canScroll: true))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSuppressedTrackingIgnoresProgrammaticScrollUpdates() {
|
||||||
|
let coordinator = TerminalScrollCoordinator()
|
||||||
|
coordinator.terminalDidScroll(to: 0.42, canScroll: true)
|
||||||
|
|
||||||
|
coordinator.suppressTracking {
|
||||||
|
coordinator.terminalDidScroll(to: 1, canScroll: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
XCTAssertFalse(coordinator.followsOutput)
|
||||||
|
XCTAssertEqual(coordinator.outputRestorePosition(canScroll: true) ?? .nan, 0.42, accuracy: 0.0001)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import XCTest
|
||||||
|
@testable import CommandNotch
|
||||||
|
|
||||||
|
final class TerminalScrollbackEstimatorTests: XCTestCase {
|
||||||
|
func testEstimateIncreasesAsScrollbackGrows() {
|
||||||
|
let small = TerminalScrollbackEstimator.estimate(
|
||||||
|
scrollbackLines: 5_000,
|
||||||
|
fontSize: 13,
|
||||||
|
openWidth: 640,
|
||||||
|
openHeight: 350
|
||||||
|
)
|
||||||
|
let large = TerminalScrollbackEstimator.estimate(
|
||||||
|
scrollbackLines: 100_000,
|
||||||
|
fontSize: 13,
|
||||||
|
openWidth: 640,
|
||||||
|
openHeight: 350
|
||||||
|
)
|
||||||
|
|
||||||
|
XCTAssertGreaterThan(large.bytes, small.bytes)
|
||||||
|
XCTAssertGreaterThan(large.columns, 0)
|
||||||
|
XCTAssertGreaterThan(large.rows, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEstimateClampsNegativeScrollbackToZero() {
|
||||||
|
let estimate = TerminalScrollbackEstimator.estimate(
|
||||||
|
scrollbackLines: -1_000,
|
||||||
|
fontSize: 13,
|
||||||
|
openWidth: 640,
|
||||||
|
openHeight: 350
|
||||||
|
)
|
||||||
|
|
||||||
|
XCTAssertGreaterThan(estimate.bytes, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -191,7 +191,7 @@ private final class InMemoryWorkspaceStore: WorkspaceStoreType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final class TestSettingsProvider: TerminalSessionConfigurationProviding {
|
private final class TestSettingsProvider: TerminalSessionConfigurationProviding {
|
||||||
let terminalSessionConfiguration = TerminalSessionConfiguration(fontSize: 13, theme: .terminalApp, shellPath: "")
|
let terminalSessionConfiguration = TerminalSessionConfiguration(fontSize: 13, theme: .terminalApp, shellPath: "", scrollbackLines: 500)
|
||||||
let hotkeySettings = AppSettings.default.hotkeys
|
let hotkeySettings = AppSettings.default.hotkeys
|
||||||
let terminalSizePresets = TerminalSizePresetStore.loadDefaults()
|
let terminalSizePresets = TerminalSizePresetStore.loadDefaults()
|
||||||
}
|
}
|
||||||
@@ -204,6 +204,7 @@ private final class RecordingTerminalSessionFactory: TerminalSessionFactoryType
|
|||||||
fontSize: CGFloat,
|
fontSize: CGFloat,
|
||||||
theme: TerminalTheme,
|
theme: TerminalTheme,
|
||||||
shellPath: String,
|
shellPath: String,
|
||||||
|
scrollbackLines: Int,
|
||||||
initialDirectory: String?
|
initialDirectory: String?
|
||||||
) -> TerminalSession {
|
) -> TerminalSession {
|
||||||
requestedDirectories.append(initialDirectory)
|
requestedDirectories.append(initialDirectory)
|
||||||
@@ -211,6 +212,7 @@ private final class RecordingTerminalSessionFactory: TerminalSessionFactoryType
|
|||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
shellPath: shellPath,
|
shellPath: shellPath,
|
||||||
|
scrollbackLines: scrollbackLines,
|
||||||
initialDirectory: initialDirectory,
|
initialDirectory: initialDirectory,
|
||||||
startImmediately: false
|
startImmediately: false
|
||||||
)
|
)
|
||||||
@@ -223,6 +225,7 @@ private struct UnusedTerminalSessionFactory: TerminalSessionFactoryType {
|
|||||||
fontSize: CGFloat,
|
fontSize: CGFloat,
|
||||||
theme: TerminalTheme,
|
theme: TerminalTheme,
|
||||||
shellPath: String,
|
shellPath: String,
|
||||||
|
scrollbackLines: Int,
|
||||||
initialDirectory: String?
|
initialDirectory: String?
|
||||||
) -> TerminalSession {
|
) -> TerminalSession {
|
||||||
fatalError("WorkspaceRegistryTests should not create live terminal sessions.")
|
fatalError("WorkspaceRegistryTests should not create live terminal sessions.")
|
||||||
|
|||||||
Reference in New Issue
Block a user