Skip to content

Commit

Permalink
feat: add support to import files as code fence (#538)
Browse files Browse the repository at this point in the history
  • Loading branch information
znck authored and ulivz committed Jun 2, 2018
1 parent 9cb174d commit 26ecff7
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 0 deletions.
12 changes: 12 additions & 0 deletions docs/guide/markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@ export default {
}
```

## Import Code Snippets

**Input**

```
<<< @/test/markdown/fragments/snippet.js{2}
```

**Output**

<<< @/test/markdown/fragments/snippet.js{2}

## Advanced Configuration

VuePress uses [markdown-it](https://github.com/markdown-it/markdown-it) as the markdown renderer. A lot of the extensions above are implemented via custom plugins. You can further customize the `markdown-it` instance using the `markdown` option in `.vuepress/config.js`:
Expand Down
2 changes: 2 additions & 0 deletions lib/markdown/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const component = require('./component')
const hoistScriptStyle = require('./hoist')
const convertRouterLink = require('./link')
const containers = require('./containers')
const snippet = require('./snippet')
const emoji = require('markdown-it-emoji')
const anchor = require('markdown-it-anchor')
const toc = require('markdown-it-table-of-contents')
Expand All @@ -24,6 +25,7 @@ module.exports = ({ markdown = {}} = {}) => {
.use(component)
.use(highlightLines)
.use(preWrapper)
.use(snippet)
.use(convertRouterLink, Object.assign({
target: '_blank',
rel: 'noopener noreferrer'
Expand Down
43 changes: 43 additions & 0 deletions lib/markdown/snippet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const fs = require('fs')

module.exports = function snippet (md, options = {}) {
const root = options.root || process.cwd()
function parser (state, startLine, endLine, silent) {
const CH = '<'.charCodeAt(0)
const pos = state.bMarks[startLine] + state.tShift[startLine]
const max = state.eMarks[startLine]

// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) {
return false
}

for (let i = 0; i < 3; ++i) {
const ch = state.src.charCodeAt(pos + i)
if (ch !== CH || pos + i >= max) return false
}

if (silent) {
return true
}

const start = pos + 3
const end = state.skipSpacesBack(max, pos)
const rawPath = state.src.slice(start, end).trim().replace(/^@/, root)
const filename = rawPath.split(/[{:\s]/).shift()
const content = fs.existsSync(filename) ? fs.readFileSync(filename).toString() : 'Not found: ' + filename
const meta = rawPath.replace(filename, '')

state.line = startLine + 1

const token = state.push('fence', 'code', 0)
token.info = filename.split('.').pop() + meta
token.content = content
token.markup = '```'
token.map = [startLine, startLine + 1]

return true
}

md.block.ruler.before('fence', 'snippet', parser)
}
23 changes: 23 additions & 0 deletions test/markdown/__snapshots__/snippet.spec.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`snippet import snippet 1`] = `
<pre><code class="language-js">export default function () {
// ..
}</code></pre>
`;

exports[`snippet import snippet with highlight multiple lines 1`] = `
<div class="highlight-lines">
<div class="highlighted">&nbsp;</div>
<div class="highlighted">&nbsp;</div>
<div class="highlighted">&nbsp;</div>
</div>export default function () { // .. }
`;
exports[`snippet import snippet with highlight single line 1`] = `
<div class="highlight-lines">
<div class="highlighted">&nbsp;</div>
<br>
<div class="highlighted">&nbsp;</div>
</div>export default function () { // .. }
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<<< @/test/markdown/fragments/snippet.js{1-3}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<<< @/test/markdown/fragments/snippet.js{1,3}
1 change: 1 addition & 0 deletions test/markdown/fragments/code-snippet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<<< @/test/markdown/fragments/snippet.js
3 changes: 3 additions & 0 deletions test/markdown/fragments/snippet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function () {
// ..
}
26 changes: 26 additions & 0 deletions test/markdown/snippet.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Md, getFragment } from './util'
import snippet from '@/markdown/snippet.js'
import highlightLines from '@/markdown/highlightLines.js'

const md = Md().use(snippet)
const mdH = Md().use(snippet).use(highlightLines)

describe('snippet', () => {
test('import snippet', async () => {
const input = await getFragment('code-snippet')
const output = md.render(input)
expect(output).toMatchSnapshot()
})

test('import snippet with highlight single line', async () => {
const input = await getFragment('code-snippet-highlightLines-single')
const output = mdH.render(input)
expect(output).toMatchSnapshot()
})

test('import snippet with highlight multiple lines', async () => {
const input = await getFragment('code-snippet-highlightLines-multiple')
const output = mdH.render(input)
expect(output).toMatchSnapshot()
})
})

0 comments on commit 26ecff7

Please sign in to comment.