mirror of
https://github.com/Microsoft/vscode
synced 2024-10-05 19:02:54 +00:00
Fix markdown link inserting (#198702)
Fixes #190769 Fixes #195349 Also makes some small code cleanups
This commit is contained in:
parent
8de751f794
commit
ad31b067ab
|
@ -79,7 +79,7 @@ async function insertLink(activeEditor: vscode.TextEditor, selectedFiles: vscode
|
|||
function createInsertLinkEdit(activeEditor: vscode.TextEditor, selectedFiles: vscode.Uri[], insertAsMedia: boolean, title = '', placeholderValue = 0, pasteAsMarkdownLink = true, isExternalLink = false) {
|
||||
const snippetEdits = coalesce(activeEditor.selections.map((selection, i): vscode.SnippetTextEdit | undefined => {
|
||||
const selectionText = activeEditor.document.getText(selection);
|
||||
const snippet = createUriListSnippet(activeEditor.document, selectedFiles, [], title, placeholderValue, pasteAsMarkdownLink, isExternalLink, {
|
||||
const snippet = createUriListSnippet(activeEditor.document, selectedFiles.map(uri => ({ uri })), title, placeholderValue, pasteAsMarkdownLink, isExternalLink, {
|
||||
insertAsMedia,
|
||||
placeholderText: selectionText,
|
||||
placeholderStartIndex: (i + 1) * selectedFiles.length,
|
||||
|
|
|
@ -44,12 +44,12 @@ class ResourceDropProvider implements vscode.DocumentDropEditProvider {
|
|||
private async _getUriListEdit(document: vscode.TextDocument, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.DocumentDropEdit | undefined> {
|
||||
const urlList = await dataTransfer.get(Mime.textUriList)?.asString();
|
||||
if (!urlList || token.isCancellationRequested) {
|
||||
return undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
const snippet = await tryGetUriListSnippet(document, urlList, token);
|
||||
const snippet = tryGetUriListSnippet(document, urlList);
|
||||
if (!snippet) {
|
||||
return undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
const edit = new vscode.DocumentDropEdit(snippet.snippet);
|
||||
|
|
|
@ -53,7 +53,7 @@ class PasteResourceEditProvider implements vscode.DocumentPasteEditProvider {
|
|||
}
|
||||
|
||||
const pasteUrlSetting = getPasteUrlAsFormattedLinkSetting(document);
|
||||
const pasteEdit = await createEditAddingLinksForUriList(document, ranges, uriList, false, pasteUrlSetting === PasteUrlAsFormattedLink.Smart, token);
|
||||
const pasteEdit = createEditAddingLinksForUriList(document, ranges, uriList, false, pasteUrlSetting === PasteUrlAsFormattedLink.Smart);
|
||||
if (!pasteEdit) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ class PasteUrlEditProvider implements vscode.DocumentPasteEditProvider {
|
|||
return;
|
||||
}
|
||||
|
||||
const pasteEdit = await createEditAddingLinksForUriList(document, ranges, validateLink(urlList).cleanedUrlList, true, pasteUrlSetting === PasteUrlAsFormattedLink.Smart, token);
|
||||
const pasteEdit = createEditAddingLinksForUriList(document, ranges, validateLink(urlList).cleanedUrlList, true, pasteUrlSetting === PasteUrlAsFormattedLink.Smart);
|
||||
if (!pasteEdit) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -75,14 +75,13 @@ export function getPasteUrlAsFormattedLinkSetting(document: vscode.TextDocument)
|
|||
return vscode.workspace.getConfiguration('markdown', document).get<PasteUrlAsFormattedLink>('editor.pasteUrlAsFormattedLink.enabled', PasteUrlAsFormattedLink.Smart);
|
||||
}
|
||||
|
||||
export async function createEditAddingLinksForUriList(
|
||||
export function createEditAddingLinksForUriList(
|
||||
document: SkinnyTextDocument,
|
||||
ranges: readonly vscode.Range[],
|
||||
urlList: string,
|
||||
isExternalLink: boolean,
|
||||
useSmartPaste: boolean,
|
||||
token: vscode.CancellationToken,
|
||||
): Promise<{ additionalEdits: vscode.WorkspaceEdit; label: string; markdownLink: boolean } | undefined> {
|
||||
useSmartPaste: boolean
|
||||
): { additionalEdits: vscode.WorkspaceEdit; label: string; markdownLink: boolean } | undefined {
|
||||
|
||||
if (ranges.length === 0) {
|
||||
return;
|
||||
|
@ -104,7 +103,7 @@ export async function createEditAddingLinksForUriList(
|
|||
markdownLink = pasteAsMarkdownLink; // FIX: this will only match the last range
|
||||
}
|
||||
|
||||
const snippet = await tryGetUriListSnippet(document, urlList, token, document.getText(range), placeHolderValue, pasteAsMarkdownLink, isExternalLink);
|
||||
const snippet = tryGetUriListSnippet(document, urlList, document.getText(range), placeHolderValue, pasteAsMarkdownLink, isExternalLink);
|
||||
if (!snippet) {
|
||||
return;
|
||||
}
|
||||
|
@ -158,21 +157,16 @@ export function validateLink(urlList: string): { isValid: boolean; cleanedUrlLis
|
|||
return { isValid, cleanedUrlList: splitUrlList[0] };
|
||||
}
|
||||
|
||||
export async function tryGetUriListSnippet(document: SkinnyTextDocument, urlList: String, token: vscode.CancellationToken, title = '', placeHolderValue = 0, pasteAsMarkdownLink = true, isExternalLink = false): Promise<{ snippet: vscode.SnippetString; label: string } | undefined> {
|
||||
if (token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
const uriStrings: string[] = [];
|
||||
const uris: vscode.Uri[] = [];
|
||||
for (const resource of urlList.split(/\r?\n/g)) {
|
||||
export function tryGetUriListSnippet(document: SkinnyTextDocument, urlList: String, title = '', placeHolderValue = 0, pasteAsMarkdownLink = true, isExternalLink = false): { snippet: vscode.SnippetString; label: string } | undefined {
|
||||
const entries = coalesce(urlList.split(/\r?\n/g).map(resource => {
|
||||
try {
|
||||
uris.push(vscode.Uri.parse(resource));
|
||||
uriStrings.push(resource);
|
||||
return { uri: vscode.Uri.parse(resource), str: resource };
|
||||
} catch {
|
||||
// noop
|
||||
// Uri parse failure
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return createUriListSnippet(document, uris, uriStrings, title, placeHolderValue, pasteAsMarkdownLink, isExternalLink);
|
||||
}));
|
||||
return createUriListSnippet(document, entries, title, placeHolderValue, pasteAsMarkdownLink, isExternalLink);
|
||||
}
|
||||
|
||||
interface UriListSnippetOptions {
|
||||
|
@ -193,20 +187,21 @@ interface UriListSnippetOptions {
|
|||
export function appendToLinkSnippet(
|
||||
snippet: vscode.SnippetString,
|
||||
title: string,
|
||||
uriString: string,
|
||||
link: string,
|
||||
placeholderValue: number,
|
||||
isExternalLink: boolean,
|
||||
): vscode.SnippetString {
|
||||
): void {
|
||||
snippet.appendText('[');
|
||||
snippet.appendPlaceholder(escapeBrackets(title) || 'Title', placeholderValue);
|
||||
snippet.appendText(`](${escapeMarkdownLinkPath(uriString, isExternalLink)})`);
|
||||
return snippet;
|
||||
snippet.appendText(`](${escapeMarkdownLinkPath(link, isExternalLink)})`);
|
||||
}
|
||||
|
||||
export function createUriListSnippet(
|
||||
document: SkinnyTextDocument,
|
||||
uris: readonly vscode.Uri[],
|
||||
uriStrings?: readonly string[],
|
||||
uris: ReadonlyArray<{
|
||||
readonly uri: vscode.Uri;
|
||||
readonly str?: string;
|
||||
}>,
|
||||
title = '',
|
||||
placeholderValue = 0,
|
||||
pasteAsMarkdownLink = true,
|
||||
|
@ -219,15 +214,15 @@ export function createUriListSnippet(
|
|||
|
||||
const documentDir = getDocumentDir(document.uri);
|
||||
|
||||
let snippet = new vscode.SnippetString();
|
||||
const snippet = new vscode.SnippetString();
|
||||
let insertedLinkCount = 0;
|
||||
let insertedImageCount = 0;
|
||||
let insertedAudioVideoCount = 0;
|
||||
|
||||
uris.forEach((uri, i) => {
|
||||
const mdPath = getMdPath(documentDir, uri);
|
||||
const mdPath = getRelativeMdPath(documentDir, uri.uri) ?? uri.str ?? uri.uri.toString();
|
||||
|
||||
const ext = URI.Utils.extname(uri).toLowerCase().replace('.', '');
|
||||
const ext = URI.Utils.extname(uri.uri).toLowerCase().replace('.', '');
|
||||
const insertAsMedia = typeof options?.insertAsMedia === 'undefined' ? mediaFileExtensions.has(ext) : !!options.insertAsMedia;
|
||||
const insertAsVideo = mediaFileExtensions.get(ext) === MediaKind.Video;
|
||||
const insertAsAudio = mediaFileExtensions.get(ext) === MediaKind.Audio;
|
||||
|
@ -257,11 +252,7 @@ export function createUriListSnippet(
|
|||
}
|
||||
} else {
|
||||
insertedLinkCount++;
|
||||
if (uriStrings && isExternalLink) {
|
||||
snippet = appendToLinkSnippet(snippet, title, uriStrings[i], placeholderValue, isExternalLink);
|
||||
} else {
|
||||
snippet.appendText(escapeMarkdownLinkPath(mdPath, isExternalLink));
|
||||
}
|
||||
appendToLinkSnippet(snippet, title, mdPath, placeholderValue, isExternalLink);
|
||||
}
|
||||
|
||||
if (i < uris.length - 1 && uris.length > 1) {
|
||||
|
@ -349,7 +340,7 @@ export async function createEditForMediaFiles(
|
|||
}
|
||||
}
|
||||
|
||||
const snippet = createUriListSnippet(document, fileEntries.map(entry => entry.uri));
|
||||
const snippet = createUriListSnippet(document, fileEntries);
|
||||
if (!snippet) {
|
||||
return;
|
||||
}
|
||||
|
@ -361,7 +352,7 @@ export async function createEditForMediaFiles(
|
|||
};
|
||||
}
|
||||
|
||||
function getMdPath(dir: vscode.Uri | undefined, file: vscode.Uri) {
|
||||
function getRelativeMdPath(dir: vscode.Uri | undefined, file: vscode.Uri): string | undefined {
|
||||
if (dir && dir.scheme === file.scheme && dir.authority === file.authority) {
|
||||
if (file.scheme === Schemes.file) {
|
||||
// On windows, we must use the native `path.relative` to generate the relative path
|
||||
|
@ -373,8 +364,7 @@ function getMdPath(dir: vscode.Uri | undefined, file: vscode.Uri) {
|
|||
|
||||
return path.posix.relative(dir.path, file.path);
|
||||
}
|
||||
|
||||
return file.toString(false);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function escapeHtmlAttribute(attr: string): string {
|
||||
|
|
|
@ -18,7 +18,7 @@ suite('createEditAddingLinksForUriList', () => {
|
|||
getText: function () { return 'hello world!'; },
|
||||
};
|
||||
|
||||
const result = await createEditAddingLinksForUriList(skinnyDocument, [new vscode.Range(0, 0, 0, 12)], 'https://www.microsoft.com/', true, true, new vscode.CancellationTokenSource().token);
|
||||
const result = createEditAddingLinksForUriList(skinnyDocument, [new vscode.Range(0, 0, 0, 12)], 'https://www.microsoft.com/', true, true);
|
||||
// need to check the actual result -> snippet value
|
||||
assert.strictEqual(result?.label, 'Insert Markdown Link');
|
||||
});
|
||||
|
@ -95,31 +95,36 @@ suite('createEditAddingLinksForUriList', () => {
|
|||
|
||||
test('Should create snippet with < > when pasted link has an mismatched parentheses', () => {
|
||||
const uriString = 'https://www.mic(rosoft.com';
|
||||
const snippet = appendToLinkSnippet(new vscode.SnippetString(''), 'abc', uriString, 0, true);
|
||||
const snippet = new vscode.SnippetString('');
|
||||
appendToLinkSnippet(snippet, 'abc', uriString, 0, true);
|
||||
assert.strictEqual(snippet?.value, '[${0:abc}](<https://www.mic(rosoft.com>)');
|
||||
});
|
||||
|
||||
test('Should create Markdown link snippet when pasteAsMarkdownLink is true', () => {
|
||||
const uriString = 'https://www.microsoft.com';
|
||||
const snippet = appendToLinkSnippet(new vscode.SnippetString(''), '', uriString, 0, true);
|
||||
const snippet = new vscode.SnippetString('');
|
||||
appendToLinkSnippet(snippet, '', uriString, 0, true);
|
||||
assert.strictEqual(snippet?.value, '[${0:Title}](https://www.microsoft.com)');
|
||||
});
|
||||
|
||||
test('Should use an unencoded URI string in Markdown link when passing in an external browser link', () => {
|
||||
const uriString = 'https://www.microsoft.com';
|
||||
const snippet = appendToLinkSnippet(new vscode.SnippetString(''), '', uriString, 0, true);
|
||||
const snippet = new vscode.SnippetString('');
|
||||
appendToLinkSnippet(snippet, '', uriString, 0, true);
|
||||
assert.strictEqual(snippet?.value, '[${0:Title}](https://www.microsoft.com)');
|
||||
});
|
||||
|
||||
test('Should not decode an encoded URI string when passing in an external browser link', () => {
|
||||
const uriString = 'https://www.microsoft.com/%20';
|
||||
const snippet = appendToLinkSnippet(new vscode.SnippetString(''), '', uriString, 0, true);
|
||||
const snippet = new vscode.SnippetString('');
|
||||
appendToLinkSnippet(snippet, '', uriString, 0, true);
|
||||
assert.strictEqual(snippet?.value, '[${0:Title}](https://www.microsoft.com/%20)');
|
||||
});
|
||||
|
||||
test('Should not encode an unencoded URI string when passing in an external browser link', () => {
|
||||
const uriString = 'https://www.example.com/path?query=value&another=value#fragment';
|
||||
const snippet = appendToLinkSnippet(new vscode.SnippetString(''), '', uriString, 0, true);
|
||||
const snippet = new vscode.SnippetString('');
|
||||
appendToLinkSnippet(snippet, '', uriString, 0, true);
|
||||
assert.strictEqual(snippet?.value, '[${0:Title}](https://www.example.com/path?query=value&another=value#fragment)');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue