feat: support selecting line range when importing md file (#2502)

Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
pull/2037/merge
烽宁 2 years ago committed by GitHub
parent 47c06bda38
commit 1ef33fe1c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,7 +1,11 @@
# Foo
This is before region
<!-- #region snippet -->
## Region
this is region
This is a region
<!-- #endregion snippet -->
This is after region

@ -181,7 +181,18 @@ export default config
<!--@include: @/markdown-extensions/bar.md-->
## Markdown Nested File Inclusion
<!--@include: ./nested-include.md-->
## Markdown File Inclusion with Range
<!--@include: ./foo.md{6,8}-->
## Markdown File Inclusion with Range without Start
<!--@include: ./foo.md{,8}-->
## Markdown File Inclusion with Range without End
<!--@include: ./foo.md{6,}-->

@ -5,6 +5,8 @@ const getClassList = async (locator: Locator) => {
return className?.split(' ').filter(Boolean) ?? []
}
const trim = (str?: string | null) => str?.replace(/\u200B/g, '').trim()
beforeEach(async () => {
await goto('/markdown-extensions/')
})
@ -63,7 +65,7 @@ describe('Table of Contents', () => {
test('render toc', async () => {
const items = page.locator('#table-of-contents + nav ul li')
const count = await items.count()
expect(count).toBe(27)
expect(count).toBe(33)
})
})
@ -161,7 +163,7 @@ describe('Line Numbers', () => {
describe('Import Code Snippets', () => {
test('basic', async () => {
const lines = page.locator('#basic-code-snippet + div code > span')
expect(await lines.count()).toBe(7)
expect(await lines.count()).toBe(11)
})
test('specify region', async () => {
@ -214,7 +216,7 @@ describe('Code Groups', () => {
// blocks
const blocks = div.locator('.blocks > div')
expect(await blocks.nth(0).locator('code > span').count()).toBe(7)
expect(await blocks.nth(0).locator('code > span').count()).toBe(11)
expect(await getClassList(blocks.nth(1))).toContain('line-numbers-mode')
expect(await getClassList(blocks.nth(1))).toContain('language-ts')
expect(await blocks.nth(1).locator('code > span').count()).toBe(3)
@ -229,12 +231,38 @@ describe('Markdown File Inclusion', () => {
const h1 = page.locator('#markdown-file-inclusion + h1')
expect(await h1.getAttribute('id')).toBe('foo')
})
test('render markdown using @', async () => {
const h1 = page.locator('#markdown-at-file-inclusion + h1')
expect(await h1.getAttribute('id')).toBe('bar')
})
test('render markdown using nested inclusion', async () => {
const h1 = page.locator('#markdown-nested-file-inclusion + h1')
expect(await h1.getAttribute('id')).toBe('foo-1')
})
test('support selecting range', async () => {
const h2 = page.locator('#markdown-file-inclusion-with-range + h2')
expect(trim(await h2.textContent())).toBe('Region')
const p = page.locator('#markdown-file-inclusion-with-range + h2 + p')
expect(trim(await p.textContent())).toBe('This is a region')
})
test('support selecting range without specifying start', async () => {
const p = page.locator(
'#markdown-file-inclusion-with-range-without-start ~ p'
)
expect(trim(await p.nth(0).textContent())).toBe('This is before region')
expect(trim(await p.nth(1).textContent())).toBe('This is a region')
})
test('support selecting range without specifying end', async () => {
const p = page.locator(
'#markdown-file-inclusion-with-range-without-end ~ p'
)
expect(trim(await p.nth(0).textContent())).toBe('This is a region')
expect(trim(await p.nth(1).textContent())).toBe('This is after region')
})
})

@ -738,6 +738,42 @@ Some getting started stuff.
Can be created using `.foorc.json`.
```
It also supports selecting a line range:
**Input**
```md
# Docs
## Basics
<!--@include: ./parts/basics.md{3,}-->
```
**Part file** (`parts/basics.md`)
```md
Some getting started stuff.
### Configuration
Can be created using `.foorc.json`.
```
**Equivalent code**
```md
# Docs
## Basics
### Configuration
Can be created using `.foorc.json`.
```
The format of the selected line range can be: `{3,}`, `{,10}`, `{1,10}`
::: warning
Note that this does not throw errors if your file is not present. Hence, when using this feature make sure that the contents are being rendered as expected.
:::

@ -21,6 +21,7 @@ import { getGitTimestamp } from './utils/getGitTimestamp'
const debug = _debug('vitepress:md')
const cache = new LRUCache<string, MarkdownCompileResult>({ max: 1024 })
const includesRE = /<!--\s*@include:\s*(.*?)\s*-->/g
const rangeRE = /\{(\d*),(\d*)\}$/
export interface MarkdownCompileResult {
vueSrc: string
@ -88,15 +89,27 @@ export async function createMarkdownToVueRenderFn(
let includes: string[] = []
function processIncludes(src: string): string {
return src.replace(includesRE, (m, m1) => {
return src.replace(includesRE, (m: string, m1: string) => {
if (!m1.length) return m
const range = m1.match(rangeRE)
range && (m1 = m1.slice(0, -range[0].length))
const atPresent = m1[0] === '@'
try {
const includePath = atPresent
? path.join(srcDir, m1.slice(m1[1] === '/' ? 2 : 1))
: path.join(path.dirname(fileOrig), m1)
const content = fs.readFileSync(includePath, 'utf-8')
let content = fs.readFileSync(includePath, 'utf-8')
if (range) {
const [, startLine, endLine] = range
const lines = content.split(/\r?\n/)
content = lines
.slice(
startLine ? parseInt(startLine, 10) - 1 : undefined,
endLine ? parseInt(endLine, 10) : undefined
)
.join('\n')
}
includes.push(slash(includePath))
// recursively process includes in the content
return processIncludes(content)

Loading…
Cancel
Save