Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ extension SettingsData {
[
"Shell",
"Use \"Option\" key as \"Meta\"",
"Clear to Start with ⌘K",
"Use text editor font",
"Font",
"Font Size",
Expand All @@ -39,6 +40,11 @@ extension SettingsData {
/// If true, the terminal treats the `Option` key as the `Meta` key
var optionAsMeta: Bool = false

/// If true, pressing ⌘K while the terminal is focused clears the viewport and scrollback.
///
/// Matches Terminal.app / VS Code "Clear to Start" behavior. Enabled by default.
var clearToStartOnCommandK: Bool = true

/// The selected shell to use.
var shell: TerminalShell = .system

Expand Down Expand Up @@ -68,6 +74,10 @@ extension SettingsData {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.darkAppearance = try container.decodeIfPresent(Bool.self, forKey: .darkAppearance) ?? false
self.optionAsMeta = try container.decodeIfPresent(Bool.self, forKey: .optionAsMeta) ?? false
self.clearToStartOnCommandK = try container.decodeIfPresent(
Bool.self,
forKey: .clearToStartOnCommandK
) ?? true
self.shell = try container.decodeIfPresent(TerminalShell.self, forKey: .shell) ?? .system
self.font = try container.decodeIfPresent(TerminalFont.self, forKey: .font) ?? .init()
self.cursorStyle = try container.decodeIfPresent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ struct TerminalSettingsView: View {
Section {
shellSelector
optionAsMetaToggle
clearToStartToggle
}
Section {
useTextEditorFontToggle
Expand Down Expand Up @@ -69,6 +70,11 @@ private extension TerminalSettingsView {
Toggle("Use \"Option\" key as \"Meta\"", isOn: $settings.optionAsMeta)
}

private var clearToStartToggle: some View {
Toggle("Clear to Start with ⌘K", isOn: $settings.clearToStartOnCommandK)
.help("When enabled, ⌘K clears the terminal viewport and scrollback buffer while the terminal is focused.")
}

private var useTextEditorFontToggle: some View {
Toggle("Use text editor font", isOn: $settings.useTextEditorFont)
}
Expand Down
26 changes: 26 additions & 0 deletions CodeEdit/Features/TerminalEmulator/Views/CETerminalView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,32 @@ class CETerminalView: TerminalView {
pasteboard.setString(text, forType: .string)
}

/// Clears the visible terminal contents and the scrollback buffer.
///
/// Equivalent to Terminal.app / VS Code "Clear to Start" (⌘K). Operates on the
/// emulator buffer only — nothing is sent to the shell process.
///
/// Uses CSI sequences processed by SwiftTerm:
/// - `CSI H` — move cursor home
/// - `CSI 2 J` — erase the entire display
/// - `CSI 3 J` — erase saved lines (scrollback)
func clearToStart() {
feed(text: "\u{001B}[H\u{001B}[2J\u{001B}[3J")
}

/// Intercepts ⌘K when ``SettingsData/TerminalSettings/clearToStartOnCommandK`` is enabled.
override func performKeyEquivalent(with event: NSEvent) -> Bool {
let flags = event.modifierFlags.intersection(.deviceIndependentFlagsMask)
guard flags == .command,
event.charactersIgnoringModifiers?.lowercased() == "k",
Settings.shared.preferences.terminal.clearToStartOnCommandK else {
return super.performKeyEquivalent(with: event)
}

clearToStart()
return true
}

override open func isAccessibilityElement() -> Bool {
true
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//
// TerminalClearToStartTests.swift
// CodeEditTests
//
// Created for issue #891 — Clear To Start (⌘K) on the integrated terminal.
//

import AppKit
import SwiftTerm
import XCTest
@testable import CodeEdit

final class TerminalClearToStartTests: XCTestCase {

// MARK: - Settings

func testClearToStartSettingDefaultsToTrueWhenMissing() throws {
let json = Data("{}".utf8)
let settings = try JSONDecoder().decode(SettingsData.TerminalSettings.self, from: json)

XCTAssertTrue(
settings.clearToStartOnCommandK,
"⌘K clear should be enabled by default to match Terminal.app / VS Code"
)
}

func testClearToStartSettingDecodesFalse() throws {
let json = Data(#"{"clearToStartOnCommandK":false}"#.utf8)
let settings = try JSONDecoder().decode(SettingsData.TerminalSettings.self, from: json)

XCTAssertFalse(settings.clearToStartOnCommandK)
}

func testClearToStartSettingIsSearchable() {
let settings = SettingsData.TerminalSettings()
let keys = settings.searchKeys.map { $0.lowercased() }

XCTAssertTrue(
keys.contains(where: { $0.contains("clear to start") }),
"Expected a searchable label for Clear to Start / ⌘K, got: \(settings.searchKeys)"
)
}

// MARK: - Clear behavior

@MainActor
func testClearToStartRemovesViewportAndScrollback() {
let terminalView = CELocalShellTerminalView(frame: NSRect(x: 0, y: 0, width: 800, height: 600))
let terminal = terminalView.getTerminal()

// Produce more lines than the viewport so scrollback is non-empty.
for index in 0..<200 {
terminalView.feed(text: "line-\(index)\n")
}

let before = terminal.getText(
start: Position(col: 0, row: 0),
end: Position(col: max(0, terminal.cols - 1), row: max(0, terminal.buffer.yDisp + terminal.rows - 1))
)
XCTAssertTrue(before.contains("line-"), "Precondition: terminal should contain fed output")

terminalView.clearToStart()

XCTAssertEqual(terminal.buffer.x, 0, "Cursor should be at column 0")
XCTAssertEqual(terminal.buffer.y, 0, "Cursor should be at row 0")
XCTAssertEqual(terminal.buffer.yDisp, 0, "Viewport should be scrolled to the top")

let after = terminal.getText(
start: Position(col: 0, row: 0),
end: Position(col: max(0, terminal.cols - 1), row: max(0, terminal.rows - 1))
)
XCTAssertFalse(
after.contains("line-"),
"Cleared terminal should not still show previous output, got: \(after.prefix(200))"
)

let visibleText = terminalView.accessibilityValue() as? String ?? ""
XCTAssertFalse(
visibleText.contains("line-"),
"Accessibility value should also be cleared, got: \(visibleText.prefix(200))"
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# ``CodeEdit/TerminalSettingsView``

Configure the integrated terminal: shell, Option-as-Meta, **Clear to Start with ⌘K**, fonts, and cursor.

When **Clear to Start with ⌘K** is enabled (default), pressing ⌘K while the terminal is focused
clears both the viewport and the scrollback buffer, matching Terminal.app and VS Code.

## Topics

### Model
Expand Down
Loading