feat(题目): 语法没过时把代码里每一处中文标点都标出来,和「换成英文(N 处)」对得上
- 原来编辑器里只标报错点名的第一处,按钮却写着「4 处」,学生对不上、也不知道一键替换 会改哪里。字符串和注释里的中文标点是合法的,不标(和一键替换同一套判断) - 这种情况下没交上去:结果页签那一段叫「交之前检查」,标题写「还没有交上去」, 不再叫「提交结果」 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b5d2f1589e
commit
11ff340110
3 files changed
+56
-4
No files matched your search
@@ -1,7 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useCodeStore } from "oj/store/code"
|
import { useCodeStore } from "oj/store/code"
|
||||||
import { findChinesePunctuation } from "oj/problem/utils/chinesePunctuation"
|
import { findChinesePunctuation } from "oj/problem/utils/chinesePunctuation"
|
||||||
import { applyFixes, clearErrorMark, currentCode, showErrorMark } from "oj/problem/utils/errorMark"
|
import {
|
||||||
|
applyFixes,
|
||||||
|
clearErrorMark,
|
||||||
|
currentCode,
|
||||||
|
showErrorMark,
|
||||||
|
showPunctuationMarks,
|
||||||
|
} from "oj/problem/utils/errorMark"
|
||||||
import { explainPythonCompileError } from "oj/problem/utils/pythonError"
|
import { explainPythonCompileError } from "oj/problem/utils/pythonError"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,6 +61,9 @@ watch(
|
|||||||
fixedCount.value = null
|
fixedCount.value = null
|
||||||
if (ex?.line) showErrorMark(ex.line, ex.sourceLine, ex.caret)
|
if (ex?.line) showErrorMark(ex.line, ex.sourceLine, ex.caret)
|
||||||
else clearErrorMark()
|
else clearErrorMark()
|
||||||
|
// 中文标点一处不漏地标出来,和按钮上的「N 处」对得上
|
||||||
|
const code = ex?.punctuation ? currentCode() : null
|
||||||
|
if (code !== null) showPunctuationMarks(findChinesePunctuation(code))
|
||||||
},
|
},
|
||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -45,7 +45,10 @@ const canTrial = computed(() => {
|
|||||||
<FlowchartResult v-if="drawing" />
|
<FlowchartResult v-if="drawing" />
|
||||||
<div v-show="!drawing" class="result-pane">
|
<div v-show="!drawing" class="result-pane">
|
||||||
<n-radio-group v-if="canTrial" v-model:value="resultSegment" size="small" class="segments">
|
<n-radio-group v-if="canTrial" v-model:value="resultSegment" size="small" class="segments">
|
||||||
<n-radio-button value="submit">提交结果</n-radio-button>
|
<!-- 语法没过就没交上去:那一段不叫「提交结果」 -->
|
||||||
|
<n-radio-button value="submit">{{
|
||||||
|
syntaxErrorInfo ? "交之前检查" : "提交结果"
|
||||||
|
}}</n-radio-button>
|
||||||
<n-radio-button value="samples">运行例子</n-radio-button>
|
<n-radio-button value="samples">运行例子</n-radio-button>
|
||||||
<n-radio-button value="custom">自己输入</n-radio-button>
|
<n-radio-button value="custom">自己输入</n-radio-button>
|
||||||
</n-radio-group>
|
</n-radio-group>
|
||||||
@@ -53,7 +56,7 @@ const canTrial = computed(() => {
|
|||||||
<!-- 提交结果用 v-show:切去看运行例子时不卸载,挂着的错误说明在编辑器里标着红 -->
|
<!-- 提交结果用 v-show:切去看运行例子时不卸载,挂着的错误说明在编辑器里标着红 -->
|
||||||
<div v-show="resultSegment === 'submit' || !canTrial">
|
<div v-show="resultSegment === 'submit' || !canTrial">
|
||||||
<n-flex v-if="syntaxErrorInfo" vertical>
|
<n-flex v-if="syntaxErrorInfo" vertical>
|
||||||
<n-alert type="warning" title="代码有语法错误,还没有提交" />
|
<n-alert type="warning" title="代码有语法错误,还没有交上去" />
|
||||||
<PythonErrorExplain :err-info="syntaxErrorInfo" />
|
<PythonErrorExplain :err-info="syntaxErrorInfo" />
|
||||||
</n-flex>
|
</n-flex>
|
||||||
<template v-else-if="submission">
|
<template v-else-if="submission">
|
||||||
|
|||||||
@@ -33,6 +33,36 @@ function build(state: EditorState, mark: Mark): DecorationSet {
|
|||||||
return Decoration.set(ranges)
|
return Decoration.set(ranges)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 中文标点的标记:报错只点名第一处,但「把中文标点都换成英文(N 处)」说的是 N 处 ——
|
||||||
|
* 编辑器里只看得到一处的话,学生对不上那个 N,也不知道一键替换会改哪里。
|
||||||
|
* 字符串和注释里的不标(那是合法的,见 chinesePunctuation.ts)
|
||||||
|
*/
|
||||||
|
const setPunctuation = StateEffect.define<PunctuationFix[]>()
|
||||||
|
const punctuationDeco = Decoration.mark({ class: "cm-punctuation-mark" })
|
||||||
|
|
||||||
|
const punctuationField = StateField.define<DecorationSet>({
|
||||||
|
create: () => Decoration.none,
|
||||||
|
update(deco, tr) {
|
||||||
|
deco = deco.map(tr.changes)
|
||||||
|
for (const effect of tr.effects) {
|
||||||
|
if (effect.is(setPunctuation)) {
|
||||||
|
const max = tr.state.doc.length
|
||||||
|
deco = Decoration.set(
|
||||||
|
effect.value
|
||||||
|
.filter((fix) => fix.to <= max && fix.to > fix.from)
|
||||||
|
.map((fix) => punctuationDeco.range(fix.from, fix.to)),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// 清错误标记的时候(下一次提交、一键替换)一起清
|
||||||
|
if (effect.is(setMark) && effect.value === null) deco = Decoration.none
|
||||||
|
}
|
||||||
|
return deco
|
||||||
|
},
|
||||||
|
provide: (field) => EditorView.decorations.from(field),
|
||||||
|
})
|
||||||
|
|
||||||
const markField = StateField.define<DecorationSet>({
|
const markField = StateField.define<DecorationSet>({
|
||||||
create: () => Decoration.none,
|
create: () => Decoration.none,
|
||||||
update(deco, tr) {
|
update(deco, tr) {
|
||||||
@@ -68,9 +98,19 @@ const theme = EditorView.baseTheme({
|
|||||||
textUnderlineOffset: "3px",
|
textUnderlineOffset: "3px",
|
||||||
backgroundColor: "rgba(208, 48, 80, 0.18)",
|
backgroundColor: "rgba(208, 48, 80, 0.18)",
|
||||||
},
|
},
|
||||||
|
".cm-punctuation-mark": {
|
||||||
|
backgroundColor: "rgba(240, 160, 32, 0.35)",
|
||||||
|
outline: "1px solid rgba(240, 160, 32, 0.8)",
|
||||||
|
borderRadius: "2px",
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const errorMarkExtensions = [markField, tracker, theme]
|
export const errorMarkExtensions = [markField, punctuationField, tracker, theme]
|
||||||
|
|
||||||
|
/** 标出这些中文标点(位置是整篇代码里的偏移,来自 findChinesePunctuation) */
|
||||||
|
export function showPunctuationMarks(fixes: PunctuationFix[]) {
|
||||||
|
current?.dispatch({ effects: setPunctuation.of(fixes) })
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标出第 `line` 行并滚过去。`sourceLine` 是报错里打出来的那一行(去了行首空格),
|
* 标出第 `line` 行并滚过去。`sourceLine` 是报错里打出来的那一行(去了行首空格),
|
||||||
|
|||||||
Reference in new issue
Block a user