diff --git a/README.ja.md b/README.ja.md index 6491f60020f..d4736f7b1f0 100644 --- a/README.ja.md +++ b/README.ja.md @@ -68,6 +68,7 @@ VS Codeのフォーク。本家にはないUI/UX改善を追加した(してい | `coderm.workbench.editor.resizeIncrement` | `number` | `60` | ペインリサイズの増分(px) | | `coderm.terminal.horizontalPadding` | `number` | `20` | ターミナルの水平パディング(px, 0–100) | | `coderm.quickOpen.includeTerminals` | `boolean` | `true` | Quick Openにターミナルエディタを含める | +| `coderm.quickOpen.localFiles` | `boolean` | `true` | SSH接続時にQuick Openで絶対パスのローカルファイルを候補に含める | | `coderm.updateDownloadProgress.enabled` | `boolean` | `true` | アップデートダウンロード時に進捗通知を表示 | | `coderm.terminal.closeEmptyPaneOnKill` | `boolean` | `true` | ターミナルkill時に空ペインを閉じてフォーカス復帰 | | `coderm.titleBar.hideMoreActions` | `boolean` | `true` | タイトルバー右端の「More Actions (`...`)」オーバーフローボタンを非表示 | diff --git a/README.md b/README.md index f6d6b1252f6..bce15b2f04b 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ Settings unique to Coderm that are not available in upstream VS Code. | `coderm.workbench.editor.resizeIncrement` | `number` | `60` | Pane resize increment (px) | | `coderm.terminal.horizontalPadding` | `number` | `20` | Terminal horizontal padding (px, 0–100) | | `coderm.quickOpen.includeTerminals` | `boolean` | `true` | Include terminal editors in Quick Open | +| `coderm.quickOpen.localFiles` | `boolean` | `true` | Include local files with absolute paths in Quick Open when connected via SSH | | `coderm.updateDownloadProgress.enabled` | `boolean` | `true` | Show progress notification during update download | | `coderm.terminal.closeEmptyPaneOnKill` | `boolean` | `true` | Close empty pane and restore focus on terminal kill | | `coderm.titleBar.hideMoreActions` | `boolean` | `true` | Hide the trailing "More Actions" overflow button (`...`) in the title bar | diff --git a/src/vs/workbench/contrib/coderm/browser/coderm.contribution.ts b/src/vs/workbench/contrib/coderm/browser/coderm.contribution.ts index b051005ba1a..1cce4eb1001 100644 --- a/src/vs/workbench/contrib/coderm/browser/coderm.contribution.ts +++ b/src/vs/workbench/contrib/coderm/browser/coderm.contribution.ts @@ -20,6 +20,7 @@ import './gitWorktreeDefaults.js'; import './hideTitleBarMoreActions.js'; import './preventNewGroupOnFocus.js'; import './quickOpenIncludeTerminals.js'; +import './quickOpenLocalFiles.js'; import './resizePaneActions.js'; import './remoteSSHGuard.js'; import './terminalHorizontalPadding.js'; diff --git a/src/vs/workbench/contrib/coderm/browser/quickOpenLocalFiles.ts b/src/vs/workbench/contrib/coderm/browser/quickOpenLocalFiles.ts new file mode 100644 index 00000000000..e00a47d7b99 --- /dev/null +++ b/src/vs/workbench/contrib/coderm/browser/quickOpenLocalFiles.ts @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { localize } from '../../../../nls.js'; +import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationRegistry } from '../../../../platform/configuration/common/configurationRegistry.js'; +import { Registry } from '../../../../platform/registry/common/platform.js'; + +/** + * Configuration key that controls whether local files with absolute paths + * can be opened via Quick Open when in remote SSH connection. + */ +export const CodermQuickOpenLocalFilesSetting = 'coderm.quickOpen.localFiles'; + +Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ + id: 'coderm.quickOpenLocalFiles', + order: 104, + title: localize('codermConfigurationTitle', 'Coderm'), + type: 'object', + properties: { + [CodermQuickOpenLocalFilesSetting]: { + type: 'boolean', + default: true, + scope: ConfigurationScope.APPLICATION, + description: localize('coderm.quickOpen.localFiles', + 'Controls whether local files with absolute paths (e.g., /Users/... or C:\\...) can be opened via Quick Open (Ctrl+P) when connected via SSH. When enabled, both local file:// and remote vscode-remote:// URIs are shown as candidates.'), + }, + }, +}); \ No newline at end of file diff --git a/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts b/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts index 0f9829a3800..e53d5c2a67e 100644 --- a/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts +++ b/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts @@ -13,6 +13,8 @@ import { getOutOfWorkspaceEditorResources, extractRangeFromFilter, IWorkbenchSea import { ISearchService, ISearchComplete } from '../../../services/search/common/search.js'; import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; import { untildify } from '../../../../base/common/labels.js'; +import { posix, win32 } from '../../../../base/common/path.js'; +import { OS, OperatingSystem } from '../../../../base/common/platform.js'; import { IPathService } from '../../../services/path/common/pathService.js'; import { URI } from '../../../../base/common/uri.js'; import { toLocalResource, dirname, basenameOrAuthority } from '../../../../base/common/resources.js'; @@ -59,6 +61,7 @@ import { IChatWidgetService, IQuickChatService } from '../../chat/browser/chat.j import { ILogService } from '../../../../platform/log/common/log.js'; import { ICustomEditorLabelService } from '../../../services/editor/common/customEditorLabelService.js'; import { CodermQuickOpenIncludeTerminalsSetting } from '../../coderm/browser/quickOpenIncludeTerminals.js'; +import { CodermQuickOpenLocalFilesSetting } from '../../coderm/browser/quickOpenLocalFiles.js'; interface IAnythingQuickPickItem extends IPickerQuickAccessItem, IQuickPickItemWithResource { } @@ -219,6 +222,9 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider(CodermQuickOpenIncludeTerminalsSetting), + // --- Coderm start: open local files via Quick Open in remote sessions --- + includeLocalFiles: this.configurationService.getValue(CodermQuickOpenLocalFilesSetting), + // --- Coderm end --- }; } @@ -574,30 +580,46 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider; + const absolutePathMatches: URI[] = []; if (absolutePathResult) { - if (excludes.has(absolutePathResult)) { - return []; // excluded + absolutePathMatches.push(absolutePathResult); + } + // --- Coderm start: merge local absolute path results (dedup) --- + for (const localResult of localAbsolutePathResults) { + if (!absolutePathMatches.some(existing => this.uriIdentityService.extUri.isEqual(existing, localResult))) { + absolutePathMatches.push(localResult); } + } + // --- Coderm end --- + if (absolutePathMatches.length > 0) { + return absolutePathMatches + .filter(resource => !excludes.has(resource)) + .map(resource => { + // Apply full highlights to ensure the pick is displayed. + // Since a ~ might have been used for searching, our fuzzy + // scorer may otherwise not properly respect the pick. + const absolutePathPick = this.createAnythingPick(resource, this.configuration); + absolutePathPick.highlights = { + label: [{ start: 0, end: absolutePathPick.label.length }], + description: absolutePathPick.description ? [{ start: 0, end: absolutePathPick.description.length }] : undefined + }; - // Create a single result pick and make sure to apply full - // highlights to ensure the pick is displayed. Since a - // ~ might have been used for searching, our fuzzy scorer - // may otherwise not properly respect the pick as a result - const absolutePathPick = this.createAnythingPick(absolutePathResult, this.configuration); - absolutePathPick.highlights = { - label: [{ start: 0, end: absolutePathPick.label.length }], - description: absolutePathPick.description ? [{ start: 0, end: absolutePathPick.description.length }] : undefined - }; - - return [absolutePathPick]; + return absolutePathPick; + }); } // Otherwise run the file search (with a delayer if cache is not ready yet) @@ -773,6 +795,50 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider { + // Only active in remote sessions: in local sessions the workspace is + // already on the local filesystem, so resolving absolute paths as local + // would just duplicate the existing results. + if (!this.configuration.includeLocalFiles || !this.environmentService.remoteAuthority) { + return []; + } + + if (!query.containsPathSeparator) { + return []; + } + + const localUserHome = this.pathService.userHome({ preferLocal: true }); + const detildifiedQuery = untildify(query.original, localUserHome.fsPath); + if (token.isCancellationRequested) { + return []; + } + + // Use the local OS path library (not the remote one) to decide whether + // the query is an absolute path on the client machine. + const localPathLib = OS === OperatingSystem.Windows ? win32 : posix; + if (!localPathLib.isAbsolute(detildifiedQuery)) { + return []; + } + + const resource = URI.file(detildifiedQuery); + if (token.isCancellationRequested) { + return []; + } + + try { + const stat = await this.fileService.stat(resource); + if (stat.isFile) { + return [await this.matchFilenameCasing(resource)]; + } + } catch (error) { + // ignore if file does not exist + } + + return []; + } + // --- Coderm end --- + private async getRelativePathFileResults(query: IPreparedQuery, token: CancellationToken): Promise { if (!query.containsPathSeparator) { return;