at main 2.4 kB view raw
1// deno-lint-ignore-file no-explicit-any 2// ^- NOTE: No idea for the typing of markdown-it plugin context, so we disable this check 3// Taken from https://github.com/pixeldesu/pixelde.su/blob/main/plugins/markdown-it/vscode.ts and edited for my use 4 5import "lume/types.ts"; 6 7// Cache object for frontmatter line counts so we only reload files once 8const FRONTMATTER_LINE_CACHE: Record<string, number> = {}; 9 10function markdownItOpenInEditor(md: any) { 11 // Override the default paragraph renderer 12 const defaultRender = md.renderer.rules.paragraph_open || 13 function ( 14 tokens: Record<number, any>, 15 idx: number, 16 options: any, 17 _env: any, 18 self: any, 19 ) { 20 return self.renderToken(tokens, idx, options); 21 }; 22 23 md.renderer.rules.paragraph_open = function ( 24 tokens: Record<number, any>, 25 idx: number, 26 options: any, 27 env: any, 28 self: any, 29 ) { 30 const token = tokens[idx]; 31 const filePath = env.data.page.src.entry.src || ""; 32 33 // FIXME: This is extremely ugly, having to reload the file to get the full context to 34 // calculate the line number offset for the frontmatter. For some reason this is 35 // pretty fast however, so I'll let it slide for now. 36 if (!FRONTMATTER_LINE_CACHE[filePath]) { 37 FRONTMATTER_LINE_CACHE[filePath] = countFrontMatterLines( 38 Deno.readTextFileSync(filePath), 39 ); 40 } 41 const lineNumber = FRONTMATTER_LINE_CACHE[filePath] + 42 (token.map ? token.map[0] : 1); 43 44 // Create a wrapper element with context to open the file in the editor 45 const clickableElementStart = `<div data-editor-file="${filePath}:${lineNumber}">`; 46 47 return clickableElementStart + 48 defaultRender(tokens, idx, options, env, self); 49 }; 50 51 md.renderer.rules.paragraph_close = function ( 52 tokens: Record<number, any>, 53 idx: number, 54 options: any, 55 _env: any, 56 self: any, 57 ) { 58 return self.renderToken(tokens, idx, options) + "</div>"; 59 }; 60} 61 62function countFrontMatterLines(content: string) { 63 const frontMatterPattern = /^---\s*\n([\s\S]*?)\n---\s*\n/; 64 const match = content.match(frontMatterPattern); 65 if (match) { 66 return match[0].split("\n").length; 67 } 68 return 0; 69} 70 71export default function () { 72 return function (site: Lume.Site) { 73 site.hooks.addMarkdownItPlugin(markdownItOpenInEditor); 74 }; 75}