




















@@ -20,6 +20,7 @@ type RenderEnv = {
2020type MarkdownToken = {
2121type: string;
2222content?: string;
23+info?: string;
2324children?: MarkdownToken[];
2425attrs?: [string, string][];
2526attrGet?: (name: string) => string | null;
@@ -40,6 +41,7 @@ export type MarkdownStyleSpan = {
4041start: number;
4142end: number;
4243style: MarkdownStyle;
44+language?: string;
4345};
44464547export type MarkdownLinkSpan = {
@@ -54,6 +56,18 @@ export type MarkdownIR = {
5456links: MarkdownLinkSpan[];
5557};
565859+function createStyleSpan(params: MarkdownStyleSpan): MarkdownStyleSpan {
60+const span: MarkdownStyleSpan = {
61+start: params.start,
62+end: params.end,
63+style: params.style,
64+};
65+if (params.language) {
66+span.language = params.language;
67+}
68+return span;
69+}
70+5771export type MarkdownTableData = {
5872headers: string[];
5973rows: string[][];
@@ -325,15 +339,27 @@ function renderInlineCode(state: RenderState, content: string) {
325339target.styles.push({ start, end: start + content.length, style: "code" });
326340}
327341328-function renderCodeBlock(state: RenderState, content: string) {
342+function resolveFenceLanguage(info: string | undefined): string | undefined {
343+const language = info?.trim().split(/\s+/, 1)[0]?.trim();
344+return language || undefined;
345+}
346+347+function renderCodeBlock(state: RenderState, content: string, info?: string) {
329348let code = content ?? "";
330349if (!code.endsWith("\n")) {
331350code = `${code}\n`;
332351}
333352const target = resolveRenderTarget(state);
334353const start = target.text.length;
335354target.text += code;
336-target.styles.push({ start, end: start + code.length, style: "code_block" });
355+target.styles.push(
356+createStyleSpan({
357+ start,
358+end: start + code.length,
359+style: "code_block",
360+language: resolveFenceLanguage(info),
361+}),
362+);
337363if (state.env.listStack.length === 0) {
338364target.text += "\n";
339365}
@@ -732,7 +758,7 @@ function renderTokens(tokens: MarkdownToken[], state: RenderState): void {
732758break;
733759case "code_block":
734760case "fence":
735-renderCodeBlock(state, token.content ?? "");
761+renderCodeBlock(state, token.content ?? "", token.info);
736762break;
737763case "html_block":
738764case "html_inline":
@@ -834,7 +860,7 @@ function clampStyleSpans(spans: MarkdownStyleSpan[], maxLength: number): Markdow
834860const start = Math.max(0, Math.min(span.start, maxLength));
835861const end = Math.max(start, Math.min(span.end, maxLength));
836862if (end > start) {
837-clamped.push({ start, end, style: span.style });
863+clamped.push(createStyleSpan({ start, end, style: span.style, language: span.language }));
838864}
839865}
840866return clamped;
@@ -869,6 +895,7 @@ function mergeStyleSpans(spans: MarkdownStyleSpan[]): MarkdownStyleSpan[] {
869895if (
870896prev &&
871897prev.style === span.style &&
898+prev.language === span.language &&
872899// Blockquotes are container blocks. Adjacent blockquote spans should not merge or
873900// consecutive blockquotes can "style bleed" across the paragraph boundary.
874901(span.start < prev.end || (span.start === prev.end && span.style !== "blockquote"))
@@ -908,11 +935,14 @@ function sliceStyleSpans(
908935if (!bounds) {
909936continue;
910937}
911-sliced.push({
912-start: bounds.start - start,
913-end: bounds.end - start,
914-style: span.style,
915-});
938+sliced.push(
939+createStyleSpan({
940+start: bounds.start - start,
941+end: bounds.end - start,
942+style: span.style,
943+language: span.language,
944+}),
945+);
916946}
917947return mergeStyleSpans(sliced);
918948}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。