Fix file uri markdown link pasting (#203377)

Fixes #203180

Enables this feature for uris without authorities and also makes sure these uris are not rewritten to relative paths
This commit is contained in:
Matt Bierner 2024-01-29 17:24:28 +00:00 committed by GitHub
parent 053610ec1c
commit 4be04d5d8c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 31 additions and 6 deletions

View file

@ -7,8 +7,8 @@ import * as vscode from 'vscode';
import { IMdParser } from '../../markdownEngine';
import { ITextDocument } from '../../types/textDocument';
import { Mime } from '../../util/mimes';
import { createInsertUriListEdit } from './shared';
import { Schemes } from '../../util/schemes';
import { createInsertUriListEdit } from './shared';
export enum PasteUrlAsMarkdownLink {
Always = 'always',
@ -59,7 +59,7 @@ class PasteUrlEditProvider implements vscode.DocumentPasteEditProvider {
return;
}
const edit = createInsertUriListEdit(document, ranges, uriText);
const edit = createInsertUriListEdit(document, ranges, uriText, { preserveAbsoluteUris: true });
if (!edit) {
return;
}
@ -212,8 +212,10 @@ const externalUriSchemes: ReadonlySet<string> = new Set([
export function findValidUriInText(text: string): string | undefined {
const trimmedUrlList = text.trim();
// Uri must consist of a single sequence of characters without spaces
if (!/^\S+$/.test(trimmedUrlList)) {
if (
!/^\S+$/.test(trimmedUrlList) // Uri must consist of a single sequence of characters without spaces
|| !trimmedUrlList.includes(':') // And it must have colon somewhere for the scheme. We will verify the schema again later
) {
return;
}
@ -225,7 +227,21 @@ export function findValidUriInText(text: string): string | undefined {
return;
}
if (!externalUriSchemes.has(uri.scheme.toLowerCase()) || uri.authority.length <= 1) {
// `Uri.parse` is lenient and will return a `file:` uri even for non-uri text such as `abc`
// Make sure that the resolved scheme starts the original text
if (!trimmedUrlList.toLowerCase().startsWith(uri.scheme.toLowerCase() + ':')) {
return;
}
// Only enable for an allow list of schemes. Otherwise this can be accidentally activated for non-uri text
// such as `c:\abc` or `value:foo`
if (!externalUriSchemes.has(uri.scheme.toLowerCase())) {
return;
}
// Some part of the uri must not be empty
// This disables the feature for text such as `http:`
if (!uri.authority && uri.path.length < 2 && !uri.query && !uri.fragment) {
return;
}

View file

@ -69,6 +69,7 @@ export function createInsertUriListEdit(
document: ITextDocument,
ranges: readonly vscode.Range[],
urlList: string,
options?: UriListSnippetOptions,
): { edits: vscode.SnippetTextEdit[]; label: string } | undefined {
if (!ranges.length) {
return;
@ -103,6 +104,7 @@ export function createInsertUriListEdit(
const snippet = createUriListSnippet(document.uri, entries, {
placeholderText: range.isEmpty ? undefined : document.getText(range),
placeholderStartIndex: allRangesAreEmpty ? 1 : placeHolderStartIndex,
...options,
});
if (!snippet) {
continue;
@ -134,6 +136,13 @@ interface UriListSnippetOptions {
readonly insertAsMedia?: boolean;
readonly separator?: string;
/**
* Prevents uris from being made relative to the document.
*
* This is mostly useful for `file:` uris.
*/
readonly preserveAbsoluteUris?: boolean;
}
@ -168,7 +177,7 @@ export function createUriListSnippet(
let placeholderIndex = options?.placeholderStartIndex ?? 1;
uris.forEach((uri, i) => {
const mdPath = getRelativeMdPath(documentDir, uri.uri) ?? uri.str ?? uri.uri.toString();
const mdPath = (!options?.preserveAbsoluteUris ? getRelativeMdPath(documentDir, uri.uri) : undefined) ?? uri.str ?? uri.uri.toString();
const ext = URI.Utils.extname(uri.uri).toLowerCase().replace('.', '');
const insertAsMedia = options?.insertAsMedia || (typeof options?.insertAsMedia === 'undefined' && mediaFileExtensions.has(ext));