feat(terminal): show vim key table badge
This commit is contained in:
parent
0f29735635
commit
65bb81079b
1 changed files with 70 additions and 13 deletions
|
|
@ -378,11 +378,27 @@ enum TerminalKeyboardCopyModeResolution: Equatable {
|
|||
}
|
||||
|
||||
private let terminalKeyboardCopyModeMaxCount = 9_999
|
||||
private let terminalKeyboardCopyModeIndicatorText = "vim"
|
||||
|
||||
private func terminalKeyboardCopyModeClampCount(_ value: Int) -> Int {
|
||||
min(max(value, 1), terminalKeyboardCopyModeMaxCount)
|
||||
}
|
||||
|
||||
private func terminalKeyTableIndicatorText(_ name: String) -> String {
|
||||
let trimmed = name.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
switch trimmed.lowercased() {
|
||||
case "", "set":
|
||||
return "key table"
|
||||
case "vi", "vim":
|
||||
return terminalKeyboardCopyModeIndicatorText
|
||||
default:
|
||||
let normalized = trimmed
|
||||
.replacingOccurrences(of: "_", with: " ")
|
||||
.replacingOccurrences(of: "-", with: " ")
|
||||
return normalized.isEmpty ? "key table" : normalized
|
||||
}
|
||||
}
|
||||
|
||||
func terminalKeyboardCopyModeInitialViewportRow(
|
||||
rows: Int,
|
||||
imePointY: Double,
|
||||
|
|
@ -2090,6 +2106,7 @@ final class TerminalSurface: Identifiable, ObservableObject {
|
|||
}
|
||||
@Published private(set) var keyboardCopyModeActive: Bool = false
|
||||
private var searchNeedleCancellable: AnyCancellable?
|
||||
var currentKeyStateIndicatorText: String? { surfaceView.currentKeyStateIndicatorText }
|
||||
|
||||
init(
|
||||
tabId: UUID,
|
||||
|
|
@ -2812,7 +2829,7 @@ final class TerminalSurface: Identifiable, ObservableObject {
|
|||
if keyboardCopyModeActive != active {
|
||||
keyboardCopyModeActive = active
|
||||
}
|
||||
hostedView.setKeyboardCopyModeIndicator(visible: active)
|
||||
hostedView.syncKeyStateIndicator(text: surfaceView.currentKeyStateIndicatorText)
|
||||
}
|
||||
|
||||
func hasSelection() -> Bool {
|
||||
|
|
@ -2934,6 +2951,17 @@ class GhosttyNSView: NSView, NSUserInterfaceValidations {
|
|||
/// movements should extend the selection (visual) or scroll the viewport.
|
||||
private var keyboardCopyModeVisualActive = false
|
||||
fileprivate var isKeyboardCopyModeActive: Bool { keyboardCopyModeActive }
|
||||
fileprivate var currentKeyStateIndicatorText: String? {
|
||||
if let name = keyTables.last {
|
||||
return terminalKeyTableIndicatorText(name)
|
||||
}
|
||||
|
||||
if keyboardCopyModeActive {
|
||||
return terminalKeyboardCopyModeIndicatorText
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
#if DEBUG
|
||||
private static let keyLatencyProbeEnabled: Bool = {
|
||||
if ProcessInfo.processInfo.environment["CMUX_KEY_LATENCY_PROBE"] == "1" {
|
||||
|
|
@ -4415,6 +4443,8 @@ class GhosttyNSView: NSView, NSUserInterfaceValidations {
|
|||
default:
|
||||
break
|
||||
}
|
||||
|
||||
terminalSurface?.hostedView.syncKeyStateIndicator(text: currentKeyStateIndicatorText)
|
||||
}
|
||||
|
||||
// MARK: - Mouse Handling
|
||||
|
|
@ -4917,6 +4947,7 @@ final class GhosttySurfaceScrollView: NSView {
|
|||
private let flashOverlayView: GhosttyFlashOverlayView
|
||||
private let flashLayer: CAShapeLayer
|
||||
private let keyboardCopyModeBadgeView: GhosttyPassthroughVisualEffectView
|
||||
private let keyboardCopyModeBadgeIconView: NSImageView
|
||||
private let keyboardCopyModeBadgeLabel: NSTextField
|
||||
private var searchOverlayHostingView: NSHostingView<SurfaceSearchOverlay>?
|
||||
private var lastSearchOverlayStateID: ObjectIdentifier?
|
||||
|
|
@ -5085,7 +5116,8 @@ final class GhosttySurfaceScrollView: NSView {
|
|||
flashOverlayView = GhosttyFlashOverlayView(frame: .zero)
|
||||
flashLayer = CAShapeLayer()
|
||||
keyboardCopyModeBadgeView = GhosttyPassthroughVisualEffectView(frame: .zero)
|
||||
keyboardCopyModeBadgeLabel = NSTextField(labelWithString: "VI MODE")
|
||||
keyboardCopyModeBadgeIconView = NSImageView(frame: .zero)
|
||||
keyboardCopyModeBadgeLabel = NSTextField(labelWithString: terminalKeyboardCopyModeIndicatorText)
|
||||
scrollView.hasVerticalScroller = true
|
||||
scrollView.hasHorizontalScroller = false
|
||||
scrollView.autohidesScrollers = false
|
||||
|
|
@ -5163,20 +5195,41 @@ final class GhosttySurfaceScrollView: NSView {
|
|||
keyboardCopyModeBadgeView.material = .hudWindow
|
||||
keyboardCopyModeBadgeView.blendingMode = .withinWindow
|
||||
keyboardCopyModeBadgeView.state = .active
|
||||
keyboardCopyModeBadgeView.layer?.cornerRadius = 7
|
||||
keyboardCopyModeBadgeView.layer?.cornerRadius = 18
|
||||
keyboardCopyModeBadgeView.layer?.masksToBounds = true
|
||||
keyboardCopyModeBadgeView.layer?.borderWidth = 1
|
||||
keyboardCopyModeBadgeView.layer?.borderColor = cmuxAccentNSColor().withAlphaComponent(0.45).cgColor
|
||||
keyboardCopyModeBadgeView.layer?.borderColor = NSColor.white.withAlphaComponent(0.12).cgColor
|
||||
keyboardCopyModeBadgeView.layer?.shadowColor = NSColor.black.cgColor
|
||||
keyboardCopyModeBadgeView.layer?.shadowOpacity = 0.22
|
||||
keyboardCopyModeBadgeView.layer?.shadowRadius = 10
|
||||
keyboardCopyModeBadgeView.layer?.shadowOffset = CGSize(width: 0, height: 2)
|
||||
keyboardCopyModeBadgeView.alphaValue = 0.97
|
||||
keyboardCopyModeBadgeIconView.translatesAutoresizingMaskIntoConstraints = false
|
||||
keyboardCopyModeBadgeIconView.symbolConfiguration = NSImage.SymbolConfiguration(
|
||||
pointSize: 13,
|
||||
weight: .regular,
|
||||
scale: .medium
|
||||
)
|
||||
keyboardCopyModeBadgeIconView.image = NSImage(
|
||||
systemSymbolName: "keyboard.badge.ellipsis",
|
||||
accessibilityDescription: "Key table"
|
||||
)
|
||||
keyboardCopyModeBadgeIconView.contentTintColor = NSColor.secondaryLabelColor
|
||||
keyboardCopyModeBadgeLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
keyboardCopyModeBadgeLabel.textColor = NSColor.labelColor
|
||||
keyboardCopyModeBadgeLabel.font = NSFont.systemFont(ofSize: 13, weight: .semibold)
|
||||
keyboardCopyModeBadgeLabel.lineBreakMode = .byClipping
|
||||
keyboardCopyModeBadgeView.addSubview(keyboardCopyModeBadgeIconView)
|
||||
keyboardCopyModeBadgeView.addSubview(keyboardCopyModeBadgeLabel)
|
||||
NSLayoutConstraint.activate([
|
||||
keyboardCopyModeBadgeLabel.leadingAnchor.constraint(equalTo: keyboardCopyModeBadgeView.leadingAnchor, constant: 8),
|
||||
keyboardCopyModeBadgeLabel.trailingAnchor.constraint(equalTo: keyboardCopyModeBadgeView.trailingAnchor, constant: -8),
|
||||
keyboardCopyModeBadgeLabel.topAnchor.constraint(equalTo: keyboardCopyModeBadgeView.topAnchor, constant: 4),
|
||||
keyboardCopyModeBadgeLabel.bottomAnchor.constraint(equalTo: keyboardCopyModeBadgeView.bottomAnchor, constant: -4),
|
||||
keyboardCopyModeBadgeIconView.leadingAnchor.constraint(equalTo: keyboardCopyModeBadgeView.leadingAnchor, constant: 12),
|
||||
keyboardCopyModeBadgeIconView.centerYAnchor.constraint(equalTo: keyboardCopyModeBadgeView.centerYAnchor),
|
||||
keyboardCopyModeBadgeIconView.widthAnchor.constraint(equalToConstant: 18),
|
||||
keyboardCopyModeBadgeIconView.heightAnchor.constraint(equalToConstant: 18),
|
||||
keyboardCopyModeBadgeLabel.leadingAnchor.constraint(equalTo: keyboardCopyModeBadgeIconView.trailingAnchor, constant: 7),
|
||||
keyboardCopyModeBadgeLabel.trailingAnchor.constraint(equalTo: keyboardCopyModeBadgeView.trailingAnchor, constant: -14),
|
||||
keyboardCopyModeBadgeLabel.topAnchor.constraint(equalTo: keyboardCopyModeBadgeView.topAnchor, constant: 8),
|
||||
keyboardCopyModeBadgeLabel.bottomAnchor.constraint(equalTo: keyboardCopyModeBadgeView.bottomAnchor, constant: -8),
|
||||
])
|
||||
keyboardCopyModeBadgeView.isHidden = true
|
||||
addSubview(keyboardCopyModeBadgeView)
|
||||
|
|
@ -5603,22 +5656,26 @@ final class GhosttySurfaceScrollView: NSView {
|
|||
lastSearchOverlayStateID = searchStateID
|
||||
}
|
||||
|
||||
func setKeyboardCopyModeIndicator(visible: Bool) {
|
||||
func syncKeyStateIndicator(text: String?) {
|
||||
if !Thread.isMainThread {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.setKeyboardCopyModeIndicator(visible: visible)
|
||||
self?.syncKeyStateIndicator(text: text)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
keyboardCopyModeBadgeView.isHidden = !visible
|
||||
if visible {
|
||||
if let text, !text.isEmpty {
|
||||
keyboardCopyModeBadgeLabel.stringValue = text
|
||||
keyboardCopyModeBadgeView.isHidden = false
|
||||
if let overlay = searchOverlayHostingView {
|
||||
addSubview(keyboardCopyModeBadgeView, positioned: .above, relativeTo: overlay)
|
||||
} else {
|
||||
addSubview(keyboardCopyModeBadgeView, positioned: .above, relativeTo: nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
keyboardCopyModeBadgeView.isHidden = true
|
||||
}
|
||||
|
||||
private func dropZoneOverlayFrame(for zone: DropZone, in size: CGSize) -> CGRect {
|
||||
|
|
@ -6947,7 +7004,7 @@ struct GhosttyTerminalView: NSViewRepresentable {
|
|||
)
|
||||
hostedView.setNotificationRing(visible: showsUnreadNotificationRing)
|
||||
hostedView.setSearchOverlay(searchState: searchState)
|
||||
hostedView.setKeyboardCopyModeIndicator(visible: terminalSurface.keyboardCopyModeActive)
|
||||
hostedView.syncKeyStateIndicator(text: terminalSurface.currentKeyStateIndicatorText)
|
||||
hostedView.setFocusHandler { onFocus?(terminalSurface.id) }
|
||||
hostedView.setTriggerFlashHandler(onTriggerFlash)
|
||||
let portalExpectedSurfaceId = terminalSurface.id
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue