Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 (`...`)」オーバーフローボタンを非表示 |
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
30 changes: 30 additions & 0 deletions src/vs/workbench/contrib/coderm/browser/quickOpenLocalFiles.ts
Original file line number Diff line number Diff line change
@@ -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<IConfigurationRegistry>(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.'),
},
},
});
98 changes: 82 additions & 16 deletions src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 { }

Expand Down Expand Up @@ -219,6 +222,9 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
historyFilterSortOrder: searchConfig?.quickOpen?.history?.filterSortOrder,
preserveInput: quickAccessConfig?.preserveInput,
includeTerminals: this.configurationService.getValue<boolean>(CodermQuickOpenIncludeTerminalsSetting),
// --- Coderm start: open local files via Quick Open in remote sessions ---
includeLocalFiles: this.configurationService.getValue<boolean>(CodermQuickOpenLocalFilesSetting),
// --- Coderm end ---
};
}

Expand Down Expand Up @@ -574,30 +580,46 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
return [];
}

// Absolute path result
const absolutePathResult = await this.getAbsolutePathFileResult(query, token);
// --- Coderm start: open local files via Quick Open in remote sessions ---
// Resolve absolute path results for both the remote (vscode-remote://)
// and the local (file://) filesystem so both candidates can be shown.
const [absolutePathResult, localAbsolutePathResults] = await Promise.all([
this.getAbsolutePathFileResult(query, token),
this.getLocalAbsolutePathFileResults(query, token)
]);
// --- Coderm end ---
if (token.isCancellationRequested) {
return [];
}

// Use absolute path result as only results if present
// Use absolute path results as only results if present
let fileMatches: Array<URI>;
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)
Expand Down Expand Up @@ -773,6 +795,50 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
return;
}

// --- Coderm start: open local files via Quick Open in remote sessions ---
private async getLocalAbsolutePathFileResults(query: IPreparedQuery, token: CancellationToken): Promise<URI[]> {
// 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<URI[] | undefined> {
if (!query.containsPathSeparator) {
return;
Expand Down
Loading