Skip to content

Commit dbcae0f

Browse files
committed
Commands resource proper computation
Commands can get exeucted from a command pallete, from a context menu or from some list using a keybinding To cover all these cases we need to properly compute the resource on which the command is being executed fixes microsoft#41263 fixes microsoft#41314
1 parent 94efa78 commit dbcae0f

3 files changed

Lines changed: 72 additions & 97 deletions

File tree

src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import uri from 'vs/base/common/uri';
1515
import { ITerminalService } from 'vs/workbench/parts/execution/common/execution';
1616
import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
1717
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
18-
import { toResource } from 'vs/workbench/common/editor';
1918
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
2019
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
2120
import { ITerminalService as IIntegratedTerminalService, KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED } from 'vs/workbench/parts/terminal/common/terminal';
@@ -25,6 +24,8 @@ import { IHistoryService } from 'vs/workbench/services/history/common/history';
2524
import { ResourceContextKey } from 'vs/workbench/common/resources';
2625
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
2726
import { IFileService } from 'vs/platform/files/common/files';
27+
import { IListService } from 'vs/platform/list/browser/listService';
28+
import { getResourceForCommand } from 'vs/workbench/parts/files/electron-browser/fileCommands';
2829

2930
if (env.isWindows) {
3031
registerSingleton(ITerminalService, WinTerminalService);
@@ -88,21 +89,13 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
8889
const fileService = accessor.get(IFileService);
8990
const integratedTerminalService = accessor.get(IIntegratedTerminalService);
9091
const terminalService = accessor.get(ITerminalService);
92+
resource = getResourceForCommand(resource, accessor.get(IListService), editorService);
9193

9294
// Try workspace path first
9395
const root = historyService.getLastActiveWorkspaceRoot('file');
9496
return !uri.isUri(resource) ? TPromise.as(root && root.fsPath) : fileService.resolveFile(resource).then(stat => {
9597
return stat.isDirectory ? stat.resource.fsPath : paths.dirname(stat.resource.fsPath);
9698
}).then(directoryToOpen => {
97-
98-
// Otherwise check if we have an active file open
99-
if (!directoryToOpen) {
100-
const file = toResource(editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' });
101-
if (file) {
102-
directoryToOpen = paths.dirname(file.fsPath); // take parent folder of file
103-
}
104-
}
105-
10699
if (configurationService.getValue<ITerminalConfiguration>().terminal.explorerKind === 'integrated') {
107100
const instance = integratedTerminalService.createInstance({ cwd: directoryToOpen }, true);
108101
if (instance) {

src/vs/workbench/parts/files/electron-browser/fileCommands.ts

Lines changed: 54 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { IListService } from 'vs/platform/list/browser/listService';
2929
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
3030
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
3131
import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
32-
import { IResourceInput, Position, IEditorInput } from 'vs/platform/editor/common/editor';
32+
import { IResourceInput, Position } from 'vs/platform/editor/common/editor';
3333
import { IFileService } from 'vs/platform/files/common/files';
3434
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
3535
import { IEditorViewState } from 'vs/editor/common/editorCommon';
@@ -73,25 +73,38 @@ export const openWindowCommand = (accessor: ServicesAccessor, paths: string[], f
7373
windowsService.openWindow(paths, { forceNewWindow });
7474
};
7575

76-
function save(resource: URI, isSaveAs: boolean, editorService: IWorkbenchEditorService, fileService: IFileService, untitledEditorService: IUntitledEditorService,
77-
textFileService: ITextFileService, editorGroupService: IEditorGroupService): TPromise<any> {
76+
// Commands can get exeucted from a command pallete, from a context menu or from some list using a keybinding
77+
// To cover all these cases we need to properly compute the resource on which the command is being executed
78+
export function getResourceForCommand(resource: URI, listService: IListService, editorService: IWorkbenchEditorService): URI {
79+
if (URI.isUri(resource)) {
80+
return resource;
81+
}
7882

79-
let source: URI;
80-
if (resource instanceof URI) {
81-
source = resource;
82-
} else {
83-
source = toResource(editorService.getActiveEditorInput(), { supportSideBySide: true });
83+
const list = listService.lastFocusedList;
84+
if (list && list.isDOMFocused()) {
85+
const focus = list.getFocus();
86+
if (focus instanceof FileStat) {
87+
return focus.resource;
88+
} else if (focus instanceof OpenEditor) {
89+
return focus.editorInput.getResource();
90+
}
8491
}
8592

86-
if (source && (fileService.canHandleResource(source) || source.scheme === 'untitled')) {
93+
return toResource(editorService.getActiveEditorInput(), { supportSideBySide: true });
94+
}
95+
96+
function save(resource: URI, isSaveAs: boolean, editorService: IWorkbenchEditorService, fileService: IFileService, untitledEditorService: IUntitledEditorService,
97+
textFileService: ITextFileService, editorGroupService: IEditorGroupService): TPromise<any> {
98+
99+
if (resource && (fileService.canHandleResource(resource) || resource.scheme === 'untitled')) {
87100

88101
// Save As (or Save untitled with associated path)
89-
if (isSaveAs || source.scheme === 'untitled') {
102+
if (isSaveAs || resource.scheme === 'untitled') {
90103
let encodingOfSource: string;
91-
if (source.scheme === 'untitled') {
92-
encodingOfSource = untitledEditorService.getEncoding(source);
93-
} else if (source.scheme === 'file') {
94-
const textModel = textFileService.models.get(source);
104+
if (resource.scheme === 'untitled') {
105+
encodingOfSource = untitledEditorService.getEncoding(resource);
106+
} else if (resource.scheme === 'file') {
107+
const textModel = textFileService.models.get(resource);
95108
encodingOfSource = textModel && textModel.getEncoding(); // text model can be null e.g. if this is a binary file!
96109
}
97110

@@ -100,17 +113,17 @@ function save(resource: URI, isSaveAs: boolean, editorService: IWorkbenchEditorS
100113
const editor = getCodeEditor(activeEditor);
101114
if (editor) {
102115
const activeResource = toResource(activeEditor.input, { supportSideBySide: true });
103-
if (activeResource && (fileService.canHandleResource(activeResource) || source.scheme === 'untitled') && activeResource.toString() === source.toString()) {
116+
if (activeResource && (fileService.canHandleResource(activeResource) || resource.scheme === 'untitled') && activeResource.toString() === resource.toString()) {
104117
viewStateOfSource = editor.saveViewState();
105118
}
106119
}
107120

108121
// Special case: an untitled file with associated path gets saved directly unless "saveAs" is true
109122
let savePromise: TPromise<URI>;
110-
if (!isSaveAs && source.scheme === 'untitled' && untitledEditorService.hasAssociatedFilePath(source)) {
111-
savePromise = textFileService.save(source).then((result) => {
123+
if (!isSaveAs && resource.scheme === 'untitled' && untitledEditorService.hasAssociatedFilePath(resource)) {
124+
savePromise = textFileService.save(resource).then((result) => {
112125
if (result) {
113-
return URI.file(source.fsPath);
126+
return URI.file(resource.fsPath);
114127
}
115128

116129
return null;
@@ -119,11 +132,11 @@ function save(resource: URI, isSaveAs: boolean, editorService: IWorkbenchEditorS
119132

120133
// Otherwise, really "Save As..."
121134
else {
122-
savePromise = textFileService.saveAs(source);
135+
savePromise = textFileService.saveAs(resource);
123136
}
124137

125138
return savePromise.then((target) => {
126-
if (!target || target.toString() === source.toString()) {
139+
if (!target || target.toString() === resource.toString()) {
127140
return void 0; // save canceled or same resource used
128141
}
129142

@@ -137,22 +150,20 @@ function save(resource: URI, isSaveAs: boolean, editorService: IWorkbenchEditorS
137150
};
138151

139152
return editorService.replaceEditors([{
140-
toReplace: { resource: source },
153+
toReplace: { resource: resource },
141154
replaceWith
142155
}]).then(() => true);
143156
});
144157
}
145158

146159
// Pin the active editor if we are saving it
147-
if (!resource) {
148-
const editor = editorService.getActiveEditor();
149-
if (editor) {
150-
editorGroupService.pinEditor(editor.position, editor.input);
151-
}
160+
const editor = editorService.getActiveEditor();
161+
if (editor && editor.input && editor.input.getResource().toString() === resource.toString()) {
162+
editorGroupService.pinEditor(editor.position, editor.input);
152163
}
153164

154165
// Just save
155-
return textFileService.save(source, { force: true /* force a change to the file to trigger external watchers if any */ });
166+
return textFileService.save(resource, { force: true /* force a change to the file to trigger external watchers if any */ });
156167
}
157168

158169
return TPromise.as(false);
@@ -244,10 +255,7 @@ CommandsRegistry.registerCommand({
244255
const editorService = accessor.get(IWorkbenchEditorService);
245256
const textFileService = accessor.get(ITextFileService);
246257
const messageService = accessor.get(IMessageService);
247-
248-
if (!URI.isUri(resource)) {
249-
resource = toResource(editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' });
250-
}
258+
resource = getResourceForCommand(resource, accessor.get(IListService), editorService);
251259

252260
if (resource && resource.scheme !== 'untitled') {
253261
return textFileService.revert(resource, { force: true }).then(null, error => {
@@ -270,29 +278,16 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
270278
const editorService = accessor.get(IWorkbenchEditorService);
271279
const listService = accessor.get(IListService);
272280
const tree = listService.lastFocusedList;
273-
274-
let resourceOrEditor: URI | IEditorInput;
275-
if (URI.isUri(resource)) {
276-
resourceOrEditor = resource;
277-
} else {
278-
const focus = tree.getFocus();
279-
if (focus instanceof FileStat && !focus.isDirectory) {
280-
resourceOrEditor = focus.resource;
281-
} else if (focus instanceof OpenEditor) {
282-
resourceOrEditor = focus.editorInput;
283-
}
284-
}
281+
resource = getResourceForCommand(resource, listService, editorService);
285282

286283
// Remove highlight
287284
if (tree instanceof Tree) {
288285
tree.clearHighlight();
289286
}
290287

291288
// Set side input
292-
if (URI.isUri(resourceOrEditor)) {
293-
return editorService.openEditor({ resource: resourceOrEditor, options: { preserveFocus: false } }, true);
294-
} else if (resourceOrEditor) {
295-
return editorService.openEditor(resourceOrEditor, { preserveFocus: false }, true);
289+
if (URI.isUri(resource)) {
290+
return editorService.openEditor({ resource, options: { preserveFocus: false } }, true);
296291
}
297292

298293
return TPromise.as(true);
@@ -315,9 +310,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
315310
}
316311

317312
const editorService = accessor.get(IWorkbenchEditorService);
318-
if (!URI.isUri(resource)) {
319-
resource = toResource(editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' });
320-
}
313+
resource = getResourceForCommand(resource, accessor.get(IListService), editorService);
321314

322315
if (resource && resource.scheme === 'file') {
323316
const name = paths.basename(resource.fsPath);
@@ -343,7 +336,7 @@ CommandsRegistry.registerCommand({
343336
tree.DOMFocus();
344337
}
345338

346-
globalResourceToCompare = resource;
339+
globalResourceToCompare = getResourceForCommand(resource, listService, accessor.get(IWorkbenchEditorService));
347340
if (!resourceSelectedForCompareContext) {
348341
resourceSelectedForCompareContext = ResourceSelectedForCompareContext.bindTo(accessor.get(IContextKeyService));
349342
}
@@ -364,17 +357,14 @@ CommandsRegistry.registerCommand({
364357

365358
return editorService.openEditor({
366359
leftResource: globalResourceToCompare,
367-
rightResource: resource
360+
rightResource: getResourceForCommand(resource, listService, editorService)
368361
});
369362
}
370363
});
371364

372365
const revealInOSHandler = (accessor: ServicesAccessor, resource: URI) => {
373366
// Without resource, try to look at the active editor
374-
if (!URI.isUri(resource)) {
375-
const editorService = accessor.get(IWorkbenchEditorService);
376-
resource = toResource(editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' });
377-
}
367+
resource = getResourceForCommand(resource, accessor.get(IListService), accessor.get(IWorkbenchEditorService));
378368

379369
if (resource) {
380370
const windowsService = accessor.get(IWindowsService);
@@ -410,18 +400,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
410400
},
411401
id: COPY_PATH_COMMAND_ID,
412402
handler: (accessor, resource: URI) => {
413-
// Without resource, try to look at the active editor
414-
if (!URI.isUri(resource)) {
415-
const editorGroupService = accessor.get(IEditorGroupService);
416-
const editorService = accessor.get(IWorkbenchEditorService);
417-
const activeEditor = editorService.getActiveEditor();
418-
419-
resource = activeEditor ? toResource(activeEditor.input, { supportSideBySide: true }) : void 0;
420-
if (activeEditor) {
421-
editorGroupService.focusGroup(activeEditor.position); // focus back to active editor group
422-
}
423-
}
424-
403+
resource = getResourceForCommand(resource, accessor.get(IListService), accessor.get(IWorkbenchEditorService));
425404
if (resource) {
426405
const clipboardService = accessor.get(IClipboardService);
427406
clipboardService.writeText(resource.scheme === 'file' ? labels.getPathLabel(resource) : resource.toString());
@@ -437,6 +416,7 @@ CommandsRegistry.registerCommand({
437416
handler: (accessor, resource: URI) => {
438417
const viewletService = accessor.get(IViewletService);
439418
const contextService = accessor.get(IWorkspaceContextService);
419+
resource = getResourceForCommand(resource, accessor.get(IListService), accessor.get(IWorkbenchEditorService));
440420

441421
viewletService.openViewlet(VIEWLET_ID, false).then((viewlet: ExplorerViewlet) => {
442422
const isInsideWorkspace = contextService.isInsideWorkspace(resource);
@@ -462,7 +442,9 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
462442
when: undefined,
463443
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_S,
464444
handler: (accessor, resource: URI) => {
465-
return save(resource, true, accessor.get(IWorkbenchEditorService), accessor.get(IFileService), accessor.get(IUntitledEditorService), accessor.get(ITextFileService), accessor.get(IEditorGroupService));
445+
const editorService = accessor.get(IWorkbenchEditorService);
446+
resource = getResourceForCommand(resource, accessor.get(IListService), editorService);
447+
return save(resource, true, editorService, accessor.get(IFileService), accessor.get(IUntitledEditorService), accessor.get(ITextFileService), accessor.get(IEditorGroupService));
466448
}
467449
});
468450

@@ -472,7 +454,9 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
472454
primary: KeyMod.CtrlCmd | KeyCode.KEY_S,
473455
id: SAVE_FILE_COMMAND_ID,
474456
handler: (accessor, resource: URI) => {
475-
return save(resource, false, accessor.get(IWorkbenchEditorService), accessor.get(IFileService), accessor.get(IUntitledEditorService), accessor.get(ITextFileService), accessor.get(IEditorGroupService));
457+
const editorService = accessor.get(IWorkbenchEditorService);
458+
resource = getResourceForCommand(resource, accessor.get(IListService), editorService);
459+
return save(resource, false, editorService, accessor.get(IFileService), accessor.get(IUntitledEditorService), accessor.get(ITextFileService), accessor.get(IEditorGroupService));
476460
}
477461
});
478462

src/vs/workbench/parts/search/electron-browser/search.contribution.ts

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import nls = require('vs/nls');
1414
import { TPromise } from 'vs/base/common/winjs.base';
1515
import { Action } from 'vs/base/common/actions';
1616
import * as objects from 'vs/base/common/objects';
17-
import { explorerItemToFileResource, ExplorerFolderContext, ExplorerRootContext } from 'vs/workbench/parts/files/common/files';
17+
import { ExplorerFolderContext, ExplorerRootContext } from 'vs/workbench/parts/files/common/files';
1818
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
1919
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
2020
import { QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions as QuickOpenExtensions } from 'vs/workbench/browser/quickopen';
@@ -41,12 +41,15 @@ import { OpenSymbolHandler } from 'vs/workbench/parts/search/browser/openSymbolH
4141
import { OpenAnythingHandler } from 'vs/workbench/parts/search/browser/openAnythingHandler';
4242
import { registerLanguageCommand } from 'vs/editor/browser/editorExtensions';
4343
import { getWorkspaceSymbols } from 'vs/workbench/parts/search/common/search';
44-
import { illegalArgument, onUnexpectedError } from 'vs/base/common/errors';
44+
import { illegalArgument } from 'vs/base/common/errors';
4545
import { WorkbenchListFocusContextKey, IListService } from 'vs/platform/list/browser/listService';
4646
import URI from 'vs/base/common/uri';
4747
import { relative } from 'path';
4848
import { dirname } from 'vs/base/common/resources';
4949
import { ResourceContextKey } from 'vs/workbench/common/resources';
50+
import { getResourceForCommand } from 'vs/workbench/parts/files/electron-browser/fileCommands';
51+
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
52+
import { IFileService } from 'vs/platform/files/common/files';
5053

5154
registerSingleton(ISearchWorkbenchService, SearchWorkbenchService);
5255
replaceContributions();
@@ -188,30 +191,25 @@ CommandsRegistry.registerCommand({
188191
handler: (accessor, resource?: URI) => {
189192
const listService = accessor.get(IListService);
190193
const viewletService = accessor.get(IViewletService);
194+
const fileService = accessor.get(IFileService);
195+
resource = getResourceForCommand(resource, listService, accessor.get(IWorkbenchEditorService));
191196

192-
if (!URI.isUri(resource)) {
193-
const lastFocusedList = listService.lastFocusedList;
194-
const focus = lastFocusedList ? lastFocusedList.getFocus() : void 0;
195-
if (focus) {
196-
const file = explorerItemToFileResource(focus);
197-
if (file) {
198-
resource = file.isDirectory ? file.resource : dirname(file.resource);
199-
}
200-
}
201-
}
202-
203-
viewletService.openViewlet(Constants.VIEWLET_ID, true).then(viewlet => {
197+
return viewletService.openViewlet(Constants.VIEWLET_ID, true).then(viewlet => {
204198
if (resource) {
205-
(viewlet as SearchViewlet).searchInFolder(resource, (from, to) => relative(from, to));
199+
fileService.resolveFile(resource).then(stat => {
200+
return stat.isDirectory ? stat.resource : dirname(stat.resource);
201+
}).then(resource =>
202+
(viewlet as SearchViewlet).searchInFolder(resource, (from, to) => relative(from, to))
203+
);
206204
}
207-
}).done(null, onUnexpectedError);
205+
});
208206
}
209207
});
210208

211209
const FIND_IN_WORKSPACE_ID = 'filesExplorer.findInWorkspace';
212210
CommandsRegistry.registerCommand({
213211
id: FIND_IN_WORKSPACE_ID,
214-
handler: (accessor, ) => {
212+
handler: (accessor) => {
215213
const viewletService = accessor.get(IViewletService);
216214
return viewletService.openViewlet(Constants.VIEWLET_ID, true).then(viewlet => {
217215
(viewlet as SearchViewlet).searchInFolder(null, (from, to) => relative(from, to));

0 commit comments

Comments
 (0)