mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
macos: making the surface state get passed down...
This commit is contained in:
@ -15,6 +15,9 @@ struct TerminalSurface: NSViewRepresentable {
|
|||||||
category: String(describing: TerminalSurfaceView.self)
|
category: String(describing: TerminalSurfaceView.self)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/// The view to render for the terminal surface.
|
||||||
|
let view: TerminalSurfaceView
|
||||||
|
|
||||||
/// This should be set to true wen the surface has focus. This is up to the parent because
|
/// This should be set to true wen the surface has focus. This is up to the parent because
|
||||||
/// focus is also defined by window focus. It is important this is set correctly since if it is
|
/// focus is also defined by window focus. It is important this is set correctly since if it is
|
||||||
/// false then the surface will idle at almost 0% CPU.
|
/// false then the surface will idle at almost 0% CPU.
|
||||||
@ -34,27 +37,18 @@ struct TerminalSurface: NSViewRepresentable {
|
|||||||
/// set the appropriate title of the window/tab/split/etc. if they care.
|
/// set the appropriate title of the window/tab/split/etc. if they care.
|
||||||
@Binding var title: String
|
@Binding var title: String
|
||||||
|
|
||||||
@StateObject private var state: TerminalSurfaceView
|
|
||||||
|
|
||||||
init(_ app: ghostty_app_t, hasFocus: Bool, size: CGSize, title: Binding<String>) {
|
|
||||||
self._state = StateObject(wrappedValue: TerminalSurfaceView(app))
|
|
||||||
self._title = title
|
|
||||||
self.hasFocus = hasFocus
|
|
||||||
self.size = size
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeNSView(context: Context) -> TerminalSurfaceView {
|
func makeNSView(context: Context) -> TerminalSurfaceView {
|
||||||
// We need the view as part of the state to be created previously because
|
// We need the view as part of the state to be created previously because
|
||||||
// the view is sent to the Ghostty API so that it can manipulate it
|
// the view is sent to the Ghostty API so that it can manipulate it
|
||||||
// directly since we draw on a render thread.
|
// directly since we draw on a render thread.
|
||||||
state.delegate = context.coordinator
|
view.delegate = context.coordinator
|
||||||
return state;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNSView(_ view: TerminalSurfaceView, context: Context) {
|
func updateNSView(_ view: TerminalSurfaceView, context: Context) {
|
||||||
state.delegate = context.coordinator
|
view.delegate = context.coordinator
|
||||||
state.focusDidChange(hasFocus)
|
view.focusDidChange(hasFocus)
|
||||||
state.sizeDidChange(size)
|
view.sizeDidChange(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeCoordinator() -> Coordinator {
|
func makeCoordinator() -> Coordinator {
|
||||||
@ -81,11 +75,13 @@ protocol TerminalSurfaceDelegate: AnyObject {
|
|||||||
|
|
||||||
/// The actual NSView implementation for the terminal surface.
|
/// The actual NSView implementation for the terminal surface.
|
||||||
class TerminalSurfaceView: NSView, NSTextInputClient, ObservableObject {
|
class TerminalSurfaceView: NSView, NSTextInputClient, ObservableObject {
|
||||||
|
// This can be set to receive event callbacks.
|
||||||
weak var delegate: TerminalSurfaceDelegate?
|
weak var delegate: TerminalSurfaceDelegate?
|
||||||
|
|
||||||
// The current title of the surface as defined by the pty. This can be
|
// The current title of the surface as defined by the pty. This can be
|
||||||
// changed with escape codes.
|
// changed with escape codes. This is public because the callbacks go
|
||||||
var title: String = "" {
|
// to the app level and it is set from there.
|
||||||
|
@Published var title: String = "" {
|
||||||
didSet {
|
didSet {
|
||||||
if let delegate = self.delegate {
|
if let delegate = self.delegate {
|
||||||
delegate.titleDidChange(to: title)
|
delegate.titleDidChange(to: title)
|
||||||
@ -93,8 +89,9 @@ class TerminalSurfaceView: NSView, NSTextInputClient, ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var surface: ghostty_surface_t? = nil
|
private(set) var surface: ghostty_surface_t?
|
||||||
var error: Error? = nil
|
var error: Error? = nil
|
||||||
|
|
||||||
private var markedText: NSMutableAttributedString;
|
private var markedText: NSMutableAttributedString;
|
||||||
|
|
||||||
// We need to support being a first responder so that we can get input events
|
// We need to support being a first responder so that we can get input events
|
||||||
@ -104,123 +101,6 @@ class TerminalSurfaceView: NSView, NSTextInputClient, ObservableObject {
|
|||||||
// so we'll use that to tell ghostty to refresh.
|
// so we'll use that to tell ghostty to refresh.
|
||||||
override var wantsUpdateLayer: Bool { return true }
|
override var wantsUpdateLayer: Bool { return true }
|
||||||
|
|
||||||
// Mapping of event keyCode to ghostty input key values. This is cribbed from
|
|
||||||
// glfw mostly since we started as a glfw-based app way back in the day!
|
|
||||||
static let keycodes: [UInt16 : ghostty_input_key_e] = [
|
|
||||||
0x1D: GHOSTTY_KEY_ZERO,
|
|
||||||
0x12: GHOSTTY_KEY_ONE,
|
|
||||||
0x13: GHOSTTY_KEY_TWO,
|
|
||||||
0x14: GHOSTTY_KEY_THREE,
|
|
||||||
0x15: GHOSTTY_KEY_FOUR,
|
|
||||||
0x17: GHOSTTY_KEY_FIVE,
|
|
||||||
0x16: GHOSTTY_KEY_SIX,
|
|
||||||
0x1A: GHOSTTY_KEY_SEVEN,
|
|
||||||
0x1C: GHOSTTY_KEY_EIGHT,
|
|
||||||
0x19: GHOSTTY_KEY_NINE,
|
|
||||||
0x00: GHOSTTY_KEY_A,
|
|
||||||
0x0B: GHOSTTY_KEY_B,
|
|
||||||
0x08: GHOSTTY_KEY_C,
|
|
||||||
0x02: GHOSTTY_KEY_D,
|
|
||||||
0x0E: GHOSTTY_KEY_E,
|
|
||||||
0x03: GHOSTTY_KEY_F,
|
|
||||||
0x05: GHOSTTY_KEY_G,
|
|
||||||
0x04: GHOSTTY_KEY_H,
|
|
||||||
0x22: GHOSTTY_KEY_I,
|
|
||||||
0x26: GHOSTTY_KEY_J,
|
|
||||||
0x28: GHOSTTY_KEY_K,
|
|
||||||
0x25: GHOSTTY_KEY_L,
|
|
||||||
0x2E: GHOSTTY_KEY_M,
|
|
||||||
0x2D: GHOSTTY_KEY_N,
|
|
||||||
0x1F: GHOSTTY_KEY_O,
|
|
||||||
0x23: GHOSTTY_KEY_P,
|
|
||||||
0x0C: GHOSTTY_KEY_Q,
|
|
||||||
0x0F: GHOSTTY_KEY_R,
|
|
||||||
0x01: GHOSTTY_KEY_S,
|
|
||||||
0x11: GHOSTTY_KEY_T,
|
|
||||||
0x20: GHOSTTY_KEY_U,
|
|
||||||
0x09: GHOSTTY_KEY_V,
|
|
||||||
0x0D: GHOSTTY_KEY_W,
|
|
||||||
0x07: GHOSTTY_KEY_X,
|
|
||||||
0x10: GHOSTTY_KEY_Y,
|
|
||||||
0x06: GHOSTTY_KEY_Z,
|
|
||||||
|
|
||||||
0x27: GHOSTTY_KEY_APOSTROPHE,
|
|
||||||
0x2A: GHOSTTY_KEY_BACKSLASH,
|
|
||||||
0x2B: GHOSTTY_KEY_COMMA,
|
|
||||||
0x18: GHOSTTY_KEY_EQUAL,
|
|
||||||
0x32: GHOSTTY_KEY_GRAVE_ACCENT,
|
|
||||||
0x21: GHOSTTY_KEY_LEFT_BRACKET,
|
|
||||||
0x1B: GHOSTTY_KEY_MINUS,
|
|
||||||
0x2F: GHOSTTY_KEY_PERIOD,
|
|
||||||
0x1E: GHOSTTY_KEY_RIGHT_BRACKET,
|
|
||||||
0x29: GHOSTTY_KEY_SEMICOLON,
|
|
||||||
0x2C: GHOSTTY_KEY_SLASH,
|
|
||||||
|
|
||||||
0x33: GHOSTTY_KEY_BACKSPACE,
|
|
||||||
0x39: GHOSTTY_KEY_CAPS_LOCK,
|
|
||||||
0x75: GHOSTTY_KEY_DELETE,
|
|
||||||
0x7D: GHOSTTY_KEY_DOWN,
|
|
||||||
0x77: GHOSTTY_KEY_END,
|
|
||||||
0x24: GHOSTTY_KEY_ENTER,
|
|
||||||
0x35: GHOSTTY_KEY_ESCAPE,
|
|
||||||
0x7A: GHOSTTY_KEY_F1,
|
|
||||||
0x78: GHOSTTY_KEY_F2,
|
|
||||||
0x63: GHOSTTY_KEY_F3,
|
|
||||||
0x76: GHOSTTY_KEY_F4,
|
|
||||||
0x60: GHOSTTY_KEY_F5,
|
|
||||||
0x61: GHOSTTY_KEY_F6,
|
|
||||||
0x62: GHOSTTY_KEY_F7,
|
|
||||||
0x64: GHOSTTY_KEY_F8,
|
|
||||||
0x65: GHOSTTY_KEY_F9,
|
|
||||||
0x6D: GHOSTTY_KEY_F10,
|
|
||||||
0x67: GHOSTTY_KEY_F11,
|
|
||||||
0x6F: GHOSTTY_KEY_F12,
|
|
||||||
0x69: GHOSTTY_KEY_PRINT_SCREEN,
|
|
||||||
0x6B: GHOSTTY_KEY_F14,
|
|
||||||
0x71: GHOSTTY_KEY_F15,
|
|
||||||
0x6A: GHOSTTY_KEY_F16,
|
|
||||||
0x40: GHOSTTY_KEY_F17,
|
|
||||||
0x4F: GHOSTTY_KEY_F18,
|
|
||||||
0x50: GHOSTTY_KEY_F19,
|
|
||||||
0x5A: GHOSTTY_KEY_F20,
|
|
||||||
0x73: GHOSTTY_KEY_HOME,
|
|
||||||
0x72: GHOSTTY_KEY_INSERT,
|
|
||||||
0x7B: GHOSTTY_KEY_LEFT,
|
|
||||||
0x3A: GHOSTTY_KEY_LEFT_ALT,
|
|
||||||
0x3B: GHOSTTY_KEY_LEFT_CONTROL,
|
|
||||||
0x38: GHOSTTY_KEY_LEFT_SHIFT,
|
|
||||||
0x37: GHOSTTY_KEY_LEFT_SUPER,
|
|
||||||
0x47: GHOSTTY_KEY_NUM_LOCK,
|
|
||||||
0x79: GHOSTTY_KEY_PAGE_DOWN,
|
|
||||||
0x74: GHOSTTY_KEY_PAGE_UP,
|
|
||||||
0x7C: GHOSTTY_KEY_RIGHT,
|
|
||||||
0x3D: GHOSTTY_KEY_RIGHT_ALT,
|
|
||||||
0x3E: GHOSTTY_KEY_RIGHT_CONTROL,
|
|
||||||
0x3C: GHOSTTY_KEY_RIGHT_SHIFT,
|
|
||||||
0x36: GHOSTTY_KEY_RIGHT_SUPER,
|
|
||||||
0x31: GHOSTTY_KEY_SPACE,
|
|
||||||
0x30: GHOSTTY_KEY_TAB,
|
|
||||||
0x7E: GHOSTTY_KEY_UP,
|
|
||||||
|
|
||||||
0x52: GHOSTTY_KEY_KP_0,
|
|
||||||
0x53: GHOSTTY_KEY_KP_1,
|
|
||||||
0x54: GHOSTTY_KEY_KP_2,
|
|
||||||
0x55: GHOSTTY_KEY_KP_3,
|
|
||||||
0x56: GHOSTTY_KEY_KP_4,
|
|
||||||
0x57: GHOSTTY_KEY_KP_5,
|
|
||||||
0x58: GHOSTTY_KEY_KP_6,
|
|
||||||
0x59: GHOSTTY_KEY_KP_7,
|
|
||||||
0x5B: GHOSTTY_KEY_KP_8,
|
|
||||||
0x5C: GHOSTTY_KEY_KP_9,
|
|
||||||
0x45: GHOSTTY_KEY_KP_ADD,
|
|
||||||
0x41: GHOSTTY_KEY_KP_DECIMAL,
|
|
||||||
0x4B: GHOSTTY_KEY_KP_DIVIDE,
|
|
||||||
0x4C: GHOSTTY_KEY_KP_ENTER,
|
|
||||||
0x51: GHOSTTY_KEY_KP_EQUAL,
|
|
||||||
0x43: GHOSTTY_KEY_KP_MULTIPLY,
|
|
||||||
0x4E: GHOSTTY_KEY_KP_SUBTRACT,
|
|
||||||
];
|
|
||||||
|
|
||||||
init(_ app: ghostty_app_t) {
|
init(_ app: ghostty_app_t) {
|
||||||
self.markedText = NSMutableAttributedString()
|
self.markedText = NSMutableAttributedString()
|
||||||
|
|
||||||
@ -483,4 +363,121 @@ class TerminalSurfaceView: NSView, NSTextInputClient, ObservableObject {
|
|||||||
|
|
||||||
return ghostty_input_mods_e(mods)
|
return ghostty_input_mods_e(mods)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mapping of event keyCode to ghostty input key values. This is cribbed from
|
||||||
|
// glfw mostly since we started as a glfw-based app way back in the day!
|
||||||
|
static let keycodes: [UInt16 : ghostty_input_key_e] = [
|
||||||
|
0x1D: GHOSTTY_KEY_ZERO,
|
||||||
|
0x12: GHOSTTY_KEY_ONE,
|
||||||
|
0x13: GHOSTTY_KEY_TWO,
|
||||||
|
0x14: GHOSTTY_KEY_THREE,
|
||||||
|
0x15: GHOSTTY_KEY_FOUR,
|
||||||
|
0x17: GHOSTTY_KEY_FIVE,
|
||||||
|
0x16: GHOSTTY_KEY_SIX,
|
||||||
|
0x1A: GHOSTTY_KEY_SEVEN,
|
||||||
|
0x1C: GHOSTTY_KEY_EIGHT,
|
||||||
|
0x19: GHOSTTY_KEY_NINE,
|
||||||
|
0x00: GHOSTTY_KEY_A,
|
||||||
|
0x0B: GHOSTTY_KEY_B,
|
||||||
|
0x08: GHOSTTY_KEY_C,
|
||||||
|
0x02: GHOSTTY_KEY_D,
|
||||||
|
0x0E: GHOSTTY_KEY_E,
|
||||||
|
0x03: GHOSTTY_KEY_F,
|
||||||
|
0x05: GHOSTTY_KEY_G,
|
||||||
|
0x04: GHOSTTY_KEY_H,
|
||||||
|
0x22: GHOSTTY_KEY_I,
|
||||||
|
0x26: GHOSTTY_KEY_J,
|
||||||
|
0x28: GHOSTTY_KEY_K,
|
||||||
|
0x25: GHOSTTY_KEY_L,
|
||||||
|
0x2E: GHOSTTY_KEY_M,
|
||||||
|
0x2D: GHOSTTY_KEY_N,
|
||||||
|
0x1F: GHOSTTY_KEY_O,
|
||||||
|
0x23: GHOSTTY_KEY_P,
|
||||||
|
0x0C: GHOSTTY_KEY_Q,
|
||||||
|
0x0F: GHOSTTY_KEY_R,
|
||||||
|
0x01: GHOSTTY_KEY_S,
|
||||||
|
0x11: GHOSTTY_KEY_T,
|
||||||
|
0x20: GHOSTTY_KEY_U,
|
||||||
|
0x09: GHOSTTY_KEY_V,
|
||||||
|
0x0D: GHOSTTY_KEY_W,
|
||||||
|
0x07: GHOSTTY_KEY_X,
|
||||||
|
0x10: GHOSTTY_KEY_Y,
|
||||||
|
0x06: GHOSTTY_KEY_Z,
|
||||||
|
|
||||||
|
0x27: GHOSTTY_KEY_APOSTROPHE,
|
||||||
|
0x2A: GHOSTTY_KEY_BACKSLASH,
|
||||||
|
0x2B: GHOSTTY_KEY_COMMA,
|
||||||
|
0x18: GHOSTTY_KEY_EQUAL,
|
||||||
|
0x32: GHOSTTY_KEY_GRAVE_ACCENT,
|
||||||
|
0x21: GHOSTTY_KEY_LEFT_BRACKET,
|
||||||
|
0x1B: GHOSTTY_KEY_MINUS,
|
||||||
|
0x2F: GHOSTTY_KEY_PERIOD,
|
||||||
|
0x1E: GHOSTTY_KEY_RIGHT_BRACKET,
|
||||||
|
0x29: GHOSTTY_KEY_SEMICOLON,
|
||||||
|
0x2C: GHOSTTY_KEY_SLASH,
|
||||||
|
|
||||||
|
0x33: GHOSTTY_KEY_BACKSPACE,
|
||||||
|
0x39: GHOSTTY_KEY_CAPS_LOCK,
|
||||||
|
0x75: GHOSTTY_KEY_DELETE,
|
||||||
|
0x7D: GHOSTTY_KEY_DOWN,
|
||||||
|
0x77: GHOSTTY_KEY_END,
|
||||||
|
0x24: GHOSTTY_KEY_ENTER,
|
||||||
|
0x35: GHOSTTY_KEY_ESCAPE,
|
||||||
|
0x7A: GHOSTTY_KEY_F1,
|
||||||
|
0x78: GHOSTTY_KEY_F2,
|
||||||
|
0x63: GHOSTTY_KEY_F3,
|
||||||
|
0x76: GHOSTTY_KEY_F4,
|
||||||
|
0x60: GHOSTTY_KEY_F5,
|
||||||
|
0x61: GHOSTTY_KEY_F6,
|
||||||
|
0x62: GHOSTTY_KEY_F7,
|
||||||
|
0x64: GHOSTTY_KEY_F8,
|
||||||
|
0x65: GHOSTTY_KEY_F9,
|
||||||
|
0x6D: GHOSTTY_KEY_F10,
|
||||||
|
0x67: GHOSTTY_KEY_F11,
|
||||||
|
0x6F: GHOSTTY_KEY_F12,
|
||||||
|
0x69: GHOSTTY_KEY_PRINT_SCREEN,
|
||||||
|
0x6B: GHOSTTY_KEY_F14,
|
||||||
|
0x71: GHOSTTY_KEY_F15,
|
||||||
|
0x6A: GHOSTTY_KEY_F16,
|
||||||
|
0x40: GHOSTTY_KEY_F17,
|
||||||
|
0x4F: GHOSTTY_KEY_F18,
|
||||||
|
0x50: GHOSTTY_KEY_F19,
|
||||||
|
0x5A: GHOSTTY_KEY_F20,
|
||||||
|
0x73: GHOSTTY_KEY_HOME,
|
||||||
|
0x72: GHOSTTY_KEY_INSERT,
|
||||||
|
0x7B: GHOSTTY_KEY_LEFT,
|
||||||
|
0x3A: GHOSTTY_KEY_LEFT_ALT,
|
||||||
|
0x3B: GHOSTTY_KEY_LEFT_CONTROL,
|
||||||
|
0x38: GHOSTTY_KEY_LEFT_SHIFT,
|
||||||
|
0x37: GHOSTTY_KEY_LEFT_SUPER,
|
||||||
|
0x47: GHOSTTY_KEY_NUM_LOCK,
|
||||||
|
0x79: GHOSTTY_KEY_PAGE_DOWN,
|
||||||
|
0x74: GHOSTTY_KEY_PAGE_UP,
|
||||||
|
0x7C: GHOSTTY_KEY_RIGHT,
|
||||||
|
0x3D: GHOSTTY_KEY_RIGHT_ALT,
|
||||||
|
0x3E: GHOSTTY_KEY_RIGHT_CONTROL,
|
||||||
|
0x3C: GHOSTTY_KEY_RIGHT_SHIFT,
|
||||||
|
0x36: GHOSTTY_KEY_RIGHT_SUPER,
|
||||||
|
0x31: GHOSTTY_KEY_SPACE,
|
||||||
|
0x30: GHOSTTY_KEY_TAB,
|
||||||
|
0x7E: GHOSTTY_KEY_UP,
|
||||||
|
|
||||||
|
0x52: GHOSTTY_KEY_KP_0,
|
||||||
|
0x53: GHOSTTY_KEY_KP_1,
|
||||||
|
0x54: GHOSTTY_KEY_KP_2,
|
||||||
|
0x55: GHOSTTY_KEY_KP_3,
|
||||||
|
0x56: GHOSTTY_KEY_KP_4,
|
||||||
|
0x57: GHOSTTY_KEY_KP_5,
|
||||||
|
0x58: GHOSTTY_KEY_KP_6,
|
||||||
|
0x59: GHOSTTY_KEY_KP_7,
|
||||||
|
0x5B: GHOSTTY_KEY_KP_8,
|
||||||
|
0x5C: GHOSTTY_KEY_KP_9,
|
||||||
|
0x45: GHOSTTY_KEY_KP_ADD,
|
||||||
|
0x41: GHOSTTY_KEY_KP_DECIMAL,
|
||||||
|
0x4B: GHOSTTY_KEY_KP_DIVIDE,
|
||||||
|
0x4C: GHOSTTY_KEY_KP_ENTER,
|
||||||
|
0x51: GHOSTTY_KEY_KP_EQUAL,
|
||||||
|
0x43: GHOSTTY_KEY_KP_MULTIPLY,
|
||||||
|
0x4E: GHOSTTY_KEY_KP_SUBTRACT,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,9 @@ import SwiftUI
|
|||||||
import GhosttyKit
|
import GhosttyKit
|
||||||
|
|
||||||
struct TerminalView: View {
|
struct TerminalView: View {
|
||||||
let app: ghostty_app_t
|
// The surface to create a view for
|
||||||
|
let surfaceView: TerminalSurfaceView
|
||||||
|
|
||||||
@FocusState private var surfaceFocus: Bool
|
@FocusState private var surfaceFocus: Bool
|
||||||
@Environment(\.isKeyWindow) private var isKeyWindow: Bool
|
@Environment(\.isKeyWindow) private var isKeyWindow: Bool
|
||||||
@State private var title: String = "Ghostty"
|
@State private var title: String = "Ghostty"
|
||||||
@ -11,12 +13,17 @@ struct TerminalView: View {
|
|||||||
// it is both individually focused and the containing window is key.
|
// it is both individually focused and the containing window is key.
|
||||||
private var hasFocus: Bool { surfaceFocus && isKeyWindow }
|
private var hasFocus: Bool { surfaceFocus && isKeyWindow }
|
||||||
|
|
||||||
|
// Initialize a TerminalView with a new surface view state.
|
||||||
|
init(_ app: ghostty_app_t) {
|
||||||
|
self.surfaceView = TerminalSurfaceView(app)
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
// We use a GeometryReader to get the frame bounds so that our metal surface
|
// We use a GeometryReader to get the frame bounds so that our metal surface
|
||||||
// is up to date. See TerminalSurfaceView for why we don't use the NSView
|
// is up to date. See TerminalSurfaceView for why we don't use the NSView
|
||||||
// resize callback.
|
// resize callback.
|
||||||
GeometryReader { geo in
|
GeometryReader { geo in
|
||||||
TerminalSurface(app, hasFocus: hasFocus, size: geo.size, title: $title)
|
TerminalSurface(view: surfaceView, hasFocus: hasFocus, size: geo.size, title: $title)
|
||||||
.focused($surfaceFocus)
|
.focused($surfaceFocus)
|
||||||
.navigationTitle(title)
|
.navigationTitle(title)
|
||||||
}
|
}
|
||||||
@ -54,7 +61,7 @@ struct TerminalSplittableView: View {
|
|||||||
Button("Split Vertical") { splitDirection = .vertical }
|
Button("Split Vertical") { splitDirection = .vertical }
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminalView(app: app)
|
TerminalView(app)
|
||||||
.focused($focusedSide, equals: .TopLeft)
|
.focused($focusedSide, equals: .TopLeft)
|
||||||
}
|
}
|
||||||
case .horizontal:
|
case .horizontal:
|
||||||
|
Reference in New Issue
Block a user