Skip to content

Commit 1463012

Browse files
authored
test generate godbolt link from codeblock
1 parent df1ad7e commit 1463012

File tree

7 files changed

+1325
-192
lines changed

7 files changed

+1325
-192
lines changed

docs/libs/beman.optional/index.md

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,69 @@ for (const auto& i : opt) {
5757
```
5858

5959
Full code can be found in [./examples/range_loop.cpp](https://github.com/bemanproject/optional/blob/main/examples/range_loop.cpp). Build and run instructions in
60-
[./examples/README.md](https://github.com/bemanproject/optional/blob/main/examples/README.md). Or try it on Compiler Explorer:
60+
[./examples/README.md](https://github.com/bemanproject/optional/blob/main/examples/README.md).
6161

62-
https://godbolt.org/z/qdzz8Y7jT
62+
```cpp { "compiler": "clang_trunk", "libs": ["beman_optional@trunk"], "options": "-std=c++26" }
63+
// examples/optional_ref.cpp -*-C++-*-
64+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65+
66+
#include <beman/optional/optional.hpp>
67+
68+
#include <string>
69+
70+
struct Cat {
71+
int catalog_index{0};
72+
};
73+
74+
namespace std17 {
75+
76+
// Prior to C++26, the code would look like this.
77+
// Using raw pointers to represent optional references.
78+
// Note: Using smart pointers would also be a choice, but it involves ownership semantics.
79+
80+
Cat* find_cat(std::string) { return nullptr; }
81+
82+
Cat* do_it(Cat& cat) { return &cat; }
83+
84+
Cat* api() {
85+
Cat* cat = find_cat("Fido");
86+
if (cat != nullptr) {
87+
return do_it(*cat);
88+
}
89+
return nullptr;
90+
}
91+
92+
} // namespace std17
93+
94+
namespace std26 {
95+
// After C++26 with P2988R5, the code would look like this.
96+
// Using directly optional to represent optional references.
97+
98+
beman::optional::optional<Cat&> find_cat(std::string) { return {}; }
99+
100+
beman::optional::optional<Cat&> do_it(Cat& cat) { return {cat}; }
101+
102+
beman::optional::optional<Cat&> api() {
103+
beman::optional::optional<Cat&> cat = find_cat("Fido");
104+
return cat.and_then(do_it);
105+
}
106+
107+
} // namespace std26
108+
109+
int main() {
110+
// Example from P2988R5: optional reference.
111+
[[maybe_unused]] Cat* old_cat = std17::api();
112+
[[maybe_unused]] beman::optional::optional<Cat&> new_cat = std26::api();
113+
114+
return 0;
115+
}
116+
117+
// # build example:
118+
// $ cmake --workflow --preset gcc-14
119+
//
120+
// # run example:
121+
// $ .build/gcc-14/examples/RelWithDebInfo/optional_ref
122+
```
63123
64124
### optional_ref
65125

docusaurus.config.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { execSync } from 'child_process';
66
const remarkEmbedder = require('@remark-embedder/core');
77
const YouTubeTransformer = require('./src/components/youtube-transformer.js');
88
const GodboltTransformer = require('./src/components/godbolt-transformer.js');
9+
const remarkCodeblockMeta = require('./src/plugins/remark-codeblock-meta');
910

1011
// Note: This runs in Node.js - Don't use client-side code here (browser APIs, JSX...)
1112

@@ -23,7 +24,6 @@ try {
2324
console.error(`Error determining branch name: ${err}`);
2425
}
2526

26-
2727
const config: Config = {
2828
title: 'The Beman Project',
2929
tagline:
@@ -43,6 +43,8 @@ const config: Config = {
4343
onBrokenLinks: 'throw',
4444
onBrokenMarkdownLinks: 'warn',
4545

46+
// plugins: [require.resolve("./src/plugins/codeblock-metadata")],
47+
4648
// Even if you don't use internationalization, you can use this field to set
4749
// useful metadata like html lang. For example, if your site is Chinese, you
4850
// may want to replace "en" with "zh-Hans".
@@ -62,7 +64,7 @@ const config: Config = {
6264
// Remove this to remove the 'edit this page' links.
6365
editUrl: `https://github.com/bemanproject/website/tree/${branchName}`,
6466
remarkPlugins: [
65-
[remarkEmbedder, { transformers: [YouTubeTransformer, GodboltTransformer] }],
67+
[remarkEmbedder, { transformers: [YouTubeTransformer, GodboltTransformer] }], remarkCodeblockMeta
6668
],
6769
},
6870
blog: {
@@ -72,7 +74,7 @@ const config: Config = {
7274
xslt: true,
7375
},
7476
remarkPlugins: [
75-
[remarkEmbedder, { transformers: [YouTubeTransformer, GodboltTransformer] }],
77+
[remarkEmbedder, { transformers: [YouTubeTransformer, GodboltTransformer] }], remarkCodeblockMeta
7678
],
7779
// Remove this to remove the 'edit this page' links.
7880
editUrl: `https://github.com/bemanproject/website/tree/${branchName}`,

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@
1717
"dependencies": {
1818
"@docusaurus/core": "3.7.0",
1919
"@docusaurus/preset-classic": "3.7.0",
20+
"@docusaurus/theme-live-codeblock": "^3.8.1",
2021
"@mdx-js/react": "^3.0.0",
2122
"@remark-embedder/core": "^3.0.3",
2223
"clsx": "^2.0.0",
2324
"prism-react-renderer": "^2.3.0",
2425
"react": "^19.0.0",
25-
"react-dom": "^19.0.0"
26+
"react-dom": "^19.0.0",
27+
"remark-code-blocks": "^2.0.1",
28+
"unist-util-visit": "^5.0.0"
2629
},
2730
"devDependencies": {
2831
"@docusaurus/module-type-aliases": "3.7.0",
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React from "react";
2+
import CodeBlock from "@theme/CodeBlock";
3+
4+
export default function CodeBlockWithMetadata({ children, meta, language }) {
5+
const sourceCode = children.trim();
6+
7+
let metadata = {};
8+
try {
9+
metadata = JSON.parse(meta || "{}");
10+
} catch (err) {
11+
console.error("Invalid metadata JSON in code block:", err);
12+
}
13+
14+
const lang = (language == "cpp" ? "c++" : language);
15+
16+
console.log("CodeBlock language:", lang);
17+
18+
const transformedLibs = (metadata.libs || []).map((lib) => {
19+
const [id, version] = lib.split("@");
20+
return { id, version };
21+
});
22+
23+
const compilerConfig = {
24+
id: metadata.compiler,
25+
libs: transformedLibs,
26+
options: metadata.options || "",
27+
};
28+
const executor = { compiler: compilerConfig };
29+
const session = {
30+
id: 1,
31+
lang,
32+
source: sourceCode,
33+
compilers: [],
34+
executors: [executor],
35+
};
36+
const clientState = { sessions: [session] };
37+
38+
const clientStateB64 = btoa(JSON.stringify(clientState)).replace(/\//g, "%2F");
39+
40+
return (
41+
<div style={{ marginBottom: "1em" }}>
42+
<a
43+
href={`https://godbolt.org/clientstate/${clientStateB64}`}
44+
target="_blank"
45+
rel="noopener noreferrer"
46+
style={{ display: "inline-block", marginBottom: "0.5em", color: "#0b5ed7" }}
47+
>
48+
Try it on Compiler Explorer 🚀
49+
</a>
50+
<CodeBlock language={language}>{sourceCode}</CodeBlock>
51+
</div>
52+
);
53+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// plugins/remark-codeblock-meta.js
2+
3+
// Try importing visit using both methods
4+
let visit;
5+
try {
6+
// ES Modules style import
7+
({ visit } = require("unist-util-visit"));
8+
} catch (err) {
9+
// Fallback if not available like that
10+
visit = require("unist-util-visit").default || require("unist-util-visit");
11+
}
12+
13+
module.exports = function remarkCodeblockMeta() {
14+
return (tree) => {
15+
visit(tree, "code", (node) => {
16+
const meta = node.meta?.trim();
17+
if (meta && meta.startsWith("{") && meta.endsWith("}")) {
18+
// Attach metadata and change node to use our custom component
19+
node.data = {
20+
hName: "CodeBlockWithMetadata",
21+
hProperties: {
22+
meta,
23+
language: node.lang,
24+
children: node.value,
25+
},
26+
};
27+
}
28+
});
29+
};
30+
};

src/theme/Layout/index.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from 'react';
2+
import Layout from '@theme-original/Layout';
3+
import CodeBlockWithMetadata from '@site/src/components/CodeBlockWithMetadata';
4+
import { MDXProvider } from '@mdx-js/react';
5+
6+
export default function LayoutWrapper(props) {
7+
return (
8+
<MDXProvider
9+
components={{
10+
CodeBlockWithMetadata,
11+
}}
12+
>
13+
<Layout {...props} />
14+
</MDXProvider>
15+
);
16+
}

0 commit comments

Comments
 (0)