Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/webview/leetCodeResultProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class LeetCodeResultProvider implements Disposable {
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
${markdownEngine.getStylesHTML()}
${markdownEngine.getStyles()}
</head>
<body>
<pre><code>${result.trim()}</code></pre>
Expand Down
2 changes: 1 addition & 1 deletion src/webview/leetCodeSolutionProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class LeetCodeSolutionProvider implements Disposable {
}

private getWebViewContent(solution: Solution): string {
const styles: string = markdownEngine.getStylesHTML();
const styles: string = markdownEngine.getStyles();
const { title, url, lang, author, votes } = solution;
const head: string = markdownEngine.render(`# [${title}](${url})`);
const auth: string = `[${author}](https://leetcode.com/${author}/)`;
Expand Down
88 changes: 72 additions & 16 deletions src/webview/markdownEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,70 @@ import * as os from "os";
import * as path from "path";
import * as vscode from "vscode";
import { leetCodeChannel } from "../leetCodeChannel";
import { isWindows } from "../utils/osUtils";

class MarkdownEngine {
class MarkdownEngine implements vscode.Disposable {

private readonly engine: MarkdownIt;
private readonly extRoot: string; // root path of vscode built-in markdown extension
private engine: MarkdownIt;
private config: MarkdownConfiguration;
private listener: vscode.Disposable;

public constructor() {
this.engine = this.initEngine();
this.extRoot = path.join(vscode.env.appRoot, "extensions", "markdown-language-features");
this.reload();
this.listener = vscode.workspace.onDidChangeConfiguration((event: vscode.ConfigurationChangeEvent) => {
if (event.affectsConfiguration("markdown")) {
this.reload();
}
}, this);
}

public get localResourceRoots(): vscode.Uri[] {
return [vscode.Uri.file(path.join(this.extRoot, "media"))];
return [vscode.Uri.file(path.join(this.config.extRoot, "media"))];
}

public get styles(): vscode.Uri[] {
try {
const stylePaths: string[] = require(path.join(this.extRoot, "package.json"))["contributes"]["markdown.previewStyles"];
return stylePaths.map((p: string) => vscode.Uri.file(path.join(this.extRoot, p)).with({ scheme: "vscode-resource" }));
} catch (error) {
leetCodeChannel.appendLine("[Error] Fail to load built-in markdown style file.");
return [];
}
public dispose(): void {
this.listener.dispose();
}

public getStylesHTML(): string {
return this.styles.map((style: vscode.Uri) => `<link rel="stylesheet" type="text/css" href="${style.toString()}">`).join(os.EOL);
public reload(): void {
this.engine = this.initEngine();
this.config = new MarkdownConfiguration();
}

public render(md: string, env?: any): string {
return this.engine.render(md, env);
}

public getStyles(): string {
return [
this.getBuiltinStyles(),
this.getSettingsStyles(),
].join(os.EOL);
}

private getBuiltinStyles(): string {
let styles: vscode.Uri[] = [];
try {
const stylePaths: string[] = require(path.join(this.config.extRoot, "package.json"))["contributes"]["markdown.previewStyles"];
styles = stylePaths.map((p: string) => vscode.Uri.file(path.join(this.config.extRoot, p)).with({ scheme: "vscode-resource" }));
} catch (error) {
leetCodeChannel.appendLine("[Error] Fail to load built-in markdown style file.");
}
return styles.map((style: vscode.Uri) => `<link rel="stylesheet" type="text/css" href="${style.toString()}">`).join(os.EOL);
}

private getSettingsStyles(): string {
return [
`<style>`,
`body {`,
` ${this.config.fontFamily ? `font-family: ${this.config.fontFamily};` : ``}`,
` ${isNaN(this.config.fontSize) ? `` : `font-size: ${this.config.fontSize}px;`}`,
` ${isNaN(this.config.lineHeight) ? `` : `line-height: ${this.config.lineHeight};`}`,
`}`,
`</style>`,
].join(os.EOL);
}

private initEngine(): MarkdownIt {
const md: MarkdownIt = new MarkdownIt({
linkify: true,
Expand Down Expand Up @@ -107,4 +138,29 @@ class MarkdownEngine {
}
}

// tslint:disable-next-line: max-classes-per-file
class MarkdownConfiguration {

public readonly extRoot: string; // root path of vscode built-in markdown extension
public readonly lineHeight: number;
public readonly fontSize: number;
public readonly fontFamily: string | undefined;

public constructor() {
const markdownConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("markdown");
this.extRoot = path.join(vscode.env.appRoot, "extensions", "markdown-language-features");
this.lineHeight = Math.max(0.6, +markdownConfig.get<number>("preview.lineHeight", NaN));
this.fontSize = Math.max(8, +markdownConfig.get<number>("preview.fontSize", NaN));
this.fontFamily = this.resolveFontFamily(markdownConfig);
}

private resolveFontFamily(config: vscode.WorkspaceConfiguration): string | undefined {
let fontFamily: string | undefined = config.get<string | undefined>("preview.fontFamily", undefined);
if (isWindows() && fontFamily && fontFamily === config.inspect<string>("preview.fontFamily")!.defaultValue) {
fontFamily = `${fontFamily}, 'Microsoft Yahei UI'`;
}
return fontFamily;
}
}

export const markdownEngine: MarkdownEngine = new MarkdownEngine();