Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
10 changes: 8 additions & 2 deletions .github/workflows/qt-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
"-DTERMFORGE_CONPTY_BACKEND_DIR=$dependencyRoot/conpty" `
"-DTERMFORGE_MSVC_RUNTIME_DIR=$dependencyRoot/crt"
- name: Build Qt product and independent smoke
run: cmake --build build/qt-cpp --config Release --target termforge_qt_shell qt_cpp_shell_smoke qt_cpp_resize_smoke qt_unicode_input_test qt_unicode_render_test qt_eight_session_test qt_terminal_modes_test qt_hidden_retention_test qt_history_navigation_test qt_selection_migration_test qt_find_test qt_scrollbar_size_test qt_clipboard_system_test qt_query_reply_test --parallel 2
run: cmake --build build/qt-cpp --config Release --target termforge_qt_shell qt_cpp_shell_smoke qt_cpp_resize_smoke qt_unicode_input_test qt_unicode_render_test qt_eight_session_test qt_terminal_modes_test qt_hidden_retention_test qt_history_navigation_test qt_selection_migration_test qt_find_test qt_scrollbar_size_test qt_clipboard_system_test qt_query_reply_test qt_paste_test --parallel 2
- name: Stage the frozen Qt product and verify every file identity
run: |
python -m tools.stage_qt_product stage `
Expand Down Expand Up @@ -104,6 +104,7 @@ jobs:
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
python tools/msvc_runtime.py manifest --directory build/qt-cpp/qt-query-reply-bin/Release --executable qt_query_reply_test.exe
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
python tools/msvc_runtime.py manifest --directory build/qt-cpp/qt-paste-bin/Release --executable qt_paste_test.exe
- name: Preserve runtime file identities without binaries
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
Expand All @@ -124,14 +125,19 @@ jobs:
build/qt-cpp/qt-selection-bin/Release/runtime-manifest.json
build/qt-cpp/qt-clipboard-bin/Release/runtime-manifest.json
build/qt-cpp/qt-query-reply-bin/Release/runtime-manifest.json
build/qt-cpp/qt-paste-bin/Release/runtime-manifest.json
- name: Run Qt offscreen smoke in its owned Job
run: ctest --test-dir build/qt-cpp -C Release -R '^(qt_cpp_(shell|resize)|qt_unicode_input|qt_unicode_render|qt_eight_session|qt_terminal_modes(_retained)?|qt_hidden_retention|qt_history_navigation|qt_selection_migration|qt_find|qt_scrollbar_size|qt_query_reply)$' --no-tests=error --verbose
run: ctest --test-dir build/qt-cpp -C Release -R '^(qt_cpp_(shell|resize)|qt_unicode_input|qt_unicode_render|qt_eight_session|qt_terminal_modes(_retained)?|qt_hidden_retention|qt_history_navigation|qt_selection_migration|qt_find|qt_scrollbar_size|qt_query_reply|qt_paste)$' --no-tests=error --verbose
- name: Run hosted-only Qt system clipboard copy
run: python src/qt/run_smoke.py build/qt-cpp/qt-clipboard-bin/Release/qt_clipboard_system_test.exe --hosted-copy
- name: Run hosted Windows QPA product-writer clipboard copy
env:
TERMFORGE_QT_QPA_PLATFORM: windows
run: python src/qt/run_smoke.py build/qt-cpp/qt-clipboard-bin/Release/qt_clipboard_system_test.exe --hosted-windows-copy
- name: Run hosted Windows QPA product-reader paste
env:
TERMFORGE_QT_QPA_PLATFORM: windows
run: python src/qt/run_smoke.py build/qt-cpp/qt-clipboard-bin/Release/qt_clipboard_system_test.exe --hosted-windows-paste
# Keep this configuration independent from the default/system-backend and
# Alacritty reference jobs. SDKs, runtime folders and raw logs are not
# publication artifacts; this job does not produce a release package.
46 changes: 46 additions & 0 deletions .github/workflows/qt-hosted-paste-multiline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Opt-in single hosted Windows QPA run for the #324 multiline paste recovery.
# The default qt-cpp.yml lane keeps the historical single-line hosted scope; the
# multiline real-CF dialog branch only executes with TERMFORGE_QT_HOSTED_MULTILINE=1.
# Attempt 3 consumed the recovery quota on 2026-11-12 (run 43101420107 / job
# 130793595825, passed); the trigger is dispatch-only so later pushes of result
# docs or trace cleanups cannot re-execute the real hosted path.
name: Qt hosted Windows multiline paste recovery

on:
workflow_dispatch:

permissions:
contents: read

jobs:
hosted-multiline-paste:
runs-on: windows-2025
timeout-minutes: 20
env:
PYTHONUTF8: '1'
TERMFORGE_QT_HOSTED_MULTILINE: '1'
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.12'
- name: Verify preparation failure contracts
run: python -m unittest tools.test_prepare_qt_build tools.test_prepare_msvc_runtime tools.test_msvc_runtime -v
- name: Prepare manifest-pinned Qt qtbase, Microsoft ConPTY and CRT
run: python -m tools.prepare_qt_build
- name: Configure explicit Qt product and test entries
run: |
$dependencyRoot = Join-Path $env:GITHUB_WORKSPACE 'local/qt-build-deps'
cmake -S . -B build/qt-cpp -G 'Visual Studio 18 2026' -A x64 `
-DTERMFORGE_BUILD_QT_SHELL=ON -DBUILD_TESTING=ON `
-DTERMFORGE_BUILD_CANDIDATE_ADAPTER=OFF `
"-DPython3_EXECUTABLE=$((Get-Command python).Source)" `
"-DQt6_DIR=$dependencyRoot/qt/lib/cmake/Qt6" `
"-DTERMFORGE_CONPTY_BACKEND_DIR=$dependencyRoot/conpty" `
"-DTERMFORGE_MSVC_RUNTIME_DIR=$dependencyRoot/crt"
- name: Build Qt clipboard system test
run: cmake --build build/qt-cpp --config Release --target qt_clipboard_system_test --parallel 2
- name: Run hosted Windows QPA multiline paste recovery
env:
TERMFORGE_QT_QPA_PLATFORM: windows
run: python src/qt/run_smoke.py build/qt-cpp/qt-clipboard-bin/Release/qt_clipboard_system_test.exe --hosted-windows-paste
14 changes: 14 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,20 @@ if(TERMFORGE_BUILD_QT_SHELL)
"${PROJECT_SOURCE_DIR}/src/qt/run_smoke.py" "$<TARGET_FILE:qt_selection_migration_test>")
set_tests_properties(qt_selection_migration PROPERTIES TIMEOUT 40
ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
add_executable(qt_paste_test src/qt/paste_test.cpp)
set_target_properties(qt_paste_test PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qt-paste-bin/$<CONFIG>")
termforge_qt_entry(qt_paste_test)
target_link_libraries(qt_paste_test PRIVATE Qt6::Test)
add_custom_command(TARGET qt_paste_test POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"$<TARGET_FILE:Qt6::QOffscreenIntegrationPlugin>"
"$<TARGET_FILE_DIR:qt_paste_test>/platforms/"
VERBATIM)
add_test(NAME qt_paste COMMAND "${Python3_EXECUTABLE}"
"${PROJECT_SOURCE_DIR}/src/qt/run_smoke.py" "$<TARGET_FILE:qt_paste_test>")
set_tests_properties(qt_paste PROPERTIES TIMEOUT 45
ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
add_executable(qt_find_test src/qt/find_test.cpp)
set_target_properties(qt_find_test PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qt-find-bin/$<CONFIG>")
Expand Down
1 change: 1 addition & 0 deletions docs/EVIDENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
| Qt 历史/重排页选择源位置迁移(#29 切片) | [真实 Qt 鼠标/历史浏览、受控 child 与截图](../experiments/shell/results/2026-11-06-qt-selection-migration/README.md):反向跨软续行、部分列+硬行边界、60×20 重排/恢复、浏览页变化、无关输出、真实淘汰/ED3/RIS 失效、双会话隔离;字面文本与高亮列数独立核对,Qt 正式路径 9/9 | 单屏 offscreen、固定短 ASCII/单一软续行;宽字/结合字选择列、系统剪贴板/复制 UI、粘贴、选词选行、自动滚动、Find、物理呈现/DPI/其他尺寸/性能未覆盖;内部提取≠系统剪贴板;旧失败/A/B/C/#27/#29 状态不变 |
| Qt 历史滚动条与源阅读锚点(#29 切片) | [实现、真实鼠标/键盘与截图](../experiments/shell/results/2026-11-07-qt-history-scrollbar/README.md):真实 QScrollBar 拖动/页区/Home/End,值仅显示页 top,经 HistoryViewport 源锚点定位;覆盖新输出锚点、回底、缩窄恢复、Find 同步、双会话;Qt 正式路径 10/10 | 离屏 Qt;不覆盖物理呈现/DPI、TUI/备用屏、自动滚动/选词选行/持久化/性能;滚动条+child 尺寸独立 ACK 仍为边界;不代表 #29/#30/R2 完成 |
| Qt 有界系统复制入口(#29/#30 切片) | [实现、fake 入口回归与 hosted 阻塞](../experiments/shell/results/2026-11-06-qt-system-copy/README.md):Ctrl+Shift+C/实际 Copy 菜单接入 CF_UNICODETEXT,空/失效/容量/失败分列;本地 fake writer 入口测试通过,Qt 正式路径 9/9;hosted-only CF 入口通过(QPA/offscreen 分层) | **系统 CF 已在一次性 GitHub-hosted Windows run `42160062253` 分层验证**:offscreen 注入 owner 与 Windows QPA 默认 writer/真实控件 HWND 均独立读回键盘/实际菜单/空 sentinel/占用失败/释放后成功/淘汰;首次 offscreen winId 非 HWND 的 `OpenClipboard:1400` 只修正测试 owner,不改产品;宽字/结合字复制列、占用重试、粘贴、Find、物理呈现/性能未覆盖;不把 offscreen 缓存当 CF;旧 B/CD/A/B/C/#27/#29/#30 状态不变 |
| Qt 有界系统粘贴入口(#29/#30 切片) | [实现、本地 child 字节回归与 hosted Windows QPA CF](../experiments/shell/results/2026-11-06-qt-system-paste/README.md):Ctrl+Shift+V/Shift+Insert/实际 Paste 菜单接默认 CF 读取器、分块发送、目标绑定、多行确认;本地 fake reader + 真实 child 1/1、Qt 10/10(含双会话切换/读取中关闭/新会话隔离);hosted Windows QPA run `42183487961`/job `127778260596` 三入口/真实占用失败/释放后成功通过 | hosted 多行确认保留为历史失败(首次 `eecf21f`、修复后 `5ea8e44` 均未收到 `L1\rL2`;恢复额度已用尽,未再 hosted 重试,见[尝试账本](../experiments/shell/results/2026-11-06-qt-system-paste/attempt-ledger.md));不覆盖 bracketed paste/TUI/自动逐行/Find/物理呈现/DPI/性能;系统 CF 仅该一次性 hosted 运行;#27/#29/#30/#35/#7 不关闭 |
| Qt 有界字面量 Find(#29 切片) | [实现、本地确定性 child 与截图](../experiments/shell/results/2026-11-06-qt-find/README.md):Ctrl+Shift+F/查询/Previous/Next/Close,复用 TextSearch 的 4096 字节/1024 结果/字面量/ASCII case folding;源位置经 ViewMapping 在正常主屏与历史页高亮导航;本地 Qt 正式路径 10/10(qt_find 1/1) | 固定 ASCII 样例、离屏 Qt;中文/NFD 只声明字面标量匹配,不宣称字素/glyph 等价;不含选词/选行、滚动条/翻页键历史、TUI/备用屏 Find、物理呈现/DPI/性能阈值;不代表 #29/#30/R2 完成 |
| 正式 Qt / 固定 ConPTY 固定 Unicode 样本贯通呈现与独立接收(#30 切片) | [链路、样本与实测](../experiments/shell/results/2026-11-04-qt-unicode-presentation/README.md):新增 `qt_unicode_render`,5 条固定样本经公开 Qt 事件→真实 child `ReadConsoleW` 精确接收→同字节 CR→CRLF 回显→核心解析→`TerminalWidget` 离屏抓图;receiver/echo SHA-256 与源字节逐字节一致,CJK 实测 fallback `Alibaba PuHuiTi`、emoji `Segoe UI Emoji`(advance 21>span 18 但无裁剪参考墨迹 3..17 未越格),结合标 `marks=1`,第二条空会话 0 字节且无样本文字;Qt 正式路径 6/6 | U+200D/U+FE0F 仍被 recovery parser 替换为 U+FFFD(只记录,不批准新聚类/宽度策略);offscreen + 宿主 fallback 依赖、`presented_done=null`,不覆盖物理呈现/原生 IME/真实 DPI/完整字素或 #30/#155 验收 |
| 正式 Qt / 固定 ConPTY 八会话文本输入目标隔离与生命周期(#30 切片) | [入口、矩阵、时序与实测](../experiments/shell/results/2026-11-08-qt-eight-session-isolation/README.md):新增 `qt_eight_session`,通过公开 `+`/标签切换/关闭入口创建 8 个真实固定 ConPTY child(+1 替代页),每会话独立 PID/nonce/接收文件;硬编码字面预期核对 ASCII/CJK/补充平面/结合标与无修饰 Home 只进入活动目标,非创建顺序 `[4,0,7,2,5,1,6,3]` 切换,8×120 行受控后台输出全部排空(queued 0),关闭非活动/活动标签后存活目标继续精确接收,替代页首输入无待发单元泄漏,父窗关闭 6 会话 `cleanup_verified/active_processes_after=0`、status 0;Qt 正式路径 CTest 12/12,核心 42/42 | 仅 offscreen 合成 Qt 事件、固定 8 会话/80×24/1 替代页,`presented_done=null`;`SessionTabs` 当前无会话上限,未定义/未测试第 9 个会话行为;不覆盖真实键盘、原生 IME、系统剪贴板、真实 DPI、完整 Copy→Paste→IME、八会话以上或性能;#30/#155/#7 不关闭 |
Expand Down
Loading