Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions app/pagesList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,18 @@ export const pagesList = [
lang: "C++",
description: "C++の基本から高度な機能までを学べるチュートリアル",
pages: [
{ id: 1, title: "C++の世界へようこそ" },
{ id: 2, title: "型システムとメモリ" },
{ id: 3, title: "関数と参照" },
{ id: 4, title: "ポインタと動的メモリ" },
{ id: 5, title: "クラスの基礎" },
{ id: 6, title: "クラスを使いこなす" },
{ id: 7, title: "継承とポリモーフィズム" },
{ id: 8, title: "テンプレート" },
{ id: 9, title: "STL ①:コンテナ" },
{ id: 10, title: "STL ②:アルゴリズムとラムダ式"},
{ id: 11, title: "RAIIとスマートポインタ" },
{ id: 12, title: "プロジェクトの分割とビルド" },
],
},
] as const;
Expand Down
14 changes: 3 additions & 11 deletions app/terminal/exec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export type ExecLang = "python" | "cpp";
interface ExecProps {
/*
* Pythonの場合はメインファイル1つのみを指定する。
* C++の場合はソースコード(.cpp)とヘッダー(.h)を全部指定し、ExecFile内で拡張子を元にソースコードと追加コードを分ける
* C++の場合はソースコード(.cpp)を全部指定する
*/
filenames: string[];
language: ExecLang;
Expand Down Expand Up @@ -63,17 +63,9 @@ export function ExecFile(props: ExecProps) {
if (!props.filenames || props.filenames.length === 0) {
throw new Error("C++の実行には filenames プロパティが必要です");
}
commandline = wandbox.cppOptions
? `${wandbox.cppOptions.commandline} ${props.filenames.join(" ")} && ./a.out`
: "";
commandline = wandbox.getCommandlineStr("C++", props.filenames);
runtimeInitializing = false;
const namesSource = props.filenames!.filter((name) =>
name.endsWith(".cpp")
);
const namesAdditional = props.filenames!.filter(
(name) => !name.endsWith(".cpp")
);
exec = () => wandbox.runFiles("C++", namesSource, namesAdditional);
exec = () => wandbox.runFiles("C++", props.filenames);
break;
default:
props.language satisfies never;
Expand Down
5 changes: 4 additions & 1 deletion app/terminal/repl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { useSectionCode } from "../[docs_id]/section";
import { Terminal } from "@xterm/xterm";

export interface ReplOutput {
type: "stdout" | "stderr" | "error" | "return" | "system"; // 出力の種類
type: "stdout" | "stderr" | "error" | "return" | "trace" | "system"; // 出力の種類
message: string; // 出力メッセージ
}
export interface ReplCommand {
Expand All @@ -41,6 +41,9 @@ export function writeOutput(
case "error":
term.write(chalk.red(message));
break;
case "trace":
term.write(chalk.blue.italic(message));
break;
case "system":
term.write(systemMessageColor(message));
break;
Expand Down
146 changes: 146 additions & 0 deletions app/terminal/wandbox/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import { type Fetcher } from "swr";
import { type ReplOutput } from "../repl";

const WANDBOX = "https://wandbox.org";
// https://github.com/melpon/wandbox/blob/ajax/kennel2/API.rst <- 古いけど、説明と例がある
// https://github.com/melpon/wandbox/blob/master/feline/src/types.rs
/* RustのVec<u8>はバイト配列ですが、serialize_with = "serialize_utf8"という指定があるため、
JSONにシリアライズされる際にはUTF-8文字列に変換されると解釈し、TypeScriptの型はstringとします。
by gemini
*/
export interface SwitchOption {
name: string;
"display-flags": string;
"display-name": string;
}
export interface SwitchSingle {
type: "single";
name: string;
"display-name": string;
"display-flags": string;
default: boolean;
}
export interface SwitchSelect {
type: "select";
name: string;
options: SwitchOption[];
default: string;
}
/**
* Rustの 'Switch' enum に対応するディスクリミネேテッドユニオン型です。
* 'type' プロパティの値によって `SwitchSingle` か `SwitchSelect` かを判別できます。
*/
export type Switch = SwitchSingle | SwitchSelect;
export interface CompilerInfo {
name: string;
version: string;
language: string;
"display-name": string;
templates: string[];
"compiler-option-raw": boolean;
"runtime-option-raw": boolean;
"display-compile-command": string;
switches: Switch[];
}
interface Code {
file: string;
code: string;
}
export interface CompileParameter {
compiler: string;
code: string;
codes?: Code[];
options?: string;
stdin?: string;
"compiler-option-raw"?: string;
"runtime-option-raw"?: string;
github_user?: string;
title?: string;
description?: string;
save?: boolean;
created_at?: number;
is_private?: boolean;
"compiler-info"?: CompilerInfo;
}
export interface CompileResult {
status: string;
signal: string;
compiler_output: string;
compiler_error: string;
compiler_message: string;
program_output: string;
program_error: string;
program_message: string;
permlink: string;
url: string;
}

export const compilerInfoFetcher: Fetcher<CompilerInfo[]> = () =>
fetch(new URL("/api/list.json", WANDBOX)).then(
(res) => res.json() as Promise<CompilerInfo[]>
);

interface CompileProps {
compilerName: string;
compilerOptions: string[];
compilerOptionsRaw: string[];
codes: Code[];
}
export interface CompileResultWithOutput extends CompileResult {
compilerOutput: ReplOutput[];
compilerError: ReplOutput[];
programOutput: ReplOutput[];
programError: ReplOutput[];
}

export async function compileAndRun(
options: CompileProps
): Promise<CompileResultWithOutput> {
const result: CompileResult = await fetch(
new URL("/api/compile.json", WANDBOX),
{
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
compiler: options.compilerName,
code: "",
codes: options.codes,
options: options.compilerOptions.join(","),
stdin: "",
"compiler-option-raw": options.compilerOptionsRaw.join("\n"),
"runtime-option-raw": "",
save: false,
is_private: true,
} satisfies CompileParameter),
}
).then((res) => res.json());
return {
...result,
compilerOutput: result.compiler_output.trim()
? result.compiler_output
.trim()
.split("\n")
.map((line) => ({ type: "stdout" as const, message: line }))
: [],
compilerError: result.compiler_error.trim()
? result.compiler_error
.trim()
.split("\n")
.map((line) => ({ type: "error" as const, message: line }))
: [],
programOutput: result.program_output.trim()
? result.program_output
.trim()
.split("\n")
.map((line) => ({ type: "stdout" as const, message: line }))
: [],
programError: result.program_error.trim()
? result.program_error
.trim()
.split("\n")
.map((line) => ({ type: "error" as const, message: line }))
: [],
};
}
Loading