Repository: microsoft/vscode
File: src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatInlineAnchorWidget.ts (TypeScript)

Code before:
import { ExplorerFolderContext } from '../../../../files/common/files.js';
import { IWorkspaceSymbol } from '../../../../search/common/search.js';
import { IChatContentInlineReference } from '../../../common/chatService/chatService.js';
import { IChatWidgetService } from '../../chat.js';
import { chatAttachmentResourceContextKey, hookUpSymbolAttachmentDragAndContextMenu } from '../../attachments/chatAttachmentWidgets.js';
import { IChatMarkdownAnchorService } from './chatMarkdownAnchorService.js';

type ContentRefData =
	| { readonly kind: 'symbol'; readonly symbol: IWorkspaceSymbol }
	| {
		readonly kind?: undefined;
		readonly uri: URI;
		readonly range?: IRange;
	};

type InlineAnchorWidgetMetadata = {
	vscodeLinkType: 'file';
	fileName?: string;
};

export function renderFileWidgets(element: HTMLElement, instantiationService: IInstantiationService, chatMarkdownAnchorService: IChatMarkdownAnchorService, disposables: DisposableStore) {
	// eslint-disable-next-line no-restricted-syntax
	const links = element.querySelectorAll('a');
	links.forEach(a => {
		// Empty link text -> render file widget
		// Also support metadata format: [{"vscodeLinkType": "file", ...}](uri)
		const linkText = a.textContent?.trim();
		let shouldRenderWidget = false;
		let metadata: InlineAnchorWidgetMetadata | undefined;

		if (!linkText) {
			shouldRenderWidget = true;
		} else {
			// Sanity check length to avoid parsing huge strings
			if (linkText.length <= 1000) {
				try {
					const parsed = JSON.parse(linkText);
					// Validate that the parsed result is a plain object and not an array or primitive
					if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
						metadata = parsed as InlineAnchorWidgetMetadata;
						if (metadata.vscodeLinkType === 'file') {
							// If fileName is present, it must be a string
							if (metadata.fileName !== undefined && typeof metadata.fileName !== 'string') {
								shouldRenderWidget = false;
							} else {
								shouldRenderWidget = true;
							}
						}
					}
				} catch { }
			}

Review comment (suggestion):
Could we do something more like standard markdown, such as:
```
[fileName](file:///...uri?vscodeLinkType=file)
```

The link destination could also be a custom scheme if we want to put more info in it:

```
[fileName](vscode-file-link:/file?uri={...json})
```


Code after:
import { ExplorerFolderContext } from '../../../../files/common/files.js';
import { IWorkspaceSymbol } from '../../../../search/common/search.js';
import { IChatContentInlineReference } from '../../../common/chatService/chatService.js';
import { IChatWidgetService } from '../../chat.js';
import { chatAttachmentResourceContextKey, hookUpSymbolAttachmentDragAndContextMenu } from '../../attachments/chatAttachmentWidgets.js';
import { IChatMarkdownAnchorService } from './chatMarkdownAnchorService.js';

type ContentRefData =
	| { readonly kind: 'symbol'; readonly symbol: IWorkspaceSymbol }
	| {
		readonly kind?: undefined;
		readonly uri: URI;
		readonly range?: IRange;
	};

type InlineAnchorWidgetMetadata = {
	vscodeLinkType: string;
	linkText?: string;
};

export function renderFileWidgets(element: HTMLElement, instantiationService: IInstantiationService, chatMarkdownAnchorService: IChatMarkdownAnchorService, disposables: DisposableStore) {
	// eslint-disable-next-line no-restricted-syntax
	const links = element.querySelectorAll('a');
	links.forEach(a => {
		// Empty link text -> render file widget
		// Also support metadata format: [linkText](file:///...uri?vscodeLinkType=...)
		const linkText = a.textContent?.trim();
		let shouldRenderWidget = false;
		let metadata: InlineAnchorWidgetMetadata | undefined;

		const href = a.getAttribute('data-href');
		let uri: URI | undefined;
		if (href) {
			try {
				uri = URI.parse(href);
			} catch {
				// Invalid URI, skip rendering widget
			}
		}

		if (!linkText) {
			shouldRenderWidget = true;
		} else if (uri) {
			// Check for vscodeLinkType in query parameters
			const searchParams = new URLSearchParams(uri.query);
			const vscodeLinkType = searchParams.get('vscodeLinkType');
			if (vscodeLinkType) {
				metadata = {
					vscodeLinkType,
					linkText
				};