@rhseung/ps-cli 1.10.2 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-7DZDLCGW.js → chunk-3DTUNRPH.js} +6 -53
- package/dist/chunk-3LR2NGRC.js +55 -0
- package/dist/{chunk-GV265WOR.js → chunk-4VPUJY7G.js} +52 -2
- package/dist/{chunk-NYMNFORB.js → chunk-C25Y3KFE.js} +2 -98
- package/dist/chunk-CCTXJBQK.js +135 -0
- package/dist/{chunk-CUSSKX2F.js → chunk-COPOWZM5.js} +234 -16
- package/dist/chunk-EZLFR55N.js +70 -0
- package/dist/{chunk-HCUVCES6.js → chunk-LCHSAHUP.js} +2 -64
- package/dist/chunk-MZUR7SER.js +103 -0
- package/dist/chunk-NQ267PM5.js +135 -0
- package/dist/chunk-QT2FQELR.js +427 -0
- package/dist/chunk-XNZBOLC2.js +144 -0
- package/dist/{chunk-XUDGIZ2U.js → chunk-Z4O2T5WH.js} +2 -126
- package/dist/commands/archive.js +2 -1
- package/dist/commands/config.js +3 -138
- package/dist/commands/fetch.js +2 -1
- package/dist/commands/init.js +3 -422
- package/dist/commands/open.js +2 -1
- package/dist/commands/run.js +2 -51
- package/dist/commands/search.js +13 -6
- package/dist/commands/stats.js +3 -129
- package/dist/commands/submit.js +2 -1
- package/dist/commands/test.js +11 -2
- package/package.json +1 -1
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
copyToClipboard
|
|
4
|
+
} from "./chunk-MZUR7SER.js";
|
|
5
|
+
import {
|
|
6
|
+
openBrowser
|
|
7
|
+
} from "./chunk-QGMWUOJ3.js";
|
|
2
8
|
import {
|
|
3
9
|
runSolution
|
|
4
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-4VPUJY7G.js";
|
|
5
11
|
import {
|
|
6
12
|
Command,
|
|
7
13
|
CommandBuilder,
|
|
8
14
|
CommandDef,
|
|
9
15
|
__decorateClass,
|
|
10
16
|
defineFlags,
|
|
17
|
+
detectProblemIdFromPath,
|
|
18
|
+
findSolutionFile,
|
|
11
19
|
getProblemTimeLimitMs,
|
|
12
20
|
getSupportedLanguagesString,
|
|
13
21
|
icons,
|
|
@@ -16,8 +24,9 @@ import {
|
|
|
16
24
|
} from "./chunk-AHE4QHJD.js";
|
|
17
25
|
|
|
18
26
|
// src/commands/test.tsx
|
|
19
|
-
import { Alert, Spinner } from "@inkjs/ui";
|
|
20
|
-
import { Box as Box2, Text as Text2 } from "ink";
|
|
27
|
+
import { Alert, Badge as Badge2, Spinner, StatusMessage as StatusMessage2 } from "@inkjs/ui";
|
|
28
|
+
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
29
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
21
30
|
|
|
22
31
|
// src/components/test-result.tsx
|
|
23
32
|
import { Badge, StatusMessage } from "@inkjs/ui";
|
|
@@ -195,8 +204,7 @@ function useTestRunner({
|
|
|
195
204
|
problemDir,
|
|
196
205
|
language,
|
|
197
206
|
watch,
|
|
198
|
-
timeoutMs
|
|
199
|
-
onComplete
|
|
207
|
+
timeoutMs
|
|
200
208
|
}) {
|
|
201
209
|
const [status, setStatus] = useState("loading");
|
|
202
210
|
const [results, setResults] = useState([]);
|
|
@@ -254,13 +262,6 @@ function useTestRunner({
|
|
|
254
262
|
void watcher.close();
|
|
255
263
|
};
|
|
256
264
|
}, [problemDir, watch, runTests]);
|
|
257
|
-
useEffect(() => {
|
|
258
|
-
if (!watch && status === "ready") {
|
|
259
|
-
const timer = setTimeout(() => onComplete(), 200);
|
|
260
|
-
return () => clearTimeout(timer);
|
|
261
|
-
}
|
|
262
|
-
return void 0;
|
|
263
|
-
}, [status, watch, onComplete]);
|
|
264
265
|
return {
|
|
265
266
|
status,
|
|
266
267
|
results,
|
|
@@ -269,6 +270,62 @@ function useTestRunner({
|
|
|
269
270
|
};
|
|
270
271
|
}
|
|
271
272
|
|
|
273
|
+
// src/hooks/use-testcase-ac.ts
|
|
274
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
275
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
276
|
+
var TESTCASE_AC_BASE_URL = "https://testcase.ac";
|
|
277
|
+
function useTestcaseAc({
|
|
278
|
+
problemId,
|
|
279
|
+
sourcePath,
|
|
280
|
+
onComplete
|
|
281
|
+
}) {
|
|
282
|
+
const [status, setStatus] = useState2(
|
|
283
|
+
"loading"
|
|
284
|
+
);
|
|
285
|
+
const [message, setMessage] = useState2("testcase.ac \uC900\uBE44 \uC911...");
|
|
286
|
+
const [error, setError] = useState2(null);
|
|
287
|
+
const [url, setUrl] = useState2("");
|
|
288
|
+
const [clipboardSuccess, setClipboardSuccess] = useState2(false);
|
|
289
|
+
const [clipboardError, setClipboardError] = useState2(null);
|
|
290
|
+
useEffect2(() => {
|
|
291
|
+
async function open() {
|
|
292
|
+
try {
|
|
293
|
+
setMessage("\uC18C\uC2A4 \uCF54\uB4DC\uB97C \uC77D\uB294 \uC911...");
|
|
294
|
+
const sourceCode = await readFile2(sourcePath, "utf-8");
|
|
295
|
+
setMessage("\uD074\uB9BD\uBCF4\uB4DC\uC5D0 \uBCF5\uC0AC\uD558\uB294 \uC911...");
|
|
296
|
+
const clipboardResult = await copyToClipboard(sourceCode);
|
|
297
|
+
setClipboardSuccess(clipboardResult);
|
|
298
|
+
if (!clipboardResult) {
|
|
299
|
+
setClipboardError("\uD074\uB9BD\uBCF4\uB4DC \uBCF5\uC0AC\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
|
|
300
|
+
}
|
|
301
|
+
const url2 = `${TESTCASE_AC_BASE_URL}/problems/${problemId}`;
|
|
302
|
+
setUrl(url2);
|
|
303
|
+
setMessage("\uBE0C\uB77C\uC6B0\uC800\uB97C \uC5EC\uB294 \uC911...");
|
|
304
|
+
await openBrowser(url2);
|
|
305
|
+
setStatus("success");
|
|
306
|
+
setTimeout(() => {
|
|
307
|
+
onComplete();
|
|
308
|
+
}, 2e3);
|
|
309
|
+
} catch (err) {
|
|
310
|
+
setStatus("error");
|
|
311
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
312
|
+
setTimeout(() => {
|
|
313
|
+
onComplete();
|
|
314
|
+
}, 2e3);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
void open();
|
|
318
|
+
}, [problemId, sourcePath, onComplete]);
|
|
319
|
+
return {
|
|
320
|
+
status,
|
|
321
|
+
message,
|
|
322
|
+
error,
|
|
323
|
+
url,
|
|
324
|
+
clipboardSuccess,
|
|
325
|
+
clipboardError
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
272
329
|
// src/commands/test.tsx
|
|
273
330
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
274
331
|
var testFlagsSchema = {
|
|
@@ -283,21 +340,146 @@ var testFlagsSchema = {
|
|
|
283
340
|
shortFlag: "w",
|
|
284
341
|
description: `watch \uBAA8\uB4DC (\uD30C\uC77C \uBCC0\uACBD \uC2DC \uC790\uB3D9 \uC7AC\uD14C\uC2A4\uD2B8)
|
|
285
342
|
solution.*, testcases/**/*.txt \uD30C\uC77C \uBCC0\uACBD \uAC10\uC9C0`
|
|
343
|
+
},
|
|
344
|
+
testcaseAc: {
|
|
345
|
+
type: "boolean",
|
|
346
|
+
description: "\uB85C\uCEEC \uD14C\uC2A4\uD2B8 \uC2E4\uD589 \uC5C6\uC774 testcase.ac \uBB38\uC81C \uD398\uC774\uC9C0\uB97C \uC5F4\uACE0 \uC18C\uC2A4\uB97C \uD074\uB9BD\uBCF4\uB4DC\uC5D0 \uBCF5\uC0AC\uD569\uB2C8\uB2E4"
|
|
286
347
|
}
|
|
287
348
|
};
|
|
349
|
+
function TestcaseAcPanel({
|
|
350
|
+
problemId,
|
|
351
|
+
sourcePath,
|
|
352
|
+
onComplete
|
|
353
|
+
}) {
|
|
354
|
+
const { status, message, error, url, clipboardSuccess, clipboardError } = useTestcaseAc({
|
|
355
|
+
problemId,
|
|
356
|
+
sourcePath,
|
|
357
|
+
onComplete
|
|
358
|
+
});
|
|
359
|
+
if (status === "loading") {
|
|
360
|
+
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsx2(Spinner, { label: message }) });
|
|
361
|
+
}
|
|
362
|
+
if (status === "error") {
|
|
363
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: 1, children: [
|
|
364
|
+
/* @__PURE__ */ jsxs2(Alert, { variant: "error", children: [
|
|
365
|
+
"testcase.ac \uC5F4\uAE30 \uC2E4\uD328: ",
|
|
366
|
+
error
|
|
367
|
+
] }),
|
|
368
|
+
url && /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsxs2(Text2, { color: "gray", children: [
|
|
369
|
+
"URL: ",
|
|
370
|
+
url
|
|
371
|
+
] }) })
|
|
372
|
+
] });
|
|
373
|
+
}
|
|
374
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: "100%", marginTop: 1, children: [
|
|
375
|
+
/* @__PURE__ */ jsx2(StatusMessage2, { variant: "success", children: "testcase.ac \uD398\uC774\uC9C0\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4!" }),
|
|
376
|
+
/* @__PURE__ */ jsxs2(
|
|
377
|
+
Box2,
|
|
378
|
+
{
|
|
379
|
+
flexDirection: "column",
|
|
380
|
+
borderStyle: "round",
|
|
381
|
+
borderColor: "gray",
|
|
382
|
+
marginTop: 1,
|
|
383
|
+
paddingX: 1,
|
|
384
|
+
paddingY: 0,
|
|
385
|
+
alignSelf: "flex-start",
|
|
386
|
+
children: [
|
|
387
|
+
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
388
|
+
/* @__PURE__ */ jsx2(Text2, { color: "cyan", bold: true, children: "\uBB38\uC81C \uBC88\uD638:" }),
|
|
389
|
+
" ",
|
|
390
|
+
problemId
|
|
391
|
+
] }),
|
|
392
|
+
url && /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
393
|
+
/* @__PURE__ */ jsx2(Text2, { color: "cyan", bold: true, children: "URL:" }),
|
|
394
|
+
" ",
|
|
395
|
+
/* @__PURE__ */ jsx2(Text2, { color: "blue", underline: true, children: url })
|
|
396
|
+
] }),
|
|
397
|
+
/* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: clipboardSuccess ? /* @__PURE__ */ jsx2(Badge2, { color: "green", children: "\uD074\uB9BD\uBCF4\uB4DC\uC5D0 \uBCF5\uC0AC\uB428" }) : /* @__PURE__ */ jsx2(Badge2, { color: "yellow", children: "\uD074\uB9BD\uBCF4\uB4DC \uBCF5\uC0AC \uC2E4\uD328" }) }),
|
|
398
|
+
clipboardError && !clipboardSuccess && /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx2(Alert, { variant: "warning", children: clipboardError }) })
|
|
399
|
+
]
|
|
400
|
+
}
|
|
401
|
+
)
|
|
402
|
+
] });
|
|
403
|
+
}
|
|
288
404
|
function TestView({
|
|
289
405
|
problemDir,
|
|
290
406
|
language,
|
|
291
407
|
watch,
|
|
292
408
|
timeoutMs,
|
|
293
|
-
onComplete
|
|
409
|
+
onComplete,
|
|
410
|
+
problemId,
|
|
411
|
+
sourcePath
|
|
294
412
|
}) {
|
|
295
413
|
const { status, results, summary, error } = useTestRunner({
|
|
296
414
|
problemDir,
|
|
297
415
|
language,
|
|
298
416
|
watch,
|
|
299
417
|
timeoutMs,
|
|
300
|
-
onComplete
|
|
418
|
+
onComplete: () => {
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
const [completed, setCompleted] = useState3(false);
|
|
422
|
+
const [showSuggestion, setShowSuggestion] = useState3(false);
|
|
423
|
+
const [acceptedSuggestion, setAcceptedSuggestion] = useState3(false);
|
|
424
|
+
const allPassed = summary.total > 0 && summary.total === summary.passed && summary.failed === 0 && summary.errored === 0;
|
|
425
|
+
useEffect3(() => {
|
|
426
|
+
if (watch || completed) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
if (status === "error") {
|
|
430
|
+
const timer = setTimeout(() => {
|
|
431
|
+
setCompleted(true);
|
|
432
|
+
onComplete();
|
|
433
|
+
}, 200);
|
|
434
|
+
return () => clearTimeout(timer);
|
|
435
|
+
}
|
|
436
|
+
if (status === "ready") {
|
|
437
|
+
const canSuggest = allPassed && !!problemId && !!sourcePath && !acceptedSuggestion;
|
|
438
|
+
if (!canSuggest) {
|
|
439
|
+
const timer = setTimeout(() => {
|
|
440
|
+
setCompleted(true);
|
|
441
|
+
onComplete();
|
|
442
|
+
}, 200);
|
|
443
|
+
return () => clearTimeout(timer);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return void 0;
|
|
447
|
+
}, [
|
|
448
|
+
status,
|
|
449
|
+
watch,
|
|
450
|
+
completed,
|
|
451
|
+
onComplete,
|
|
452
|
+
allPassed,
|
|
453
|
+
acceptedSuggestion,
|
|
454
|
+
problemId,
|
|
455
|
+
sourcePath
|
|
456
|
+
]);
|
|
457
|
+
useEffect3(() => {
|
|
458
|
+
if (watch) {
|
|
459
|
+
setShowSuggestion(false);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if (status === "ready" && allPassed && problemId && sourcePath) {
|
|
463
|
+
setShowSuggestion(true);
|
|
464
|
+
} else {
|
|
465
|
+
setShowSuggestion(false);
|
|
466
|
+
}
|
|
467
|
+
}, [status, allPassed, watch]);
|
|
468
|
+
useInput((input, key) => {
|
|
469
|
+
if (!showSuggestion || acceptedSuggestion || completed) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
const lower = input.toLowerCase();
|
|
473
|
+
if (lower === "y" || key.return) {
|
|
474
|
+
setAcceptedSuggestion(true);
|
|
475
|
+
setShowSuggestion(false);
|
|
476
|
+
} else if (lower === "n" || key.escape) {
|
|
477
|
+
setShowSuggestion(false);
|
|
478
|
+
if (!completed) {
|
|
479
|
+
setCompleted(true);
|
|
480
|
+
onComplete();
|
|
481
|
+
}
|
|
482
|
+
}
|
|
301
483
|
});
|
|
302
484
|
if (status === "loading") {
|
|
303
485
|
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: /* @__PURE__ */ jsx2(Spinner, { label: "\uD14C\uC2A4\uD2B8 \uC2E4\uD589 \uC911..." }) });
|
|
@@ -321,12 +503,46 @@ function TestView({
|
|
|
321
503
|
watch && ` ${icons.solving} watch`
|
|
322
504
|
] })
|
|
323
505
|
] }),
|
|
324
|
-
/* @__PURE__ */ jsx2(TestResultView, { results, summary })
|
|
506
|
+
/* @__PURE__ */ jsx2(TestResultView, { results, summary }),
|
|
507
|
+
showSuggestion && !acceptedSuggestion && /* @__PURE__ */ jsxs2(Box2, { marginTop: 1, flexDirection: "column", children: [
|
|
508
|
+
/* @__PURE__ */ jsx2(Alert, { variant: "info", children: "\uBAA8\uB4E0 \uB85C\uCEEC \uD14C\uC2A4\uD2B8\uB97C \uD1B5\uACFC\uD588\uC2B5\uB2C8\uB2E4. testcase.ac\uC5D0\uC11C \uCD94\uAC00 \uD14C\uC2A4\uD2B8\uB97C \uC2E4\uD589\uD574 \uBCFC\uAE4C\uC694? (Y/n)" }),
|
|
509
|
+
/* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx2(Text2, { color: "gray", children: "Y \uB610\uB294 Enter: testcase.ac \uC5F4\uAE30 / N \uB610\uB294 Esc: \uAC74\uB108\uB6F0\uAE30" }) })
|
|
510
|
+
] }),
|
|
511
|
+
acceptedSuggestion && problemId && sourcePath && !completed && /* @__PURE__ */ jsx2(
|
|
512
|
+
TestcaseAcPanel,
|
|
513
|
+
{
|
|
514
|
+
problemId,
|
|
515
|
+
sourcePath,
|
|
516
|
+
onComplete: () => {
|
|
517
|
+
if (!completed) {
|
|
518
|
+
setCompleted(true);
|
|
519
|
+
onComplete();
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
)
|
|
325
524
|
] });
|
|
326
525
|
}
|
|
327
526
|
var TestCommand = class extends Command {
|
|
328
527
|
async execute(args, flags) {
|
|
329
528
|
const context = await resolveProblemContext(args);
|
|
529
|
+
const sourcePath = await findSolutionFile(context.archiveDir);
|
|
530
|
+
let finalProblemId = context.problemId;
|
|
531
|
+
if (finalProblemId === null) {
|
|
532
|
+
finalProblemId = detectProblemIdFromPath(context.archiveDir);
|
|
533
|
+
}
|
|
534
|
+
if (flags.testcaseAc) {
|
|
535
|
+
if (finalProblemId === null) {
|
|
536
|
+
throw new Error(
|
|
537
|
+
"\uBB38\uC81C \uBC88\uD638\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBB38\uC81C \uBC88\uD638\uB97C \uC778\uC790\uB85C \uC804\uB2EC\uD558\uAC70\uB098 \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589\uD574\uC8FC\uC138\uC694."
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
await this.renderView(TestcaseAcPanel, {
|
|
541
|
+
problemId: finalProblemId,
|
|
542
|
+
sourcePath
|
|
543
|
+
});
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
330
546
|
const language = await resolveLanguage(
|
|
331
547
|
context.archiveDir,
|
|
332
548
|
flags.language
|
|
@@ -335,7 +551,9 @@ var TestCommand = class extends Command {
|
|
|
335
551
|
problemDir: context.archiveDir,
|
|
336
552
|
language,
|
|
337
553
|
watch: Boolean(flags.watch),
|
|
338
|
-
timeoutMs: flags.timeoutMs
|
|
554
|
+
timeoutMs: flags.timeoutMs,
|
|
555
|
+
problemId: finalProblemId,
|
|
556
|
+
sourcePath
|
|
339
557
|
});
|
|
340
558
|
}
|
|
341
559
|
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
useArchive
|
|
4
|
+
} from "./chunk-LCHSAHUP.js";
|
|
5
|
+
import {
|
|
6
|
+
Command,
|
|
7
|
+
CommandBuilder,
|
|
8
|
+
CommandDef,
|
|
9
|
+
__decorateClass,
|
|
10
|
+
logger,
|
|
11
|
+
resolveProblemContext
|
|
12
|
+
} from "./chunk-AHE4QHJD.js";
|
|
13
|
+
|
|
14
|
+
// src/commands/archive.tsx
|
|
15
|
+
import { StatusMessage, Alert, Spinner } from "@inkjs/ui";
|
|
16
|
+
import { Box } from "ink";
|
|
17
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
18
|
+
function ArchiveView({ problemId, onComplete }) {
|
|
19
|
+
const { status, message, error } = useArchive({
|
|
20
|
+
problemId,
|
|
21
|
+
onComplete
|
|
22
|
+
});
|
|
23
|
+
if (status === "loading") {
|
|
24
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsx(Spinner, { label: message }) });
|
|
25
|
+
}
|
|
26
|
+
if (status === "error") {
|
|
27
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Alert, { variant: "error", children: [
|
|
28
|
+
"\uC624\uB958 \uBC1C\uC0DD: ",
|
|
29
|
+
error
|
|
30
|
+
] }) });
|
|
31
|
+
}
|
|
32
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", width: "100%", children: /* @__PURE__ */ jsx(StatusMessage, { variant: "success", children: message }) });
|
|
33
|
+
}
|
|
34
|
+
var ArchiveCommand = class extends Command {
|
|
35
|
+
async execute(args, _) {
|
|
36
|
+
const context = await resolveProblemContext(args, { requireId: false });
|
|
37
|
+
if (context.problemId === null) {
|
|
38
|
+
logger.error("\uBB38\uC81C \uBC88\uD638\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694.");
|
|
39
|
+
console.log(`\uB3C4\uC6C0\uB9D0: ps archive --help`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
await this.renderView(ArchiveView, {
|
|
44
|
+
problemId: context.problemId
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
ArchiveCommand = __decorateClass([
|
|
49
|
+
CommandDef({
|
|
50
|
+
name: "archive",
|
|
51
|
+
description: `\uBB38\uC81C\uB97C \uC544\uCE74\uC774\uBE0C\uD558\uACE0 Git \uCEE4\uBC0B\uC744 \uC0DD\uC131\uD569\uB2C8\uB2E4.
|
|
52
|
+
- solving \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uBB38\uC81C\uB97C \uCC3E\uC544 archive \uB514\uB809\uD1A0\uB9AC\uB85C \uC774\uB3D9
|
|
53
|
+
- Git add \uBC0F commit \uC2E4\uD589 (\uCEE4\uBC0B \uBA54\uC2DC\uC9C0: "solve: {\uBB38\uC81C\uBC88\uD638} - {\uBB38\uC81C\uC774\uB984}")
|
|
54
|
+
- \uC544\uCE74\uC774\uBE0C \uACBD\uB85C, \uC804\uB7B5, \uC790\uB3D9 \uCEE4\uBC0B \uC5EC\uBD80 \uB4F1\uC740 ps config\uC5D0\uC11C \uC124\uC815 \uAC00\uB2A5\uD569\uB2C8\uB2E4.`,
|
|
55
|
+
flags: [],
|
|
56
|
+
autoDetectProblemId: true,
|
|
57
|
+
requireProblemId: false,
|
|
58
|
+
examples: [
|
|
59
|
+
"archive 1000",
|
|
60
|
+
"archive # \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uBB38\uC81C \uBC88\uD638 \uC790\uB3D9 \uAC10\uC9C0"
|
|
61
|
+
]
|
|
62
|
+
})
|
|
63
|
+
], ArchiveCommand);
|
|
64
|
+
var archive_default = CommandBuilder.fromClass(ArchiveCommand);
|
|
65
|
+
|
|
66
|
+
export {
|
|
67
|
+
ArchiveView,
|
|
68
|
+
ArchiveCommand,
|
|
69
|
+
archive_default
|
|
70
|
+
};
|
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
Command,
|
|
4
|
-
CommandBuilder,
|
|
5
|
-
CommandDef,
|
|
6
|
-
__decorateClass,
|
|
7
3
|
findProjectRoot,
|
|
8
4
|
getArchiveAutoCommit,
|
|
9
5
|
getArchiveCommitMessage,
|
|
10
6
|
getArchiveDirPath,
|
|
11
7
|
getSolvingDir,
|
|
12
|
-
getSolvingDirPath
|
|
13
|
-
logger,
|
|
14
|
-
resolveProblemContext
|
|
8
|
+
getSolvingDirPath
|
|
15
9
|
} from "./chunk-AHE4QHJD.js";
|
|
16
10
|
|
|
17
|
-
// src/commands/archive.tsx
|
|
18
|
-
import { StatusMessage, Alert, Spinner } from "@inkjs/ui";
|
|
19
|
-
import { Box } from "ink";
|
|
20
|
-
|
|
21
11
|
// src/hooks/use-archive.ts
|
|
22
12
|
import { access, readFile, rename, mkdir, readdir, rmdir } from "fs/promises";
|
|
23
13
|
import { join, dirname } from "path";
|
|
@@ -153,58 +143,6 @@ function useArchive({
|
|
|
153
143
|
};
|
|
154
144
|
}
|
|
155
145
|
|
|
156
|
-
// src/commands/archive.tsx
|
|
157
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
158
|
-
function ArchiveView({ problemId, onComplete }) {
|
|
159
|
-
const { status, message, error } = useArchive({
|
|
160
|
-
problemId,
|
|
161
|
-
onComplete
|
|
162
|
-
});
|
|
163
|
-
if (status === "loading") {
|
|
164
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsx(Spinner, { label: message }) });
|
|
165
|
-
}
|
|
166
|
-
if (status === "error") {
|
|
167
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Alert, { variant: "error", children: [
|
|
168
|
-
"\uC624\uB958 \uBC1C\uC0DD: ",
|
|
169
|
-
error
|
|
170
|
-
] }) });
|
|
171
|
-
}
|
|
172
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", width: "100%", children: /* @__PURE__ */ jsx(StatusMessage, { variant: "success", children: message }) });
|
|
173
|
-
}
|
|
174
|
-
var ArchiveCommand = class extends Command {
|
|
175
|
-
async execute(args, _) {
|
|
176
|
-
const context = await resolveProblemContext(args, { requireId: false });
|
|
177
|
-
if (context.problemId === null) {
|
|
178
|
-
logger.error("\uBB38\uC81C \uBC88\uD638\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694.");
|
|
179
|
-
console.log(`\uB3C4\uC6C0\uB9D0: ps archive --help`);
|
|
180
|
-
process.exit(1);
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
await this.renderView(ArchiveView, {
|
|
184
|
-
problemId: context.problemId
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
ArchiveCommand = __decorateClass([
|
|
189
|
-
CommandDef({
|
|
190
|
-
name: "archive",
|
|
191
|
-
description: `\uBB38\uC81C\uB97C \uC544\uCE74\uC774\uBE0C\uD558\uACE0 Git \uCEE4\uBC0B\uC744 \uC0DD\uC131\uD569\uB2C8\uB2E4.
|
|
192
|
-
- solving \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uBB38\uC81C\uB97C \uCC3E\uC544 archive \uB514\uB809\uD1A0\uB9AC\uB85C \uC774\uB3D9
|
|
193
|
-
- Git add \uBC0F commit \uC2E4\uD589 (\uCEE4\uBC0B \uBA54\uC2DC\uC9C0: "solve: {\uBB38\uC81C\uBC88\uD638} - {\uBB38\uC81C\uC774\uB984}")
|
|
194
|
-
- \uC544\uCE74\uC774\uBE0C \uACBD\uB85C, \uC804\uB7B5, \uC790\uB3D9 \uCEE4\uBC0B \uC5EC\uBD80 \uB4F1\uC740 ps config\uC5D0\uC11C \uC124\uC815 \uAC00\uB2A5\uD569\uB2C8\uB2E4.`,
|
|
195
|
-
flags: [],
|
|
196
|
-
autoDetectProblemId: true,
|
|
197
|
-
requireProblemId: false,
|
|
198
|
-
examples: [
|
|
199
|
-
"archive 1000",
|
|
200
|
-
"archive # \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uBB38\uC81C \uBC88\uD638 \uC790\uB3D9 \uAC10\uC9C0"
|
|
201
|
-
]
|
|
202
|
-
})
|
|
203
|
-
], ArchiveCommand);
|
|
204
|
-
var archive_default = CommandBuilder.fromClass(ArchiveCommand);
|
|
205
|
-
|
|
206
146
|
export {
|
|
207
|
-
|
|
208
|
-
ArchiveCommand,
|
|
209
|
-
archive_default
|
|
147
|
+
useArchive
|
|
210
148
|
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
openBrowser
|
|
4
|
+
} from "./chunk-QGMWUOJ3.js";
|
|
5
|
+
|
|
6
|
+
// src/hooks/use-submit.ts
|
|
7
|
+
import { readFile } from "fs/promises";
|
|
8
|
+
import { useEffect, useState } from "react";
|
|
9
|
+
|
|
10
|
+
// src/utils/clipboard.ts
|
|
11
|
+
import { execa, execaCommand } from "execa";
|
|
12
|
+
async function copyToClipboard(text) {
|
|
13
|
+
try {
|
|
14
|
+
if (process.platform === "win32") {
|
|
15
|
+
await execaCommand("clip", {
|
|
16
|
+
shell: true,
|
|
17
|
+
input: text
|
|
18
|
+
});
|
|
19
|
+
} else if (process.platform === "darwin") {
|
|
20
|
+
await execaCommand("pbcopy", {
|
|
21
|
+
shell: false,
|
|
22
|
+
input: text
|
|
23
|
+
});
|
|
24
|
+
} else {
|
|
25
|
+
try {
|
|
26
|
+
await execa("xclip", ["-selection", "clipboard"], {
|
|
27
|
+
input: text
|
|
28
|
+
});
|
|
29
|
+
} catch {
|
|
30
|
+
try {
|
|
31
|
+
await execa("xsel", ["--clipboard", "--input"], {
|
|
32
|
+
input: text
|
|
33
|
+
});
|
|
34
|
+
} catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
} catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/hooks/use-submit.ts
|
|
46
|
+
var BOJ_BASE_URL = "https://www.acmicpc.net";
|
|
47
|
+
function useSubmit({
|
|
48
|
+
problemId,
|
|
49
|
+
language: _language,
|
|
50
|
+
sourcePath,
|
|
51
|
+
onComplete
|
|
52
|
+
}) {
|
|
53
|
+
const [status, setStatus] = useState(
|
|
54
|
+
"loading"
|
|
55
|
+
);
|
|
56
|
+
const [message, setMessage] = useState("\uC81C\uCD9C \uC900\uBE44 \uC911...");
|
|
57
|
+
const [error, setError] = useState(null);
|
|
58
|
+
const [submitUrl, setSubmitUrl] = useState("");
|
|
59
|
+
const [clipboardSuccess, setClipboardSuccess] = useState(false);
|
|
60
|
+
const [clipboardError, setClipboardError] = useState(null);
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
async function submit() {
|
|
63
|
+
try {
|
|
64
|
+
setMessage("\uC18C\uC2A4 \uCF54\uB4DC\uB97C \uC77D\uB294 \uC911...");
|
|
65
|
+
const sourceCode = await readFile(sourcePath, "utf-8");
|
|
66
|
+
setMessage("\uD074\uB9BD\uBCF4\uB4DC\uC5D0 \uBCF5\uC0AC\uD558\uB294 \uC911...");
|
|
67
|
+
const clipboardResult = await copyToClipboard(sourceCode);
|
|
68
|
+
setClipboardSuccess(clipboardResult);
|
|
69
|
+
if (!clipboardResult) {
|
|
70
|
+
setClipboardError("\uD074\uB9BD\uBCF4\uB4DC \uBCF5\uC0AC\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
|
|
71
|
+
}
|
|
72
|
+
const url = `${BOJ_BASE_URL}/submit/${problemId}`;
|
|
73
|
+
setSubmitUrl(url);
|
|
74
|
+
setMessage("\uBE0C\uB77C\uC6B0\uC800\uB97C \uC5EC\uB294 \uC911...");
|
|
75
|
+
await openBrowser(url);
|
|
76
|
+
setStatus("success");
|
|
77
|
+
setTimeout(() => {
|
|
78
|
+
onComplete();
|
|
79
|
+
}, 2e3);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
setStatus("error");
|
|
82
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
83
|
+
setTimeout(() => {
|
|
84
|
+
onComplete();
|
|
85
|
+
}, 2e3);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
void submit();
|
|
89
|
+
}, [problemId, sourcePath, onComplete]);
|
|
90
|
+
return {
|
|
91
|
+
status,
|
|
92
|
+
message,
|
|
93
|
+
error,
|
|
94
|
+
submitUrl,
|
|
95
|
+
clipboardSuccess,
|
|
96
|
+
clipboardError
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export {
|
|
101
|
+
copyToClipboard,
|
|
102
|
+
useSubmit
|
|
103
|
+
};
|