add function for extracting files from editor
This commit is contained in:
parent
05cdc423fc
commit
d04f61752d
|
@ -29,7 +29,8 @@
|
||||||
"shiki": "^1.7.0",
|
"shiki": "^1.7.0",
|
||||||
"starlight-links-validator": "^0.7.1",
|
"starlight-links-validator": "^0.7.1",
|
||||||
"tm-themes": "^1.4.3",
|
"tm-themes": "^1.4.3",
|
||||||
"typescript": "^5.4.5"
|
"typescript": "^5.4.5",
|
||||||
|
"use-immer": "^0.10.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"sass": "^1.77.6"
|
"sass": "^1.77.6"
|
||||||
|
|
|
@ -65,6 +65,9 @@ dependencies:
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.4.5
|
specifier: ^5.4.5
|
||||||
version: 5.4.5
|
version: 5.4.5
|
||||||
|
use-immer:
|
||||||
|
specifier: ^0.10.0
|
||||||
|
version: 0.10.0(immer@10.1.1)(react@18.3.1)
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
sass:
|
sass:
|
||||||
|
@ -3278,6 +3281,10 @@ packages:
|
||||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/immer@10.1.1:
|
||||||
|
resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/immutable@4.3.6:
|
/immutable@4.3.6:
|
||||||
resolution: {integrity: sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==}
|
resolution: {integrity: sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==}
|
||||||
|
|
||||||
|
@ -5490,6 +5497,16 @@ packages:
|
||||||
picocolors: 1.0.1
|
picocolors: 1.0.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/use-immer@0.10.0(immer@10.1.1)(react@18.3.1):
|
||||||
|
resolution: {integrity: sha512-/eVwNR4TG9Tm/dd+aHYLLaI0FLfYKlkTqKMkn78Ah/EYVzWd/zJIgpkdoFEKbhQJOGo8XN7/mWrTx0exp1c+Ug==}
|
||||||
|
peerDependencies:
|
||||||
|
immer: '>=8.0.0'
|
||||||
|
react: ^16.8.0 || ^17.0.1 || ^18.0.0
|
||||||
|
dependencies:
|
||||||
|
immer: 10.1.1
|
||||||
|
react: 18.3.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/util-deprecate@1.0.2:
|
/util-deprecate@1.0.2:
|
||||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useMonaco, type Monaco } from "@monaco-editor/react";
|
import { useMonaco, type Monaco } from "@monaco-editor/react";
|
||||||
import FileView from "./playground/FileView";
|
import { useImmer, type ImmerHook, type Updater } from "use-immer";
|
||||||
import Editor from "./playground/Editor";
|
|
||||||
|
|
||||||
import "@styles/playground.scss";
|
import "@styles/playground.scss";
|
||||||
|
|
||||||
import mainFileContent from "@assets/playground/main.shu?raw";
|
import mainFileContent from "@assets/playground/main.shu?raw";
|
||||||
import packTomlContent from "@assets/playground/pack.toml?raw";
|
import packTomlContent from "@assets/playground/pack.toml?raw";
|
||||||
|
import FileView from "./playground/FileView";
|
||||||
|
import Editor from "./playground/Editor";
|
||||||
import Header from "./playground/Header";
|
import Header from "./playground/Header";
|
||||||
|
|
||||||
export type File = {
|
export type File = {
|
||||||
|
@ -21,7 +21,7 @@ export type Directory = {
|
||||||
export type SetState<T> = React.Dispatch<React.SetStateAction<T>>;
|
export type SetState<T> = React.Dispatch<React.SetStateAction<T>>;
|
||||||
|
|
||||||
export default function Playground() {
|
export default function Playground() {
|
||||||
const rootDir: Directory = {
|
const [rootDir, updateRootDir] = useImmer({
|
||||||
dirs: {
|
dirs: {
|
||||||
src: {
|
src: {
|
||||||
files: {
|
files: {
|
||||||
|
@ -46,15 +46,29 @@ export default function Playground() {
|
||||||
language: "toml",
|
language: "toml",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
} as Directory);
|
||||||
|
|
||||||
const [fileName, setFileName] = useState("src/main.shu");
|
const [fileName, setFileName] = useState("src/main.shu");
|
||||||
const file = getFile(rootDir, fileName)!;
|
const file = getFile(rootDir, fileName)!;
|
||||||
|
|
||||||
|
const onBuild: () => void = () => {
|
||||||
|
if (monaco) {
|
||||||
|
console.log(getFiles(monaco));
|
||||||
|
} else {
|
||||||
|
console.error("monaco has not loaded");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onZip: () => void = () => {
|
||||||
|
if (monaco) {
|
||||||
|
loadFile(monaco, updateRootDir, {content: "zip"}, "dist/pack.zip");
|
||||||
|
} else {
|
||||||
|
console.error("onZip not set");}
|
||||||
|
};
|
||||||
|
|
||||||
const monaco = useMonaco();
|
const monaco = useMonaco();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (monaco) {
|
if (monaco) {
|
||||||
loadFiles(monaco, rootDir);
|
loadFiles(monaco, updateRootDir, rootDir);
|
||||||
}
|
}
|
||||||
}, [monaco]);
|
}, [monaco]);
|
||||||
|
|
||||||
|
@ -68,7 +82,7 @@ export default function Playground() {
|
||||||
marginTop: "0.5cm",
|
marginTop: "0.5cm",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Header />
|
<Header onBuild={onBuild} onZip={onZip} />
|
||||||
<FileView
|
<FileView
|
||||||
className="file-view"
|
className="file-view"
|
||||||
root={rootDir}
|
root={rootDir}
|
||||||
|
@ -81,6 +95,38 @@ export default function Playground() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFiles(monaco: Monaco): Directory {
|
||||||
|
const files: Directory = {};
|
||||||
|
|
||||||
|
for (const model of monaco.editor.getModels()) {
|
||||||
|
const parts = model.uri.path.slice(1).split("/");
|
||||||
|
const name = parts.pop()!;
|
||||||
|
|
||||||
|
let dir = files;
|
||||||
|
for (const part of parts) {
|
||||||
|
if (!dir.dirs) {
|
||||||
|
dir.dirs = {};
|
||||||
|
}
|
||||||
|
if (!dir.dirs[part]) {
|
||||||
|
dir.dirs[part] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
dir = dir.dirs[part].files ?? {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dir.files) {
|
||||||
|
dir.files = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
dir.files[name] = {
|
||||||
|
content: model.getValue(),
|
||||||
|
language: model.getLanguageId(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
function getFile(root: Directory, path: string): File | null {
|
function getFile(root: Directory, path: string): File | null {
|
||||||
if (path.includes("/")) {
|
if (path.includes("/")) {
|
||||||
let dir = root;
|
let dir = root;
|
||||||
|
@ -101,19 +147,46 @@ function getFile(root: Directory, path: string): File | null {
|
||||||
return root.files?.[path] ?? null;
|
return root.files?.[path] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadFiles(monaco: Monaco, dir: Directory, prefix = "") {
|
function loadFiles(monaco: Monaco, updater: Updater<Directory>, dir: Directory, prefix = "") {
|
||||||
for (const [name, d] of Object.entries(dir.dirs ?? {})) {
|
for (const [name, d] of Object.entries(dir.dirs ?? {})) {
|
||||||
loadFiles(monaco, d, prefix + name + "/");
|
loadFiles(monaco, updater, d, prefix + name + "/");
|
||||||
|
updater(dir => {
|
||||||
|
let current = dir;
|
||||||
|
for(const part of [...prefix.split("/").filter(s => s !== ""), name]) {
|
||||||
|
if (!current.dirs) {
|
||||||
|
current.dirs = {};
|
||||||
|
}
|
||||||
|
current = current.dirs[part];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [name, file] of Object.entries(dir.files ?? {})) {
|
for (const [name, file] of Object.entries(dir.files ?? {})) {
|
||||||
loadFile(monaco, file, prefix + name);
|
loadFile(monaco, updater, file, prefix + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadFile(monaco: Monaco, file: File, name: string) {
|
function loadFile(monaco: Monaco, updater: Updater<Directory>, file: File, name: string) {
|
||||||
const uri = monaco.Uri.parse(name);
|
const uri = monaco.Uri.parse(name);
|
||||||
if (!monaco.editor.getModel(uri)) {
|
if (!monaco.editor.getModel(uri)) {
|
||||||
monaco.editor.createModel(file.content, file.language, uri);
|
monaco.editor.createModel(file.content, file.language, uri);
|
||||||
}
|
}
|
||||||
|
updater(dir => {
|
||||||
|
let current = dir;
|
||||||
|
const parts = name.split("/").filter(s => s !== "");
|
||||||
|
const last = parts.pop()!;
|
||||||
|
for(const part of parts) {
|
||||||
|
console.log(part);
|
||||||
|
if (!current.dirs) {
|
||||||
|
current.dirs = {};
|
||||||
}
|
}
|
||||||
|
current = current.dirs[part];
|
||||||
|
}
|
||||||
|
if (!current.files) {
|
||||||
|
current.files = {};
|
||||||
|
}
|
||||||
|
current.files[last] = file;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
import SplitButton from "./SplitButton";
|
import SplitButton from "./SplitButton";
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header({onBuild, onZip}: {onBuild: () => void; onZip: () => void;}){
|
||||||
const clickBuild = () => {
|
|
||||||
console.log("build");
|
|
||||||
}
|
|
||||||
const clickZip = () => {
|
|
||||||
console.log("zip");
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header style={{
|
<header style={{
|
||||||
|
@ -15,7 +9,7 @@ export default function Header() {
|
||||||
marginBottom: "0.5cm",
|
marginBottom: "0.5cm",
|
||||||
}}>
|
}}>
|
||||||
<h1 id="_top">Playground</h1>
|
<h1 id="_top">Playground</h1>
|
||||||
<SplitButton onClick={clickBuild} options={[["Download zip", clickZip]]}>Build</SplitButton>
|
<SplitButton onClick={onBuild} options={[["Download zip", onZip]]}>Build</SplitButton>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue