@@ -17,8 +17,8 @@ export class MarkdownEngine {
17
17
private md ?: MarkdownIt ;
18
18
19
19
private firstLine ?: number ;
20
-
21
20
private currentDocument ?: vscode . Uri ;
21
+ private _slugCount = new Map < string , number > ( ) ;
22
22
23
23
public constructor (
24
24
private readonly extensionPreviewResourceProvider : MarkdownContributions ,
@@ -36,7 +36,6 @@ export class MarkdownEngine {
36
36
private async getEngine ( resource : vscode . Uri ) : Promise < MarkdownIt > {
37
37
if ( ! this . md ) {
38
38
const hljs = await import ( 'highlight.js' ) ;
39
- const mdnh = await import ( 'markdown-it-named-headers' ) ;
40
39
this . md = ( await import ( 'markdown-it' ) ) ( {
41
40
html : true ,
42
41
highlight : ( str : string , lang ?: string ) => {
@@ -54,8 +53,6 @@ export class MarkdownEngine {
54
53
}
55
54
return `<code><div>${ this . md ! . utils . escapeHtml ( str ) } </div></code>` ;
56
55
}
57
- } ) . use ( mdnh , {
58
- slugify : ( header : string ) => this . slugifier . fromHeading ( header ) . value
59
56
} ) ;
60
57
61
58
for ( const plugin of this . extensionPreviewResourceProvider . markdownItPlugins ) {
@@ -71,6 +68,7 @@ export class MarkdownEngine {
71
68
72
69
this . addLinkNormalizer ( this . md ) ;
73
70
this . addLinkValidator ( this . md ) ;
71
+ this . addNamedHeaders ( this . md ) ;
74
72
}
75
73
76
74
const config = vscode . workspace . getConfiguration ( 'markdown' , resource ) ;
@@ -101,13 +99,17 @@ export class MarkdownEngine {
101
99
}
102
100
this . currentDocument = document ;
103
101
this . firstLine = offset ;
102
+ this . _slugCount = new Map < string , number > ( ) ;
103
+
104
104
const engine = await this . getEngine ( document ) ;
105
105
return engine . render ( text ) ;
106
106
}
107
107
108
108
public async parse ( document : vscode . Uri , source : string ) : Promise < Token [ ] > {
109
109
const { text, offset } = this . stripFrontmatter ( source ) ;
110
110
this . currentDocument = document ;
111
+ this . _slugCount = new Map < string , number > ( ) ;
112
+
111
113
const engine = await this . getEngine ( document ) ;
112
114
113
115
return engine . parse ( text , { } ) . map ( token => {
@@ -219,4 +221,29 @@ export class MarkdownEngine {
219
221
return validateLink ( link ) || link . indexOf ( 'file:' ) === 0 ;
220
222
} ;
221
223
}
224
+
225
+ private addNamedHeaders ( md : any ) : void {
226
+ const original = md . renderer . rules . heading_open ;
227
+ md . renderer . rules . heading_open = ( tokens : any , idx : number , options : any , env : any , self : any ) => {
228
+ const title = tokens [ idx + 1 ] . children . reduce ( ( acc : string , t : any ) => acc + t . content , '' ) ;
229
+ let slug = this . slugifier . fromHeading ( title ) ;
230
+
231
+ if ( this . _slugCount . has ( slug . value ) ) {
232
+ const count = this . _slugCount . get ( slug . value ) ! ;
233
+ this . _slugCount . set ( slug . value , count + 1 ) ;
234
+ slug = this . slugifier . fromHeading ( slug . value + '-' + ( count + 1 ) ) ;
235
+ } else {
236
+ this . _slugCount . set ( slug . value , 0 ) ;
237
+ }
238
+
239
+ tokens [ idx ] . attrs = tokens [ idx ] . attrs || [ ] ;
240
+ tokens [ idx ] . attrs . push ( [ 'id' , slug . value ] ) ;
241
+
242
+ if ( original ) {
243
+ return original ( tokens , idx , options , env , self ) ;
244
+ } else {
245
+ return self . renderToken ( tokens , idx , options , env , self ) ;
246
+ }
247
+ } ;
248
+ }
222
249
}
0 commit comments