Path: blob/main/extensions/mermaid-chat-features/src/extension.ts
3520 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/4import * as vscode from 'vscode';56/**7* View type that uniquely identifies the Mermaid chat output renderer.8*/9const viewType = 'vscode.chatMermaidDiagram';1011/**12* Mime type used to identify Mermaid diagram data in chat output.13*/14const mime = 'text/vnd.mermaid';1516export function activate(context: vscode.ExtensionContext) {1718// Register tools19context.subscriptions.push(20vscode.lm.registerTool<{ markup: string }>('renderMermaidDiagram', {21invoke: async (options, _token) => {22const sourceCode = options.input.markup;23return writeMermaidToolOutput(sourceCode);24},25})26);2728// Register the chat output renderer for Mermaid diagrams.29// This will be invoked with the data generated by the tools.30// It can also be invoked when rendering old Mermaid diagrams in the chat history.31context.subscriptions.push(32vscode.chat.registerChatOutputRenderer(viewType, {33async renderChatOutput({ value }, webview, _ctx, _token) {34const mermaidSource = new TextDecoder().decode(value);3536// Set the options for the webview37const mediaRoot = vscode.Uri.joinPath(context.extensionUri, 'chat-webview-out');38webview.options = {39enableScripts: true,40localResourceRoots: [mediaRoot],41};4243// Set the HTML content for the webview44const nonce = getNonce();45const mermaidScript = vscode.Uri.joinPath(mediaRoot, 'index.js');4647webview.html = `48<!DOCTYPE html>49<html lang="en">5051<head>52<meta charset="UTF-8">53<meta name="viewport" content="width=device-width, initial-scale=1.0">54<title>Mermaid Diagram</title>55<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src ${webview.cspSource} 'nonce-${nonce}'; style-src 'self' 'unsafe-inline';" />56</head>5758<body>59<pre class="mermaid">60${escapeHtmlText(mermaidSource)}61</pre>6263<script type="module" nonce="${nonce}" src="${webview.asWebviewUri(mermaidScript)}"></script>64</body>65</html>`;66},67}));68}697071function writeMermaidToolOutput(sourceCode: string): vscode.LanguageModelToolResult {72// Expose the source code as a tool result for the LM73const result = new vscode.LanguageModelToolResult([74new vscode.LanguageModelTextPart(sourceCode)75]);7677// And store custom data in the tool result details to indicate that a custom renderer should be used for it.78// In this case we just store the source code as binary data.7980// Add cast to use proposed API81(result as vscode.ExtendedLanguageModelToolResult2).toolResultDetails2 = {82mime,83value: new TextEncoder().encode(sourceCode),84};8586return result;87}8889function escapeHtmlText(str: string): string {90return str91.replace(/&/g, '&')92.replace(/</g, '<')93.replace(/>/g, '>')94.replace(/"/g, '"')95.replace(/'/g, ''');96}9798function getNonce() {99let text = '';100const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';101for (let i = 0; i < 64; i++) {102text += possible.charAt(Math.floor(Math.random() * possible.length));103}104return text;105}106107108