diff --git a/docs/config/README.md b/docs/config/README.md
index 2c4cd8370b..9582d02e2b 100644
--- a/docs/config/README.md
+++ b/docs/config/README.md
@@ -127,6 +127,13 @@ Provide config options to the used theme. The options will vary depending on the
## Markdown
+### markdown.lineNumbers
+
+- Type: `boolean`
+- Default: `undefined`
+
+Whether to show line numbers to the left of each code blocks.
+
### markdown.slugify
- Type: `Function`
diff --git a/docs/zh/config/README.md b/docs/zh/config/README.md
index 1cde934b7d..2bd994f758 100644
--- a/docs/zh/config/README.md
+++ b/docs/zh/config/README.md
@@ -126,6 +126,13 @@ module.exports = {
## Markdown
+### markdown.lineNumbers
+
+- 类型: `boolean`
+- 默认值: `undefined`
+
+是否在每个代码块的左侧显示行号。
+
### markdown.anchor
- 类型: `Object`
diff --git a/lib/default-theme/styles/code.styl b/lib/default-theme/styles/code.styl
index 54cced7e3e..3c6c3fb45c 100644
--- a/lib/default-theme/styles/code.styl
+++ b/lib/default-theme/styles/code.styl
@@ -30,7 +30,8 @@ div[class*="language-"]
user-select none
padding-top 1.3rem
position absolute
- z-index 0
+ top 0
+ left 0
width 100%
line-height 1.4
.highlighted
@@ -45,61 +46,106 @@ div[class*="language-"]
right 1em
font-size 0.75rem
color rgba(255, 255, 255, 0.4)
-
-div[class="language-js"], div[class="language-javascript"]
+ &:not(.line-numbers-mode)
+ .line-numbers-wrapper
+ display none
+ &.line-numbers-mode
+ .highlight-lines .highlighted
+ position relative
+ &:before
+ content ' '
+ position absolute
+ z-index 3
+ left 0
+ top 0
+ display block
+ width $lineNumbersWrapperWidth
+ height 100%
+ background-color rgba(0, 0, 0, 66%)
+ pre
+ padding-left $lineNumbersWrapperWidth + 1 rem
+ vertical-align middle
+ .line-numbers-wrapper
+ position absolute
+ top 0
+ width $lineNumbersWrapperWidth
+ text-align center
+ color rgba(255, 255, 255, 0.3)
+ padding 1.25rem 0
+ line-height 1.4
+ br
+ user-select none
+ .line-number
+ position relative
+ z-index 4
+ user-select none
+ font-size 0.85em
+ &::after
+ content ''
+ position absolute
+ z-index 2
+ top 0
+ left 0
+ width $lineNumbersWrapperWidth
+ height 100%
+ border-radius 6px 0 0 6px
+ border-right 1px solid rgba(0, 0, 0, 66%)
+ background-color $codeBgColor
+
+div[class*="language-js"], div[class*="language-javascript"]
&:before
content "js"
-div[class="language-ts"], div[class="language-typescript"]
+div[class*="language-ts"], div[class*="language-typescript"]
&:before
content "ts"
-div[class="language-html"], div[class="language-markup"]
+div[class*="language-html"], div[class*="language-markup"]
&:before
content "html"
-div[class="language-markdown"], div[class="language-md"]
+div[class*="language-markdown"], div[class*="language-md"]
&:before
content "md"
-div[class="language-vue"]:before
+div[class*="language-vue"]:before
content "vue"
-div[class="language-css"]:before
+div[class*="language-css"]:before
content "css"
-div[class="language-sass"]:before
+div[class*="language-sass"]:before
content "sass"
-div[class="language-less"]:before
+div[class*="language-less"]:before
content "less"
-div[class="language-scss"]:before
+div[class*="language-scss"]:before
content "scss"
-div[class="language-stylus"]:before
+div[class*="language-stylus"]:before
content "stylus"
-div[class="language-json"]:before
+div[class*="language-json"]:before
content "json"
-div[class="language-ruby"]:before
+div[class*="language-ruby"]:before
content "rb"
-div[class="language-python"]:before
+div[class*="language-python"]:before
content "py"
-div[class="language-go"]:before
+div[class*="language-go"]:before
content "go"
-div[class="language-java"]:before
+div[class*="language-java"]:before
content "java"
-div[class="language-c"]:before
+div[class*="language-c"]:before
content "c"
-div[class="language-bash"]:before
+div[class*="language-bash"]:before
content "sh"
-div[class="language-yaml"]:before
+div[class*="language-yaml"]:before
content "yaml"
diff --git a/lib/default-theme/styles/config.styl b/lib/default-theme/styles/config.styl
index 158de9024f..385551e054 100644
--- a/lib/default-theme/styles/config.styl
+++ b/lib/default-theme/styles/config.styl
@@ -15,4 +15,7 @@ $MQNarrow = 959px
$MQMobile = 719px
$MQMobileNarrow = 419px
+// code
+$lineNumbersWrapperWidth = 3.5rem
+
@import '~@temp/override.styl' // generated from user config
diff --git a/lib/default-theme/styles/theme.styl b/lib/default-theme/styles/theme.styl
index cefae34472..1c62ec8ec3 100644
--- a/lib/default-theme/styles/theme.styl
+++ b/lib/default-theme/styles/theme.styl
@@ -138,7 +138,7 @@ a.header-anchor
&:hover
text-decoration none
-code, kbd
+code, kbd, .line-number
font-family source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace
p, ul, ol
diff --git a/lib/markdown/index.js b/lib/markdown/index.js
index 5ea8fef1f0..29c994039b 100644
--- a/lib/markdown/index.js
+++ b/lib/markdown/index.js
@@ -1,6 +1,7 @@
const highlight = require('./highlight')
const highlightLines = require('./highlightLines')
const preWrapper = require('./preWrapper')
+const lineNumbers = require('./lineNumbers')
const component = require('./component')
const hoistScriptStyle = require('./hoist')
const convertRouterLink = require('./link')
@@ -49,6 +50,10 @@ module.exports = ({ markdown = {}} = {}) => {
markdown.config(md)
}
+ if (markdown.lineNumbers) {
+ md.use(lineNumbers)
+ }
+
// override render to allow custom plugins return data
const render = md.render
md.render = (...args) => {
diff --git a/lib/markdown/lineNumbers.js b/lib/markdown/lineNumbers.js
new file mode 100644
index 0000000000..bc95d2b064
--- /dev/null
+++ b/lib/markdown/lineNumbers.js
@@ -0,0 +1,26 @@
+// markdown-it plugin for generating line numbers.
+// It depends on preWrapper plugin.
+
+module.exports = md => {
+ const fence = md.renderer.rules.fence
+ md.renderer.rules.fence = (...args) => {
+ const rawCode = fence(...args)
+ const code = rawCode.slice(
+ rawCode.indexOf(''),
+ rawCode.indexOf('
')
+ )
+
+ const lines = code.split('\n')
+ const lineNumbersCode = [...Array(lines.length - 1)]
+ .map((line, index) => `${index + 1}
`).join('')
+
+ const lineNumbersWrapperCode =
+ `