- 调试逻辑下沉到 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:
74
src/composables/debug.ts
Normal file
74
src/composables/debug.ts
Normal 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=True,trace 中至多只有 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
|
||||
}
|
||||
Reference in New Issue
Block a user