Skip to content

Commit 2f5c974

Browse files
authored
Merge pull request #510 from code-hike/better-from
More flexible !from directive
2 parents 960dd61 + 6f221af commit 2f5c974

File tree

10 files changed

+125
-18
lines changed

10 files changed

+125
-18
lines changed

.changeset/silent-shoes-add.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"codehike": patch
3+
---
4+
5+
More flexible `!from` directive
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
!from ./assets/index.js

apps/web/content/docs/concepts/code.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ You can use the [Theme Editor](https://themes.codehike.org/editor) to customize
129129
To include code from a file in your markdown codeblocks, you can use the `!from` directive followed by the path to the file (relative to the markdown file).
130130

131131
````txt
132-
```js index.js
132+
```js
133133
!from ./assets/index.js
134134
```
135135
````

packages/codehike/src/mdx/0.import-code-from-path.ts

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
import { Code, Root } from "mdast"
22
import { visit } from "unist-util-visit"
3-
43
/**
5-
* Find all codeblocks like:
6-
*
7-
* ```jsx
8-
* !from ./foo/bar.js
9-
* ```
10-
* and replace the value with the content of the referenced file.
4+
* Find all codeblocks that contain lines starting with !from
5+
* and replace those lines with the content from the referenced files.
116
*/
127
export async function transformImportedCode(
138
tree: Root,
149
file?: { history?: string[] },
1510
) {
1611
const nodes: Code[] = []
1712
visit(tree, "code", (node) => {
18-
if (node.value?.startsWith("!from ")) {
13+
if (node.value?.includes("\n!from ") || node.value?.startsWith("!from ")) {
1914
nodes.push(node)
2015
}
2116
})
@@ -27,9 +22,18 @@ export async function transformImportedCode(
2722
const mdxPath = file?.history ? file.history[file.history.length - 1] : null
2823
await Promise.all(
2924
nodes.map(async (code) => {
30-
const fromData = code.value.slice(6).trim()
31-
const [codepath, range] = fromData?.split(/\s+/) || []
32-
code.value = await readFile(codepath, mdxPath, range)
25+
const lines = code.value.split("\n")
26+
const newLines = await Promise.all(
27+
lines.map(async (line) => {
28+
if (line.startsWith("!from ")) {
29+
const fromData = line.slice(6).trim()
30+
const [codepath, range] = fromData?.split(/\s+/) || []
31+
return await readFile(codepath, mdxPath, range)
32+
}
33+
return line
34+
}),
35+
)
36+
code.value = newLines.join("\n")
3337
}),
3438
)
3539

packages/codehike/tests/md-suite/_readme.md

+7
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,20 @@ snapshots:
1313
- after-rehype
1414
- before-recma-compiled-js
1515
- before-recma-compiled-jsx
16+
- before-recma-compiled-function
1617
- before-recma-js
18+
- before-recma-js-dev
1719
- before-recma-jsx
1820
- after-recma-js
21+
- after-recma-js-dev
1922
- after-recma-jsx
2023
- compiled-js
24+
- compiled-js-dev
2125
- compiled-jsx
26+
- compiled-function
2227
- parsed-jsx
28+
- rendered
29+
- rendered-dev
2330
---
2431
```
2532

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1+
# !mark inside
12
import random
2-
3-
my_list = [1, 'a', 32, 'c', 'd', 31]
4-
print(random.choice(my_list))
3+
my_list = []

packages/codehike/tests/md-suite/import-code.0.mdx

+11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
snapshots:
33
- compiled-jsx
4+
- rendered
45
---
56

67
hello
@@ -12,3 +13,13 @@ hello
1213
```py !
1314
!from ./assets/test.py
1415
```
16+
17+
```py
18+
# !mark(2) bar
19+
!from ./assets/test.py
20+
21+
def hello():
22+
print("hello")
23+
24+
!from ./assets/test.py
25+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { MDXContent } from "mdx/types"
2+
import { AnnotationHandler, highlight, Pre, RawCode } from "../../src/code"
3+
import React from "react"
4+
5+
export function render(Content: MDXContent) {
6+
// @ts-ignore
7+
return <Content components={{ MyCode }} />
8+
}
9+
10+
async function MyCode({ codeblock }: { codeblock: RawCode }) {
11+
const highlighted = await highlight(codeblock, "github-dark")
12+
return <Pre code={highlighted} handlers={[mark]} />
13+
}
14+
15+
const mark: AnnotationHandler = {
16+
name: "mark",
17+
Pre: ({ _stack, ...props }) => <section {...props} />,
18+
Block: ({ children, annotation }) => (
19+
<mark className={annotation.query}>{children}</mark>
20+
),
21+
}

packages/codehike/tests/md-suite/import-code.7.compiled-jsx.jsx

+9-3
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,17 @@ function _createMdxContent(props) {
1111
children: (
1212
<>
1313
<_components.p>{"hello"}</_components.p>
14+
<MyCode
15+
codeblock={{
16+
value: "# !mark inside\r\nimport random\r\nmy_list = []",
17+
lang: "py",
18+
meta: "",
19+
}}
20+
/>
1421
<MyCode
1522
codeblock={{
1623
value:
17-
"import random\r\n\r\nmy_list = [1, 'a', 32, 'c', 'd', 31]\r\nprint(random.choice(my_list))",
24+
'# !mark(2) bar\r\n# !mark inside\r\nimport random\r\nmy_list = []\n\r\ndef hello():\r\n print("hello")\r\n\r\n# !mark inside\r\nimport random\r\nmy_list = []',
1825
lang: "py",
1926
meta: "",
2027
}}
@@ -26,8 +33,7 @@ function _createMdxContent(props) {
2633
header: "",
2734
},
2835
code: {
29-
value:
30-
"import random\r\n\r\nmy_list = [1, 'a', 32, 'c', 'd', 31]\r\nprint(random.choice(my_list))",
36+
value: "# !mark inside\r\nimport random\r\nmy_list = []",
3137
lang: "py",
3238
meta: "",
3339
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<p>hello</p>
2+
<section data-theme="github-dark" data-lang="python">
3+
<mark class="inside">
4+
<div>
5+
<span style="color: #ff7b72">import</span>
6+
<span style="color: #c9d1d9">random</span>
7+
</div>
8+
</mark>
9+
<div>
10+
<span style="color: #c9d1d9">my_list</span>
11+
<span style="color: #ff7b72">=</span>
12+
<span style="color: #c9d1d9">[]</span>
13+
</div>
14+
</section>
15+
<section data-theme="github-dark" data-lang="python">
16+
<mark class="inside">
17+
<div>
18+
<span style="color: #ff7b72">import</span>
19+
<span style="color: #c9d1d9">random</span>
20+
</div>
21+
</mark>
22+
<mark class="bar">
23+
<div>
24+
<span style="color: #c9d1d9">my_list</span>
25+
<span style="color: #ff7b72">=</span>
26+
<span style="color: #c9d1d9">[]</span>
27+
</div>
28+
</mark>
29+
<div></div>
30+
<div>
31+
<span style="color: #ff7b72">def</span>
32+
<span style="color: #d2a8ff">hello</span>
33+
<span style="color: #c9d1d9">():</span>
34+
</div>
35+
<div>
36+
<span style="color: #79c0ff">print</span>
37+
<span style="color: #c9d1d9">(</span>
38+
<span style="color: #a5d6ff">&quot;hello&quot;</span>
39+
<span style="color: #c9d1d9">)</span>
40+
</div>
41+
<div></div>
42+
<mark class="inside">
43+
<div>
44+
<span style="color: #ff7b72">import</span>
45+
<span style="color: #c9d1d9">random</span>
46+
</div>
47+
</mark>
48+
<div>
49+
<span style="color: #c9d1d9">my_list</span>
50+
<span style="color: #ff7b72">=</span>
51+
<span style="color: #c9d1d9">[]</span>
52+
</div>
53+
</section>

0 commit comments

Comments
 (0)