Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
08535d9
Fix terminal-suggest extension icon
mjbvz Mar 5, 2026
655fe3f
Initial plan
Copilot Mar 5, 2026
002eadd
fix: correct deprecated TypeScript format.enable setting name in tooltip
Copilot Mar 5, 2026
1775c2e
Initial plan
Copilot Mar 6, 2026
4743e19
fix: use vscode codicon as theme icon for Release Notes tab
Copilot Mar 6, 2026
2dbd83b
chat: register file system provider via workbench contribution (#299528)
connor4312 Mar 6, 2026
8e0baf5
Refactor workspace trust editor styles for improved layout (#299798)
mrleemurray Mar 6, 2026
3623d50
Render command title vs ID for chat tip hover (#299811)
meganrogge Mar 6, 2026
2b32258
merge to main (#299794)
sandy081 Mar 6, 2026
6bb50a9
fix: accept Azure DevOps Git URLs without .git suffix in plugin marke…
Copilot Mar 6, 2026
8734c3f
debug: fix variable updating after set response (#299473)
DrSergei Mar 6, 2026
3b4da4f
Revert "chore - Refactor inline chat classes to use private class fie…
chrmarti Mar 6, 2026
be9986c
Fixes problem with code coverage on windows
hediet Mar 6, 2026
77375f1
Ensures ColorId.DefaultBackground is set when no colors are registered.
hediet Mar 6, 2026
844d9b2
Always require `tooltips` for markdown command links
mjbvz Mar 6, 2026
43db920
[MCP_Sandboxing]: Notifying network domains that need access (#299701)
dileepyavan Mar 6, 2026
41c9352
fix: pass Codicon.vscode directly instead of registering a new icon
Copilot Mar 6, 2026
1b0e946
groups component explorer updates
hediet Mar 6, 2026
140fced
ensure deleting attachment works on windows (#299824)
meganrogge Mar 6, 2026
705054b
Merge pull request #299613 from microsoft/copilot/fix-tooltip-depreca…
mjbvz Mar 6, 2026
527f8aa
Merge pull request #299397 from mjbvz/dev/mjbvz/polite-chipmunk
mjbvz Mar 6, 2026
051f735
Merge pull request #299825 from mjbvz/dev/mjbvz/weekly-tern
mjbvz Mar 6, 2026
b607547
tweak wording of chat tip for clarity (#299832)
meganrogge Mar 6, 2026
2f67478
Merge pull request #299646 from microsoft/copilot/add-release-notes-icon
mjbvz Mar 6, 2026
abe7ae5
fix: include sessions built-in prompts in esbuild resource patterns (…
joshspicer Mar 6, 2026
c30864b
Sessions - initial implementation for git changes (#299855)
lszomoru Mar 6, 2026
22933ce
add `closeOnResult` for editor's find widget (#299865)
meganrogge Mar 6, 2026
b35cc30
alert when an image is attached via paste (#299862)
meganrogge Mar 6, 2026
e842b42
Fix browser positioning issues (#299842)
kycutler Mar 6, 2026
0747aea
chat: fix stale pending divider headers from persisting (#299868)
connor4312 Mar 6, 2026
ca433bc
sessions: 'update from VS Code' (#299359)
joshspicer Mar 6, 2026
f3680f6
Support rendering reserved output separately (#299867)
lramos15 Mar 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,20 @@ updates:
allow:
- dependency-name: "@vscode/component-explorer"
- dependency-name: "@vscode/component-explorer-cli"
groups:
component-explorer:
patterns:
- "@vscode/component-explorer"
- "@vscode/component-explorer-cli"
- package-ecosystem: "npm"
directory: "/build/vite"
schedule:
interval: "daily"
allow:
- dependency-name: "@vscode/component-explorer"
- dependency-name: "@vscode/component-explorer-vite-plugin"
groups:
component-explorer:
patterns:
- "@vscode/component-explorer"
- "@vscode/component-explorer-vite-plugin"
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,9 @@ export class SourceMapStore {
}
}

if (/^[a-zA-Z]:/.test(source) || source.startsWith('/')) {
return vscode.Uri.file(source);
}
return vscode.Uri.parse(source);
}

Expand Down
1 change: 1 addition & 0 deletions build/gulpfile.vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ const vscodeResourceIncludes = [

// Sessions
'out-build/vs/sessions/contrib/chat/browser/media/*.svg',
'out-build/vs/sessions/prompts/*.prompt.md',

// Extensions
'out-build/vs/workbench/contrib/extensions/browser/media/{theme-icon.png,language-icon.svg}',
Expand Down
3 changes: 3 additions & 0 deletions build/next/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,9 @@ const desktopResourcePatterns = [
'vs/workbench/services/extensionManagement/common/media/*.png',
'vs/workbench/browser/parts/editor/media/*.png',
'vs/workbench/contrib/debug/browser/media/*.png',

// Sessions - built-in prompts
'vs/sessions/prompts/*.prompt.md',
];

// Resources for server target (minimal - no UI)
Expand Down
26 changes: 0 additions & 26 deletions extensions/github/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,28 +90,6 @@ function resolveSessionRepo(gitAPI: GitAPI, sessionMetadata: { worktreePath?: st
return { repository, remoteInfo, gitRemote: { name: gitRemote.name, fetchUrl: gitRemote.fetchUrl! }, head: head as ResolvedSessionRepo['head'] };
}

async function checkOpenPullRequest(gitAPI: GitAPI, _sessionResource: vscode.Uri | undefined, sessionMetadata: { worktreePath?: string } | undefined): Promise<void> {
const resolved = resolveSessionRepo(gitAPI, sessionMetadata, false);
if (!resolved) {
vscode.commands.executeCommand('setContext', 'github.hasOpenPullRequest', false);
return;
}

try {
const octokit = await getOctokit();
const { data: openPRs } = await octokit.pulls.list({
owner: resolved.remoteInfo.owner,
repo: resolved.remoteInfo.repo,
head: `${resolved.remoteInfo.owner}:${resolved.head.name}`,
state: 'all',
});

vscode.commands.executeCommand('setContext', 'github.hasOpenPullRequest', openPRs.length > 0);
} catch {
vscode.commands.executeCommand('setContext', 'github.hasOpenPullRequest', false);
}
}

async function createPullRequest(gitAPI: GitAPI, sessionResource: vscode.Uri | undefined, sessionMetadata: { worktreePath?: string } | undefined): Promise<void> {
if (!sessionResource) {
return;
Expand Down Expand Up @@ -263,9 +241,5 @@ export function registerCommands(gitAPI: GitAPI): vscode.Disposable {
return openPullRequest(gitAPI, sessionResource, sessionMetadata);
}));

disposables.add(vscode.commands.registerCommand('github.checkOpenPullRequest', async (sessionResource: vscode.Uri | undefined, sessionMetadata: { worktreePath?: string } | undefined) => {
return checkOpenPullRequest(gitAPI, sessionResource, sessionMetadata);
}));

return disposables;
}
8 changes: 8 additions & 0 deletions extensions/markdown-language-features/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,14 @@
"group": "1_markdown"
}
],
"modalEditor/editorTitle": [
{
"command": "markdown.showPreviewToSide",
"when": "editorLangId =~ /^(markdown|prompt|instructions|chatagent|skill)$/ && !notebookEditorFocused && !hasCustomMarkdownPreview",
"alt": "markdown.showPreview",
"group": "navigation"
}
],
"explorer/context": [
{
"command": "markdown.showPreview",
Expand Down
2 changes: 1 addition & 1 deletion extensions/terminal-suggest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"version": "1.0.1",
"private": true,
"license": "MIT",
"icon": "./src/media/icon.png",
"icon": "./media/icon.png",
"engines": {
"vscode": "^1.95.0"
},
Expand Down
2 changes: 1 addition & 1 deletion extensions/typescript-language-features/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"format.semicolons.remove": "Remove unnecessary semicolons.",
"format.indentSwitchCase": "Indent case clauses in switch statements. Requires using TypeScript 5.1+ in the workspace.",
"format.enable": "Enable/disable the default JavaScript and TypeScript formatter.",
"configuration.format.enable.unifiedDeprecationMessage": "This setting is deprecated. Use `#js/ts.format.enable#` instead.",
"configuration.format.enable.unifiedDeprecationMessage": "This setting is deprecated. Use `#js/ts.format.enabled#` instead.",
"configuration.format.insertSpaceAfterCommaDelimiter.unifiedDeprecationMessage": "This setting is deprecated. Use `#js/ts.format.insertSpaceAfterCommaDelimiter#` instead.",
"configuration.format.insertSpaceAfterConstructor.unifiedDeprecationMessage": "This setting is deprecated. Use `#js/ts.format.insertSpaceAfterConstructor#` instead.",
"configuration.format.insertSpaceAfterSemicolonInForStatements.unifiedDeprecationMessage": "This setting is deprecated. Use `#js/ts.format.insertSpaceAfterSemicolonInForStatements#` instead.",
Expand Down
4 changes: 2 additions & 2 deletions src/vs/base/common/htmlContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,9 @@ export function createMarkdownLink(text: string, href: string, title?: string, e
return `[${escapeTokens ? escapeMarkdownSyntaxTokens(text) : text}](${href}${title ? ` "${escapeMarkdownSyntaxTokens(title)}"` : ''})`;
}

export function createMarkdownCommandLink(command: { title: string; id: string; arguments?: unknown[]; tooltip?: string }, escapeTokens = true): string {
export function createMarkdownCommandLink(command: { text: string; id: string; arguments?: unknown[]; tooltip: string }, escapeTokens = true): string {
const uri = createCommandUri(command.id, ...(command.arguments || [])).toString();
return createMarkdownLink(command.title, uri, command.tooltip, escapeTokens);
return createMarkdownLink(command.text, uri, command.tooltip, escapeTokens);
}

export function createCommandUri(commandId: string, ...commandArgs: unknown[]): URI {
Expand Down
11 changes: 11 additions & 0 deletions src/vs/editor/common/config/editorOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1744,6 +1744,10 @@ export interface IEditorFindOptions {
* Controls whether the search result and diff result automatically restarts from the beginning (or the end) when no further matches can be found
*/
loop?: boolean;
/**
* Controls whether to close the Find Widget after an explicit find navigation command lands on a match.
*/
closeOnResult?: boolean;
/**
* @internal
* Controls how the find widget search history should be stored
Expand Down Expand Up @@ -1772,6 +1776,7 @@ class EditorFind extends BaseEditorOption<EditorOption.find, IEditorFindOptions,
globalFindClipboard: false,
addExtraSpaceOnTop: true,
loop: true,
closeOnResult: false,
history: 'workspace',
replaceHistory: 'workspace',
};
Expand Down Expand Up @@ -1821,6 +1826,11 @@ class EditorFind extends BaseEditorOption<EditorOption.find, IEditorFindOptions,
default: defaults.loop,
description: nls.localize('find.loop', "Controls whether the search automatically restarts from the beginning (or the end) when no further matches can be found.")
},
'editor.find.closeOnResult': {
type: 'boolean',
default: defaults.closeOnResult,
description: nls.localize('find.closeOnResult', "Controls whether the Find Widget closes after an explicit find navigation command lands on a result.")
},
'editor.find.history': {
type: 'string',
enum: ['never', 'workspace'],
Expand Down Expand Up @@ -1867,6 +1877,7 @@ class EditorFind extends BaseEditorOption<EditorOption.find, IEditorFindOptions,
globalFindClipboard: boolean(input.globalFindClipboard, this.defaultValue.globalFindClipboard),
addExtraSpaceOnTop: boolean(input.addExtraSpaceOnTop, this.defaultValue.addExtraSpaceOnTop),
loop: boolean(input.loop, this.defaultValue.loop),
closeOnResult: boolean(input.closeOnResult, this.defaultValue.closeOnResult),
history: stringSet<'never' | 'workspace'>(input.history, this.defaultValue.history, ['never', 'workspace']),
replaceHistory: stringSet<'never' | 'workspace'>(input.replaceHistory, this.defaultValue.replaceHistory, ['never', 'workspace']),
};
Expand Down
5 changes: 4 additions & 1 deletion src/vs/editor/common/viewModel/minimapTokensColorTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ export class MinimapTokensColorTracker extends Disposable {
private _updateColorMap(): void {
const colorMap = TokenizationRegistry.getColorMap();
if (!colorMap) {
this._colors = [RGBA8.Empty];
this._colors = [];
for (let i = 0; i <= ColorId.DefaultBackground; i++) {
this._colors[i] = RGBA8.Empty;
}
this._backgroundIsLight = true;
return;
}
Expand Down
17 changes: 17 additions & 0 deletions src/vs/editor/contrib/find/browser/findController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -725,11 +725,28 @@ async function matchFindAction(editor: ICodeEditor, next: boolean): Promise<void
if (!controller) {
return;
}
const shouldCloseOnResult = editor.getOption(EditorOption.find).closeOnResult;
const wasFindWidgetVisible = controller.getState().isRevealed;

const runMatch = (): boolean => {
const previousSelection = controller.editor.getSelection();
const result = next ? controller.moveToNextMatch() : controller.moveToPrevMatch();

let landedOnMatch = false;
if (result) {
const currentSelection = controller.editor.getSelection();
if (!previousSelection && currentSelection) {
landedOnMatch = true;
} else if (previousSelection && currentSelection && !previousSelection.equalsSelection(currentSelection)) {
landedOnMatch = true;
}
}

if (landedOnMatch) {
controller.editor.pushUndoStop();
if (shouldCloseOnResult && wasFindWidgetVisible && controller.isFindInputFocused()) {
controller.closeFindWidget();
}
return true;
}
return false;
Expand Down
61 changes: 61 additions & 0 deletions src/vs/editor/contrib/find/test/browser/findController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,67 @@ suite('FindController', () => {
});
});

test('editor.find.closeOnResult: closes find widget when a match is found from explicit navigation', async () => {
await withAsyncTestCodeEditor([
'ABC',
'ABC',
'XYZ',
], { serviceCollection: serviceCollection, find: { closeOnResult: true } }, async (editor, _, instantiationService) => {
const findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
const findState = findController.getState();

await executeAction(instantiationService, editor, StartFindAction);
assert.strictEqual(findState.isRevealed, true);

findState.change({ searchString: 'ABC' }, true);
await editor.runAction(NextMatchFindAction);

assert.strictEqual(findState.isRevealed, false);
findController.dispose();
});
});

test('editor.find.closeOnResult: keeps find widget open when no match is found', async () => {
await withAsyncTestCodeEditor([
'ABC',
'DEF',
'XYZ',
], { serviceCollection: serviceCollection, find: { closeOnResult: true } }, async (editor, _, instantiationService) => {
const findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
const findState = findController.getState();

await executeAction(instantiationService, editor, StartFindAction);
assert.strictEqual(findState.isRevealed, true);

findState.change({ searchString: 'NO_MATCH' }, true);
await editor.runAction(NextMatchFindAction);

assert.strictEqual(findState.matchesCount, 0);
assert.strictEqual(findState.isRevealed, true);
findController.dispose();
});
});

test('editor.find.closeOnResult: disabled keeps find widget open after navigation', async () => {
await withAsyncTestCodeEditor([
'ABC',
'ABC',
'XYZ',
], { serviceCollection: serviceCollection, find: { closeOnResult: false } }, async (editor, _, instantiationService) => {
const findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
const findState = findController.getState();

await executeAction(instantiationService, editor, StartFindAction);
assert.strictEqual(findState.isRevealed, true);

findState.change({ searchString: 'ABC' }, true);
await editor.runAction(NextMatchFindAction);

assert.strictEqual(findState.isRevealed, true);
findController.dispose();
});
});

test('issue #9043: Clear search scope when find widget is hidden', async () => {
await withAsyncTestCodeEditor([
'var x = (3 * 5)',
Expand Down
4 changes: 4 additions & 0 deletions src/vs/monaco.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4255,6 +4255,10 @@ declare namespace monaco.editor {
* Controls whether the search result and diff result automatically restarts from the beginning (or the end) when no further matches can be found
*/
loop?: boolean;
/**
* Controls whether to close the Find Widget after an explicit find navigation command lands on a match.
*/
closeOnResult?: boolean;
}

export type GoToLocationValues = 'peek' | 'gotoAndPeek' | 'goto';
Expand Down
1 change: 1 addition & 0 deletions src/vs/platform/actions/common/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export class MenuId {
static readonly EditorContextShare = new MenuId('EditorContextShare');
static readonly EditorTitle = new MenuId('EditorTitle');
static readonly ModalEditorTitle = new MenuId('ModalEditorTitle');
static readonly ModalEditorEditorTitle = new MenuId('ModalEditorEditorTitle');
static readonly CompactWindowEditorTitle = new MenuId('CompactWindowEditorTitle');
static readonly EditorTitleRun = new MenuId('EditorTitleRun');
static readonly EditorTitleContext = new MenuId('EditorTitleContext');
Expand Down
5 changes: 2 additions & 3 deletions src/vs/platform/update/common/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,13 @@ export const enum DisablementReason {
MissingConfiguration,
InvalidConfiguration,
RunningAsAdmin,
EmbeddedApp,
}

export type Uninitialized = { type: StateType.Uninitialized };
export type Disabled = { type: StateType.Disabled; reason: DisablementReason };
export type Idle = { type: StateType.Idle; updateType: UpdateType; error?: string };
export type CheckingForUpdates = { type: StateType.CheckingForUpdates; explicit: boolean };
export type AvailableForDownload = { type: StateType.AvailableForDownload; update: IUpdate };
export type AvailableForDownload = { type: StateType.AvailableForDownload; update: IUpdate; canInstall?: boolean };
export type Downloading = { type: StateType.Downloading; update?: IUpdate; explicit: boolean; overwrite: boolean; downloadedBytes?: number; totalBytes?: number; startTime?: number };
export type Downloaded = { type: StateType.Downloaded; update: IUpdate; explicit: boolean; overwrite: boolean };
export type Updating = { type: StateType.Updating; update: IUpdate; currentProgress?: number; maxProgress?: number };
Expand All @@ -83,7 +82,7 @@ export const State = {
Disabled: (reason: DisablementReason): Disabled => ({ type: StateType.Disabled, reason }),
Idle: (updateType: UpdateType, error?: string): Idle => ({ type: StateType.Idle, updateType, error }),
CheckingForUpdates: (explicit: boolean): CheckingForUpdates => ({ type: StateType.CheckingForUpdates, explicit }),
AvailableForDownload: (update: IUpdate): AvailableForDownload => ({ type: StateType.AvailableForDownload, update }),
AvailableForDownload: (update: IUpdate, canInstall?: boolean): AvailableForDownload => ({ type: StateType.AvailableForDownload, update, canInstall }),
Downloading: (update: IUpdate | undefined, explicit: boolean, overwrite: boolean, downloadedBytes?: number, totalBytes?: number, startTime?: number): Downloading => ({ type: StateType.Downloading, update, explicit, overwrite, downloadedBytes, totalBytes, startTime }),
Downloaded: (update: IUpdate, explicit: boolean, overwrite: boolean): Downloaded => ({ type: StateType.Downloaded, update, explicit, overwrite }),
Updating: (update: IUpdate, currentProgress?: number, maxProgress?: number): Updating => ({ type: StateType.Updating, update, currentProgress, maxProgress }),
Expand Down
24 changes: 17 additions & 7 deletions src/vs/platform/update/electron-main/updateService.darwin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { ILogService } from '../../log/common/log.js';
import { IProductService } from '../../product/common/productService.js';
import { asJson, IRequestService } from '../../request/common/request.js';
import { ITelemetryService } from '../../telemetry/common/telemetry.js';
import { AvailableForDownload, DisablementReason, IUpdate, State, StateType, UpdateType } from '../common/update.js';
import { AvailableForDownload, IUpdate, State, StateType, UpdateType } from '../common/update.js';
import { IMeteredConnectionService } from '../../meteredConnection/common/meteredConnection.js';
import { AbstractUpdateService, createUpdateURL, getUpdateRequestHeaders, IUpdateURLOptions, UpdateErrorClassification } from './abstractUpdateService.js';
import { INodeProcess } from '../../../base/common/platform.js';
Expand Down Expand Up @@ -68,13 +68,15 @@ export class DarwinUpdateService extends AbstractUpdateService implements IRelau
}

protected override async initialize(): Promise<void> {
await super.initialize();

// In the embedded app we still want to detect available updates via HTTP,
// but we must not wire up Electron's autoUpdater (which auto-downloads).
if ((process as INodeProcess).isEmbeddedApp) {
this.setState(State.Disabled(DisablementReason.EmbeddedApp));
this.logService.info('update#ctor - updates are disabled from embedded app');
this.logService.info('update#ctor - embedded app: checking for updates without auto-download');
return;
}

await super.initialize();
this.onRawError(this.onError, this, this.disposables);
this.onRawCheckingForUpdate(this.onCheckingForUpdate, this, this.disposables);
this.onRawUpdateAvailable(this.onUpdateAvailable, this, this.disposables);
Expand Down Expand Up @@ -135,6 +137,13 @@ export class DarwinUpdateService extends AbstractUpdateService implements IRelau
return;
}

// In the embedded app, always check without triggering Electron's auto-download.
if ((process as INodeProcess).isEmbeddedApp) {
this.logService.info('update#doCheckForUpdates - embedded app: checking for update without auto-download');
this.checkForUpdateNoDownload(url, /* canInstall */ false);
return;
}

// When connection is metered and this is not an explicit check, avoid electron call as to not to trigger auto-download.
if (!explicit && this.meteredConnectionService.isConnectionMetered) {
this.logService.info('update#doCheckForUpdates - checking for update without auto-download because connection is metered');
Expand All @@ -148,9 +157,10 @@ export class DarwinUpdateService extends AbstractUpdateService implements IRelau

/**
* Manually check the update feed URL without triggering Electron's auto-download.
* Used when connection is metered to show update availability without downloading.
* Used when connection is metered or in the embedded app.
* @param canInstall When false, signals that the update cannot be installed from this app.
*/
private async checkForUpdateNoDownload(url: string): Promise<void> {
private async checkForUpdateNoDownload(url: string, canInstall?: boolean): Promise<void> {
const headers = getUpdateRequestHeaders(this.productService.version);
this.logService.trace('update#checkForUpdateNoDownload - checking update server', { url, headers });

Expand All @@ -165,7 +175,7 @@ export class DarwinUpdateService extends AbstractUpdateService implements IRelau
this.setState(State.Idle(UpdateType.Archive));
} else {
this.logService.trace('update#checkForUpdateNoDownload - update available', { version: update.version, productVersion: update.productVersion });
this.setState(State.AvailableForDownload(update));
this.setState(State.AvailableForDownload(update, canInstall));
}
} catch (err) {
this.logService.error('update#checkForUpdateNoDownload - failed to check for update', err);
Expand Down
Loading
Loading