From 5ad2628b1ac442bccf3045bc10b357f8264f0378 Mon Sep 17 00:00:00 2001 From: abel533 Date: Sat, 4 Apr 2026 18:43:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Ctrl+C=20=E5=8F=8C=E5=87=BB=E9=80=80?= =?UTF-8?q?=E5=87=BA=EF=BC=88=E5=8C=B9=E9=85=8D=E5=8E=9F=E7=89=88=20Claude?= =?UTF-8?q?=20Code=20=E8=A1=8C=E4=B8=BA=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 第一次 Ctrl+C: Agent 运行中则取消任务,空闲时清空输入 - 第二次 Ctrl+C (2秒内): 退出应用 - 快捷键栏显示 'Press Ctrl-C again to exit' 黄色提示 - 2秒超时后自动清除提示(虚拟线程定时) - 移除未使用的 cmdCount 字段 - 保留 Esc 中断和 Ctrl+D 退出作为备选 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../claudecode/tui/ClaudeCodeComponent.java | 41 ++++++++++++++++--- .../com/claudecode/tui/JinkReplSession.java | 1 - 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/claudecode/tui/ClaudeCodeComponent.java b/src/main/java/com/claudecode/tui/ClaudeCodeComponent.java index ff27e5d..e10ebc8 100644 --- a/src/main/java/com/claudecode/tui/ClaudeCodeComponent.java +++ b/src/main/java/com/claudecode/tui/ClaudeCodeComponent.java @@ -67,7 +67,6 @@ public class ClaudeCodeComponent extends Component private final String model; private final String baseUrl; private final int toolCount; - private final int cmdCount; private final TokenTracker tokenTracker; private final Runnable onExit; @@ -97,6 +96,10 @@ public class ClaudeCodeComponent extends Component private volatile int lastRenderedItemCount = 0; private volatile int lastMaxVisibleLines = 20; + /** Ctrl+C 双击退出:上次按下时间 */ + private volatile long lastCtrlCTime = 0; + private static final long CTRL_C_EXIT_WINDOW_MS = 2000; // 2秒内再按一次退出 + /** 首次用户输入回调(用于 conversation summary) */ private Consumer onFirstUserInput; @@ -104,7 +107,7 @@ public class ClaudeCodeComponent extends Component CommandRegistry commandRegistry, ToolRegistry toolRegistry, String provider, String model, String baseUrl, - int toolCount, int cmdCount, + int toolCount, TokenTracker tokenTracker, Runnable onExit) { super(TuiState.empty()); @@ -115,7 +118,6 @@ public class ClaudeCodeComponent extends Component this.model = model; this.baseUrl = baseUrl; this.toolCount = toolCount; - this.cmdCount = cmdCount; this.tokenTracker = tokenTracker; this.onExit = onExit; } @@ -539,8 +541,14 @@ public class ClaudeCodeComponent extends Component } } + // Ctrl+C 双击退出提示 + boolean ctrlCPending = (System.currentTimeMillis() - lastCtrlCTime) < CTRL_C_EXIT_WINDOW_MS; + Renderable leftText = ctrlCPending + ? Text.of("Press Ctrl-C again to exit").color(Color.BRIGHT_YELLOW) + : Text.of("↑↓ history Esc interrupt").dimmed(); + return Box.of( - Text.of("↑↓ history Esc interrupt Ctrl+D exit").dimmed(), + leftText, Spacer.create(), Text.of(tokenInfo).color(Color.BRIGHT_GREEN) ).paddingX(1).height(1); @@ -565,13 +573,34 @@ public class ClaudeCodeComponent extends Component return; } - // Ctrl+C: 取消当前输入或中断 Agent + // Ctrl+C: 中断 Agent 或双击退出 if (key.ctrl() && "c".equals(input)) { if (agentRunning.get()) { + // Agent 运行中 → 取消任务 agentLoop.cancel(); addMessageInternal(new SystemMsg("^C (interrupt)", Color.BRIGHT_YELLOW), s); + lastCtrlCTime = System.currentTimeMillis(); } else { - setState(new TuiState("", s.messages, s.scrollOffset, false, "")); + long now = System.currentTimeMillis(); + if (now - lastCtrlCTime < CTRL_C_EXIT_WINDOW_MS) { + // 第二次 Ctrl+C → 退出 + if (onExit != null) onExit.run(); + } else { + // 第一次 Ctrl+C → 清空输入 + 提示再按一次退出 + lastCtrlCTime = now; + setState(new TuiState("", s.messages, s.scrollOffset, false, "")); + // 启动定时器,超时后清除提示 + Thread.startVirtualThread(() -> { + try { Thread.sleep(CTRL_C_EXIT_WINDOW_MS); } catch (InterruptedException ignored) {} + // 超时后刷新显示(清除 "Press Ctrl-C again to exit" 提示) + synchronized (stateLock) { + if (System.currentTimeMillis() - lastCtrlCTime >= CTRL_C_EXIT_WINDOW_MS) { + TuiState cur = getState(); + setState(new TuiState(cur.inputText, cur.messages, cur.scrollOffset, cur.thinking, cur.thinkingText)); + } + } + }); + } } return; } diff --git a/src/main/java/com/claudecode/tui/JinkReplSession.java b/src/main/java/com/claudecode/tui/JinkReplSession.java index 9309af0..f0d143c 100644 --- a/src/main/java/com/claudecode/tui/JinkReplSession.java +++ b/src/main/java/com/claudecode/tui/JinkReplSession.java @@ -79,7 +79,6 @@ public class JinkReplSession { providerInfo.model(), providerInfo.baseUrl(), toolRegistry.size(), - commandRegistry.getCommands().size(), tokenTracker, this::exit );