Skip to content

Commit

Permalink
Runnable code block example
Browse files Browse the repository at this point in the history
  • Loading branch information
Rigidity committed Sep 19, 2023
1 parent b99058d commit 60f8238
Show file tree
Hide file tree
Showing 7 changed files with 7,018 additions and 6,812 deletions.
6 changes: 6 additions & 0 deletions docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ title: About Chialisp
slug: /
---

import Runnable from '../src/components/Runnable.tsx';

Chialisp is a pure and functional language with a focus on security and auditability. Chialisp is commonly used on the Chia blockchain to lock funds in smart coins until spent and released by their owner. This enables behavior similar to that of smart contracts.

Here is an example:

<Runnable flavor='chialisp'>

```chialisp
(mod ()
(defun square (number)
Expand All @@ -19,6 +23,8 @@ Here is an example:
)
```

</Runnable>

## Design Decisions

There are many reasons to choose [Lisp](<https://en.wikipedia.org/wiki/Lisp_(programming_language)>) as the basis for this language, even though it is over 60 years old.
Expand Down
6 changes: 3 additions & 3 deletions docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,14 @@ module.exports = {
],
themes: [
[
"@easyops-cn/docusaurus-search-local",
'@easyops-cn/docusaurus-search-local',
/** @type {import("@easyops-cn/docusaurus-search-local").PluginOptions} */
({
hashed: true,
language: ["en", "zh"],
language: ['en', 'zh'],
highlightSearchTermsOnTargetPage: true,
explicitSearchResultPath: true,
docsRouteBasePath: "/"
docsRouteBasePath: '/',
}),
],
],
Expand Down
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@
"serve": "docusaurus serve"
},
"dependencies": {
"@docusaurus/core": "^2.1.0",
"@docusaurus/plugin-google-analytics": "^2.1.0",
"@docusaurus/plugin-google-gtag": "^2.1.0",
"@docusaurus/preset-classic": "^2.1.0",
"@docusaurus/core": "^2.4.1",
"@docusaurus/plugin-google-analytics": "^2.4.1",
"@docusaurus/plugin-google-gtag": "^2.4.1",
"@docusaurus/preset-classic": "^2.4.1",
"@easyops-cn/docusaurus-search-local": "^0.33.5",
"@mdx-js/react": "^1.6.21",
"@svgr/webpack": "^6.5.0",
"clsx": "^1.1.1",
"clvm-lib": "^1.0.0",
"file-loader": "^6.2.0",
"nodejieba": "^2.5.2",
"prism-react-renderer": "^1.2.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-icons": "^4.11.0",
"react-simple-code-editor": "^0.13.1",
"yarn": "^1.22.19"
},
"browserslist": {
Expand Down
175 changes: 175 additions & 0 deletions src/components/Runnable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { useColorMode } from '@docusaurus/theme-common';
import { Program } from 'clvm-lib';
import Highlight, { Prism } from 'prism-react-renderer';
import React, {
Children,
PropsWithChildren,
ReactElement,
ReactNode,
isValidElement,
useMemo,
useState,
} from 'react';
import { FaPlay } from 'react-icons/fa';
import Editor from 'react-simple-code-editor';
import darkTheme from '../theme/prism-dark-theme-chialisp';
import lightTheme from '../theme/prism-light-theme-chialisp';

export default function Runnable({
children,
flavor,
}: PropsWithChildren<{ flavor: 'clvm' | 'chialisp' }>) {
const { colorMode } = useColorMode();

const initialValue = useMemo(() => onlyText(children), []);
const [code, setCode] = useState(initialValue.trim());

const [output, setOutput] = useState<string | null>(null);

return (
<Highlight
Prism={Prism}
theme={(colorMode === 'dark' ? darkTheme : lightTheme) as any}
code={code}
language={'chialisp' as any}
>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={className} style={{ ...style, position: 'relative' }}>
<Editor
value={code}
onValueChange={(code) => setCode(code)}
highlight={() =>
tokens.map((line, i) => (
<div key={i} {...getLineProps({ line })}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({ token })} />
))}
</div>
))
}
padding={0}
/>
<FaPlay
size={24}
className="play-button"
style={{
position: 'absolute',
top: '16px',
right: '16px',
cursor: 'pointer',
}}
onClick={() => {
let program: Program;
try {
program = Program.fromSource(code);
} catch (error) {
setOutput(
`Parsing error: ${('' + error).replace('Error: ', '')}`
);
return;
}

let compiled: Program;

if (flavor === 'chialisp') {
try {
compiled = program.compile().value;
} catch (error) {
setOutput(
`Compilation error: ${('' + error).replace('Error: ', '')}`
);
return;
}

if (compiled.isAtom) {
setOutput(compiled.toSource());
return;
}
} else {
compiled = program;
}

let output: Program;
try {
output = compiled.run(Program.nil).value;
} catch (error) {
setOutput(`Eval error: ${('' + error).replace('Error: ', '')}`);
return;
}

setOutput(output.toSource());
}}
/>
{output === null ? (
''
) : (
<>
<hr />
<Highlight
Prism={Prism}
theme={(colorMode === 'dark' ? darkTheme : lightTheme) as any}
code={output}
language={'chialisp' as any}
>
{({ tokens, getLineProps, getTokenProps }) =>
tokens.map((line, i) => (
<div key={i} {...getLineProps({ line })}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({ token })} />
))}
</div>
))
}
</Highlight>
</>
)}
</pre>
)}
</Highlight>
);
}

export const childToString = (child?: ReactNode): string => {
if (
typeof child === 'undefined' ||
child === null ||
typeof child === 'boolean'
) {
return '';
}

if (JSON.stringify(child) === '{}') {
return '';
}

return (child as number | string).toString();
};

const hasChildren = (
element: ReactNode
): element is ReactElement<{ children: ReactNode | ReactNode[] }> =>
isValidElement<{ children?: ReactNode[] }>(element) &&
Boolean(element.props.children);

const onlyText = (children: ReactNode | ReactNode[]): string => {
if (!(children instanceof Array) && !isValidElement(children)) {
return childToString(children);
}

return Children.toArray(children).reduce(
(text: string, child: ReactNode): string => {
let newText = '';

if (isValidElement(child) && hasChildren(child)) {
newText = onlyText(child.props.children);
} else if (isValidElement(child) && !hasChildren(child)) {
newText = '';
} else {
newText = childToString(child);
}

return text.concat(newText);
},
''
);
};
8 changes: 8 additions & 0 deletions src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,11 @@ h4 {
.footer__logo {
width:10rem;
}

.play-button {
transition: 0.5s;
}

.play-button:hover {
color: #888;
}
Loading

0 comments on commit 60f8238

Please sign in to comment.