Skip to content

Commit 0c04f9a

Browse files
authored
Show exit code and duration in checker details. Show checker running state. (#659)
1 parent 9a4637c commit 0c04f9a

6 files changed

Lines changed: 103 additions & 17 deletions

File tree

src/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@ export type RunningCommand = {
226226
id: number;
227227
} & WebviewMessageCommon;
228228

229+
export type CheckingCommand = {
230+
command: 'checking';
231+
id: number;
232+
} & WebviewMessageCommon;
233+
229234
export type NotRunningCommand = {
230235
command: 'not-running';
231236
};
@@ -279,6 +284,7 @@ export type UpdateOnlineJudgeEnvCommand = {
279284
export type VSToWebViewMessage =
280285
| ResultCommand
281286
| RunningCommand
287+
| CheckingCommand
282288
| RunAllInWebViewCommand
283289
| CompilingStartCommand
284290
| CompilingStopCommand

src/webview/frontend/App.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
VSToWebViewMessage,
99
ResultCommand,
1010
RunningCommand,
11+
CheckingCommand,
1112
WebViewpersistenceState,
1213
} from '../../types';
1314
import CaseView from './CaseView';
@@ -97,6 +98,7 @@ function Judge(props: {
9798

9899
const [focusLast, setFocusLast] = useState<boolean>(false);
99100
const [forceRunning, setForceRunning] = useState<number | false>(false);
101+
const [forceChecking, setForceChecking] = useState<number | false>(false);
100102
const [compiling, setCompiling] = useState<boolean>(false);
101103
const [notification, setNotification] = useState<string | null>(null);
102104
const [waitingForSubmit, setWaitingForSubmit] = useState<boolean>(false);
@@ -217,8 +219,8 @@ function Judge(props: {
217219
handleRunning(data);
218220
break;
219221
}
220-
case 'run-all': {
221-
runAll();
222+
case 'checking': {
223+
handleChecking(data);
222224
break;
223225
}
224226
case 'compiling-start': {
@@ -253,6 +255,10 @@ function Judge(props: {
253255
setForceRunning(data.id);
254256
};
255257

258+
const handleChecking = (data: CheckingCommand) => {
259+
setForceChecking(data.id);
260+
};
261+
256262
const refreshOnlineJudge = () => {
257263
let sendEnv = 'false';
258264
if (onlineJudgeEnv) sendEnv = 'true';
@@ -369,6 +375,16 @@ function Judge(props: {
369375
return false;
370376
};
371377

378+
const getCheckingProp = (value: Case) => {
379+
if (forceChecking === value.id) {
380+
setTimeout(() => {
381+
setForceChecking(false);
382+
}, 100);
383+
return true;
384+
}
385+
return false;
386+
};
387+
372388
const toggleOnlineJudgeEnv = () => {
373389
const newEnv = !onlineJudgeEnv;
374390
setOnlineJudgeEnv(newEnv);
@@ -438,6 +454,7 @@ function Judge(props: {
438454
remove={remove}
439455
doFocus={true}
440456
forceRunning={getRunningProp(value)}
457+
forceChecking={getCheckingProp(value)}
441458
updateCase={updateCase}
442459
customCheckerPath={problem.customCheckerPath}
443460
></CaseView>,
@@ -453,6 +470,7 @@ function Judge(props: {
453470
key={value.id.toString()}
454471
remove={remove}
455472
forceRunning={getRunningProp(value)}
473+
forceChecking={getCheckingProp(value)}
456474
updateCase={updateCase}
457475
customCheckerPath={problem.customCheckerPath}
458476
></CaseView>,

src/webview/frontend/CaseView.tsx

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ export default function CaseView(props: {
2222
notify: (text: string) => void;
2323
doFocus?: boolean;
2424
forceRunning: boolean;
25+
forceChecking: boolean;
2526
customCheckerPath?: string;
2627
}) {
2728
const { id, result } = props.case;
2829

2930
const [input, setInput] = useState<string>(props.case.testcase.input);
3031
const [output, setOutput] = useState<string>(props.case.testcase.output);
3132
const [running, setRunning] = useState<boolean>(false);
33+
const [checking, setChecking] = useState<boolean>(false);
3234
const [minimized, setMinimized] = useState<boolean>(
3335
props.case.result?.pass === true,
3436
);
@@ -47,9 +49,17 @@ export default function CaseView(props: {
4749
useEffect(() => {
4850
if (props.forceRunning) {
4951
setRunning(true);
52+
setChecking(false);
5053
}
5154
}, [props.forceRunning]);
5255

56+
useEffect(() => {
57+
if (props.forceChecking) {
58+
setRunning(false);
59+
setChecking(true);
60+
}
61+
}, [props.forceChecking]);
62+
5363
const handleInputChange = (
5464
event: React.ChangeEvent<HTMLTextAreaElement>,
5565
) => {
@@ -85,15 +95,16 @@ export default function CaseView(props: {
8595
useEffect(() => {
8696
if (props.case.result !== null) {
8797
setRunning(false);
98+
setChecking(false);
8899
props.case.result.pass ? setMinimized(true) : setMinimized(false);
89100
}
90101
}, [props.case.result]);
91102

92103
useEffect(() => {
93-
if (running) {
104+
if (running || checking) {
94105
setMinimized(true);
95106
}
96-
}, [running]);
107+
}, [running, checking]);
97108

98109
useEffect(() => {
99110
window.addEventListener('message', function (event) {
@@ -118,15 +129,16 @@ export default function CaseView(props: {
118129
if (!result) {
119130
resultText = t('runToShowOutput');
120131
}
121-
if (running) {
132+
if (running || checking) {
122133
resultText = '...';
123134
}
124135
const passFailText = result
125136
? result.pass
126137
? t('passed')
127138
: t('failed')
128139
: '';
129-
const caseClassName = 'case ' + (running ? 'running' : passFailText);
140+
const caseClassName =
141+
'case ' + (running || checking ? 'running' : passFailText);
130142
const timeText = result?.timeOut ? t('timedOut') : result?.time + 'ms';
131143

132144
return (
@@ -150,10 +162,12 @@ export default function CaseView(props: {
150162
)}
151163
&nbsp;TC {props.num}
152164
</span>
153-
{running && (
154-
<span className="running-text">{t('running')}</span>
165+
{(running || checking) && (
166+
<span className="running-text">
167+
{running ? t('running') : t('checking')}
168+
</span>
155169
)}
156-
{result && !running && (
170+
{result && !running && !checking && (
157171
<>
158172
<span className="result-data">
159173
<span
@@ -280,14 +294,34 @@ export default function CaseView(props: {
280294
{t('checkerLog')}
281295
</summary>
282296
<div style={{ marginTop: '5px' }}>
283-
<small>{t('checkerInvocation')}</small>
297+
<small
298+
style={{
299+
display: 'block',
300+
marginTop: '5px',
301+
}}
302+
>
303+
{t('checkerExitCode')}{' '}
304+
<code>
305+
{props.case.result.checkerRun.code}
306+
</code>
307+
</small>
308+
<small
309+
style={{
310+
display: 'block',
311+
marginTop: '10px',
312+
}}
313+
>
314+
{t('checkerOutput')}
315+
</small>
284316
<textarea
285317
className="selectable"
286318
readOnly
287-
value={props.case.result.checkerRun.command}
319+
value={trunctateStdout(
320+
`STDOUT:\n${props.case.result.checkerRun.stdout}\n\nSTDERR:\n${props.case.result.checkerRun.stderr}`,
321+
)}
288322
style={{
289323
fontSize: '0.9em',
290-
height: '40px',
324+
height: '100px',
291325
width: '100%',
292326
display: 'block',
293327
marginTop: '5px',
@@ -299,22 +333,29 @@ export default function CaseView(props: {
299333
marginTop: '10px',
300334
}}
301335
>
302-
{t('checkerOutput')}
336+
{t('checkerInvocation')}
303337
</small>
304338
<textarea
305339
className="selectable"
306340
readOnly
307-
value={trunctateStdout(
308-
`STDOUT:\n${props.case.result.checkerRun.stdout}\n\nSTDERR:\n${props.case.result.checkerRun.stderr}`,
309-
)}
341+
value={props.case.result.checkerRun.command}
310342
style={{
311343
fontSize: '0.9em',
312-
height: '100px',
344+
height: '40px',
313345
width: '100%',
314346
display: 'block',
315347
marginTop: '5px',
316348
}}
317349
/>
350+
<small
351+
style={{
352+
display: 'block',
353+
marginTop: '10px',
354+
}}
355+
>
356+
{t('checkerDuration')}{' '}
357+
{props.case.result.checkerRun.time}ms
358+
</small>
318359
</div>
319360
</details>
320361
)}

src/webview/frontend/app.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,10 @@ body.vscode-light .result-fail {
465465
font-size: 1.15em;
466466
}
467467

468+
body.vscode-light .running-text {
469+
color: rgb(160, 160, 0);
470+
}
471+
468472
.problem-name {
469473
display: inline-block;
470474
font-size: 1.1em;

src/webview/processRunSingle.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ export const runSingleAndSave = async (
7070
) {
7171
const checkerPath = problem.customCheckerPath.trim();
7272
if (fs.existsSync(checkerPath)) {
73+
getJudgeViewProvider().extensionToJudgeViewMessage({
74+
command: 'checking',
75+
id,
76+
problem,
77+
});
7378
checkerRun = await runCustomChecker(
7479
checkerPath,
7580
testCase.input,

src/webview/translations.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export const translations: Record<string, any> = {
5858
runToShowOutput: 'Run to show output',
5959
timedOut: 'Timed Out',
6060
running: 'Running',
61+
checking: 'Checking',
6162
inputLabel: 'Input:',
6263
expectedOutputLabel: 'Expected Output:',
6364
receivedOutputLabel: 'Received Output:',
@@ -100,6 +101,8 @@ export const translations: Record<string, any> = {
100101
checkerLog: 'Checker Log',
101102
checkerInvocation: 'Checker Invocation:',
102103
checkerOutput: 'Checker Output:',
104+
checkerExitCode: 'Checker Exit Code:',
105+
checkerDuration: 'Checker Duration:',
103106
argScriptPath:
104107
'The full filesystem path to your Python checker script.',
105108
argInputFile:
@@ -165,6 +168,7 @@ export const translations: Record<string, any> = {
165168
runToShowOutput: '运行以显示输出',
166169
timedOut: '超时',
167170
running: '运行中',
171+
checking: '检查中',
168172
inputLabel: '输入:',
169173
expectedOutputLabel: '预期输出:',
170174
receivedOutputLabel: '实际输出:',
@@ -206,6 +210,8 @@ export const translations: Record<string, any> = {
206210
checkerLog: '判题日志',
207211
checkerInvocation: '判题脚本调用:',
208212
checkerOutput: '判题脚本输出:',
213+
checkerExitCode: '退出代码:',
214+
checkerDuration: '执行耗时:',
209215
argScriptPath: '您的 Python 判题脚本的完整文件路径。',
210216
argInputFile: '由 CPH 生成的临时文件,包含当前测试用例的输入数据。',
211217
argOutputFile: '由 CPH 生成的临时文件,包含您的程序生成的实际输出。',
@@ -268,6 +274,7 @@ export const translations: Record<string, any> = {
268274
runToShowOutput: '출력을 보려면 실행하세요',
269275
timedOut: '시간 초과',
270276
running: '실행 중',
277+
checking: '채점 중',
271278
inputLabel: '입력:',
272279
expectedOutputLabel: '예상 출력:',
273280
receivedOutputLabel: '실제 출력:',
@@ -309,6 +316,8 @@ export const translations: Record<string, any> = {
309316
checkerLog: '채점 로그',
310317
checkerInvocation: '스크립트 호출:',
311318
checkerOutput: '스크립트 출력:',
319+
checkerExitCode: '종료 코드:',
320+
checkerDuration: '실행 시간:',
312321
argScriptPath: 'Python 채점 스크립트의 전체 파일 시스템 경로입니다.',
313322
argInputFile:
314323
'현재 테스트케이스의 입력 데이터가 포함된 CPH 생성 임시 파일입니다.',
@@ -374,6 +383,7 @@ export const translations: Record<string, any> = {
374383
runToShowOutput: '実行して出力を表示',
375384
timedOut: 'タイムアウト',
376385
running: '実行中',
386+
checking: '判定中',
377387
inputLabel: '入力:',
378388
expectedOutputLabel: '期待される出力:',
379389
receivedOutputLabel: '実際の出力:',
@@ -416,6 +426,8 @@ export const translations: Record<string, any> = {
416426
checkerLog: '判題ログ',
417427
checkerInvocation: 'スクリプト呼び出し:',
418428
checkerOutput: 'スクリプト出力:',
429+
checkerExitCode: '終了コード:',
430+
checkerDuration: '実行時間:',
419431
argScriptPath: 'Python 判題スクリプトのフルパスです。',
420432
argInputFile:
421433
'現在のテストケースの入力データを含む、CPH が生成したテンポラリファイルです。',

0 commit comments

Comments
 (0)