diff --git a/extensions/markdown/package.json b/extensions/markdown/package.json index 9cb11fd182c..c0917c8bcba 100644 --- a/extensions/markdown/package.json +++ b/extensions/markdown/package.json @@ -180,8 +180,16 @@ "type": "boolean", "default": false, "description": "%markdown.preview.enableExperimentalExtensionApi.desc%" + }, + "markdown.trace": { + "type": "string", + "enum": [ + "off", + "verbose" + ], + "default": "off", + "description": "%markdown.trace.desc%" } - } }, "configurationDefaults": { diff --git a/extensions/markdown/package.nls.json b/extensions/markdown/package.nls.json index b57f70513b3..b58fe4c5e40 100644 --- a/extensions/markdown/package.nls.json +++ b/extensions/markdown/package.nls.json @@ -12,5 +12,6 @@ "markdown.showSource.title" : "Show Source", "markdown.styles.dec": "A list of URLs or local paths to CSS style sheets to use from the markdown preview. Relative paths are interpreted relative to the folder open in the explorer. If there is no open folder, they are interpreted relative to the location of the markdown file. All '\\' need to be written as '\\\\'.", "markdown.showPreviewSecuritySelector.title": "Change Markdown Preview Security Settings", - "markdown.preview.enableExperimentalExtensionApi.desc": "[Experimental] Allow extensions to extend the markdown preview." + "markdown.preview.enableExperimentalExtensionApi.desc": "[Experimental] Allow extensions to extend the markdown preview.", + "markdown.trace.desc": "Enable debug logging for the markdown extension." } \ No newline at end of file diff --git a/extensions/markdown/src/extension.ts b/extensions/markdown/src/extension.ts index bbaacb9a322..7038cda2f65 100644 --- a/extensions/markdown/src/extension.ts +++ b/extensions/markdown/src/extension.ts @@ -14,6 +14,7 @@ import MDDocumentSymbolProvider from './documentSymbolProvider'; import { ExtensionContentSecurityPolicyArbiter, PreviewSecuritySelector } from './security'; import { MDDocumentContentProvider, getMarkdownUri, isMarkdownFile } from './previewContentProvider'; import { TableOfContentsProvider } from './tableOfContentsProvider'; +import { Logger } from "./logger"; interface IPackageInfo { name: string; @@ -46,7 +47,9 @@ export function activate(context: vscode.ExtensionContext) { const cspArbiter = new ExtensionContentSecurityPolicyArbiter(context.globalState); const engine = new MarkdownEngine(); - const contentProvider = new MDDocumentContentProvider(engine, context, cspArbiter); + const logger = new Logger(); + + const contentProvider = new MDDocumentContentProvider(engine, context, cspArbiter, logger); const contentProviderRegistration = vscode.workspace.registerTextDocumentContentProvider('markdown', contentProvider); const previewSecuritySelector = new PreviewSecuritySelector(cspArbiter, contentProvider); if (vscode.workspace.getConfiguration('markdown').get('enableExperimentalExtensionApi', false)) { @@ -106,6 +109,8 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.commands.registerCommand('_markdown.revealLine', (uri, line) => { const sourceUri = vscode.Uri.parse(decodeURIComponent(uri)); + logger.log('revealLine', { uri, sourceUri: sourceUri.toString(), line }); + vscode.window.visibleTextEditors .filter(editor => isMarkdownFile(editor.document) && editor.document.uri.fsPath === sourceUri.fsPath) .forEach(editor => { @@ -176,13 +181,17 @@ export function activate(context: vscode.ExtensionContext) { })); context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => { + logger.updateConfiguration(); contentProvider.updateConfiguration(); })); context.subscriptions.push(vscode.window.onDidChangeTextEditorSelection(event => { if (isMarkdownFile(event.textEditor.document)) { + const markdownFile = getMarkdownUri(event.textEditor.document.uri); + logger.log('updatePreviewForSelection', { markdownFile: markdownFile.toString() }); + vscode.commands.executeCommand('_workbench.htmlPreview.postMessage', - getMarkdownUri(event.textEditor.document.uri), + markdownFile, { line: event.selections[0].active.line }); diff --git a/extensions/markdown/src/logger.ts b/extensions/markdown/src/logger.ts new file mode 100644 index 00000000000..e4b5864fa0d --- /dev/null +++ b/extensions/markdown/src/logger.ts @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import { OutputChannel, window, workspace } from "vscode"; + +enum Trace { + Off, + Verbose +} + +namespace Trace { + export function fromString(value: string): Trace { + value = value.toLowerCase(); + switch (value) { + case 'off': + return Trace.Off; + case 'verbose': + return Trace.Verbose; + default: + return Trace.Off; + } + } +} + + +function isString(value: any): value is string { + return Object.prototype.toString.call(value) === '[object String]'; +} + +export class Logger { + private trace: Trace; + private _output: OutputChannel; + + constructor() { + this.updateConfiguration(); + } + + public log(message: string, data?: any): void { + if (this.trace === Trace.Verbose) { + this.output.appendLine(`[Log - ${(new Date().toLocaleTimeString())}] ${message}`); + if (data) { + this.output.appendLine(this.data2String(data)); + } + } + } + + public updateConfiguration() { + this.trace = this.readTrace(); + } + + private get output(): OutputChannel { + if (!this._output) { + this._output = window.createOutputChannel('Markdown'); + } + return this._output; + } + + private readTrace(): Trace { + return Trace.fromString(workspace.getConfiguration().get('markdown.trace', 'off')); + } + + private data2String(data: any): string { + if (data instanceof Error) { + if (isString(data.stack)) { + return data.stack; + } + return (data as Error).message; + } + if (isString(data)) { + return data; + } + return JSON.stringify(data, undefined, 2); + } +} \ No newline at end of file diff --git a/extensions/markdown/src/previewContentProvider.ts b/extensions/markdown/src/previewContentProvider.ts index 568ffb3c1e1..401bb28e7f7 100644 --- a/extensions/markdown/src/previewContentProvider.ts +++ b/extensions/markdown/src/previewContentProvider.ts @@ -10,6 +10,7 @@ import * as path from 'path'; import { MarkdownEngine } from './markdownEngine'; import * as nls from 'vscode-nls'; +import { Logger } from "./logger"; const localize = nls.loadMessageBundle(); export interface ContentSecurityPolicyArbiter { @@ -109,7 +110,8 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv constructor( private engine: MarkdownEngine, private context: vscode.ExtensionContext, - private cspArbiter: ContentSecurityPolicyArbiter + private cspArbiter: ContentSecurityPolicyArbiter, + private logger: Logger ) { this.config = MarkdownPreviewConfig.getCurrentConfig(); } @@ -191,6 +193,7 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv public provideTextDocumentContent(uri: vscode.Uri): Thenable { const sourceUri = vscode.Uri.parse(uri.query); + return vscode.workspace.openTextDocument(sourceUri).then(document => { this.config = MarkdownPreviewConfig.getCurrentConfig(); @@ -209,6 +212,8 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv doubleClickToSwitchToEditor: this.config.doubleClickToSwitchToEditor }; + this.logger.log('provideTextDocumentContent', initialData); + // Content Security Policy const nonce = new Date().getTime() + '' + new Date().getMilliseconds(); let csp = ``;