mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-24 12:19:20 +00:00
Merge remote-tracking branch 'origin/master' into misolori/new-icons
This commit is contained in:
@@ -39,7 +39,7 @@ function parseLink(
|
||||
|
||||
return {
|
||||
uri: OpenDocumentLinkCommand.createCommandUri(resourcePath, tempUri.fragment),
|
||||
tooltip: localize('documentLink.tooltip', 'follow link')
|
||||
tooltip: localize('documentLink.tooltip', 'Follow link')
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -412,7 +412,7 @@ export class MarkdownPreview extends Disposable {
|
||||
|
||||
this.currentVersion = pendingVersion;
|
||||
if (this._resource === resource) {
|
||||
const content = await this._contentProvider.provideTextDocumentContent(document, this._previewConfigurations, this.line, this.state);
|
||||
const content = await this._contentProvider.provideTextDocumentContent(document, await this.editor.webview.resourceRoot, this._previewConfigurations, this.line, this.state);
|
||||
// Another call to `doUpdate` may have happened.
|
||||
// Make sure we are still updating for the correct document
|
||||
if (this.currentVersion && this.currentVersion.equals(pendingVersion)) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Logger } from '../logger';
|
||||
import { ContentSecurityPolicyArbiter, MarkdownPreviewSecurityLevel } from '../security';
|
||||
import { MarkdownPreviewConfigurationManager, MarkdownPreviewConfiguration } from './previewConfig';
|
||||
import { MarkdownContributionProvider } from '../markdownExtensions';
|
||||
import { toResoruceUri } from '../util/resources';
|
||||
|
||||
/**
|
||||
* Strings used inside the markdown preview.
|
||||
@@ -50,6 +51,7 @@ export class MarkdownContentProvider {
|
||||
|
||||
public async provideTextDocumentContent(
|
||||
markdownDocument: vscode.TextDocument,
|
||||
webviewResourceRoot: string,
|
||||
previewConfigurations: MarkdownPreviewConfigurationManager,
|
||||
initialLine: number | undefined = undefined,
|
||||
state?: any
|
||||
@@ -63,14 +65,15 @@ export class MarkdownContentProvider {
|
||||
scrollPreviewWithEditor: config.scrollPreviewWithEditor,
|
||||
scrollEditorWithPreview: config.scrollEditorWithPreview,
|
||||
doubleClickToSwitchToEditor: config.doubleClickToSwitchToEditor,
|
||||
disableSecurityWarnings: this.cspArbiter.shouldDisableSecurityWarnings()
|
||||
disableSecurityWarnings: this.cspArbiter.shouldDisableSecurityWarnings(),
|
||||
webviewResourceRoot: webviewResourceRoot,
|
||||
};
|
||||
|
||||
this.logger.log('provideTextDocumentContent', initialData);
|
||||
|
||||
// Content Security Policy
|
||||
const nonce = new Date().getTime() + '' + new Date().getMilliseconds();
|
||||
const csp = this.getCspForResource(sourceUri, nonce);
|
||||
const csp = this.getCspForResource(webviewResourceRoot, sourceUri, nonce);
|
||||
|
||||
const body = await this.engine.render(markdownDocument);
|
||||
return `<!DOCTYPE html>
|
||||
@@ -82,14 +85,14 @@ export class MarkdownContentProvider {
|
||||
data-settings="${escapeAttribute(JSON.stringify(initialData))}"
|
||||
data-strings="${escapeAttribute(JSON.stringify(previewStrings))}"
|
||||
data-state="${escapeAttribute(JSON.stringify(state || {}))}">
|
||||
<script src="${this.extensionResourcePath('pre.js')}" nonce="${nonce}"></script>
|
||||
${this.getStyles(sourceUri, nonce, config, state)}
|
||||
<base href="${markdownDocument.uri.with({ scheme: 'vscode-resource' }).toString(true)}">
|
||||
<script src="${this.extensionResourcePath(webviewResourceRoot, 'pre.js')}" nonce="${nonce}"></script>
|
||||
${this.getStyles(webviewResourceRoot, sourceUri, nonce, config, state)}
|
||||
<base href="${toResoruceUri(webviewResourceRoot, markdownDocument.uri)}">
|
||||
</head>
|
||||
<body class="vscode-body ${config.scrollBeyondLastLine ? 'scrollBeyondLastLine' : ''} ${config.wordWrap ? 'wordWrap' : ''} ${config.markEditorSelection ? 'showEditorSelection' : ''}">
|
||||
${body}
|
||||
<div class="code-line" data-line="${markdownDocument.lineCount}"></div>
|
||||
${this.getScripts(nonce)}
|
||||
${this.getScripts(webviewResourceRoot, nonce)}
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
@@ -107,13 +110,12 @@ export class MarkdownContentProvider {
|
||||
</html>`;
|
||||
}
|
||||
|
||||
private extensionResourcePath(mediaFile: string): string {
|
||||
return vscode.Uri.file(this.context.asAbsolutePath(path.join('media', mediaFile)))
|
||||
.with({ scheme: 'vscode-resource' })
|
||||
private extensionResourcePath(webviewResourceRoot: string, mediaFile: string): string {
|
||||
return toResoruceUri(webviewResourceRoot, vscode.Uri.file(this.context.asAbsolutePath(path.join('media', mediaFile))))
|
||||
.toString();
|
||||
}
|
||||
|
||||
private fixHref(resource: vscode.Uri, href: string): string {
|
||||
private fixHref(webviewResourceRoot: string, resource: vscode.Uri, href: string): string {
|
||||
if (!href) {
|
||||
return href;
|
||||
}
|
||||
@@ -124,29 +126,23 @@ export class MarkdownContentProvider {
|
||||
|
||||
// Assume it must be a local file
|
||||
if (path.isAbsolute(href)) {
|
||||
return vscode.Uri.file(href)
|
||||
.with({ scheme: 'vscode-resource' })
|
||||
.toString();
|
||||
return toResoruceUri(webviewResourceRoot, vscode.Uri.file(href)).toString();
|
||||
}
|
||||
|
||||
// Use a workspace relative path if there is a workspace
|
||||
const root = vscode.workspace.getWorkspaceFolder(resource);
|
||||
if (root) {
|
||||
return vscode.Uri.file(path.join(root.uri.fsPath, href))
|
||||
.with({ scheme: 'vscode-resource' })
|
||||
.toString();
|
||||
return toResoruceUri(webviewResourceRoot, vscode.Uri.file(path.join(root.uri.fsPath, href))).toString();
|
||||
}
|
||||
|
||||
// Otherwise look relative to the markdown file
|
||||
return vscode.Uri.file(path.join(path.dirname(resource.fsPath), href))
|
||||
.with({ scheme: 'vscode-resource' })
|
||||
.toString();
|
||||
return toResoruceUri(webviewResourceRoot, vscode.Uri.file(path.join(path.dirname(resource.fsPath), href))).toString();
|
||||
}
|
||||
|
||||
private computeCustomStyleSheetIncludes(resource: vscode.Uri, config: MarkdownPreviewConfiguration): string {
|
||||
private computeCustomStyleSheetIncludes(webviewResourceRoot: string, resource: vscode.Uri, config: MarkdownPreviewConfiguration): string {
|
||||
if (Array.isArray(config.styles)) {
|
||||
return config.styles.map(style => {
|
||||
return `<link rel="stylesheet" class="code-user-style" data-source="${escapeAttribute(style)}" href="${escapeAttribute(this.fixHref(resource, style))}" type="text/css" media="screen">`;
|
||||
return `<link rel="stylesheet" class="code-user-style" data-source="${escapeAttribute(style)}" href="${escapeAttribute(this.fixHref(webviewResourceRoot, resource, style))}" type="text/css" media="screen">`;
|
||||
}).join('\n');
|
||||
}
|
||||
return '';
|
||||
@@ -177,37 +173,41 @@ export class MarkdownContentProvider {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private getStyles(resource: vscode.Uri, nonce: string, config: MarkdownPreviewConfiguration, state?: any): string {
|
||||
private getStyles(webviewResourceRoot: string, resource: vscode.Uri, nonce: string, config: MarkdownPreviewConfiguration, state?: any): string {
|
||||
const baseStyles = this.contributionProvider.contributions.previewStyles
|
||||
.map(resource => `<link rel="stylesheet" type="text/css" href="${escapeAttribute(resource.toString())}">`)
|
||||
.map(resource => `<link rel="stylesheet" type="text/css" href="${escapeAttribute(toResoruceUri(webviewResourceRoot, resource).toString())}">`)
|
||||
.join('\n');
|
||||
|
||||
return `${baseStyles}
|
||||
${this.getSettingsOverrideStyles(nonce, config)}
|
||||
${this.computeCustomStyleSheetIncludes(resource, config)}
|
||||
${this.computeCustomStyleSheetIncludes(webviewResourceRoot, resource, config)}
|
||||
${this.getImageStabilizerStyles(state)}`;
|
||||
}
|
||||
|
||||
private getScripts(nonce: string): string {
|
||||
private getScripts(resourceRoot: string, nonce: string): string {
|
||||
return this.contributionProvider.contributions.previewScripts
|
||||
.map(resource => `<script async src="${escapeAttribute(resource.toString())}" nonce="${nonce}" charset="UTF-8"></script>`)
|
||||
.map(resource => `<script async src="${escapeAttribute(toResoruceUri(resourceRoot, resource).toString())}" nonce="${nonce}" charset="UTF-8"></script>`)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
private getCspForResource(resource: vscode.Uri, nonce: string): string {
|
||||
private getCspForResource(
|
||||
webviewResourceRoot: string,
|
||||
resource: vscode.Uri,
|
||||
nonce: string
|
||||
): string {
|
||||
switch (this.cspArbiter.getSecurityLevelForResource(resource)) {
|
||||
case MarkdownPreviewSecurityLevel.AllowInsecureContent:
|
||||
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: http: https: data:; media-src vscode-resource: http: https: data:; script-src 'nonce-${nonce}'; style-src 'self' vscode-resource: 'unsafe-inline' http: https: data:; font-src vscode-resource: http: https: data:;">`;
|
||||
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' ${webviewResourceRoot} http: https: data:; media-src 'self' ${webviewResourceRoot} http: https: data:; script-src 'nonce-${nonce}'; style-src 'self' ${webviewResourceRoot} 'unsafe-inline' http: https: data:; font-src 'self' ${webviewResourceRoot} http: https: data:;">`;
|
||||
|
||||
case MarkdownPreviewSecurityLevel.AllowInsecureLocalContent:
|
||||
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: https: data: http://localhost:* http://127.0.0.1:*; media-src vscode-resource: https: data: http://localhost:* http://127.0.0.1:*; script-src 'nonce-${nonce}'; style-src 'self' vscode-resource: 'unsafe-inline' https: data: http://localhost:* http://127.0.0.1:*; font-src vscode-resource: https: data: http://localhost:* http://127.0.0.1:*;">`;
|
||||
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' ${webviewResourceRoot} https: data: http://localhost:* http://127.0.0.1:*; media-src 'self' ${webviewResourceRoot} https: data: http://localhost:* http://127.0.0.1:*; script-src 'nonce-${nonce}'; style-src 'self' ${webviewResourceRoot} 'unsafe-inline' https: data: http://localhost:* http://127.0.0.1:*; font-src 'self' ${webviewResourceRoot} https: data: http://localhost:* http://127.0.0.1:*;">`;
|
||||
|
||||
case MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent:
|
||||
return '';
|
||||
|
||||
case MarkdownPreviewSecurityLevel.Strict:
|
||||
default:
|
||||
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: https: data:; media-src vscode-resource: https: data:; script-src 'nonce-${nonce}'; style-src 'self' vscode-resource: 'unsafe-inline' https: data:; font-src vscode-resource: https: data:;">`;
|
||||
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' ${webviewResourceRoot} https: data:; media-src 'self' ${webviewResourceRoot} https: data:; script-src 'nonce-${nonce}'; style-src 'self' ${webviewResourceRoot} 'unsafe-inline' https: data:; font-src 'self' ${webviewResourceRoot} https: data:;">`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ import { Disposable } from './util/dispose';
|
||||
import * as arrays from './util/arrays';
|
||||
|
||||
const resolveExtensionResource = (extension: vscode.Extension<any>, resourcePath: string): vscode.Uri => {
|
||||
return vscode.Uri.file(path.join(extension.extensionPath, resourcePath))
|
||||
.with({ scheme: 'vscode-resource' });
|
||||
return vscode.Uri.file(path.join(extension.extensionPath, resourcePath));
|
||||
};
|
||||
|
||||
const resolveExtensionResources = (extension: vscode.Extension<any>, resourcePaths: unknown): vscode.Uri[] => {
|
||||
|
||||
16
extensions/markdown-language-features/src/util/resources.ts
Normal file
16
extensions/markdown-language-features/src/util/resources.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
|
||||
export function toResoruceUri(webviewResourceRoot: string, uri: vscode.Uri): vscode.Uri {
|
||||
const rootUri = vscode.Uri.parse(webviewResourceRoot);
|
||||
return rootUri.with({
|
||||
path: rootUri.path + uri.path,
|
||||
query: uri.query,
|
||||
fragment: uri.fragment,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user