fix: restore header border, defer title init, fix title encoding
- Restore bordered headerBox as single scrollable item in messagesArea - Defer terminal title init to first render() (after jink ready) - Title uses ConsolePatcher.getOriginalOut() to bypass interception - Ctrl+C fix in jink: INT signal handler now respects exitOnCtrlC flag Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -87,6 +87,7 @@ public class ClaudeCodeComponent extends Component<ClaudeCodeComponent.TuiState>
|
|||||||
private volatile Thread spinnerThread;
|
private volatile Thread spinnerThread;
|
||||||
/** 终端标题(从首条用户消息推断) */
|
/** 终端标题(从首条用户消息推断) */
|
||||||
private volatile String sessionTitle = null;
|
private volatile String sessionTitle = null;
|
||||||
|
private volatile boolean titleInitialized = false;
|
||||||
|
|
||||||
/** 权限确认回调(由权限请求设置,用户输入后调用) */
|
/** 权限确认回调(由权限请求设置,用户输入后调用) */
|
||||||
private volatile Consumer<String> permissionCallback;
|
private volatile Consumer<String> permissionCallback;
|
||||||
@@ -142,14 +143,18 @@ public class ClaudeCodeComponent extends Component<ClaudeCodeComponent.TuiState>
|
|||||||
this.toolCount = toolCount;
|
this.toolCount = toolCount;
|
||||||
this.tokenTracker = tokenTracker;
|
this.tokenTracker = tokenTracker;
|
||||||
this.onExit = onExit;
|
this.onExit = onExit;
|
||||||
// 设置初始终端标题(匹配官方 process.title = 'claude')
|
// 注意:终端标题在 jink 初始化后设置(constructor 阶段太早,ConsolePatcher 未就绪)
|
||||||
setTerminalTitle(TITLE_STATIC_PREFIX + " Claude Code");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 渲染 ====================
|
// ==================== 渲染 ====================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Renderable render() {
|
public Renderable render() {
|
||||||
|
// 首次渲染时设置终端标题(此时 jink 已初始化,ConsolePatcher 已就绪)
|
||||||
|
if (!titleInitialized) {
|
||||||
|
titleInitialized = true;
|
||||||
|
setTerminalTitle(TITLE_STATIC_PREFIX + " Claude Code");
|
||||||
|
}
|
||||||
TuiState s = getState();
|
TuiState s = getState();
|
||||||
int w = getColumns();
|
int w = getColumns();
|
||||||
int h = getRows();
|
int h = getRows();
|
||||||
@@ -229,8 +234,8 @@ public class ClaudeCodeComponent extends Component<ClaudeCodeComponent.TuiState>
|
|||||||
.flexDirection(FlexDirection.COLUMN).width(w).height(h);
|
.flexDirection(FlexDirection.COLUMN).width(w).height(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 标题框行列表 — ASCII Logo + 信息(作为消息区首部随消息滚动) */
|
/** 标题框 — ASCII Logo + 信息(作为消息区首项,随消息滚动) */
|
||||||
private List<Renderable> headerLines() {
|
private Renderable headerBox(int w) {
|
||||||
// ASCII 冒烟咖啡杯
|
// ASCII 冒烟咖啡杯
|
||||||
String[] logo = {
|
String[] logo = {
|
||||||
" ) ) ) ",
|
" ) ) ) ",
|
||||||
@@ -282,15 +287,23 @@ public class ClaudeCodeComponent extends Component<ClaudeCodeComponent.TuiState>
|
|||||||
rightPart
|
rightPart
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
return rows;
|
|
||||||
|
return Box.of(rows.toArray(new Renderable[0]))
|
||||||
|
.flexDirection(FlexDirection.COLUMN)
|
||||||
|
.borderStyle(BorderStyle.ROUND)
|
||||||
|
.borderColor(Color.BRIGHT_MAGENTA)
|
||||||
|
.paddingX(1)
|
||||||
|
.width(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 消息列表(带虚拟滚动) */
|
/** 消息列表(带虚拟滚动) */
|
||||||
private Renderable messagesArea(TuiState s, int maxLines) {
|
private Renderable messagesArea(TuiState s, int maxLines) {
|
||||||
|
int w = getColumns();
|
||||||
List<Renderable> allItems = new ArrayList<>();
|
List<Renderable> allItems = new ArrayList<>();
|
||||||
|
|
||||||
// 标题框内容(作为消息区首部,随消息一起滚动 — 匹配官方 LogoHeader 行为)
|
// 标题框(作为消息区首项,随消息一起滚动 — 匹配官方 LogoHeader 行为)
|
||||||
allItems.addAll(headerLines());
|
// 注意:Box with border 算作1个虚拟滚动单位,实际占约8行
|
||||||
|
allItems.add(headerBox(w));
|
||||||
allItems.add(Text.of(" ")); // 空行分隔
|
allItems.add(Text.of(" ")); // 空行分隔
|
||||||
|
|
||||||
// 初始提示消息
|
// 初始提示消息
|
||||||
|
|||||||
Reference in New Issue
Block a user