feat: 修复终端换行错乱根因 + 顶带重设计 + 移除移动端分屏
- 换行错乱根因:tmux 客户端格子改以 ghostty 实测为权威(像素除法 偏大 1 行/列 → 远端按更宽排版、本地自动换行掉字符),单 pane 实测 格子直发 refresh-client;kickoff 用 raw surface 真实格子;顶栏 格子数 tmux 模式读 clientGrid(模拟器连本机 sshd 端到端验证) - 顶带落地为真实 chrome 行:✕/⌄ 独立按钮组 + 弱化标题 + TmuxWindowTabGroup window tab 组,pane 不再被悬浮胶囊遮内容 - 放弃移动端分屏:删 SplitMenu/分屏入口,tmux window 切换上移顶部 tab,侧边栏改列活动会话;底部动作条合并状态行 - Info.plist 补 NSLocalNetworkUsageDescription(LAN 直连必需, 缺失时 socket 静默超时) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -162,7 +162,7 @@
|
||||
| UI-1 | 设计令牌地基(Nocturne chrome + blurple + JetBrains Mono) | ✅ 完成 |
|
||||
| UI-2 | 导航与多会话状态模型(AppRouter/SessionManager/SessionCanvas) | ✅ 完成 |
|
||||
| UI-3 | 终端主界面:56pt 轨道 + 浮起双胶囊 + 侧边栏三态 | ✅ 完成(pane 缝拖拽待做) |
|
||||
| UI-4 | 首页会话卡 + 关闭确认 + 分屏菜单 + pane 拖拽 | ✅ 完成(pane 拖拽待真机 tmux 验证) |
|
||||
| UI-4 | 首页会话卡 + 关闭确认 + 分屏菜单 + pane 拖拽 | ✅ 完成(分屏功能后被用户裁决整体移除,见 12.3k) |
|
||||
| UI-5 | 设置·外观 + 键盘体系(GCKeyboard 检测 + 全套 ⌘ 快捷键) | 待做 |
|
||||
| UI-6 | 竖屏参数化 + iPhone 首版 | 待做 |
|
||||
|
||||
@@ -359,6 +359,38 @@
|
||||
- **顺带修掉暴露的旧缺陷**:标题胶囊的格子数读 `screenGrid.value` 却从不刷新(旧注释"首次布局后稳定,不必 @Published"在"开合即 resize"下不成立,表现为开合后数字停在旧值)→ `GridBox` 加 `onGridChange`(去重)、`TerminalSession` 转发 `objectWillChange`。验证:展开 135×50 / 收起 164×50 实时跟随。
|
||||
- 验证:展开动画 pane 左描边逐帧 58→198.5→261→290pt(easeOut 先快后慢),无硬切;收起态 Logo 位为 »、底部只剩状态点/分割线/齿轮;展开态头部仅 Logo+名称+«。
|
||||
|
||||
### 12.3k 放弃移动端分屏 + tmux window Tab 上移 + 状态出口合并(用户裁决,2026-07-26)
|
||||
|
||||
用户判词:全面放弃移动端的分屏**操作**(非核心功能);tmux 的切换从侧边栏移到顶部作 Tab,**活动会话(主机连接)的切换仍在侧边栏**;右上状态文字移到左下并与既有文字**合并**(原两处信息重复)。
|
||||
(第一版误把「会话列表」理解成主机连接列表上移为 Tab,用户纠正 + AskUser 确认:Tab = **tmux window**(与 tmux -CC「window 映射为原生 tab」惯例一致),非 tmux session 切换——后者需 switch-client + 窗口全量重建,未做。)
|
||||
|
||||
**1. 删分屏(入口 + 逻辑)**:
|
||||
- UI 入口:底部动作条「竖分屏」按钮、分屏菜单 `SplitMenuView`(12.3d 的 3b 卡片整个删除)、`AppModal.splitMenu`。
|
||||
- 逻辑:`TmuxController.splitWindow/splitIntoNewSession`、`list-sessions` 管线(`TmuxSessionInfo`/`sessions`/`listSessions()`/`PendingKind.listSessions`——只服务分屏菜单)、`TerminalSession.tmuxSessionList`/`injectedTmuxSessions`、fixture 的 `tmuxSessions()`、无头 URL `ui/split`/`ui/split-now`。
|
||||
- **保留**:多 pane 的**被动渲染**与 `PaneSplitter` 拖拽/`resizePane`(别的客户端建好的分屏 attach 进来仍须按 layout 正确显示)、`ui/resize/<cols>`。
|
||||
- 顺带修掉 `TmuxController` 响应 switch 里重复的 `case .currentSession`(死代码)。
|
||||
|
||||
**2. tmux window Tab(`TmuxWindowTabsBar`,TerminalChrome.swift)**:顶带 = 左标题胶囊 + window Tab 条(右上状态胶囊撤销)。一个 window 一个浮起胶囊 tab(编号徽标 + 标题),点击 `selectWindow`(链路复用旧侧边栏 window 行);当前 window accent 高亮;controller 未 attach 但有 `tmuxSummary` 时按占位渲染(fixture/接回前),原生窗口不显示。三层嵌套订阅各自拆视图(`WindowTabsRow` 订阅 controller、`WindowTab` 订阅 window——title/index 是 window 自己的 @Published)。侧边栏 tmux 段(`tmuxDivider`/`tmuxLabelRow`/`tmuxRows`/`SidebarWindowRow`/`WindowRowBody`/「新建 window」行)删除,「新建 window」入口保留在底部动作条;侧边栏 = 首页 / **活动会话(保留,主机连接切换)** / 连接新主机 / tailnet / 设置,不再要 `session` 参数。
|
||||
**3. 状态出口合并(`TerminalActionBar.statusLine`)**:原右上三格分层徽标(`tsnet|mosh|tmux`)与原左下上下文文字合并为左下**唯一**状态行:`[dot 链路] | 传输(重连计数) | 会话概览(tmux 名 · N windows / 原生窗口 / 无 tmux / phaseText)`。主机名不再出现(标题胶囊与当前 tab 已有)。「只染出问题的那层”规则原样保留。
|
||||
- 验证:fixture 三会话截图对拍(window tab 高亮/占位 tab/合并状态行/侧边栏两态排版含活动会话段)+ `ui/session/2` 切换 + 开合 resize 格子数跟随(164×50⇄135×50)。真机 tmux 下点 tab 切 window 待验证(链路与旧侧边栏 window 行相同)。
|
||||
|
||||
### 12.3l 顶带落地重设计:按钮分离 / 标题弱化 / tab 组(用户定稿,2026-07-26)
|
||||
|
||||
用户判词:按钮、title、tab 可以在终端**外**区域;按钮分离出来单独悬浮;标题弱化;tab 要有「组」的概念。
|
||||
|
||||
- **浮起胶囊废除,顶带落地为真实 chrome 行**(`TerminalTopBar` 替换 `TerminalTitleCapsule`+`FloatingCapsule`):`stage` 从 ZStack overlay 改回 VStack 首行,终端 pane 从带下方开始 —— 86pt 预留带(`TX.Layout.capsuleInset`,已删令牌)与「胶囊遮内容」问题一并消失。pane 顶边现在朝 chrome:topLeading 收圆角、顶描边恢复(不再 `top:-1` 推出屏外);右边仍贴屏幕物理边缘不收角。pane 内容留 `TX.Space.s` 呼吸位。
|
||||
- **顶带层级(一眼一个主角)**:`[✕ ⌄ 独立按钮组] · 弱化标题 · [tab 组]`。按钮升到 28pt 圆角方块自成一簇(危险操作与身份信息不共容器);标题降为纯文本行(状态点 5pt + 主机名 mono12 text2 + cwd textWeak + 格子数 textFaint),**当前 window title 从标题里删掉** —— 它已由 tab 组选中 chip 承担,写两遍是重复;tab 组是顶带唯一带容器的元素。
|
||||
- **tab 组(`TmuxWindowTabGroup`)**:surfaceDark 圆角槽(radius 11)内衬 3pt,window 是槽内段式 chip(选中 = selectedBg+描边浮起,未选 = 透明贴槽底),尾部 `+` 新建 window。**坑:槽体背景必须挂在 ScrollView 的内容层** —— 挂 ScrollView 自身就是一条拖到屏幕右边的空槽(ScrollView 恒占满剩余宽度)。占位态(controller 未 attach 但有 tmuxSummary)共用 chip 本体;原生窗口不渲染 tab 组。
|
||||
- 验证:fixture 截图 ×3(tmux 态顶带 / 原生窗口态无 tab 组 / 展开侧边栏组合态),标题去重与槽体紧贴成组均确认。
|
||||
|
||||
### 12.3m 换行错乱根因修复:客户端格子的权威改为 ghostty 实测(真机报障,2026-07-26)
|
||||
|
||||
用户报障:无论侧边栏收起/展开,终端(Claude Code 等全屏 TUI)换行错乱、行首冒碎片,竞品完美。
|
||||
|
||||
- **根因**(模拟器连本机 sshd 复现实锤):`containerResized` 用「容器px ÷ 整数cell px」算 tmux 客户端格子,复刻不了 ghostty 内部取整/内边距 —— 实测算得 **164×51**、ghostty 真实 **163×50**(列差来自 `TmuxPaneView` 的 1pt padding 圈,行差来自像素除法本身)。远端按 164 列排版、surface 按 163 列自动换行 → 每条满宽行掉字符,重绘积累成花屏。
|
||||
- **修复**(`TmuxController` + `ContentView` + `TerminalChrome`):① pane resize 回调从「只报 cell 像素」升级为上报**完整实测格子**(`paneViewportChanged`);② **单 pane window 的 pane 帧==容器帧 → 它的实测格子就是客户端格子**,据此发 `refresh-client -C`(帧只由容器决定,无反馈环);③ kickoff 初值改用 raw surface 实测格子(`setClientSize` 不再被像素换算覆盖);④ 单 pane 时去掉 pane 的 1pt padding 圈(`solo`);⑤ 像素除法只兜底「全是多 pane window」的场景;⑥ 顶栏格子数 tmux 模式改读 `TmuxController.clientGrid`(`screenGrid` 随 RawTerminalView 卸载已冻结)。
|
||||
- **验证**(模拟器 → 本机 sshd + tmux 3.7b 端到端):`tput cols` 宽字符标尺恰好一行不换行;侧边栏收起 164×50 ⇄ 展开 135×50 双态各验证;`top` 全屏重绘干净;顶栏胶囊数字随开合正确跳变。回归法已写入 CLAUDE.md(模拟器 `-txPubkeyAuth 1` 连 127.0.0.1,公钥临时入 authorized_keys)。
|
||||
|
||||
### 12.4 首版明确推迟(Fable 裁决,勿在 UI-3~6 里偷偷做)
|
||||
`mosh <RTT>` 实时数字(需改 vendor/mosh iosclient 导出 SRTT,属传输层)· ⌘K 命令面板 · 无 tmux 主机的多客户端窗口(保留横幅引导)· iPad 竖屏 pane 强制上下堆叠(会推翻「路线 b」,交给 tmux relayout)· 缩略卡 ANSI 彩色(用 `readViewportText()` 文本镜像,**绝不做离屏 Metal/双 surface**——IOSurfaceLayer 泄漏史)· 设置页连字/CJK 开关(ghostty 无运行时 mutation,灰显占位)。
|
||||
</content>
|
||||
|
||||
Reference in New Issue
Block a user