diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 52beb803984a0..7352ce957ddc6 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -55,7 +55,7 @@ jobs: - name: Restore node_modules cache id: cache-node-modules - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: .build/node_modules_cache key: "node_modules-linux-${{ hashFiles('.build/packagelockhash') }}" @@ -119,7 +119,7 @@ jobs: - name: Restore built-in extensions cache id: cache-builtin-extensions - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: enableCrossOsArchive: true path: .build/builtInExtensions diff --git a/.github/workflows/monaco-editor.yml b/.github/workflows/monaco-editor.yml index 99aea9933faad..822210da8d0f7 100644 --- a/.github/workflows/monaco-editor.yml +++ b/.github/workflows/monaco-editor.yml @@ -32,7 +32,7 @@ jobs: run: echo "value=$(node build/azure-pipelines/common/computeNodeModulesCacheKey.ts)" >> $GITHUB_OUTPUT - name: Cache node modules id: cacheNodeModules - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: "**/node_modules" key: ${{ runner.os }}-cacheNodeModules20-${{ steps.nodeModulesCacheKey.outputs.value }} @@ -43,7 +43,7 @@ jobs: run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT - name: Cache npm directory if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ steps.npmCacheDirPath.outputs.dir }} key: ${{ runner.os }}-npmCacheDir-${{ steps.nodeModulesCacheKey.outputs.value }} diff --git a/.github/workflows/pr-darwin-test.yml b/.github/workflows/pr-darwin-test.yml index 01c3eb070d7ec..c946793851b84 100644 --- a/.github/workflows/pr-darwin-test.yml +++ b/.github/workflows/pr-darwin-test.yml @@ -36,7 +36,7 @@ jobs: - name: Restore node_modules cache id: cache-node-modules - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: .build/node_modules_cache key: "node_modules-macos-${{ hashFiles('.build/packagelockhash') }}" @@ -89,7 +89,7 @@ jobs: - name: Restore built-in extensions cache id: cache-builtin-extensions - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: enableCrossOsArchive: true path: .build/builtInExtensions @@ -212,7 +212,7 @@ jobs: if: always() - name: Publish Crash Reports - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: failure() continue-on-error: true with: @@ -223,7 +223,7 @@ jobs: # In order to properly symbolify above crash reports # (if any), we need the compiled native modules too - name: Publish Node Modules - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: failure() continue-on-error: true with: @@ -232,7 +232,7 @@ jobs: if-no-files-found: ignore - name: Publish Log Files - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: always() continue-on-error: true with: diff --git a/.github/workflows/pr-linux-test.yml b/.github/workflows/pr-linux-test.yml index 7e69b3d2481df..787fd4082cd93 100644 --- a/.github/workflows/pr-linux-test.yml +++ b/.github/workflows/pr-linux-test.yml @@ -53,7 +53,7 @@ jobs: - name: Restore node_modules cache id: cache-node-modules - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: .build/node_modules_cache key: "node_modules-linux-${{ hashFiles('.build/packagelockhash') }}" @@ -117,7 +117,7 @@ jobs: - name: Restore built-in extensions cache id: cache-builtin-extensions - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: enableCrossOsArchive: true path: .build/builtInExtensions @@ -258,7 +258,7 @@ jobs: if: always() - name: Publish Crash Reports - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: failure() continue-on-error: true with: @@ -269,7 +269,7 @@ jobs: # In order to properly symbolify above crash reports # (if any), we need the compiled native modules too - name: Publish Node Modules - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: failure() continue-on-error: true with: @@ -278,7 +278,7 @@ jobs: if-no-files-found: ignore - name: Publish Log Files - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: always() continue-on-error: true with: diff --git a/.github/workflows/pr-node-modules.yml b/.github/workflows/pr-node-modules.yml index cae9abdb7f879..68e65fd129815 100644 --- a/.github/workflows/pr-node-modules.yml +++ b/.github/workflows/pr-node-modules.yml @@ -25,7 +25,7 @@ jobs: - name: Restore node_modules cache id: cache-node-modules - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .build/node_modules_cache key: "node_modules-compile-${{ hashFiles('.build/packagelockhash') }}" @@ -72,7 +72,7 @@ jobs: - name: Restore built-in extensions cache id: cache-builtin-extensions - uses: actions/cache@v4 + uses: actions/cache@v5 with: enableCrossOsArchive: true path: .build/builtInExtensions @@ -104,7 +104,7 @@ jobs: - name: Restore node_modules cache id: cache-node-modules - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .build/node_modules_cache key: "node_modules-linux-${{ hashFiles('.build/packagelockhash') }}" @@ -176,7 +176,7 @@ jobs: - name: Restore node_modules cache id: cache-node-modules - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .build/node_modules_cache key: "node_modules-macos-${{ hashFiles('.build/packagelockhash') }}" @@ -239,7 +239,7 @@ jobs: node build/azure-pipelines/common/computeNodeModulesCacheKey.ts win32 ${{ env.VSCODE_ARCH }} $(node -p process.arch) > .build/packagelockhash - name: Restore node_modules cache - uses: actions/cache@v4 + uses: actions/cache@v5 id: node-modules-cache with: path: .build/node_modules_cache diff --git a/.github/workflows/pr-win32-test.yml b/.github/workflows/pr-win32-test.yml index 7314a74519c37..8b79e1695ebeb 100644 --- a/.github/workflows/pr-win32-test.yml +++ b/.github/workflows/pr-win32-test.yml @@ -38,7 +38,7 @@ jobs: node build/azure-pipelines/common/computeNodeModulesCacheKey.ts win32 ${{ env.VSCODE_ARCH }} $(node -p process.arch) > .build/packagelockhash - name: Restore node_modules cache - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 id: node-modules-cache with: path: .build/node_modules_cache @@ -98,7 +98,7 @@ jobs: - name: Restore built-in extensions cache id: cache-builtin-extensions - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: enableCrossOsArchive: true path: .build/builtInExtensions @@ -249,7 +249,7 @@ jobs: if: always() - name: Publish Crash Reports - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: failure() continue-on-error: true with: @@ -260,7 +260,7 @@ jobs: # In order to properly symbolify above crash reports # (if any), we need the compiled native modules too - name: Publish Node Modules - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: failure() continue-on-error: true with: @@ -269,7 +269,7 @@ jobs: if-no-files-found: ignore - name: Publish Log Files - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: always() continue-on-error: true with: diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 179b3e04d719b..59f9c1f427f44 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -33,7 +33,7 @@ jobs: - name: Restore node_modules cache id: cache-node-modules - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: .build/node_modules_cache key: "node_modules-compile-${{ hashFiles('.build/packagelockhash') }}" diff --git a/.vscode/settings.json b/.vscode/settings.json index 514edcd10693a..8761267a629c7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -131,6 +131,7 @@ "git.ignoreLimitWarning": true, "git.branchProtection": [ "main", + "main-*", "distro", "release/*" ], diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index b1e5a2f4ea881..eeb83a4c376a6 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -1128,20 +1128,6 @@ export class Repository implements Disposable { return undefined; } - const activeTabInput = window.tabGroups.activeTabGroup.activeTab?.input; - - // Ignore file that is on the right-hand side of a diff editor - if (activeTabInput instanceof TabInputTextDiff && pathEquals(activeTabInput.modified.fsPath, uri.fsPath)) { - this.logger.trace(`[Repository][provideOriginalResource] Resource is on the right-hand side of a diff editor: ${uri.toString()}`); - return undefined; - } - - // Ignore file that is on the right -hand side of a multi-file diff editor - if (activeTabInput instanceof TabInputTextMultiDiff && activeTabInput.textDiffs.some(diff => pathEquals(diff.modified.fsPath, uri.fsPath))) { - this.logger.trace(`[Repository][provideOriginalResource] Resource is on the right-hand side of a multi-file diff editor: ${uri.toString()}`); - return undefined; - } - const originalResource = toGitUri(uri, '', { replaceFileExtension: true }); this.logger.trace(`[Repository][provideOriginalResource] Original resource: ${originalResource.toString()}`); diff --git a/package-lock.json b/package-lock.json index 1f484e416cbf5..b1ae7c40d8015 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ "native-is-elevated": "0.8.0", "native-keymap": "^3.3.5", "native-watchdog": "^1.4.1", - "node-pty": "1.1.0-beta40", + "node-pty": "^1.1.0-beta42", "open": "^10.1.2", "tas-client": "0.3.1", "undici": "^7.9.0", @@ -12809,9 +12809,9 @@ } }, "node_modules/node-pty": { - "version": "1.1.0-beta40", - "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0-beta40.tgz", - "integrity": "sha512-ACjAwX4Fb6jApK082jXKJqpeguZq5uTgcM4bRurJ7uxaPX9mE4F4yTHm8gEbn6nLSvEmF4EiBCxr6t/HHH+Dgg==", + "version": "1.1.0-beta42", + "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0-beta42.tgz", + "integrity": "sha512-59KoV6xxhJciRVpo4lQ9wnP38SPaBlXgwszYS8nlHAHrt02d14peg+kHtJ4AOtyLWiCf8WPCeJNbxBkiA7Oy7Q==", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index b0fdae1627bd1..9aa3be3e55b66 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "native-is-elevated": "0.8.0", "native-keymap": "^3.3.5", "native-watchdog": "^1.4.1", - "node-pty": "1.1.0-beta40", + "node-pty": "^1.1.0-beta42", "open": "^10.1.2", "tas-client": "0.3.1", "undici": "^7.9.0", diff --git a/remote/package-lock.json b/remote/package-lock.json index 55d0715a4e24b..95ef4ffb52625 100644 --- a/remote/package-lock.json +++ b/remote/package-lock.json @@ -38,7 +38,7 @@ "kerberos": "2.1.1", "minimist": "^1.2.8", "native-watchdog": "^1.4.1", - "node-pty": "1.1.0-beta40", + "node-pty": "^1.1.0-beta42", "tas-client": "0.3.1", "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", @@ -848,9 +848,9 @@ } }, "node_modules/node-pty": { - "version": "1.1.0-beta40", - "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0-beta40.tgz", - "integrity": "sha512-ACjAwX4Fb6jApK082jXKJqpeguZq5uTgcM4bRurJ7uxaPX9mE4F4yTHm8gEbn6nLSvEmF4EiBCxr6t/HHH+Dgg==", + "version": "1.1.0-beta42", + "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0-beta42.tgz", + "integrity": "sha512-59KoV6xxhJciRVpo4lQ9wnP38SPaBlXgwszYS8nlHAHrt02d14peg+kHtJ4AOtyLWiCf8WPCeJNbxBkiA7Oy7Q==", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/remote/package.json b/remote/package.json index e4754d9ed54d9..1ef9407ef290e 100644 --- a/remote/package.json +++ b/remote/package.json @@ -33,7 +33,7 @@ "kerberos": "2.1.1", "minimist": "^1.2.8", "native-watchdog": "^1.4.1", - "node-pty": "1.1.0-beta40", + "node-pty": "^1.1.0-beta42", "tas-client": "0.3.1", "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", diff --git a/src/vs/base/browser/ui/toggle/toggle.ts b/src/vs/base/browser/ui/toggle/toggle.ts index e490c9820d68c..2358bc3f5922c 100644 --- a/src/vs/base/browser/ui/toggle/toggle.ts +++ b/src/vs/base/browser/ui/toggle/toggle.ts @@ -229,7 +229,6 @@ export class Toggle extends Widget { protected applyStyles(): void { if (this.domNode) { - this.domNode.style.borderColor = (this._checked && this._opts.inputActiveOptionBorder) || ''; this.domNode.style.color = (this._checked && this._opts.inputActiveOptionForeground) || 'inherit'; this.domNode.style.backgroundColor = (this._checked && this._opts.inputActiveOptionBackground) || ''; } diff --git a/src/vs/editor/contrib/clipboard/browser/clipboard.ts b/src/vs/editor/contrib/clipboard/browser/clipboard.ts index 2157be89da4bf..59079079e51c6 100644 --- a/src/vs/editor/contrib/clipboard/browser/clipboard.ts +++ b/src/vs/editor/contrib/clipboard/browser/clipboard.ts @@ -7,7 +7,6 @@ import * as browser from '../../../../base/browser/browser.js'; import { getActiveDocument, getActiveWindow } from '../../../../base/browser/dom.js'; import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js'; import * as platform from '../../../../base/common/platform.js'; -import { StopWatch } from '../../../../base/common/stopwatch.js'; import * as nls from '../../../../nls.js'; import { MenuId, MenuRegistry } from '../../../../platform/actions/common/actions.js'; import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js'; @@ -15,8 +14,6 @@ import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextke import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js'; import { ILogService } from '../../../../platform/log/common/log.js'; -import { IProductService } from '../../../../platform/product/common/productService.js'; -import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { CopyOptions, generateDataToCopyAndStoreInMemory, InMemoryClipboardMetadataManager } from '../../../browser/controller/editContext/clipboardUtils.js'; import { NativeEditContextRegistry } from '../../../browser/controller/editContext/native/nativeEditContextRegistry.js'; import { IActiveCodeEditor, ICodeEditor } from '../../../browser/editorBrowser.js'; @@ -284,8 +281,6 @@ if (PasteAction) { logService.trace('registerExecCommandImpl (addImplementation code-editor for : paste)'); const codeEditorService = accessor.get(ICodeEditorService); const clipboardService = accessor.get(IClipboardService); - const telemetryService = accessor.get(ITelemetryService); - const productService = accessor.get(IProductService); // Only if editor text focus (i.e. not if editor has widget focus). const focusedEditor = codeEditorService.getFocusedCodeEditor(); @@ -299,29 +294,12 @@ if (PasteAction) { } } - const sw = StopWatch.create(true); logService.trace('registerExecCommandImpl (before triggerPaste)'); const triggerPaste = clipboardService.triggerPaste(getActiveWindow().vscodeWindowId); if (triggerPaste) { logService.trace('registerExecCommandImpl (triggerPaste defined)'); return triggerPaste.then(async () => { logService.trace('registerExecCommandImpl (after triggerPaste)'); - if (productService.quality !== 'stable') { - const duration = sw.elapsed(); - type EditorAsyncPasteClassification = { - duration: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The duration of the paste operation.' }; - owner: 'aiday-mar'; - comment: 'Provides insight into the delay introduced by pasting async via keybindings.'; - }; - type EditorAsyncPasteEvent = { - duration: number; - }; - telemetryService.publicLog2( - 'editorAsyncPaste', - { duration } - ); - } - return CopyPasteController.get(focusedEditor)?.finishedPaste() ?? Promise.resolve(); }); } else { diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsView.ts index f3b07fa238c42..102f7e0746489 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsView.ts @@ -348,15 +348,11 @@ export class InlineEditsView extends Disposable { diff = lineRangeMappingFromRangeMappings(mappings, inlineEdit.originalText, newText); } - const tm = this._editorObs.model.read(reader); - if (!tm) { - return undefined; - } - this._previewTextModel.setLanguage(tm.getLanguageId()); + this._previewTextModel.setLanguage(textModel.getLanguageId()); const previousNewText = this._previewTextModel.getValue(); if (previousNewText !== newText.getValue()) { - this._previewTextModel.setEOL(tm.getEndOfLineSequence()); + this._previewTextModel.setEOL(textModel.getEndOfLineSequence()); const updateOldValueEdit = StringEdit.replace(new OffsetRange(0, previousNewText.length), newText.getValue()); const updateOldValueEditSmall = updateOldValueEdit.removeCommonSuffixPrefix(previousNewText); diff --git a/src/vs/platform/terminal/common/terminalProcess.ts b/src/vs/platform/terminal/common/terminalProcess.ts index 917db9710d872..28408eef7103b 100644 --- a/src/vs/platform/terminal/common/terminalProcess.ts +++ b/src/vs/platform/terminal/common/terminalProcess.ts @@ -69,41 +69,3 @@ export interface ReplayEntry { rows: number; data: string; } - -const enum Constants { - /** - * Writing large amounts of data can be corrupted for some reason, after looking into this is - * appears to be a race condition around writing to the FD which may be based on how powerful - * the hardware is. The workaround for this is to space out when large amounts of data is being - * written to the terminal. See https://github.com/microsoft/vscode/issues/38137 - */ - WriteMaxChunkSize = 50, -} - -/** - * Splits incoming pty data into chunks to try prevent data corruption that could occur when pasting - * large amounts of data. - */ -export function chunkInput(data: string): string[] { - const chunks: string[] = []; - let nextChunkStartIndex = 0; - for (let i = 0; i < data.length - 1; i++) { - if ( - // If the max chunk size is reached - i - nextChunkStartIndex + 1 >= Constants.WriteMaxChunkSize || - // If the next character is ESC, send the pending data to avoid splitting the escape - // sequence. - data[i + 1] === '\x1b' - ) { - chunks.push(data.substring(nextChunkStartIndex, i + 1)); - nextChunkStartIndex = i + 1; - // Skip the next character as the chunk would be a single character - i++; - } - } - // Push final chunk - if (nextChunkStartIndex !== data.length) { - chunks.push(data.substring(nextChunkStartIndex)); - } - return chunks; -} diff --git a/src/vs/platform/terminal/node/terminalProcess.ts b/src/vs/platform/terminal/node/terminalProcess.ts index e6deacd6b4dd6..03a6f35b42824 100644 --- a/src/vs/platform/terminal/node/terminalProcess.ts +++ b/src/vs/platform/terminal/node/terminalProcess.ts @@ -20,7 +20,6 @@ import { ChildProcessMonitor } from './childProcessMonitor.js'; import { getShellIntegrationInjection, getWindowsBuildNumber, IShellIntegrationConfigInjection } from './terminalEnvironment.js'; import { WindowsShellHelper } from './windowsShellHelper.js'; import { IPty, IPtyForkOptions, IWindowsPtyForkOptions, spawn } from 'node-pty'; -import { chunkInput } from '../common/terminalProcess.js'; import { isNumber } from '../../../base/common/types.js'; const enum ShutdownConstants { @@ -57,15 +56,6 @@ const enum Constants { * interval. */ KillSpawnSpacingDuration = 50, - /** - * How long to wait between chunk writes. - */ - WriteInterval = 5, -} - -interface IWriteObject { - data: string; - isBinary: boolean; } const posixShellTypeMap = new Map([ @@ -113,8 +103,6 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess private _windowsShellHelper: WindowsShellHelper | undefined; private _childProcessMonitor: ChildProcessMonitor | undefined; private _titleInterval: Timeout | undefined; - private _writeQueue: IWriteObject[] = []; - private _writeTimeout: Timeout | undefined; private _delayedResizer: DelayedResizer | undefined; private readonly _initialCwd: string; private readonly _ptyOptions: IPtyForkOptions | IWindowsPtyForkOptions; @@ -471,13 +459,13 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess } input(data: string, isBinary: boolean = false): void { - if (this._store.isDisposed || !this._ptyProcess) { - return; + this._logService.trace('node-pty.IPty#write', data, isBinary); + if (isBinary) { + this._ptyProcess!.write(Buffer.from(data, 'binary')); + } else { + this._ptyProcess!.write(data); } - this._writeQueue.push(...chunkInput(data).map(e => { - return { isBinary, data: e }; - })); - this._startWrite(); + this._childProcessMonitor?.handleInput(); } sendSignal(signal: string): void { @@ -522,40 +510,6 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess } } - private _startWrite(): void { - // Don't write if it's already queued of is there is nothing to write - if (this._writeTimeout !== undefined || this._writeQueue.length === 0) { - return; - } - - this._doWrite(); - - // Don't queue more writes if the queue is empty - if (this._writeQueue.length === 0) { - this._writeTimeout = undefined; - return; - } - - // Queue the next write - this._writeTimeout = setTimeout(() => { - this._writeTimeout = undefined; - this._startWrite(); - }, Constants.WriteInterval); - } - - private _doWrite(): void { - const object = this._writeQueue.shift()!; - this._logService.trace('node-pty.IPty#write', object.data); - if (object.isBinary) { - // TODO: node-pty's write should accept a Buffer, needs https://github.com/microsoft/node-pty/pull/812 - // eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any - this._ptyProcess!.write(Buffer.from(object.data, 'binary') as any); - } else { - this._ptyProcess!.write(object.data); - } - this._childProcessMonitor?.handleInput(); - } - resize(cols: number, rows: number): void { if (this._store.isDisposed) { return; diff --git a/src/vs/platform/terminal/test/common/terminalProcess.test.ts b/src/vs/platform/terminal/test/common/terminalProcess.test.ts deleted file mode 100644 index 4d4ef97709c9f..0000000000000 --- a/src/vs/platform/terminal/test/common/terminalProcess.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { deepStrictEqual } from 'assert'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js'; -import { chunkInput } from '../../common/terminalProcess.js'; - -suite('platform - terminalProcess', () => { - ensureNoDisposablesAreLeakedInTestSuite(); - suite('chunkInput', () => { - test('single chunk', () => { - deepStrictEqual(chunkInput('foo bar'), ['foo bar']); - }); - test('multi chunk', () => { - deepStrictEqual(chunkInput('foo'.repeat(50)), [ - 'foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofo', - 'ofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoof', - 'oofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo' - ]); - }); - test('small data with escapes', () => { - deepStrictEqual(chunkInput('foo \x1b[30mbar'), [ - 'foo ', - '\x1b[30mbar' - ]); - }); - test('large data with escapes', () => { - deepStrictEqual(chunkInput('foofoofoofoo\x1b[30mbarbarbarbarbar\x1b[0m'.repeat(3)), [ - 'foofoofoofoo', - '\x1B[30mbarbarbarbarbar', - '\x1B[0mfoofoofoofoo', - '\x1B[30mbarbarbarbarbar', - '\x1B[0mfoofoofoofoo', - '\x1B[30mbarbarbarbarbar', - '\x1B[0m' - ]); - }); - }); -}); diff --git a/src/vs/workbench/api/browser/mainThreadEditors.ts b/src/vs/workbench/api/browser/mainThreadEditors.ts index 5bf9b35867354..5af157c2ac0db 100644 --- a/src/vs/workbench/api/browser/mainThreadEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadEditors.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { illegalArgument } from '../../../base/common/errors.js'; -import { IDisposable, dispose, DisposableStore } from '../../../base/common/lifecycle.js'; +import { IDisposable, dispose, DisposableStore, IReference } from '../../../base/common/lifecycle.js'; import { equals as objectEquals } from '../../../base/common/objects.js'; import { URI, UriComponents } from '../../../base/common/uri.js'; import { ICodeEditorService } from '../../../editor/browser/services/codeEditorService.js'; @@ -28,13 +28,12 @@ import { IExtHostContext } from '../../services/extensions/common/extHostCustome import { IEditorControl } from '../../common/editor.js'; import { getCodeEditor, ICodeEditor } from '../../../editor/browser/editorBrowser.js'; import { IConfigurationService } from '../../../platform/configuration/common/configuration.js'; -import { IQuickDiffModelService } from '../../contrib/scm/browser/quickDiffModel.js'; +import { IQuickDiffModelService, QuickDiffModel } from '../../contrib/scm/browser/quickDiffModel.js'; import { autorun, constObservable, derived, derivedOpts, IObservable, observableFromEvent } from '../../../base/common/observable.js'; import { IUriIdentityService } from '../../../platform/uriIdentity/common/uriIdentity.js'; import { isITextModel } from '../../../editor/common/model.js'; import { LineRangeMapping } from '../../../editor/common/diff/rangeMapping.js'; import { equals } from '../../../base/common/arrays.js'; -import { Event } from '../../../base/common/event.js'; import { DiffAlgorithmName } from '../../../editor/common/services/editorWorker.js'; export interface IMainThreadEditorLocator { @@ -149,58 +148,36 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { const editorChangesObs = derived>(reader => { const editorModel = editorModelObs.read(reader); - if (!editorModel) { + const editorModelUri = codeEditor.getModel()?.uri; + + if (!editorModel || !editorModelUri) { return constObservable(undefined); } - const editorModelUri = isITextModel(editorModel) - ? editorModel.uri - : editorModel.modified.uri; - - // TextEditor + let quickDiffModelRef: IReference | undefined; if (isITextModel(editorModel)) { - const quickDiffModelRef = this._quickDiffModelService.createQuickDiffModelReference(editorModelUri); - if (!quickDiffModelRef) { - return constObservable(undefined); - } - - toDispose.push(quickDiffModelRef); - return observableFromEvent(this, quickDiffModelRef.object.onDidChange, () => { - return quickDiffModelRef.object.getQuickDiffResults() - .map(result => ({ - original: result.original, - modified: result.modified, - changes: result.changes2 - })); - }); + // TextEditor + quickDiffModelRef = this._quickDiffModelService.createQuickDiffModelReference(editorModelUri); + } else { + // DiffEditor - we create a quick diff model (using the diff algorithm used by the diff editor) + // even for diff editor so that we can provide multiple "original resources" to diff with the original + // and modified resources. + const diffAlgorithm = this._configurationService.getValue('diffEditor.diffAlgorithm'); + quickDiffModelRef = this._quickDiffModelService.createQuickDiffModelReference(editorModelUri, { algorithm: diffAlgorithm }); } - // DirtyDiffModel - we create a dirty diff model for diff editor so that - // we can provide multiple "original resources" to diff with the modified - // resource. - const diffAlgorithm = this._configurationService.getValue('diffEditor.diffAlgorithm'); - const quickDiffModelRef = this._quickDiffModelService.createQuickDiffModelReference(editorModelUri, { algorithm: diffAlgorithm }); if (!quickDiffModelRef) { return constObservable(undefined); } toDispose.push(quickDiffModelRef); - return observableFromEvent(Event.any(quickDiffModelRef.object.onDidChange, diffEditor.onDidUpdateDiff), () => { - const quickDiffInformation = quickDiffModelRef.object.getQuickDiffResults() + return observableFromEvent(this, quickDiffModelRef.object.onDidChange, () => { + return quickDiffModelRef.object.getQuickDiffResults() .map(result => ({ original: result.original, modified: result.modified, changes: result.changes2 })); - - const diffChanges = diffEditor.getDiffComputationResult()?.changes2 ?? []; - const diffInformation = [{ - original: editorModel.original.uri, - modified: editorModel.modified.uri, - changes: diffChanges.map(change => change as LineRangeMapping) - }]; - - return [...quickDiffInformation, ...diffInformation]; }); }); diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsModel.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsModel.ts index d2352c6ffe556..f138af068692f 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsModel.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsModel.ts @@ -146,7 +146,7 @@ interface IAgentSessionState { } export const enum AgentSessionSection { - Active = 'active', + InProgress = 'inProgress', Today = 'today', Yesterday = 'yesterday', Week = 'week', @@ -465,14 +465,15 @@ interface ISerializedAgentSession { readonly resource: UriComponents; - readonly icon: string; + readonly status: ChatSessionStatus; - readonly label: string; + readonly tooltip?: string | IMarkdownString; + readonly label: string; readonly description?: string | IMarkdownString; - readonly tooltip?: string | IMarkdownString; + readonly badge?: string | IMarkdownString; + readonly icon: string; - readonly status: ChatSessionStatus; readonly archived: boolean | undefined; readonly timing: { @@ -512,6 +513,7 @@ class AgentSessionsCache { icon: session.icon.id, label: session.label, description: session.description, + badge: session.badge, tooltip: session.tooltip, status: session.status, @@ -523,7 +525,7 @@ class AgentSessionsCache { }, changes: session.changes, - })); + } satisfies ISerializedAgentSession)); this.storageService.store(AgentSessionsCache.SESSIONS_STORAGE_KEY, JSON.stringify(serialized), StorageScope.WORKSPACE, StorageTarget.MACHINE); } @@ -545,6 +547,7 @@ class AgentSessionsCache { icon: ThemeIcon.fromId(session.icon), label: session.label, description: session.description, + badge: session.badge, tooltip: session.tooltip, status: session.status, diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer.ts index f4a39543de0f4..9a5ffa0e9eaa5 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer.ts @@ -252,7 +252,7 @@ export class AgentSessionRenderer implements ICompressibleTreeRenderer number | undefined; /** - * Whether to show section headers (Active, Older, Archived). + * Whether to show section headers to group sessions. * When false, sessions are shown as a flat list. */ readonly groupResults?: () => boolean | undefined; @@ -624,10 +624,10 @@ const DAY_THRESHOLD = 24 * 60 * 60 * 1000; const WEEK_THRESHOLD = 7 * DAY_THRESHOLD; export const AgentSessionSectionLabels = { - [AgentSessionSection.Active]: localize('agentSessions.activeSection', "Active"), + [AgentSessionSection.InProgress]: localize('agentSessions.inProgressSection', "In Progress"), [AgentSessionSection.Today]: localize('agentSessions.todaySection', "Today"), [AgentSessionSection.Yesterday]: localize('agentSessions.yesterdaySection', "Yesterday"), - [AgentSessionSection.Week]: localize('agentSessions.weekSection', "Week"), + [AgentSessionSection.Week]: localize('agentSessions.weekSection', "Last Week"), [AgentSessionSection.Older]: localize('agentSessions.olderSection', "Older"), [AgentSessionSection.Archived]: localize('agentSessions.archivedSection', "Archived"), }; @@ -638,7 +638,7 @@ export function groupAgentSessions(sessions: IAgentSession[]): Map([ - [AgentSessionSection.Active, { section: AgentSessionSection.Active, label: AgentSessionSectionLabels[AgentSessionSection.Active], sessions: activeSessions }], + [AgentSessionSection.InProgress, { section: AgentSessionSection.InProgress, label: AgentSessionSectionLabels[AgentSessionSection.InProgress], sessions: inProgressSessions }], [AgentSessionSection.Today, { section: AgentSessionSection.Today, label: AgentSessionSectionLabels[AgentSessionSection.Today], sessions: todaySessions }], [AgentSessionSection.Yesterday, { section: AgentSessionSection.Yesterday, label: AgentSessionSectionLabels[AgentSessionSection.Yesterday], sessions: yesterdaySessions }], [AgentSessionSection.Week, { section: AgentSessionSection.Week, label: AgentSessionSectionLabels[AgentSessionSection.Week], sessions: weekSessions }], diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/media/agentsessionsviewer.css b/src/vs/workbench/contrib/chat/browser/agentSessions/media/agentsessionsviewer.css index 92d534dfa2cf7..9c03e601cca18 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/media/agentsessionsviewer.css +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/media/agentsessionsviewer.css @@ -96,7 +96,7 @@ color: var(--vscode-errorForeground); } - &.codicon.codicon-info { + &.codicon.codicon-report { color: var(--vscode-textLink-foreground); } @@ -184,7 +184,7 @@ } .codicon { - font-size: 14px; + font-size: 12px; } } } diff --git a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts index 8a25c0deccbb5..84e7d66456e9d 100644 --- a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts +++ b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts @@ -47,7 +47,7 @@ import { AgentSessionsControl } from './agentSessions/agentSessionsControl.js'; import { AgentSessionsListDelegate } from './agentSessions/agentSessionsViewer.js'; import { ChatWidget } from './chatWidget.js'; import { ChatViewWelcomeController, IViewWelcomeDelegate } from './viewsWelcome/chatViewWelcomeController.js'; -import { IWorkbenchLayoutService, Position } from '../../../services/layout/browser/layoutService.js'; +import { IWorkbenchLayoutService, LayoutSettings, Position } from '../../../services/layout/browser/layoutService.js'; import { AgentSessionsViewerOrientation, AgentSessionsViewerPosition } from './agentSessions/agentSessions.js'; import { Link } from '../../../../platform/opener/browser/link.js'; import { IProgressService } from '../../../../platform/progress/common/progress.js'; @@ -164,6 +164,9 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate { const welcomeEnabled = this.configurationService.getValue(ChatConfiguration.ChatViewWelcomeEnabled) !== false; this.viewPaneContainer?.classList.toggle('chat-view-welcome-enabled', welcomeEnabled); + const activityBarLocationDefault = this.configurationService.getValue(LayoutSettings.ACTIVITY_BAR_LOCATION) === 'default'; + this.viewPaneContainer?.classList.toggle('activity-bar-location-default', activityBarLocationDefault); + if (fromEvent && this.lastDimensions) { this.layoutBody(this.lastDimensions.height, this.lastDimensions.width); } @@ -180,7 +183,9 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate { this._register(Event.filter(this.viewDescriptorService.onDidChangeContainerLocation, e => e.viewContainer === this.viewDescriptorService.getViewContainerByViewId(this.id))(() => this.updateContextKeys(true))); // Settings changes - this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(ChatConfiguration.ChatViewWelcomeEnabled))(() => this.updateViewPaneClasses(true))); + this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => { + return e.affectsConfiguration(ChatConfiguration.ChatViewWelcomeEnabled) || e.affectsConfiguration(LayoutSettings.ACTIVITY_BAR_LOCATION); + })(() => this.updateViewPaneClasses(true))); } private onDidChangeAgents(): void { @@ -249,7 +254,7 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate { // Sessions Control const sessionsControl = this.createSessionsControl(parent); - // Welcome Control + // Welcome Control (used to show chat specific extension provided welcome views via `chatViewsWelcome` contribution point) const welcomeController = this.welcomeController = this._register(this.instantiationService.createInstance(ChatViewWelcomeController, parent, this, ChatAgentLocation.Chat)); // Chat Control @@ -572,7 +577,6 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate { this.titleControl = this._register(this.instantiationService.createInstance(ChatViewTitleControl, parent, { - updateTitle: title => this.updateTitle(title), focusChat: () => this._widget.focusInput() } )); @@ -934,15 +938,4 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate { $mid: MarshalledId.ChatViewContext } : undefined; } - - override get singleViewPaneContainerTitle(): string | undefined { - if (this.titleControl) { - const titleControlTitle = this.titleControl.getSingleViewPaneContainerTitle(); - if (titleControlTitle) { - return titleControlTitle; - } - } - - return super.singleViewPaneContainerTitle; - } } diff --git a/src/vs/workbench/contrib/chat/browser/chatViewTitleControl.ts b/src/vs/workbench/contrib/chat/browser/chatViewTitleControl.ts index e20bc76be3d40..72c75f0095e95 100644 --- a/src/vs/workbench/contrib/chat/browser/chatViewTitleControl.ts +++ b/src/vs/workbench/contrib/chat/browser/chatViewTitleControl.ts @@ -18,19 +18,15 @@ import { HiddenItemStrategy, MenuWorkbenchToolBar } from '../../../../platform/a import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; -import { IViewContainerModel, IViewDescriptorService } from '../../../common/views.js'; -import { ActivityBarPosition, LayoutSettings } from '../../../services/layout/browser/layoutService.js'; import { IChatViewTitleActionContext } from '../common/chatActions.js'; import { IChatModel } from '../common/chatModel.js'; import { ChatConfiguration } from '../common/constants.js'; -import { ChatViewId } from './chat.js'; import { AgentSessionProviders, getAgentSessionProviderIcon, getAgentSessionProviderName } from './agentSessions/agentSessions.js'; import { ActionViewItem, IActionViewItemOptions } from '../../../../base/browser/ui/actionbar/actionViewItems.js'; import { IAction } from '../../../../base/common/actions.js'; import { AgentSessionsPicker } from './agentSessions/agentSessionsPicker.js'; export interface IChatViewTitleDelegate { - updateTitle(title: string): void; focusChat(): void; } @@ -42,15 +38,6 @@ export class ChatViewTitleControl extends Disposable { private readonly _onDidChangeHeight = this._register(new Emitter()); readonly onDidChangeHeight = this._onDidChangeHeight.event; - private get viewContainerModel(): IViewContainerModel | undefined { - const viewContainer = this.viewDescriptorService.getViewContainerByViewId(ChatViewId); - if (viewContainer) { - return this.viewDescriptorService.getViewContainerModel(viewContainer); - } - - return undefined; - } - private title: string | undefined = undefined; private titleContainer: HTMLElement | undefined; @@ -69,7 +56,6 @@ export class ChatViewTitleControl extends Disposable { private readonly container: HTMLElement, private readonly delegate: IChatViewTitleDelegate, @IConfigurationService private readonly configurationService: IConfigurationService, - @IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService, @IInstantiationService private readonly instantiationService: IInstantiationService, ) { super(); @@ -82,18 +68,9 @@ export class ChatViewTitleControl extends Disposable { private registerListeners(): void { - // Update when views change in container - if (this.viewContainerModel) { - this._register(this.viewContainerModel.onDidAddVisibleViewDescriptors(() => this.doUpdate())); - this._register(this.viewContainerModel.onDidRemoveVisibleViewDescriptors(() => this.doUpdate())); - } - // Update on configuration changes this._register(this.configurationService.onDidChangeConfiguration(e => { - if ( - e.affectsConfiguration(LayoutSettings.ACTIVITY_BAR_LOCATION) || - e.affectsConfiguration(ChatConfiguration.ChatViewTitleEnabled) - ) { + if (e.affectsConfiguration(ChatConfiguration.ChatViewTitleEnabled)) { this.doUpdate(); } })); @@ -187,8 +164,6 @@ export class ChatViewTitleControl extends Disposable { const markdownTitle = new MarkdownString(this.model?.title ?? ''); this.title = renderAsPlaintext(markdownTitle); - this.delegate.updateTitle(this.getTitleWithPrefix()); - this.updateTitle(this.title ?? ChatViewTitleControl.DEFAULT_TITLE); this.updateIcon(); @@ -262,40 +237,13 @@ export class ChatViewTitleControl extends Disposable { return false; // title hidden via setting } - if (this.viewContainerModel && this.viewContainerModel.visibleViewDescriptors.length > 1) { - return false; // multiple views visible, chat view shows a title already - } - - if (this.configurationService.getValue(LayoutSettings.ACTIVITY_BAR_LOCATION) !== ActivityBarPosition.DEFAULT) { - return false; // activity bar not in default location, view title shown already - } - - return !!this.model?.title; + return !!this.model?.title; // we need a chat showing and not being empty } private isEnabled(): boolean { return this.configurationService.getValue(ChatConfiguration.ChatViewTitleEnabled) === true; } - getSingleViewPaneContainerTitle(): string | undefined { - if ( - !this.isEnabled() || // title disabled - this.shouldRender() // title is rendered in the view, do not repeat - ) { - return undefined; - } - - return this.getTitleWithPrefix(); - } - - private getTitleWithPrefix(): string { - if (this.title) { - return localize('chatTitleWithPrefixCustom', "Chat: {0}", this.title); - } - - return ChatViewTitleControl.DEFAULT_TITLE; - } - getHeight(): number { if (!this.titleContainer || this.titleContainer.style.display === 'none') { return 0; diff --git a/src/vs/workbench/contrib/chat/browser/media/chatViewPane.css b/src/vs/workbench/contrib/chat/browser/media/chatViewPane.css index 3a39bcb76af97..008392a1f3843 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chatViewPane.css +++ b/src/vs/workbench/contrib/chat/browser/media/chatViewPane.css @@ -39,7 +39,6 @@ text-transform: uppercase; letter-spacing: 0.5px; color: var(--vscode-descriptionForeground); - padding: 8px; .agent-sessions-title { cursor: pointer; @@ -99,6 +98,14 @@ } } + &:not(.activity-bar-location-default) .agent-sessions-title-container { + padding: 0 4px 0 8px; /* align with container title and actions */ + } + + &.activity-bar-location-default .agent-sessions-title-container { + padding: 0 8px; /* align with container title and actions */ + } + .agent-sessions-link-container { display: none; /* hide link to show more when side by side */ } @@ -107,8 +114,12 @@ /* Sessions control: compact */ .chat-viewpane.has-sessions-control:not(.sessions-control-orientation-sidebyside) { - .agent-sessions-title-container { - padding: 8px 8px 8px 18px; /* align with container title */ + &:not(.activity-bar-location-default) .agent-sessions-title-container { + padding: 0 4px 0 20px; /* align with container title and actions */ + } + + &.activity-bar-location-default .agent-sessions-title-container { + padding: 0 8px 0 20px; /* align with container title and actions */ } .agent-sessions-container { diff --git a/src/vs/workbench/contrib/chat/browser/media/chatViewTitleControl.css b/src/vs/workbench/contrib/chat/browser/media/chatViewTitleControl.css index 8d56fe0ad50b6..a4ba43fa19c21 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chatViewTitleControl.css +++ b/src/vs/workbench/contrib/chat/browser/media/chatViewTitleControl.css @@ -5,10 +5,16 @@ .chat-viewpane { + &:not(.activity-bar-location-default) .chat-view-title-container { + padding: 0 8px 0 16px; /* try to align with the sessions view title */ + } + + &.activity-bar-location-default .chat-view-title-container { + padding: 0 12px 0 16px; /* try to align with the sessions view title */ + } + .chat-view-title-container { display: none; - /* try to align with the sessions view title */ - padding: 8px 12px 8px 16px; align-items: center; cursor: pointer; diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index d8b8e1cc83a73..d4d6346c8a27c 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -23,7 +23,7 @@ import { KeybindingsEditorModel, KEYBINDING_ENTRY_TEMPLATE_ID } from '../../../s import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { IKeybindingService, IUserFriendlyKeybinding } from '../../../../platform/keybinding/common/keybinding.js'; import { DefineKeybindingWidget, KeybindingsSearchWidget } from './keybindingWidgets.js'; -import { CONTEXT_KEYBINDING_FOCUS, CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_ADD, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND_TITLE, CONTEXT_WHEN_FOCUS } from '../common/preferences.js'; +import { CONTEXT_KEYBINDING_FOCUS, CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDINGS_SEARCH_HAS_VALUE, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_ADD, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND_TITLE, CONTEXT_WHEN_FOCUS } from '../common/preferences.js'; import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js'; import { IKeybindingEditingService } from '../../../services/keybinding/common/keybindingEditing.js'; import { IListContextMenuEvent } from '../../../../base/browser/ui/list/list.js'; @@ -108,6 +108,7 @@ export class KeybindingsEditor extends EditorPane imp private keybindingsEditorContextKey: IContextKey; private keybindingFocusContextKey: IContextKey; private searchFocusContextKey: IContextKey; + private searchHasValueContextKey: IContextKey; private readonly sortByPrecedenceAction: Action; private readonly recordKeysAction: Action; @@ -138,6 +139,7 @@ export class KeybindingsEditor extends EditorPane imp this.keybindingsEditorContextKey = CONTEXT_KEYBINDINGS_EDITOR.bindTo(this.contextKeyService); this.searchFocusContextKey = CONTEXT_KEYBINDINGS_SEARCH_FOCUS.bindTo(this.contextKeyService); this.keybindingFocusContextKey = CONTEXT_KEYBINDING_FOCUS.bindTo(this.contextKeyService); + this.searchHasValueContextKey = CONTEXT_KEYBINDINGS_SEARCH_HAS_VALUE.bindTo(this.contextKeyService); this.searchHistoryDelayer = new Delayer(500); this.recordKeysAction = this._register(new Action(KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, localize('recordKeysLabel', "Record Keys"), ThemeIcon.asClassName(keybindingsRecordKeysIcon))); @@ -321,6 +323,7 @@ export class KeybindingsEditor extends EditorPane imp clearSearchResults(): void { this.searchWidget.clear(); + this.searchHasValueContextKey.set(false); } showSimilarKeybindings(keybindingEntry: IKeybindingItemEntry): void { @@ -375,7 +378,9 @@ export class KeybindingsEditor extends EditorPane imp }) })); this._register(this.searchWidget.onDidChange(searchValue => { - clearInputAction.enabled = !!searchValue; + const hasValue = !!searchValue; + clearInputAction.enabled = hasValue; + this.searchHasValueContextKey.set(hasValue); this.delayedFiltering.trigger(() => this.filterKeybindings()); this.updateSearchOptions(); })); diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index 06b47097e901b..dc4ed6e1f88c8 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -43,7 +43,7 @@ import { PreferencesEditorInput, SettingsEditor2Input } from '../../../services/ import { SettingsEditorModel } from '../../../services/preferences/common/preferencesModels.js'; import { CURRENT_PROFILE_CONTEXT, IUserDataProfileService } from '../../../services/userDataProfile/common/userDataProfile.js'; import { ExplorerFolderContext, ExplorerRootContext } from '../../files/common/files.js'; -import { CONTEXT_AI_SETTING_RESULTS_AVAILABLE, CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDING_FOCUS, CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_JSON_EDITOR, CONTEXT_SETTINGS_ROW_FOCUS, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, CONTEXT_WHEN_FOCUS, KEYBINDINGS_EDITOR_COMMAND_ACCEPT_WHEN, KEYBINDINGS_EDITOR_COMMAND_ADD, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_HISTORY, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND_TITLE, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_REJECT_WHEN, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SEARCH, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_SHOW_DEFAULT_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_EXTENSION_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS, REQUIRE_TRUSTED_WORKSPACE_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_TOGGLE_AI_SEARCH } from '../common/preferences.js'; +import { CONTEXT_AI_SETTING_RESULTS_AVAILABLE, CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDINGS_SEARCH_HAS_VALUE, CONTEXT_KEYBINDING_FOCUS, CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_JSON_EDITOR, CONTEXT_SETTINGS_ROW_FOCUS, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, CONTEXT_WHEN_FOCUS, KEYBINDINGS_EDITOR_COMMAND_ACCEPT_WHEN, KEYBINDINGS_EDITOR_COMMAND_ADD, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_HISTORY, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND_TITLE, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_REJECT_WHEN, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SEARCH, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_SHOW_DEFAULT_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_EXTENSION_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS, REQUIRE_TRUSTED_WORKSPACE_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_TOGGLE_AI_SEARCH } from '../common/preferences.js'; import { PreferencesContribution } from '../common/preferencesContribution.js'; import { KeybindingsEditor } from './keybindingsEditor.js'; import { ConfigureLanguageBasedSettingsAction } from './preferencesActions.js'; @@ -965,7 +965,7 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon title: nls.localize('clear', "Clear Search Results"), keybinding: { weight: KeybindingWeight.WorkbenchContrib, - when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS), + when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDINGS_SEARCH_HAS_VALUE), primary: KeyCode.Escape, } }); diff --git a/src/vs/workbench/contrib/preferences/common/preferences.ts b/src/vs/workbench/contrib/preferences/common/preferences.ts index e08775dfbfc52..2aa5e003d165f 100644 --- a/src/vs/workbench/contrib/preferences/common/preferences.ts +++ b/src/vs/workbench/contrib/preferences/common/preferences.ts @@ -72,6 +72,7 @@ export const CONTEXT_TOC_ROW_FOCUS = new RawContextKey('settingsTocRowF export const CONTEXT_SETTINGS_ROW_FOCUS = new RawContextKey('settingRowFocus', false); export const CONTEXT_KEYBINDINGS_EDITOR = new RawContextKey('inKeybindings', false); export const CONTEXT_KEYBINDINGS_SEARCH_FOCUS = new RawContextKey('inKeybindingsSearch', false); +export const CONTEXT_KEYBINDINGS_SEARCH_HAS_VALUE = new RawContextKey('keybindingsSearchHasValue', false); export const CONTEXT_KEYBINDING_FOCUS = new RawContextKey('keybindingFocus', false); export const CONTEXT_WHEN_FOCUS = new RawContextKey('whenFocus', false); export const CONTEXT_AI_SETTING_RESULTS_AVAILABLE = new RawContextKey('aiSettingResultsAvailable', false); diff --git a/src/vs/workbench/contrib/scm/common/quickDiffService.ts b/src/vs/workbench/contrib/scm/common/quickDiffService.ts index 6759d4e35609c..c354555653a2f 100644 --- a/src/vs/workbench/contrib/scm/common/quickDiffService.ts +++ b/src/vs/workbench/contrib/scm/common/quickDiffService.ts @@ -152,5 +152,6 @@ export class QuickDiffService extends Disposable implements IQuickDiffService { export async function getOriginalResource(quickDiffService: IQuickDiffService, uri: URI, language: string | undefined, isSynchronized: boolean | undefined): Promise { const quickDiffs = await quickDiffService.getQuickDiffs(uri, language, isSynchronized); - return quickDiffs.length > 0 ? quickDiffs[0].originalResource : null; + const primaryQuickDiffs = quickDiffs.find(quickDiff => quickDiff.kind === 'primary'); + return primaryQuickDiffs ? primaryQuickDiffs.originalResource : null; }