add shiki for playground highlighting

This commit is contained in:
Moritz Hölting 2024-06-20 20:11:00 +02:00
parent 48a450c2fb
commit d5e9ec7dfc
11 changed files with 1523 additions and 26 deletions

View File

@ -18,13 +18,16 @@
"@monaco-editor/react": "^4.6.0", "@monaco-editor/react": "^4.6.0",
"@mui/icons-material": "^5.15.20", "@mui/icons-material": "^5.15.20",
"@mui/material": "^5.15.20", "@mui/material": "^5.15.20",
"@shikijs/monaco": "^1.7.0",
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"astro": "^4.10.2", "astro": "^4.10.2",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"sharp": "^0.32.6", "sharp": "^0.32.6",
"shiki": "^1.7.0",
"starlight-links-validator": "^0.7.1", "starlight-links-validator": "^0.7.1",
"tm-themes": "^1.4.3",
"typescript": "^5.4.5" "typescript": "^5.4.5"
}, },
"devDependencies": { "devDependencies": {

View File

@ -29,6 +29,9 @@ dependencies:
'@mui/material': '@mui/material':
specifier: ^5.15.20 specifier: ^5.15.20
version: 5.15.20(@emotion/react@11.11.4)(@emotion/styled@11.11.5)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) version: 5.15.20(@emotion/react@11.11.4)(@emotion/styled@11.11.5)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1)
'@shikijs/monaco':
specifier: ^1.7.0
version: 1.7.0
'@types/react': '@types/react':
specifier: ^18.3.3 specifier: ^18.3.3
version: 18.3.3 version: 18.3.3
@ -47,9 +50,15 @@ dependencies:
sharp: sharp:
specifier: ^0.32.6 specifier: ^0.32.6
version: 0.32.6 version: 0.32.6
shiki:
specifier: ^1.7.0
version: 1.7.0
starlight-links-validator: starlight-links-validator:
specifier: ^0.7.1 specifier: ^0.7.1
version: 0.7.1(@astrojs/starlight@0.24.2)(astro@4.10.2) version: 0.7.1(@astrojs/starlight@0.24.2)(astro@4.10.2)
tm-themes:
specifier: ^1.4.3
version: 1.4.3
typescript: typescript:
specifier: ^5.4.5 specifier: ^5.4.5
version: 5.4.5 version: 5.4.5
@ -141,7 +150,7 @@ packages:
remark-parse: 11.0.0 remark-parse: 11.0.0
remark-rehype: 11.1.0 remark-rehype: 11.1.0
remark-smartypants: 2.1.0 remark-smartypants: 2.1.0
shiki: 1.6.4 shiki: 1.7.0
unified: 11.0.4 unified: 11.0.4
unist-util-remove-position: 5.0.0 unist-util-remove-position: 5.0.0
unist-util-visit: 5.0.0 unist-util-visit: 5.0.0
@ -1131,7 +1140,7 @@ packages:
resolution: {integrity: sha512-aFQBPepv0zhVXqJFAvfQ4vXYv/meJKiqmEEKSxdjAfwXllIV49PDlnGEXmbGYjR4hUQQjbfDgzAbrbfePc3YVQ==} resolution: {integrity: sha512-aFQBPepv0zhVXqJFAvfQ4vXYv/meJKiqmEEKSxdjAfwXllIV49PDlnGEXmbGYjR4hUQQjbfDgzAbrbfePc3YVQ==}
dependencies: dependencies:
'@expressive-code/core': 0.35.3 '@expressive-code/core': 0.35.3
shiki: 1.6.4 shiki: 1.7.0
dev: false dev: false
/@expressive-code/plugin-text-markers@0.35.3: /@expressive-code/plugin-text-markers@0.35.3:
@ -1822,8 +1831,14 @@ packages:
dev: false dev: false
optional: true optional: true
/@shikijs/core@1.6.4: /@shikijs/core@1.7.0:
resolution: {integrity: sha512-WTU9rzZae1p2v6LOxMf6LhtmZOkIHYYW160IuahUyJy7YXPPjyWZLR1ag+SgD22ZMxZtz1gfU6Tccc8t0Il/XA==} resolution: {integrity: sha512-O6j27b7dGmJbR3mjwh/aHH8Ld+GQvA0OQsNO43wKWnqbAae3AYXrhFyScHGX8hXZD6vX2ngjzDFkZY5srtIJbQ==}
dev: false
/@shikijs/monaco@1.7.0:
resolution: {integrity: sha512-7wLuwcMhxYShdSOJ0c8z3puiwi0j9EFzCsIDWo8Q4wWc1sX2XrsGg/e4LyydwwydY4Kwc40KDgXBsX/0A211mg==}
dependencies:
'@shikijs/core': 1.7.0
dev: false dev: false
/@types/acorn@4.0.6: /@types/acorn@4.0.6:
@ -2210,7 +2225,7 @@ packages:
rehype: 13.0.1 rehype: 13.0.1
resolve: 1.22.8 resolve: 1.22.8
semver: 7.6.2 semver: 7.6.2
shiki: 1.6.4 shiki: 1.7.0
string-width: 7.1.0 string-width: 7.1.0
strip-ansi: 7.1.0 strip-ansi: 7.1.0
tsconfck: 3.1.0(typescript@5.4.5) tsconfck: 3.1.0(typescript@5.4.5)
@ -4989,10 +5004,10 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: false dev: false
/shiki@1.6.4: /shiki@1.7.0:
resolution: {integrity: sha512-X88chM7w8jnadoZtjPTi5ahCJx9pc9f8GfEkZAEYUTlcUZIEw2D/RY86HI/LkkE7Nj8TQWkiBfaFTJ3VJT6ESg==} resolution: {integrity: sha512-H5pMn4JA7ayx8H0qOz1k2qANq6mZVCMl1gKLK6kWIrv1s2Ial4EmD4s4jE8QB5Dw03d/oCQUxc24sotuyR5byA==}
dependencies: dependencies:
'@shikijs/core': 1.6.4 '@shikijs/core': 1.7.0
dev: false dev: false
/signal-exit@3.0.7: /signal-exit@3.0.7:
@ -5246,6 +5261,10 @@ packages:
b4a: 1.6.6 b4a: 1.6.6
dev: false dev: false
/tm-themes@1.4.3:
resolution: {integrity: sha512-nsUGwktLaWFMyKw2e/hNyDmcTIO+ue6Q2Mvb8L7WQkKSCflOm2TjGSspcJw6q7hi4QxQQNTuGICyvQN1UqtunQ==}
dev: false
/to-fast-properties@2.0.0: /to-fast-properties@2.0.0:
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
engines: {node: '>=4'} engines: {node: '>=4'}

View File

@ -0,0 +1,8 @@
[pack]
name = "my-shulkerscript-pack"
description = "A Minecraft datapack created with shulkerscript"
format = 48
version = "0.1.0"
[compiler]
# assets = "./assets"

View File

@ -1,10 +1,13 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Editor, { useMonaco, type Monaco } from "@monaco-editor/react"; import { useMonaco, type Monaco } from "@monaco-editor/react";
import FileView from "./playground/FileView"; import FileView from "./playground/FileView";
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 Header from "./playground/Header"; import Header from "./playground/Header";
export type File = { export type File = {
@ -24,13 +27,22 @@ export default function Playground() {
files: { files: {
"main.shu": { "main.shu": {
content: mainFileContent, content: mainFileContent,
language: "shulkerscript",
}, },
}, },
}, },
dist: {
files: {
"test.mcfunction": {
content: "",
language: "mcfunction",
}
}
}
}, },
files: { files: {
"pack.toml": { "pack.toml": {
content: "pack.toml content", content: packTomlContent,
language: "toml", language: "toml",
}, },
}, },
@ -63,15 +75,7 @@ export default function Playground() {
fileName={fileName} fileName={fileName}
setSelectedFileName={setFileName} setSelectedFileName={setFileName}
/> />
<div className="editor"> <Editor fileName={fileName} file={file} />
<Editor
height="60vh"
theme="vs-dark"
path={fileName}
defaultLanguage={file.language}
defaultValue={file.content}
/>
</div>
</main> </main>
</> </>
); );

View File

@ -0,0 +1,56 @@
import type { File } from "@components/Playground";
import MonacoEditor, { useMonaco } from "@monaco-editor/react";
import { getHighlighter, type Highlighter } from "shiki";
import { shikiToMonaco } from "@shikijs/monaco";
import { useEffect, useState } from "react";
import darkPlus from "tm-themes/themes/dark-plus.json";
import { shulkerscriptGrammar } from "@utils/shulkerscript-grammar";
import { mcfunctionGrammar } from "@utils/mcfunction-grammar";
export default function Editor({
fileName,
file,
}: {
fileName: string;
file: File;
}) {
const [highlighter, setHighlighter] = useState<Highlighter | null>(null);
const monaco = useMonaco();
useEffect(() => {
if (monaco) {
if (highlighter == null) {
getHighlighter({
themes: [darkPlus as any],
langs: ["toml", shulkerscriptGrammar, mcfunctionGrammar],
}).then((highlighter) => {
setHighlighter(highlighter);
});
} else {
shikiToMonaco(highlighter, monaco);
}
monaco.languages.register({ id: "toml" });
monaco.languages.register({ id: "shulkerscript" });
monaco.languages.register({ id: "mcfunction" });
}
}, [monaco]);
useEffect(() => {
if (highlighter != null) {
shikiToMonaco(highlighter, monaco);
}
}, [highlighter]);
return (
<div className="editor">
<MonacoEditor
height="70vh"
theme="vs-dark"
path={fileName}
defaultLanguage={file.language}
defaultValue={file.content}
/>
</div>
);
}

View File

@ -90,11 +90,11 @@ function DirElement({
([dirname, dir]) => { ([dirname, dir]) => {
return ( return (
<DirElement <DirElement
key={name} key={dirname}
name={name} name={dirname}
dir={dir} dir={dir}
fileName={fileName.slice( fileName={fileName.slice(
name.length + 1 dirname.length + 1
)} )}
setSelectedFileName={ setSelectedFileName={
modSetSelectedFileName modSetSelectedFileName
@ -107,8 +107,8 @@ function DirElement({
([currentName, _]) => { ([currentName, _]) => {
return ( return (
<FileElement <FileElement
key={name} key={currentName}
name={name} name={currentName}
disabled={fileName == currentName} disabled={fileName == currentName}
onClick={() => onClick={() =>
modSetSelectedFileName(currentName) modSetSelectedFileName(currentName)

View File

@ -1,6 +1,6 @@
.playground { .playground {
display: grid; display: grid;
grid-template-columns: 1fr 4fr; grid-template-columns: clamp(100px, 15%, 400px) auto;
grid-template-areas: grid-template-areas:
"header header" "header header"
"files editor"; "files editor";

View File

@ -15,4 +15,17 @@ export const customTheme = createTheme({
contrastText: '#000', contrastText: '#000',
}, },
}, },
typography: {
fontFamily: [
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'"Helvetica Neue"',
'Arial',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"',
].join(','),
},
}); });

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,11 @@
import type { PluginShikiOptions } from "@astrojs/starlight/expressive-code"; import type { PluginShikiOptions } from "@astrojs/starlight/expressive-code";
import { shulkerscriptGrammar } from "./shulkerscript-grammar"; import { shulkerscriptGrammar } from "./shulkerscript-grammar";
import { mcfunctionGrammar } from "./mcfunction-grammar";
const config: PluginShikiOptions = { const config: PluginShikiOptions = {
langs: [ langs: [
shulkerscriptGrammar, shulkerscriptGrammar,
mcfunctionGrammar,
], ],
}; };

View File

@ -1,5 +1,6 @@
import type { LanguageInput } from "shiki";
export const shulkerscriptGrammar = { export const shulkerscriptGrammar: LanguageInput = {
name: "shulkerscript", name: "shulkerscript",
aliases: ["shu"], aliases: ["shu"],
displayName: "ShulkerScript", displayName: "ShulkerScript",
@ -23,6 +24,8 @@ export const shulkerscriptGrammar = {
} }
], ],
repository: { repository: {
"$base": {},
"$self": {},
// Groupings // Groupings
functionContents: { functionContents: {
patterns: [ patterns: [