1- import { MarkdownRenderChild , type MarkdownSectionInformation } from 'obsidian' ;
1+ import { type MarkdownPostProcessorContext , MarkdownRenderChild } from 'obsidian' ;
22import type ShikiPlugin from 'src/main' ;
33import { toHtml } from 'hast-util-to-html' ;
44
@@ -7,32 +7,29 @@ export class CodeBlock extends MarkdownRenderChild {
77 source : string ;
88 language : string ;
99 languageShorthand : string ;
10- sectionInfo : MarkdownSectionInformation | null ;
11-
12- constructor (
13- plugin : ShikiPlugin ,
14- containerEl : HTMLElement ,
15- source : string ,
16- language : string ,
17- languageShorthand : string ,
18- sectionInfo : MarkdownSectionInformation | null ,
19- ) {
10+ ctx : MarkdownPostProcessorContext ;
11+ cachedMetaString : string ;
12+
13+ constructor ( plugin : ShikiPlugin , containerEl : HTMLElement , source : string , language : string , languageShorthand : string , ctx : MarkdownPostProcessorContext ) {
2014 super ( containerEl ) ;
2115
2216 this . plugin = plugin ;
2317 this . source = source ;
2418 this . language = language ;
2519 this . languageShorthand = languageShorthand ;
26- this . sectionInfo = sectionInfo ;
20+ this . ctx = ctx ;
21+ this . cachedMetaString = '' ;
2722 }
2823
29- getMetaString ( ) : string {
30- if ( this . sectionInfo === null ) {
24+ private getMetaString ( ) : string {
25+ const sectionInfo = this . ctx . getSectionInfo ( this . containerEl ) ;
26+
27+ if ( sectionInfo === null ) {
3128 return '' ;
3229 }
3330
34- const lines = this . sectionInfo . text . split ( '\n' ) ;
35- const startLine = lines [ this . sectionInfo . lineStart ] ;
31+ const lines = sectionInfo . text . split ( '\n' ) ;
32+ const startLine = lines [ sectionInfo . lineStart ] ;
3633
3734 // regexp to match the text after the code block language
3835 const regex = new RegExp ( '^[^`~]*?(```+|~~~+)' + this . languageShorthand + ' (.*)' , 'g' ) ;
@@ -44,11 +41,7 @@ export class CodeBlock extends MarkdownRenderChild {
4441 }
4542 }
4643
47- public async onload ( ) : Promise < void > {
48- super . onload ( ) ;
49-
50- const metaString = this . getMetaString ( ) ;
51-
44+ private async render ( metaString : string ) : Promise < void > {
5245 const renderResult = await this . plugin . ec . render ( {
5346 code : this . source ,
5447 language : this . language ,
@@ -61,7 +54,32 @@ export class CodeBlock extends MarkdownRenderChild {
6154 this . containerEl . innerHTML = toHtml ( ast ) ;
6255 }
6356
57+ public async rerenderOnNoteChange ( ) : Promise < void > {
58+ // compare the new meta string to the cached one
59+ // only rerender if they are different, to avoid unnecessary work
60+ // since the meta string is likely to be the same most of the time
61+ // and if the code block content changes obsidian will rerender for us
62+ const newMetaString = this . getMetaString ( ) ;
63+ if ( newMetaString !== this . cachedMetaString ) {
64+ this . cachedMetaString = newMetaString ;
65+ await this . render ( newMetaString ) ;
66+ }
67+ }
68+
69+ public async onload ( ) : Promise < void > {
70+ super . onload ( ) ;
71+
72+ this . plugin . addActiveCodeBlock ( this ) ;
73+
74+ this . cachedMetaString = this . getMetaString ( ) ;
75+ await this . render ( this . cachedMetaString ) ;
76+ }
77+
6478 public onunload ( ) : void {
79+ super . onunload ( ) ;
80+
81+ this . plugin . removeActiveCodeBlock ( this ) ;
82+
6583 this . containerEl . empty ( ) ;
6684 this . containerEl . innerText = 'unloaded shiki code block' ;
6785 }
0 commit comments