feat: 调试面板支持移动端,变量按作用域分组
Some checks failed
Deploy / build-and-deploy (push) Has been cancelled

- 调试逻辑下沉到 composables/debug.ts,桌面和移动端共用;模态框抽成
  DebugModal.vue(桌面 80vw / 移动 96vw),用 update:show 收口,
  关闭按钮、Esc、遮罩三条路径都会清理状态
- 移动端在"操作"菜单里补上调试入口(仅 Python)
- 变量面板改为分组展示:栈顶帧的局部变量在前、全局变量在后,
  顺序用 pg_encoder 的 ordered_globals / ordered_varnames,
  __return__ 显示成"返回值"。原来两者是 merge 成一份的,
  在函数里分不清哪个是局部、哪个是外面的全局
- 面板关闭时还原全局 output / status,否则主页输出区会停在某一调试步
- 输入切分不再过滤空行,只丢掉末尾换行产生的空串:程序可能正需要读一个
  空行,过滤掉会让输入提前耗尽、误报"需要更多输入"
- 后端超时/超限的 detail 透传到提示里,调试按钮加 loading 态
- 清掉 computed 和高亮更新里遗留的 console.log(自动播放时 500ms 刷一次)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019QGZaLUWzGPEMTk6A5RShC
This commit is contained in:
2026-09-07 04:46:01 -06:00
parent 2afc81e9ab
commit aa928dd3f5
7 changed files with 245 additions and 142 deletions

74
src/composables/debug.ts Normal file
View File

@@ -0,0 +1,74 @@
import { ref } from "vue"
import { debug as fetchDebugTrace } from "../api"
import { code, input } from "./code"
export const showDebugModal = ref(false)
export const debugData = ref<any>(null)
export const debugLoading = ref(false)
/**
* 把输入框内容切成 stdin 行。
* 只丢掉末尾换行产生的那个空串,中间的空行必须保留 ——
* 程序可能正需要读一个空行input() 返回 ""),过滤掉会导致输入提前耗尽。
*/
function splitInputLines(text: string): string[] {
if (!text) return []
const lines = text.split("\n")
if (lines[lines.length - 1] === "") lines.pop()
return lines
}
/**
* trace 末尾停在 raw_input 即说明输入不足
* pg_logger 在缺输入时会立刻 done=Truetrace 中至多只有 1 个 raw_input 事件,
* 所以不能用计数对比,只能看末尾)
*/
function endsAtRawInput(data: any): boolean {
const trace = data?.trace
if (!trace?.length) return false
return trace[trace.length - 1].event === "raw_input"
}
export type DebugResult =
| { ok: true }
| { ok: false; level: "error" | "warning"; message: string }
/**
* 请求调试数据并打开面板。
* 提示文案交给调用方展示useMessage() 只能在组件的 setup 里取。
*/
export async function startDebug(): Promise<DebugResult> {
if (debugLoading.value) return { ok: true }
debugLoading.value = true
let res
try {
res = await fetchDebugTrace(code.value, splitInputLines(input.value))
} catch (err: any) {
return {
ok: false,
level: "error",
message: `调试失败: ${err?.response?.data?.detail ?? err?.message ?? "未知错误"}`,
}
} finally {
debugLoading.value = false
}
debugData.value = res.data
if (endsAtRawInput(res.data)) {
return {
ok: false,
level: "warning",
message: "程序需要更多输入,请在输入框补全后重新点击调试",
}
}
showDebugModal.value = true
return { ok: true }
}
export function closeDebug() {
showDebugModal.value = false
debugData.value = null
}