diff --git a/authenticationprovider-sample/.vscode/settings.json b/authenticationprovider-sample/.vscode/settings.json index 30bf8c2d3f..bb4faebfdb 100644 --- a/authenticationprovider-sample/.vscode/settings.json +++ b/authenticationprovider-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "js/ts.tsc.autoDetect": "off" } \ No newline at end of file diff --git a/basic-multi-root-sample/.vscode/settings.json b/basic-multi-root-sample/.vscode/settings.json index 0e15ff1968..45655fd7f6 100644 --- a/basic-multi-root-sample/.vscode/settings.json +++ b/basic-multi-root-sample/.vscode/settings.json @@ -6,5 +6,5 @@ "search.exclude": { "out": true // set this to false to include "out" folder in search results }, - "typescript.tsc.autoDetect": "off" // Turn off tsc task auto detection since we have the necessary task as npm scripts + "js/ts.tsc.autoDetect": "off" // Turn off tsc task auto detection since we have the necessary task as npm scripts } \ No newline at end of file diff --git a/chat-context-sample/.vscode/settings.json b/chat-context-sample/.vscode/settings.json index afdab66cc1..702eff8145 100644 --- a/chat-context-sample/.vscode/settings.json +++ b/chat-context-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "js/ts.tsc.autoDetect": "off" } diff --git a/chat-sample/README.md b/chat-sample/README.md index 9a20db83d7..ccd171c623 100644 --- a/chat-sample/README.md +++ b/chat-sample/README.md @@ -10,7 +10,7 @@ This GitHub Copilot Extension sample shows: - How to contribute a simple chat participant to the GitHub Copilot Chat view. (`@cat`, [simple.ts](src/simple.ts)) - How to use the Language Model API to request access to the Language Model. -- How to use the `@vscode/chat-extension-utils` library to easily create a chat participant that uses tools. (`@catTools`, [chatUtilsSample.ts](src/chatUtilsSample.ts)) +- How to create a chat participant that uses tools with a custom persona. (`@catTools`, [chatUtilsSample.ts](src/chatUtilsSample.ts)) - How to contribute a more sophisticated chat participant that uses the LanguageModelTool API to contribute and invoke tools. (`@tool`, [toolParticipant.ts](src/toolParticipant.ts)) ![demo](./demo.png) diff --git a/chat-sample/package-lock.json b/chat-sample/package-lock.json index ad3c7ad7d2..65881b5b96 100644 --- a/chat-sample/package-lock.json +++ b/chat-sample/package-lock.json @@ -8,7 +8,6 @@ "name": "chat-sample", "version": "0.1.0", "dependencies": { - "@vscode/chat-extension-utils": "^0.0.0-alpha.1", "@vscode/prompt-tsx": "^0.3.0-alpha.12" }, "devDependencies": { @@ -593,15 +592,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@vscode/chat-extension-utils": { - "version": "0.0.0-alpha.1", - "resolved": "https://registry.npmjs.org/@vscode/chat-extension-utils/-/chat-extension-utils-0.0.0-alpha.1.tgz", - "integrity": "sha512-49eYur98d1iukPEQqMYQL4lJgaKnM0QFQB4/BFIFvuuKM+Kug2KNE/TSIJJQXrp5CrP0kDOmIIXvTnNRPtO2vg==", - "license": "MIT", - "dependencies": { - "@vscode/prompt-tsx": "^0.3.0-alpha.13" - } - }, "node_modules/@vscode/prompt-tsx": { "version": "0.3.0-alpha.13", "resolved": "https://registry.npmjs.org/@vscode/prompt-tsx/-/prompt-tsx-0.3.0-alpha.13.tgz", diff --git a/chat-sample/package.json b/chat-sample/package.json index 6eaae517d5..d20fa1b605 100644 --- a/chat-sample/package.json +++ b/chat-sample/package.json @@ -77,7 +77,7 @@ "id": "chat-tools-sample.catTools", "fullName": "Cat (Tools)", "name": "catTools", - "description": "I use tools, implemented using @vscode/chat-extension-utils, and am also a cat", + "description": "I use tools and am also a cat", "isSticky": true, "commands": [ { @@ -172,7 +172,6 @@ "watch": "tsc -watch -p ./" }, "dependencies": { - "@vscode/chat-extension-utils": "^0.0.0-alpha.1", "@vscode/prompt-tsx": "^0.3.0-alpha.12" }, "devDependencies": { @@ -184,4 +183,4 @@ "typescript": "^5.9.2", "typescript-eslint": "^8.39.0" } -} \ No newline at end of file +} diff --git a/chat-sample/src/chatUtilsSample.ts b/chat-sample/src/chatUtilsSample.ts index a76b000a5e..97684fc8b8 100644 --- a/chat-sample/src/chatUtilsSample.ts +++ b/chat-sample/src/chatUtilsSample.ts @@ -1,5 +1,26 @@ +import { renderPrompt } from '@vscode/prompt-tsx'; import * as vscode from 'vscode'; -import * as chatUtils from '@vscode/chat-extension-utils'; +import { ToolCallRound, ToolResultMetadata, ToolUserPrompt } from './toolsPrompt'; +import { TsxToolUserMetadata } from './toolParticipant'; +import { toLanguageModelChatTools, getToolsForRequest } from './lmTools'; + +const FIND_FILES_TOOL = 'chat-tools-sample_findFiles'; + +function inferRequiredToolFromPrompt( + prompt: string, + tools: readonly vscode.LanguageModelToolInformation[] +): string | undefined { + const findFilesTool = tools.find(tool => tool.name === FIND_FILES_TOOL); + if (!findFilesTool) { + return undefined; + } + + if (/\b(search|find|look\s+for|locate)\b/i.test(prompt) && /\.\w{1,10}\b/.test(prompt)) { + return findFilesTool.name; + } + + return undefined; +} export function registerChatLibChatParticipant(context: vscode.ExtensionContext) { const handler: vscode.ChatRequestHandler = async (request: vscode.ChatRequest, chatContext: vscode.ChatContext, stream: vscode.ChatResponseStream, token: vscode.CancellationToken) => { @@ -8,28 +29,110 @@ export function registerChatLibChatParticipant(context: vscode.ExtensionContext) return; } - const tools = request.command === 'all' ? - vscode.lm.tools : - vscode.lm.tools.filter(tool => tool.tags.includes('chat-tools-sample')); + let model = request.model; + if (model.vendor === 'copilot' && model.family.startsWith('o1')) { + const models = await vscode.lm.selectChatModels({ + vendor: 'copilot', + family: 'gpt-4o' + }); + model = models[0]; + } + + const tools = getToolsForRequest(request.command); + const options: vscode.LanguageModelChatRequestOptions = { + justification: 'To make a request to @catTools', + }; - const libResult = chatUtils.sendChatParticipantRequest( - request, - chatContext, + const result = await renderPrompt( + ToolUserPrompt, { - prompt: 'You are a cat! Answer as a cat.', - responseStreamOptions: { - stream, - references: true, - responseText: true - }, - tools + context: chatContext, + request, + toolCallRounds: [], + toolCallResults: {}, + additionalInstructions: 'You are a cat! Answer as a cat, but still use tools whenever they help complete the user\'s request.' }, - token); + { modelMaxPromptTokens: model.maxInputTokens }, + model); + let messages = result.messages; + result.references.forEach(ref => { + if (ref.anchor instanceof vscode.Uri || ref.anchor instanceof vscode.Location) { + stream.reference(ref.anchor); + } + }); + + const toolReferences = [...request.toolReferences]; + const inferredTool = inferRequiredToolFromPrompt(request.prompt, tools); + if (inferredTool && !toolReferences.some(ref => ref.name === inferredTool)) { + toolReferences.unshift({ name: inferredTool } as vscode.ChatLanguageModelToolReference); + } + + const accumulatedToolResults: Record = {}; + const toolCallRounds: ToolCallRound[] = []; + const runWithTools = async (): Promise => { + const requestedTool = toolReferences.shift(); + if (requestedTool) { + options.toolMode = vscode.LanguageModelChatToolMode.Required; + options.tools = toLanguageModelChatTools( + vscode.lm.tools.filter(tool => tool.name === requestedTool.name) + ); + } else { + options.toolMode = undefined; + options.tools = toLanguageModelChatTools(tools); + } + + const response = await model.sendRequest(messages, options, token); + + const toolCalls: vscode.LanguageModelToolCallPart[] = []; + let responseStr = ''; + for await (const part of response.stream) { + if (part instanceof vscode.LanguageModelTextPart) { + stream.markdown(part.value); + responseStr += part.value; + } else if (part instanceof vscode.LanguageModelToolCallPart) { + toolCalls.push(part); + } + } + + if (toolCalls.length) { + toolCallRounds.push({ + response: responseStr, + toolCalls + }); + const nextResult = (await renderPrompt( + ToolUserPrompt, + { + context: chatContext, + request, + toolCallRounds, + toolCallResults: accumulatedToolResults, + additionalInstructions: 'You are a cat! Answer as a cat, but still use tools whenever they help complete the user\'s request.' + }, + { modelMaxPromptTokens: model.maxInputTokens }, + model)); + messages = nextResult.messages; + const toolResultMetadata = nextResult.metadatas.getAll(ToolResultMetadata); + if (toolResultMetadata?.length) { + toolResultMetadata.forEach(meta => accumulatedToolResults[meta.toolCallId] = meta.result); + } + + return runWithTools(); + } + }; + + await runWithTools(); - return await libResult.result; + return { + metadata: { + toolCallsMetadata: { + toolCallResults: accumulatedToolResults, + toolCallRounds + } + } satisfies TsxToolUserMetadata, + }; }; const chatLibParticipant = vscode.chat.createChatParticipant('chat-tools-sample.catTools', handler); chatLibParticipant.iconPath = vscode.Uri.joinPath(context.extensionUri, 'cat.jpeg'); context.subscriptions.push(chatLibParticipant); -} \ No newline at end of file +} diff --git a/chat-sample/src/lmTools.ts b/chat-sample/src/lmTools.ts new file mode 100644 index 0000000000..a8d4720f57 --- /dev/null +++ b/chat-sample/src/lmTools.ts @@ -0,0 +1,24 @@ +import * as vscode from 'vscode'; + +/** + * Map registered tools to the shape expected by {@link vscode.LanguageModelChat.sendRequest}. + * Ensures every tool carries a valid JSON schema object for `inputSchema` — some models (e.g. + * Claude) reject tool definitions where `inputSchema` is `undefined`. + */ +export function toLanguageModelChatTools( + tools: readonly vscode.LanguageModelToolInformation[] +): vscode.LanguageModelChatTool[] { + return tools.map(tool => ({ + name: tool.name, + description: tool.description, + inputSchema: tool.inputSchema ?? { type: 'object', properties: {} }, + })); +} + +export function getToolsForRequest( + command: string | undefined +): readonly vscode.LanguageModelToolInformation[] { + return command === 'all' + ? vscode.lm.tools + : vscode.lm.tools.filter(tool => tool.tags.includes('chat-tools-sample')); +} diff --git a/chat-sample/src/toolParticipant.ts b/chat-sample/src/toolParticipant.ts index 36d8068ef7..de2f457010 100644 --- a/chat-sample/src/toolParticipant.ts +++ b/chat-sample/src/toolParticipant.ts @@ -1,6 +1,7 @@ import { renderPrompt } from '@vscode/prompt-tsx'; import * as vscode from 'vscode'; import { ToolCallRound, ToolResultMetadata, ToolUserPrompt } from './toolsPrompt'; +import { toLanguageModelChatTools, getToolsForRequest } from './lmTools'; export interface TsxToolUserMetadata { toolCallsMetadata: ToolCallsMetadata; @@ -36,9 +37,7 @@ export function registerToolUserChatParticipant(context: vscode.ExtensionContext } // Use all tools, or tools with the tags that are relevant. - const tools = request.command === 'all' ? - vscode.lm.tools : - vscode.lm.tools.filter(tool => tool.tags.includes('chat-tools-sample')); + const tools = getToolsForRequest(request.command); const options: vscode.LanguageModelChatRequestOptions = { justification: 'To make a request to @toolsTSX', }; @@ -69,10 +68,12 @@ export function registerToolUserChatParticipant(context: vscode.ExtensionContext const requestedTool = toolReferences.shift(); if (requestedTool) { options.toolMode = vscode.LanguageModelChatToolMode.Required; - options.tools = vscode.lm.tools.filter(tool => tool.name === requestedTool.name); + options.tools = toLanguageModelChatTools( + vscode.lm.tools.filter(tool => tool.name === requestedTool.name) + ); } else { options.toolMode = undefined; - options.tools = [...tools]; + options.tools = toLanguageModelChatTools(tools); } // Send the request to the LanguageModelChat diff --git a/chat-sample/src/toolsPrompt.tsx b/chat-sample/src/toolsPrompt.tsx index f533fbdabe..00a83dba95 100644 --- a/chat-sample/src/toolsPrompt.tsx +++ b/chat-sample/src/toolsPrompt.tsx @@ -27,6 +27,7 @@ export interface ToolUserProps extends BasePromptElementProps { context: vscode.ChatContext; toolCallRounds: ToolCallRound[]; toolCallResults: Record; + additionalInstructions?: string; } export class ToolUserPrompt extends PromptElement { @@ -47,6 +48,12 @@ export class ToolUserPrompt extends PromptElement { - Don't make assumptions about the situation- gather context first, then perform the task or answer the question.
- Don't ask the user for confirmation to use tools, just use them. + {this.props.additionalInstructions ? ( + <> +
+ {this.props.additionalInstructions} + + ) : undefined} \\/\\?\\s]+)", "indentationRules": { - "increaseIndentPattern": "^((?!.*?\\/\\*).*\\*\/)?\\s*[\\}\\]].*$", - "decreaseIndentPattern": "^((?!\\/\\/).)*(\\{[^}\"'`]*|\\([^)\"'`]*|\\[[^\\]\"'`]*)$" + "increaseIndentPattern": "^((?!\\/\\/).)*(\\{[^}\"'`]*|\\([^)\"'`]*|\\[[^\\]\"'`]*)$", + "decreaseIndentPattern": "^((?!.*?\\/\\*).*\\*\\/)?\\s*[\\}\\]].*$" } } \ No newline at end of file diff --git a/lm-api-tutorial/.vscode/settings.json b/lm-api-tutorial/.vscode/settings.json index afdab66cc1..702eff8145 100644 --- a/lm-api-tutorial/.vscode/settings.json +++ b/lm-api-tutorial/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "js/ts.tsc.autoDetect": "off" } diff --git a/lsp-embedded-language-service/.vscode/settings.json b/lsp-embedded-language-service/.vscode/settings.json index e753763c94..a665cb6fc9 100644 --- a/lsp-embedded-language-service/.vscode/settings.json +++ b/lsp-embedded-language-service/.vscode/settings.json @@ -1,5 +1,5 @@ { "editor.insertSpaces": false, - "typescript.tsc.autoDetect": "off", + "js/ts.tsc.autoDetect": "off", "typescript.preferences.quoteStyle": "single" } \ No newline at end of file diff --git a/lsp-embedded-request-forwarding/.vscode/settings.json b/lsp-embedded-request-forwarding/.vscode/settings.json index e753763c94..a665cb6fc9 100644 --- a/lsp-embedded-request-forwarding/.vscode/settings.json +++ b/lsp-embedded-request-forwarding/.vscode/settings.json @@ -1,5 +1,5 @@ { "editor.insertSpaces": false, - "typescript.tsc.autoDetect": "off", + "js/ts.tsc.autoDetect": "off", "typescript.preferences.quoteStyle": "single" } \ No newline at end of file diff --git a/lsp-multi-server-sample/.vscode/settings.json b/lsp-multi-server-sample/.vscode/settings.json index 9a7bb62a36..ff8c5a292e 100644 --- a/lsp-multi-server-sample/.vscode/settings.json +++ b/lsp-multi-server-sample/.vscode/settings.json @@ -1,5 +1,5 @@ { "editor.insertSpaces": false, - "typescript.tsc.autoDetect": "off", + "js/ts.tsc.autoDetect": "off", "typescript.preferences.quoteStyle": "single" } \ No newline at end of file diff --git a/lsp-sample/.vscode/settings.json b/lsp-sample/.vscode/settings.json index 390d2993aa..a31eae3dc0 100644 --- a/lsp-sample/.vscode/settings.json +++ b/lsp-sample/.vscode/settings.json @@ -1,6 +1,6 @@ { "editor.insertSpaces": false, - "typescript.tsc.autoDetect": "off", + "js/ts.tsc.autoDetect": "off", "typescript.preferences.quoteStyle": "single", "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" diff --git a/lsp-user-input-sample/.vscode/settings.json b/lsp-user-input-sample/.vscode/settings.json index 3ba8ccc930..29cf482e94 100644 --- a/lsp-user-input-sample/.vscode/settings.json +++ b/lsp-user-input-sample/.vscode/settings.json @@ -11,7 +11,7 @@ "editor.insertSpaces": false, "editor.tabSize": 4, "typescript.tsdk": "./node_modules/typescript/lib", - "typescript.tsc.autoDetect": "off", + "js/ts.tsc.autoDetect": "off", "eslint.enable": true, "eslint.validate": [ "typescript" diff --git a/lsp-web-extension-sample/.vscode/settings.json b/lsp-web-extension-sample/.vscode/settings.json index 390d2993aa..a31eae3dc0 100644 --- a/lsp-web-extension-sample/.vscode/settings.json +++ b/lsp-web-extension-sample/.vscode/settings.json @@ -1,6 +1,6 @@ { "editor.insertSpaces": false, - "typescript.tsc.autoDetect": "off", + "js/ts.tsc.autoDetect": "off", "typescript.preferences.quoteStyle": "single", "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" diff --git a/nodefs-provider-sample/.vscode/settings.json b/nodefs-provider-sample/.vscode/settings.json index 0e15ff1968..45655fd7f6 100644 --- a/nodefs-provider-sample/.vscode/settings.json +++ b/nodefs-provider-sample/.vscode/settings.json @@ -6,5 +6,5 @@ "search.exclude": { "out": true // set this to false to include "out" folder in search results }, - "typescript.tsc.autoDetect": "off" // Turn off tsc task auto detection since we have the necessary task as npm scripts + "js/ts.tsc.autoDetect": "off" // Turn off tsc task auto detection since we have the necessary task as npm scripts } \ No newline at end of file diff --git a/notebook-extend-markdown-renderer-sample/.vscode/settings.json b/notebook-extend-markdown-renderer-sample/.vscode/settings.json index ffeaf91cb1..fbe735ac9f 100644 --- a/notebook-extend-markdown-renderer-sample/.vscode/settings.json +++ b/notebook-extend-markdown-renderer-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "js/ts.tsc.autoDetect": "off" } diff --git a/notebook-format-code-action-sample/.vscode/settings.json b/notebook-format-code-action-sample/.vscode/settings.json index 30bf8c2d3f..bb4faebfdb 100644 --- a/notebook-format-code-action-sample/.vscode/settings.json +++ b/notebook-format-code-action-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "js/ts.tsc.autoDetect": "off" } \ No newline at end of file diff --git a/notebook-renderer-react-sample/.vscode/settings.json b/notebook-renderer-react-sample/.vscode/settings.json index ffeaf91cb1..fbe735ac9f 100644 --- a/notebook-renderer-react-sample/.vscode/settings.json +++ b/notebook-renderer-react-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "js/ts.tsc.autoDetect": "off" } diff --git a/notebook-renderer-sample/.vscode/settings.json b/notebook-renderer-sample/.vscode/settings.json index ffeaf91cb1..fbe735ac9f 100644 --- a/notebook-renderer-sample/.vscode/settings.json +++ b/notebook-renderer-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "js/ts.tsc.autoDetect": "off" } diff --git a/notebook-serializer-sample/.vscode/settings.json b/notebook-serializer-sample/.vscode/settings.json index bfcb693ae2..0497cd6eb7 100644 --- a/notebook-serializer-sample/.vscode/settings.json +++ b/notebook-serializer-sample/.vscode/settings.json @@ -2,5 +2,5 @@ "search.exclude": { "out": true }, - "typescript.tsc.autoDetect": "off" + "js/ts.tsc.autoDetect": "off" } diff --git a/notifications-sample/.vscode/settings.json b/notifications-sample/.vscode/settings.json index 30bf8c2d3f..bb4faebfdb 100644 --- a/notifications-sample/.vscode/settings.json +++ b/notifications-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "js/ts.tsc.autoDetect": "off" } \ No newline at end of file diff --git a/progress-sample/.vscode/settings.json b/progress-sample/.vscode/settings.json index dfcf0a56b9..56cd7d3071 100644 --- a/progress-sample/.vscode/settings.json +++ b/progress-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, "typescript.tsdk": "./node_modules/typescript/lib", // we want to use the TS server from our node_modules folder to control its version - "typescript.tsc.autoDetect": "off" // Turn off tsc task auto detection since we have the necessary task as npm scripts + "js/ts.tsc.autoDetect": "off" // Turn off tsc task auto detection since we have the necessary task as npm scripts } \ No newline at end of file diff --git a/quickinput-sample/.vscode/settings.json b/quickinput-sample/.vscode/settings.json index 30bf8c2d3f..bb4faebfdb 100644 --- a/quickinput-sample/.vscode/settings.json +++ b/quickinput-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "js/ts.tsc.autoDetect": "off" } \ No newline at end of file diff --git a/shell-integration-sample/.vscode/settings.json b/shell-integration-sample/.vscode/settings.json index 30bf8c2d3f..bb4faebfdb 100644 --- a/shell-integration-sample/.vscode/settings.json +++ b/shell-integration-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "js/ts.tsc.autoDetect": "off" } \ No newline at end of file diff --git a/statusbar-sample/.vscode/settings.json b/statusbar-sample/.vscode/settings.json index dfcf0a56b9..56cd7d3071 100644 --- a/statusbar-sample/.vscode/settings.json +++ b/statusbar-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, "typescript.tsdk": "./node_modules/typescript/lib", // we want to use the TS server from our node_modules folder to control its version - "typescript.tsc.autoDetect": "off" // Turn off tsc task auto detection since we have the necessary task as npm scripts + "js/ts.tsc.autoDetect": "off" // Turn off tsc task auto detection since we have the necessary task as npm scripts } \ No newline at end of file diff --git a/task-provider-sample/.vscode/settings.json b/task-provider-sample/.vscode/settings.json index e753763c94..a665cb6fc9 100644 --- a/task-provider-sample/.vscode/settings.json +++ b/task-provider-sample/.vscode/settings.json @@ -1,5 +1,5 @@ { "editor.insertSpaces": false, - "typescript.tsc.autoDetect": "off", + "js/ts.tsc.autoDetect": "off", "typescript.preferences.quoteStyle": "single" } \ No newline at end of file diff --git a/tree-view-sample/.vscode/settings.json b/tree-view-sample/.vscode/settings.json index c89394a5bc..8aec0689fe 100644 --- a/tree-view-sample/.vscode/settings.json +++ b/tree-view-sample/.vscode/settings.json @@ -7,6 +7,6 @@ "out": true // set this to false to include "out" folder in search results }, "typescript.tsdk": "./node_modules/typescript/lib", // we want to use the TS server from our node_modules folder to control its version - "typescript.tsc.autoDetect": "off", + "js/ts.tsc.autoDetect": "off", "editor.insertSpaces": false, } \ No newline at end of file diff --git a/uri-handler-sample/.vscode/settings.json b/uri-handler-sample/.vscode/settings.json index 30bf8c2d3f..bb4faebfdb 100644 --- a/uri-handler-sample/.vscode/settings.json +++ b/uri-handler-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "js/ts.tsc.autoDetect": "off" } \ No newline at end of file diff --git a/virtual-document-sample/.vscode/settings.json b/virtual-document-sample/.vscode/settings.json index dfcf0a56b9..56cd7d3071 100644 --- a/virtual-document-sample/.vscode/settings.json +++ b/virtual-document-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, "typescript.tsdk": "./node_modules/typescript/lib", // we want to use the TS server from our node_modules folder to control its version - "typescript.tsc.autoDetect": "off" // Turn off tsc task auto detection since we have the necessary task as npm scripts + "js/ts.tsc.autoDetect": "off" // Turn off tsc task auto detection since we have the necessary task as npm scripts } \ No newline at end of file diff --git a/webview-view-sample/README.md b/webview-view-sample/README.md index 99b04f5692..26d10b40c9 100644 --- a/webview-view-sample/README.md +++ b/webview-view-sample/README.md @@ -2,12 +2,24 @@ Demonstrates VS Code's [webview view API](https://github.com/microsoft/vscode/issues/46585). This includes: -- Contributing a webview based view to the explorer. +- Contributing webview based views to custom view containers (`activitybar`, `panel`, `secondarySidebar`) - Posting messages from an extension to a webview view - Posting message from a webview to an extension - Persisting state in the view. - Contributing commands to the view title. +## View containers + +This sample registers three custom [viewsContainers](https://code.visualstudio.com/api/references/contribution-points#contributes.viewsContainers): + +| Location | Container id | View id | +|----------|--------------|---------| +| Activity Bar | `calicoColors` | `calicoColors.colorsView` | +| Panel | `calicoColorsPanel` | `calicoColors.panelView` | +| Secondary Sidebar | `calicoColorsSecondary` | `calicoColors.secondaryView` | + +See [`package.json`](package.json) for the contribution points and [`src/extension.ts`](src/extension.ts) for the providers. + ## VS Code API ### `vscode` module @@ -21,4 +33,4 @@ Demonstrates VS Code's [webview view API](https://github.com/microsoft/vscode/is - `npm run watch` or `npm run compile` - `F5` to start debugging -In the explorer, expand the `Calico Colors` view. \ No newline at end of file +In the activity bar, open the **Calico Colors** view container. You can also open the panel and secondary sidebar containers from the View menu. \ No newline at end of file diff --git a/webview-view-sample/package.json b/webview-view-sample/package.json index 8cb6839702..1ea49bf9b1 100644 --- a/webview-view-sample/package.json +++ b/webview-view-sample/package.json @@ -22,13 +22,50 @@ "activationEvents": [], "main": "./out/extension.js", "contributes": { + "viewsContainers": { + "activitybar": [ + { + "id": "calicoColors", + "title": "Calico Colors", + "icon": "$(symbol-color)" + } + ], + "panel": [ + { + "id": "calicoColorsPanel", + "title": "Calico Panel", + "icon": "$(layout-panel)" + } + ], + "secondarySidebar": [ + { + "id": "calicoColorsSecondary", + "title": "Calico Secondary", + "icon": "$(layout-sidebar-right)" + } + ] + }, "views": { - "explorer": [ + "calicoColors": [ { "type": "webview", "id": "calicoColors.colorsView", "name": "Calico Colors" } + ], + "calicoColorsPanel": [ + { + "type": "webview", + "id": "calicoColors.panelView", + "name": "Panel Colors" + } + ], + "calicoColorsSecondary": [ + { + "type": "webview", + "id": "calicoColors.secondaryView", + "name": "Secondary Colors" + } ] }, "commands": [ diff --git a/webview-view-sample/src/extension.ts b/webview-view-sample/src/extension.ts index 582277f4bc..360c5d36ee 100644 --- a/webview-view-sample/src/extension.ts +++ b/webview-view-sample/src/extension.ts @@ -1,11 +1,15 @@ import * as vscode from 'vscode'; export function activate(context: vscode.ExtensionContext) { - - const provider = new ColorsViewProvider(context.extensionUri); + const provider = new ColorsViewProvider(context.extensionUri, 'Cat Colors'); + const panelProvider = new ColorsViewProvider(context.extensionUri, 'Panel Colors', 'This webview lives in a custom panel view container.'); + const secondaryProvider = new ColorsViewProvider(context.extensionUri, 'Secondary Colors', 'This webview lives in a custom secondary sidebar view container.'); context.subscriptions.push( - vscode.window.registerWebviewViewProvider(ColorsViewProvider.viewType, provider)); + vscode.window.registerWebviewViewProvider(ColorsViewProvider.viewType, provider), + vscode.window.registerWebviewViewProvider(ColorsViewProvider.panelViewType, panelProvider), + vscode.window.registerWebviewViewProvider(ColorsViewProvider.secondaryViewType, secondaryProvider), + ); context.subscriptions.push( vscode.commands.registerCommand('calicoColors.addColor', () => { @@ -21,11 +25,15 @@ export function activate(context: vscode.ExtensionContext) { class ColorsViewProvider implements vscode.WebviewViewProvider { public static readonly viewType = 'calicoColors.colorsView'; + public static readonly panelViewType = 'calicoColors.panelView'; + public static readonly secondaryViewType = 'calicoColors.secondaryView'; private _view?: vscode.WebviewView; constructor( private readonly _extensionUri: vscode.Uri, + private readonly _title: string, + private readonly _description?: string, ) { } public resolveWebviewView( @@ -36,9 +44,7 @@ class ColorsViewProvider implements vscode.WebviewViewProvider { this._view = webviewView; webviewView.webview.options = { - // Allow scripts in the webview enableScripts: true, - localResourceRoots: [ this._extensionUri ] @@ -59,7 +65,7 @@ class ColorsViewProvider implements vscode.WebviewViewProvider { public addColor() { if (this._view) { - this._view.show?.(true); // `show` is not implemented in 1.49 but is for 1.50 insiders + this._view.show?.(true); this._view.webview.postMessage({ type: 'addColor' }); } } @@ -71,43 +77,31 @@ class ColorsViewProvider implements vscode.WebviewViewProvider { } private _getHtmlForWebview(webview: vscode.Webview) { - // Get the local path to main script run in the webview, then convert it to a uri we can use in the webview. const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'media', 'main.js')); - - // Do the same for the stylesheet. const styleResetUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'media', 'reset.css')); const styleVSCodeUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'media', 'vscode.css')); const styleMainUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'media', 'main.css')); - - // Use a nonce to only allow a specific script to be run. const nonce = getNonce(); + const descriptionHtml = this._description + ? `

${this._description}

` + : ''; return ` - - - - - - Cat Colors + ${this._title} + ${descriptionHtml}
- - `; diff --git a/welcome-view-content-sample/.vscode/settings.json b/welcome-view-content-sample/.vscode/settings.json index 30bf8c2d3f..bb4faebfdb 100644 --- a/welcome-view-content-sample/.vscode/settings.json +++ b/welcome-view-content-sample/.vscode/settings.json @@ -7,5 +7,5 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "js/ts.tsc.autoDetect": "off" } \ No newline at end of file