mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Merge from vscode bead496a613e475819f89f08e9e882b841bc1fe8 (#14883)
* Merge from vscode bead496a613e475819f89f08e9e882b841bc1fe8 * Bump distro * Upgrade GCC to 4.9 due to yarn install errors * Update build image * Fix bootstrap base url * Bump distro * Fix build errors * Update source map file * Disable checkbox for blocking migration issues (#15131) * disable checkbox for blocking issues * wip * disable checkbox fixes * fix strings * Remove duplicate tsec command * Default to off for tab color if settings not present * re-skip failing tests * Fix mocha error * Bump sqlite version & fix notebooks search view * Turn off esbuild warnings * Update esbuild log level * Fix overflowactionbar tests * Fix ts-ignore in dropdown tests * cleanup/fixes * Fix hygiene * Bundle in entire zone.js module * Remove extra constructor param * bump distro for web compile break * bump distro for web compile break v2 * Undo log level change * New distro * Fix integration test scripts * remove the "no yarn.lock changes" workflow * fix scripts v2 * Update unit test scripts * Ensure ads-kerberos2 updates in .vscodeignore * Try fix unit tests * Upload crash reports * remove nogpu * always upload crashes * Use bash script * Consolidate data/ext dir names * Create in tmp directory Co-authored-by: chlafreniere <hichise@gmail.com> Co-authored-by: Christopher Suh <chsuh@microsoft.com> Co-authored-by: chgagnon <chgagnon@microsoft.com>
This commit is contained in:
@@ -14,8 +14,9 @@ import { isMarkdownFile } from '../util/file';
|
||||
import { normalizeResource, WebviewResourceProvider } from '../util/resources';
|
||||
import { getVisibleLine, TopmostLineMonitor } from '../util/topmostLineMonitor';
|
||||
import { MarkdownPreviewConfigurationManager } from './previewConfig';
|
||||
import { MarkdownContentProvider } from './previewContentProvider';
|
||||
import { MarkdownContentProvider, MarkdownContentProviderOutput } from './previewContentProvider';
|
||||
import { MarkdownEngine } from '../markdownEngine';
|
||||
import { urlToUri } from '../util/url';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -90,7 +91,7 @@ class StartingScrollLine {
|
||||
) { }
|
||||
}
|
||||
|
||||
class StartingScrollFragment {
|
||||
export class StartingScrollFragment {
|
||||
public readonly type = 'fragment';
|
||||
|
||||
constructor(
|
||||
@@ -118,6 +119,8 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider {
|
||||
private _disposed: boolean = false;
|
||||
private imageInfo: { readonly id: string, readonly width: number, readonly height: number; }[] = [];
|
||||
|
||||
private readonly _fileWatchersBySrc = new Map</* src: */ string, vscode.FileSystemWatcher>();
|
||||
|
||||
constructor(
|
||||
webview: vscode.WebviewPanel,
|
||||
resource: vscode.Uri,
|
||||
@@ -156,6 +159,16 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider {
|
||||
}
|
||||
}));
|
||||
|
||||
const watcher = this._register(vscode.workspace.createFileSystemWatcher(resource.fsPath));
|
||||
this._register(watcher.onDidChange(uri => {
|
||||
if (this.isPreviewOf(uri)) {
|
||||
// Only use the file system event when VS Code does not already know about the file
|
||||
if (!vscode.workspace.textDocuments.some(doc => doc.uri.toString() !== uri.toString())) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this._webviewPanel.webview.onDidReceiveMessage((e: CacheImageSizesMessage | RevealLineMessage | DidClickMessage | ClickLinkMessage | ShowPreviewSecuritySelectorMessage | PreviewStyleLoadErrorMessage) => {
|
||||
if (e.source !== this._resource.toString()) {
|
||||
return;
|
||||
@@ -198,6 +211,9 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider {
|
||||
super.dispose();
|
||||
this._disposed = true;
|
||||
clearTimeout(this.throttleTimer);
|
||||
for (const entry of this._fileWatchersBySrc.values()) {
|
||||
entry.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public get resource(): vscode.Uri {
|
||||
@@ -214,6 +230,10 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The first call immediately refreshes the preview,
|
||||
* calls happening shortly thereafter are debounced.
|
||||
*/
|
||||
public refresh() {
|
||||
// Schedule update if none is pending
|
||||
if (!this.throttleTimer) {
|
||||
@@ -350,7 +370,7 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider {
|
||||
this._webviewPanel.webview.html = this._contentProvider.provideFileNotFoundContent(this._resource);
|
||||
}
|
||||
|
||||
private setContent(html: string): void {
|
||||
private setContent(content: MarkdownContentProviderOutput): void {
|
||||
if (this._disposed) {
|
||||
return;
|
||||
}
|
||||
@@ -361,7 +381,30 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider {
|
||||
this._webviewPanel.iconPath = this.iconPath;
|
||||
this._webviewPanel.webview.options = this.getWebviewOptions();
|
||||
|
||||
this._webviewPanel.webview.html = html;
|
||||
this._webviewPanel.webview.html = content.html;
|
||||
|
||||
const srcs = new Set(content.containingImages.map(img => img.src));
|
||||
|
||||
// Delete stale file watchers.
|
||||
for (const [src, watcher] of [...this._fileWatchersBySrc]) {
|
||||
if (!srcs.has(src)) {
|
||||
watcher.dispose();
|
||||
this._fileWatchersBySrc.delete(src);
|
||||
}
|
||||
}
|
||||
|
||||
// Create new file watchers.
|
||||
const root = vscode.Uri.joinPath(this._resource, '../');
|
||||
for (const src of srcs) {
|
||||
const uri = urlToUri(src, root);
|
||||
if (uri && uri.scheme === 'file' && !this._fileWatchersBySrc.has(src)) {
|
||||
const watcher = vscode.workspace.createFileSystemWatcher(uri.fsPath);
|
||||
watcher.onDidChange(() => {
|
||||
this.refresh();
|
||||
});
|
||||
this._fileWatchersBySrc.set(src, watcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getWebviewOptions(): vscode.WebviewOptions {
|
||||
|
||||
@@ -39,6 +39,12 @@ function escapeAttribute(value: string | vscode.Uri): string {
|
||||
return value.toString().replace(/"/g, '"');
|
||||
}
|
||||
|
||||
export interface MarkdownContentProviderOutput {
|
||||
html: string;
|
||||
containingImages: { src: string }[];
|
||||
}
|
||||
|
||||
|
||||
export class MarkdownContentProvider {
|
||||
constructor(
|
||||
private readonly engine: MarkdownEngine,
|
||||
@@ -54,11 +60,12 @@ export class MarkdownContentProvider {
|
||||
previewConfigurations: MarkdownPreviewConfigurationManager,
|
||||
initialLine: number | undefined = undefined,
|
||||
state?: any
|
||||
): Promise<string> {
|
||||
): Promise<MarkdownContentProviderOutput> {
|
||||
const sourceUri = markdownDocument.uri;
|
||||
const config = previewConfigurations.loadAndCacheConfiguration(sourceUri);
|
||||
const initialData = {
|
||||
source: sourceUri.toString(),
|
||||
fragment: state?.fragment || markdownDocument.uri.fragment || undefined,
|
||||
line: initialLine,
|
||||
lineCount: markdownDocument.lineCount,
|
||||
scrollPreviewWithEditor: config.scrollPreviewWithEditor,
|
||||
@@ -75,7 +82,7 @@ export class MarkdownContentProvider {
|
||||
const csp = this.getCsp(resourceProvider, sourceUri, nonce);
|
||||
|
||||
const body = await this.engine.render(markdownDocument);
|
||||
return `<!DOCTYPE html>
|
||||
const html = `<!DOCTYPE html>
|
||||
<html style="${escapeAttribute(this.getSettingsOverrideStyles(config))}">
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
@@ -89,11 +96,15 @@ export class MarkdownContentProvider {
|
||||
<base href="${resourceProvider.asWebviewUri(markdownDocument.uri)}">
|
||||
</head>
|
||||
<body class="vscode-body ${config.scrollBeyondLastLine ? 'scrollBeyondLastLine' : ''} ${config.wordWrap ? 'wordWrap' : ''} ${config.markEditorSelection ? 'showEditorSelection' : ''}">
|
||||
${body}
|
||||
${body.html}
|
||||
<div class="code-line" data-line="${markdownDocument.lineCount}"></div>
|
||||
${this.getScripts(resourceProvider, nonce)}
|
||||
</body>
|
||||
</html>`;
|
||||
return {
|
||||
html,
|
||||
containingImages: body.containingImages,
|
||||
};
|
||||
}
|
||||
|
||||
public provideFileNotFoundContent(
|
||||
|
||||
@@ -9,7 +9,7 @@ import { MarkdownEngine } from '../markdownEngine';
|
||||
import { MarkdownContributionProvider } from '../markdownExtensions';
|
||||
import { Disposable, disposeAll } from '../util/dispose';
|
||||
import { TopmostLineMonitor } from '../util/topmostLineMonitor';
|
||||
import { DynamicMarkdownPreview, ManagedMarkdownPreview, StaticMarkdownPreview } from './preview';
|
||||
import { DynamicMarkdownPreview, ManagedMarkdownPreview, StartingScrollFragment, StaticMarkdownPreview } from './preview';
|
||||
import { MarkdownPreviewConfigurationManager } from './previewConfig';
|
||||
import { MarkdownContentProvider } from './previewContentProvider';
|
||||
|
||||
@@ -106,7 +106,10 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview
|
||||
preview = this.createNewDynamicPreview(resource, settings);
|
||||
}
|
||||
|
||||
preview.update(resource);
|
||||
preview.update(
|
||||
resource,
|
||||
resource.fragment ? new StartingScrollFragment(resource.fragment) : undefined
|
||||
);
|
||||
}
|
||||
|
||||
public get activePreviewResource() {
|
||||
|
||||
@@ -34,7 +34,7 @@ export default class MarkdownSmartSelect implements vscode.SelectionRangeProvide
|
||||
|
||||
const tokens = await this.engine.parse(document);
|
||||
|
||||
const blockTokens = getBlockTokensForPosition(tokens, position);
|
||||
const blockTokens = getBlockTokensForPosition(tokens, position, headerRange);
|
||||
|
||||
if (blockTokens.length === 0) {
|
||||
return undefined;
|
||||
@@ -91,13 +91,13 @@ function createHeaderRange(header: TocEntry, isClosestHeaderToPosition: boolean,
|
||||
// of this header then all content then header
|
||||
return new vscode.SelectionRange(contentRange.with(undefined, startOfChildRange), new vscode.SelectionRange(contentRange, (new vscode.SelectionRange(range, parent))));
|
||||
} else {
|
||||
// no children and not on this header line so select content then header
|
||||
// not on this header line so select content then header
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(range, parent));
|
||||
}
|
||||
}
|
||||
|
||||
function getBlockTokensForPosition(tokens: Token[], position: vscode.Position): Token[] {
|
||||
const enclosingTokens = tokens.filter(token => token.map && (token.map[0] <= position.line && token.map[1] > position.line) && isBlockElement(token));
|
||||
function getBlockTokensForPosition(tokens: Token[], position: vscode.Position, parent?: vscode.SelectionRange): Token[] {
|
||||
const enclosingTokens = tokens.filter(token => token.map && (token.map[0] <= position.line && token.map[1] > position.line) && (!parent || (token.map[0] >= parent.range.start.line && token.map[1] <= parent.range.end.line + 1)) && isBlockElement(token));
|
||||
if (enclosingTokens.length === 0) {
|
||||
return [];
|
||||
}
|
||||
@@ -131,9 +131,17 @@ function createInlineRange(document: vscode.TextDocument, cursorPosition: vscode
|
||||
const lineText = document.lineAt(cursorPosition.line).text;
|
||||
const boldSelection = createBoldRange(lineText, cursorPosition.character, cursorPosition.line, parent);
|
||||
const italicSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, true, parent);
|
||||
const linkSelection = createLinkRange(lineText, cursorPosition.character, cursorPosition.line, boldSelection ? boldSelection : italicSelection || parent);
|
||||
let comboSelection: vscode.SelectionRange | undefined;
|
||||
if (boldSelection && italicSelection && !boldSelection.range.isEqual(italicSelection.range)) {
|
||||
if (boldSelection.range.contains(italicSelection.range)) {
|
||||
comboSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, true, boldSelection);
|
||||
} else if (italicSelection.range.contains(boldSelection.range)) {
|
||||
comboSelection = createBoldRange(lineText, cursorPosition.character, cursorPosition.line, italicSelection);
|
||||
}
|
||||
}
|
||||
const linkSelection = createLinkRange(lineText, cursorPosition.character, cursorPosition.line, comboSelection || boldSelection || italicSelection || parent);
|
||||
const inlineCodeBlockSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, false, linkSelection || parent);
|
||||
return inlineCodeBlockSelection || linkSelection || boldSelection || italicSelection;
|
||||
return inlineCodeBlockSelection || linkSelection || comboSelection || boldSelection || italicSelection;
|
||||
}
|
||||
|
||||
function createFencedRange(token: Token, cursorLine: number, document: vscode.TextDocument, parent?: vscode.SelectionRange): vscode.SelectionRange {
|
||||
@@ -154,61 +162,40 @@ function createFencedRange(token: Token, cursorLine: number, document: vscode.Te
|
||||
}
|
||||
|
||||
function createBoldRange(lineText: string, cursorChar: number, cursorLine: number, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
|
||||
// find closest ** that occurs before cursor position
|
||||
let startBold = lineText.substring(0, cursorChar).lastIndexOf('**');
|
||||
|
||||
// find closest ** that occurs after the start **
|
||||
const endBoldIndex = lineText.substring(startBold + 2).indexOf('**');
|
||||
let endBold = startBold + 2 + lineText.substring(startBold + 2).indexOf('**');
|
||||
|
||||
if (startBold >= 0 && endBoldIndex >= 0 && startBold + 1 < endBold && startBold <= cursorChar && endBold >= cursorChar) {
|
||||
const range = new vscode.Range(cursorLine, startBold, cursorLine, endBold + 2);
|
||||
// **content cursor content** so select content then ** on both sides
|
||||
const contentRange = new vscode.Range(cursorLine, startBold + 2, cursorLine, endBold);
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(range, parent));
|
||||
} else if (startBold >= 0) {
|
||||
// **content**cursor or **content*cursor*
|
||||
// find end ** from end of start ** to end of line (since the cursor is within the end stars)
|
||||
let adjustedEnd = startBold + 2 + lineText.substring(startBold + 2).indexOf('**');
|
||||
startBold = lineText.substring(0, adjustedEnd - 2).lastIndexOf('**');
|
||||
if (adjustedEnd >= 0 && cursorChar === adjustedEnd || cursorChar === adjustedEnd + 1) {
|
||||
if (lineText.charAt(adjustedEnd + 1) === '*') {
|
||||
// *cursor* so need to extend end to include the second *
|
||||
adjustedEnd += 1;
|
||||
}
|
||||
return new vscode.SelectionRange(new vscode.Range(cursorLine, startBold, cursorLine, adjustedEnd + 1), parent);
|
||||
}
|
||||
} else if (endBold > 0) {
|
||||
// cursor**content** or *cursor*content**
|
||||
// find start ** from start of string to cursor + 2 (since the cursor is within the start stars)
|
||||
const adjustedStart = lineText.substring(0, cursorChar + 2).lastIndexOf('**');
|
||||
endBold = adjustedStart + 2 + lineText.substring(adjustedStart + 2).indexOf('**');
|
||||
if (adjustedStart >= 0 && adjustedStart === cursorChar || adjustedStart === cursorChar - 1) {
|
||||
return new vscode.SelectionRange(new vscode.Range(cursorLine, adjustedStart, cursorLine, endBold + 2), parent);
|
||||
}
|
||||
const regex = /(?:\*\*([^*]+)(?:\*([^*]+)([^*]+)\*)*([^*]+)\*\*)/g;
|
||||
const matches = [...lineText.matchAll(regex)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar);
|
||||
if (matches.length) {
|
||||
// should only be one match, so select first and index 0 contains the entire match
|
||||
const bold = matches[0][0];
|
||||
const startIndex = lineText.indexOf(bold);
|
||||
const cursorOnStars = cursorChar === startIndex || cursorChar === startIndex + 1 || cursorChar === startIndex + bold.length || cursorChar === startIndex + bold.length - 1;
|
||||
const contentAndStars = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex, cursorLine, startIndex + bold.length), parent);
|
||||
const content = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex + 2, cursorLine, startIndex + bold.length - 2), contentAndStars);
|
||||
return cursorOnStars ? contentAndStars : content;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function createOtherInlineRange(lineText: string, cursorChar: number, cursorLine: number, isItalic: boolean, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
|
||||
const type = isItalic ? '*' : '`';
|
||||
const start = lineText.substring(0, cursorChar + 1).lastIndexOf(type);
|
||||
let end = lineText.substring(cursorChar).indexOf(type);
|
||||
|
||||
if (start >= 0 && end >= 0) {
|
||||
end += cursorChar;
|
||||
// ensure there's no * or ` before end
|
||||
const intermediate = lineText.substring(start + 1, end - 1).indexOf(type);
|
||||
if (intermediate < 0) {
|
||||
const range = new vscode.Range(cursorLine, start, cursorLine, end + 1);
|
||||
if (cursorChar > start && cursorChar <= end) {
|
||||
// within the content so select content then include the stars or backticks
|
||||
const contentRange = new vscode.Range(cursorLine, start + 1, cursorLine, end);
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(range, parent));
|
||||
} else if (cursorChar === start) {
|
||||
return new vscode.SelectionRange(range, parent);
|
||||
}
|
||||
const italicRegexes = [/(?:[^*]+)(\*([^*]+)(?:\*\*[^*]*\*\*)*([^*]+)\*)(?:[^*]+)/g, /^(?:[^*]*)(\*([^*]+)(?:\*\*[^*]*\*\*)*([^*]+)\*)(?:[^*]*)$/g];
|
||||
let matches = [];
|
||||
if (isItalic) {
|
||||
matches = [...lineText.matchAll(italicRegexes[0])].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar);
|
||||
if (!matches.length) {
|
||||
matches = [...lineText.matchAll(italicRegexes[1])].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar);
|
||||
}
|
||||
} else {
|
||||
matches = [...lineText.matchAll(/\`[^\`]*\`/g)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar);
|
||||
}
|
||||
if (matches.length) {
|
||||
// should only be one match, so select first and select group 1 for italics because that contains just the italic section
|
||||
// doesn't include the leading and trailing characters which are guaranteed to not be * so as not to be confused with bold
|
||||
const match = isItalic ? matches[0][1] : matches[0][0];
|
||||
const startIndex = lineText.indexOf(match);
|
||||
const cursorOnType = cursorChar === startIndex || cursorChar === startIndex + match.length;
|
||||
const contentAndType = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex, cursorLine, startIndex + match.length), parent);
|
||||
const content = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex + 1, cursorLine, startIndex + match.length - 1), contentAndType);
|
||||
return cursorOnType ? contentAndType : content;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -217,7 +204,7 @@ function createLinkRange(lineText: string, cursorChar: number, cursorLine: numbe
|
||||
const regex = /(\[[^\(\)]*\])(\([^\[\]]*\))/g;
|
||||
const matches = [...lineText.matchAll(regex)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length > cursorChar);
|
||||
|
||||
if (matches.length > 0) {
|
||||
if (matches.length) {
|
||||
// should only be one match, so select first and index 0 contains the entire match, so match = [text](url)
|
||||
const link = matches[0][0];
|
||||
const linkRange = new vscode.SelectionRange(new vscode.Range(cursorLine, lineText.indexOf(link), cursorLine, lineText.indexOf(link) + link.length), parent);
|
||||
@@ -228,11 +215,12 @@ function createLinkRange(lineText: string, cursorChar: number, cursorLine: numbe
|
||||
// determine if cursor is within [text] or (url) in order to know which should be selected
|
||||
const nearestType = cursorChar >= lineText.indexOf(linkText) && cursorChar < lineText.indexOf(linkText) + linkText.length ? linkText : url;
|
||||
|
||||
const indexOfType = lineText.indexOf(nearestType);
|
||||
// determine if cursor is on a bracket or paren and if so, return the [content] or (content), skipping over the content range
|
||||
const cursorOnType = cursorChar === lineText.indexOf(nearestType) || cursorChar === lineText.indexOf(nearestType) + nearestType.length;
|
||||
const cursorOnType = cursorChar === indexOfType || cursorChar === indexOfType + nearestType.length;
|
||||
|
||||
const contentAndNearestType = new vscode.SelectionRange(new vscode.Range(cursorLine, lineText.indexOf(nearestType), cursorLine, lineText.indexOf(nearestType) + nearestType.length), linkRange);
|
||||
const content = new vscode.SelectionRange(new vscode.Range(cursorLine, lineText.indexOf(nearestType) + 1, cursorLine, lineText.indexOf(nearestType) + nearestType.length - 1), contentAndNearestType);
|
||||
const contentAndNearestType = new vscode.SelectionRange(new vscode.Range(cursorLine, indexOfType, cursorLine, indexOfType + nearestType.length), linkRange);
|
||||
const content = new vscode.SelectionRange(new vscode.Range(cursorLine, indexOfType + 1, cursorLine, indexOfType + nearestType.length - 1), contentAndNearestType);
|
||||
return cursorOnType ? contentAndNearestType : content;
|
||||
}
|
||||
return undefined;
|
||||
|
||||
Reference in New Issue
Block a user