diff --git a/macos/Sources/RustCode/DebugDriver.swift b/macos/Sources/RustCode/DebugDriver.swift index 67d54e034..eac8e7817 100644 --- a/macos/Sources/RustCode/DebugDriver.swift +++ b/macos/Sources/RustCode/DebugDriver.swift @@ -372,14 +372,13 @@ enum DebugDriver { } report("toolstream \(steps): row \(row) from \(Int(start)) scrolled \(Int(scrolled)), now \(Int(last)), worst stray \(Int(worst)), lost \(lost) of \(steps * 2) checks") case "fold": - // `fold [user|reply] [up]`: opens or folds the first long message - // of that kind in view, as its Show more control does (#2303); + // `fold [user] [up]`: opens or folds the first long user message + // in view, as its Show more control does (#2303); // with `up`, the chat is first scrolled so the message's top is // above the view. Reports where its top and end are in the view // before and over the next frames: opening and folding keep its // top, folding one whose top is above keeps its end. guard let state = ChatScrollState.current else { break } - let wantsUser = parts.count < 2 || parts[1] != "reply" let window = NSApp.windows.first { $0.isVisible && $0.contentView != nil } func frame(_ id: Int) -> (top: Int, end: Int)? { guard let top = state.debugScreenTop(id), let height = state.debugFrame(id)?.height else { return nil } @@ -387,8 +386,7 @@ enum DebugDriver { } let candidates = model.transcript.items.filter { item in switch item.content { - case .user(let text): wantsUser && MessageCollapse.mayBeLong(text) - case .assistant(let text): !wantsUser && MessageCollapse.mayBeLong(text) + case .user(let text): MessageCollapse.mayBeLong(text) default: false } } diff --git a/macos/Sources/RustCode/TranscriptRows.swift b/macos/Sources/RustCode/TranscriptRows.swift index c5b731ddc..c913dbd04 100644 --- a/macos/Sources/RustCode/TranscriptRows.swift +++ b/macos/Sources/RustCode/TranscriptRows.swift @@ -238,7 +238,7 @@ private struct AssistantMessage: View { var body: some View { let parsed = parsed VStack(alignment: .leading, spacing: 10) { - FoldingMessage(id: id, text: text, folds: MessageCollapse.folds(.assistant(text), isStreaming: isStreaming), + FoldingMessage(id: id, text: text, folds: false, isExpanded: isExpanded) { VStack(alignment: .leading, spacing: 10) { ForEach(Array(parsed.blocks.enumerated()), id: \.offset) { index, block in diff --git a/macos/Sources/RustCodeKit/MessageCollapse.swift b/macos/Sources/RustCodeKit/MessageCollapse.swift index 82a8f65de..0c5772948 100644 --- a/macos/Sources/RustCodeKit/MessageCollapse.swift +++ b/macos/Sources/RustCodeKit/MessageCollapse.swift @@ -2,10 +2,10 @@ import Foundation /// Long chat messages fold to their first lines behind Show more (#2303). /// -/// A user message or a finished reply taller than `maxLines` lines, and the -/// Show more control, shows its first `maxLines` lines under a fade. Only -/// the drawing changes: copy, the message menu, find and VoiceOver still get -/// the whole text. A reply never folds while it is written. +/// A user message taller than `maxLines` lines, and the Show more control, +/// shows its first `maxLines` lines under a fade. Only the drawing changes: +/// copy, the message menu, find and VoiceOver still get the whole text. +/// Replies never fold. public enum MessageCollapse { /// The lines a folded message shows. public static let maxLines = 12 @@ -15,14 +15,10 @@ public enum MessageCollapse { /// The height of the Show more control under a folded message. public static let controlHeight: Double = 22 - /// Whether a message of this kind folds when it is long: what the reader - /// wrote and finished replies, never a reply still being written. - public static func folds(_ content: TranscriptItem.Content, isStreaming: Bool) -> Bool { - switch content { - case .user: true - case .assistant: !isStreaming - case .thinking, .tool, .command: false - } + /// Whether a message of this kind folds when it is long: only what the + /// reader wrote. + public static func folds(_ content: TranscriptItem.Content) -> Bool { + if case .user = content { true } else { false } } /// Whether `text` may run past `maxLines` lines: each line wraps every diff --git a/macos/Tests/RustCodeKitTests/MessageCollapseTests.swift b/macos/Tests/RustCodeKitTests/MessageCollapseTests.swift index 10993891d..d972ab453 100644 --- a/macos/Tests/RustCodeKitTests/MessageCollapseTests.swift +++ b/macos/Tests/RustCodeKitTests/MessageCollapseTests.swift @@ -37,13 +37,11 @@ final class MessageCollapseTests: XCTestCase { XCTAssertTrue(MessageCollapse.isLong(height: 100 * line, lineHeight: line)) } - func testRepliesNeverFoldWhileWritten() { - XCTAssertTrue(MessageCollapse.folds(.user("hi"), isStreaming: false)) - XCTAssertTrue(MessageCollapse.folds(.user("hi"), isStreaming: true)) - XCTAssertTrue(MessageCollapse.folds(.assistant("hi"), isStreaming: false)) - XCTAssertFalse(MessageCollapse.folds(.assistant("hi"), isStreaming: true)) - XCTAssertFalse(MessageCollapse.folds(.thinking("hi"), isStreaming: false)) - XCTAssertFalse(MessageCollapse.folds(.command(input: "/x", output: lines(40)), isStreaming: false)) + func testOnlyUserMessagesFold() { + XCTAssertTrue(MessageCollapse.folds(.user("hi"))) + XCTAssertFalse(MessageCollapse.folds(.assistant(lines(40)))) + XCTAssertFalse(MessageCollapse.folds(.thinking("hi"))) + XCTAssertFalse(MessageCollapse.folds(.command(input: "/x", output: lines(40)))) } func testReplayedMessagesStartFoldedAndOpenPerChat() {