Fix command modified keys. Add plan for splitscreen
This commit is contained in:
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "2620"
|
||||
LastUpgradeVersion = "1600"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
buildArchitectures = "Automatic">
|
||||
runPostActionsOnFailure = "NO">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
@@ -15,7 +15,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1485207FA11756EC2DF4F08B"
|
||||
BlueprintIdentifier = "D5585E5732CD067DF6EF0C69"
|
||||
BuildableName = "CommandNotch.app"
|
||||
BlueprintName = "CommandNotch"
|
||||
ReferencedContainer = "container:CommandNotch.xcodeproj">
|
||||
@@ -28,7 +28,42 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
onlyGenerateCoverageForSpecifiedTargets = "NO">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D5585E5732CD067DF6EF0C69"
|
||||
BuildableName = "CommandNotch.app"
|
||||
BlueprintName = "CommandNotch"
|
||||
ReferencedContainer = "container:CommandNotch.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "036FDAECD12C0A679DA1F5D6"
|
||||
BuildableName = "CommandNotchTests.xctest"
|
||||
BlueprintName = "CommandNotchTests"
|
||||
ReferencedContainer = "container:CommandNotch.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1C8D00CBB29219BD347E9CC4"
|
||||
BuildableName = "CommandNotchUITests.xctest"
|
||||
BlueprintName = "CommandNotchUITests"
|
||||
ReferencedContainer = "container:CommandNotch.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -44,12 +79,14 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1485207FA11756EC2DF4F08B"
|
||||
BlueprintIdentifier = "D5585E5732CD067DF6EF0C69"
|
||||
BuildableName = "CommandNotch.app"
|
||||
BlueprintName = "CommandNotch"
|
||||
ReferencedContainer = "container:CommandNotch.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
@@ -61,12 +98,14 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1485207FA11756EC2DF4F08B"
|
||||
BlueprintIdentifier = "D5585E5732CD067DF6EF0C69"
|
||||
BuildableName = "CommandNotch.app"
|
||||
BlueprintName = "CommandNotch"
|
||||
ReferencedContainer = "container:CommandNotch.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "2620"
|
||||
LastUpgradeVersion = "1600"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
buildArchitectures = "Automatic">
|
||||
runPostActionsOnFailure = "NO">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
@@ -15,7 +15,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1485207FA11756EC2DF4F08B"
|
||||
BlueprintIdentifier = "D5585E5732CD067DF6EF0C69"
|
||||
BuildableName = "CommandNotch.app"
|
||||
BlueprintName = "CommandNotch"
|
||||
ReferencedContainer = "container:CommandNotch.xcodeproj">
|
||||
@@ -28,13 +28,48 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
onlyGenerateCoverageForSpecifiedTargets = "NO">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D5585E5732CD067DF6EF0C69"
|
||||
BuildableName = "CommandNotch.app"
|
||||
BlueprintName = "CommandNotch"
|
||||
ReferencedContainer = "container:CommandNotch.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "036FDAECD12C0A679DA1F5D6"
|
||||
BuildableName = "CommandNotchTests.xctest"
|
||||
BlueprintName = "CommandNotchTests"
|
||||
ReferencedContainer = "container:CommandNotch.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1C8D00CBB29219BD347E9CC4"
|
||||
BuildableName = "CommandNotchUITests.xctest"
|
||||
BlueprintName = "CommandNotchUITests"
|
||||
ReferencedContainer = "container:CommandNotch.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = ""
|
||||
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||
launchStyle = "1"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
@@ -44,12 +79,14 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1485207FA11756EC2DF4F08B"
|
||||
BlueprintIdentifier = "D5585E5732CD067DF6EF0C69"
|
||||
BuildableName = "CommandNotch.app"
|
||||
BlueprintName = "CommandNotch"
|
||||
ReferencedContainer = "container:CommandNotch.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
@@ -61,12 +98,14 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1485207FA11756EC2DF4F08B"
|
||||
BlueprintIdentifier = "D5585E5732CD067DF6EF0C69"
|
||||
BuildableName = "CommandNotch.app"
|
||||
BlueprintName = "CommandNotch"
|
||||
ReferencedContainer = "container:CommandNotch.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import AppKit
|
||||
import Carbon.HIToolbox
|
||||
import SwiftTerm
|
||||
|
||||
enum TerminalCommandArrowBehavior {
|
||||
private static let relevantModifiers: NSEvent.ModifierFlags = [.command, .control, .option, .shift]
|
||||
private static let lineKill: [UInt8] = [0x15]
|
||||
private static let clearScreen: [UInt8] = [0x0c]
|
||||
|
||||
static func sequence(
|
||||
for modifierFlags: NSEvent.ModifierFlags,
|
||||
keyCode: UInt16,
|
||||
applicationCursor: Bool
|
||||
) -> [UInt8]? {
|
||||
let flags = modifierFlags.intersection(relevantModifiers)
|
||||
guard flags == [.command] else { return nil }
|
||||
|
||||
switch Int(keyCode) {
|
||||
case kVK_LeftArrow:
|
||||
return applicationCursor ? EscapeSequences.moveHomeApp : EscapeSequences.moveHomeNormal
|
||||
case kVK_RightArrow:
|
||||
return applicationCursor ? EscapeSequences.moveEndApp : EscapeSequences.moveEndNormal
|
||||
case kVK_Delete:
|
||||
return lineKill
|
||||
case kVK_ANSI_L:
|
||||
return clearScreen
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ class TerminalSession: NSObject, ObservableObject, LocalProcessDelegate, @precon
|
||||
let id = UUID()
|
||||
let terminalView: TerminalView
|
||||
private var process: LocalProcess?
|
||||
private var keyEventMonitor: Any?
|
||||
private let backgroundColor = NSColor.black
|
||||
private let configuredShellPath: String
|
||||
|
||||
@@ -26,10 +27,17 @@ class TerminalSession: NSObject, ObservableObject, LocalProcessDelegate, @precon
|
||||
let font = NSFont.monospacedSystemFont(ofSize: fontSize, weight: .regular)
|
||||
terminalView.font = font
|
||||
applyTheme(theme)
|
||||
installCommandArrowMonitor()
|
||||
|
||||
startShell()
|
||||
}
|
||||
|
||||
deinit {
|
||||
if let keyEventMonitor {
|
||||
NSEvent.removeMonitor(keyEventMonitor)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Shell management
|
||||
|
||||
private func startShell() {
|
||||
@@ -58,6 +66,26 @@ class TerminalSession: NSObject, ObservableObject, LocalProcessDelegate, @precon
|
||||
return ProcessInfo.processInfo.environment["SHELL"] ?? "/bin/zsh"
|
||||
}
|
||||
|
||||
private func installCommandArrowMonitor() {
|
||||
keyEventMonitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { [weak self] event in
|
||||
guard let self else { return event }
|
||||
guard let window = self.terminalView.window else { return event }
|
||||
guard event.window === window else { return event }
|
||||
guard window.firstResponder === self.terminalView else { return event }
|
||||
|
||||
guard let sequence = TerminalCommandArrowBehavior.sequence(
|
||||
for: event.modifierFlags,
|
||||
keyCode: event.keyCode,
|
||||
applicationCursor: self.terminalView.getTerminal().applicationCursor
|
||||
) else {
|
||||
return event
|
||||
}
|
||||
|
||||
self.terminalView.send(data: sequence[...])
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func updateFontSize(_ size: CGFloat) {
|
||||
terminalView.font = NSFont.monospacedSystemFont(ofSize: size, weight: .regular)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import AppKit
|
||||
import Carbon.HIToolbox
|
||||
import XCTest
|
||||
import SwiftTerm
|
||||
@testable import CommandNotch
|
||||
|
||||
final class TerminalCommandArrowBehaviorTests: XCTestCase {
|
||||
func testCommandLeftUsesHomeSequence() {
|
||||
let sequence = TerminalCommandArrowBehavior.sequence(
|
||||
for: [.command],
|
||||
keyCode: UInt16(kVK_LeftArrow),
|
||||
applicationCursor: false
|
||||
)
|
||||
|
||||
XCTAssertEqual(sequence, EscapeSequences.moveHomeNormal)
|
||||
}
|
||||
|
||||
func testCommandRightUsesApplicationEndSequence() {
|
||||
let sequence = TerminalCommandArrowBehavior.sequence(
|
||||
for: [.command],
|
||||
keyCode: UInt16(kVK_RightArrow),
|
||||
applicationCursor: true
|
||||
)
|
||||
|
||||
XCTAssertEqual(sequence, EscapeSequences.moveEndApp)
|
||||
}
|
||||
|
||||
func testOptionLeftKeepsSwiftTermWordNavigationPath() {
|
||||
let sequence = TerminalCommandArrowBehavior.sequence(
|
||||
for: [.option],
|
||||
keyCode: UInt16(kVK_LeftArrow),
|
||||
applicationCursor: false
|
||||
)
|
||||
|
||||
XCTAssertNil(sequence)
|
||||
}
|
||||
|
||||
func testCommandDeleteUsesLineKillSequence() {
|
||||
let sequence = TerminalCommandArrowBehavior.sequence(
|
||||
for: [.command],
|
||||
keyCode: UInt16(kVK_Delete),
|
||||
applicationCursor: false
|
||||
)
|
||||
|
||||
XCTAssertEqual(sequence, [0x15])
|
||||
}
|
||||
|
||||
func testCommandLUsesClearScreenSequence() {
|
||||
let sequence = TerminalCommandArrowBehavior.sequence(
|
||||
for: [.command],
|
||||
keyCode: UInt16(kVK_ANSI_L),
|
||||
applicationCursor: false
|
||||
)
|
||||
|
||||
XCTAssertEqual(sequence, [0x0c])
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,45 @@ packages:
|
||||
SwiftTerm:
|
||||
url: https://github.com/migueldeicaza/SwiftTerm.git
|
||||
from: "1.2.0"
|
||||
schemes:
|
||||
CommandNotch:
|
||||
build:
|
||||
targets:
|
||||
CommandNotch: all
|
||||
test:
|
||||
config: Debug
|
||||
targets:
|
||||
- CommandNotchTests
|
||||
- CommandNotchUITests
|
||||
run:
|
||||
config: Debug
|
||||
profile:
|
||||
config: Release
|
||||
analyze:
|
||||
config: Debug
|
||||
archive:
|
||||
config: Release
|
||||
management:
|
||||
shared: true
|
||||
Release-CommandNotch:
|
||||
build:
|
||||
targets:
|
||||
CommandNotch: all
|
||||
test:
|
||||
config: Debug
|
||||
targets:
|
||||
- CommandNotchTests
|
||||
- CommandNotchUITests
|
||||
run:
|
||||
config: Release
|
||||
profile:
|
||||
config: Release
|
||||
analyze:
|
||||
config: Debug
|
||||
archive:
|
||||
config: Release
|
||||
management:
|
||||
shared: true
|
||||
targets:
|
||||
CommandNotch:
|
||||
type: application
|
||||
@@ -29,9 +68,9 @@ targets:
|
||||
properties:
|
||||
CFBundleName: CommandNotch
|
||||
CFBundleDisplayName: CommandNotch
|
||||
CFBundleIdentifier: com.commandnotch.app
|
||||
CFBundleIdentifier: "$(PRODUCT_BUNDLE_IDENTIFIER)"
|
||||
CFBundleVersion: "1"
|
||||
CFBundleShortVersionString: "0.2.0"
|
||||
CFBundleShortVersionString: "0.0.3"
|
||||
CFBundlePackageType: APPL
|
||||
CFBundleExecutable: CommandNotch
|
||||
LSMinimumSystemVersion: "14.0"
|
||||
|
||||
Reference in New Issue
Block a user