From e74ef45315df0b549daccd48192ddfa96800b837 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sun, 4 Sep 2016 10:26:50 +0200 Subject: [PATCH] Recent folders list changes when opening folder in extension debug window (fixes #11164) --- src/vs/code/electron-main/menus.ts | 63 +-------- src/vs/code/electron-main/windows.ts | 185 +++++++++++++++++---------- 2 files changed, 121 insertions(+), 127 deletions(-) diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 1b4459ea5d6d5..7bc6d21a960ea 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform'; import * as arrays from 'vs/base/common/arrays'; import * as env from 'vs/code/electron-main/env'; import { ipcMain as ipc, app, shell, dialog, Menu, MenuItem } from 'electron'; -import { IWindowsService, WindowsManager, IOpenedPathsList } from 'vs/code/electron-main/windows'; +import { IWindowsService } from 'vs/code/electron-main/windows'; import { IPath, VSCodeWindow } from 'vs/code/electron-main/window'; import { IStorageService } from 'vs/code/electron-main/storage'; import { IUpdateService, State as UpdateState } from 'vs/code/electron-main/update-manager'; @@ -45,7 +45,6 @@ export class VSCodeMenu { private static lastKnownKeybindingsMapStorageKey = 'lastKnownKeybindings'; private static MAX_MENU_RECENT_ENTRIES = 10; - private static MAX_TOTAL_RECENT_ENTRIES = 100; private isQuitting: boolean; private appMenuInstalled: boolean; @@ -154,7 +153,6 @@ export class VSCodeMenu { } private onOpen(path: IPath): void { - this.addToOpenedPathsList(path.filePath || path.workspacePath, !!path.filePath); this.updateMenu(); } @@ -239,59 +237,6 @@ export class VSCodeMenu { } } - private addToOpenedPathsList(path?: string, isFile?: boolean): void { - if (!path) { - return; - } - - const mru = this.getOpenedPathsList(); - if (isFile) { - mru.files.unshift(path); - mru.files = arrays.distinct(mru.files, (f) => platform.isLinux ? f : f.toLowerCase()); - } else { - mru.folders.unshift(path); - mru.folders = arrays.distinct(mru.folders, (f) => platform.isLinux ? f : f.toLowerCase()); - } - - // Make sure its bounded - mru.folders = mru.folders.slice(0, VSCodeMenu.MAX_TOTAL_RECENT_ENTRIES); - mru.files = mru.files.slice(0, VSCodeMenu.MAX_TOTAL_RECENT_ENTRIES); - - this.storageService.setItem(WindowsManager.openedPathsListStorageKey, mru); - } - - private removeFromOpenedPathsList(path: string): void { - const mru = this.getOpenedPathsList(); - - let index = mru.files.indexOf(path); - if (index >= 0) { - mru.files.splice(index, 1); - } - - index = mru.folders.indexOf(path); - if (index >= 0) { - mru.folders.splice(index, 1); - } - - this.storageService.setItem(WindowsManager.openedPathsListStorageKey, mru); - } - - private clearOpenedPathsList(): void { - this.storageService.setItem(WindowsManager.openedPathsListStorageKey, { folders: [], files: [] }); - app.clearRecentDocuments(); - - this.updateMenu(); - } - - private getOpenedPathsList(): IOpenedPathsList { - let mru = this.storageService.getItem(WindowsManager.openedPathsListStorageKey); - if (!mru) { - mru = { folders: [], files: [] }; - } - - return mru; - } - private setMacApplicationMenu(macApplicationMenu: Electron.Menu): void { const about = new MenuItem({ label: nls.localize('mAbout', "About {0}", this.envService.product.nameLong), role: 'about' }); const checkForUpdates = this.getUpdateMenuItems(); @@ -424,7 +369,7 @@ export class VSCodeMenu { private setOpenRecentMenu(openRecentMenu: Electron.Menu): void { openRecentMenu.append(this.createMenuItem(nls.localize({ key: 'miReopenClosedEditor', comment: ['&& denotes a mnemonic'] }, "&&Reopen Closed Editor"), 'workbench.action.reopenClosedEditor')); - const {folders, files} = this.getOpenedPathsList(); + const {folders, files} = this.windowsService.getRecentPathsList(); // Folders if (folders.length > 0) { @@ -446,7 +391,7 @@ export class VSCodeMenu { if (folders.length || files.length) { openRecentMenu.append(__separator__()); - openRecentMenu.append(new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miClearItems', comment: ['&& denotes a mnemonic'] }, "&&Clear Items")), click: () => this.clearOpenedPathsList() })); + openRecentMenu.append(new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miClearItems', comment: ['&& denotes a mnemonic'] }, "&&Clear Items")), click: () => { this.windowsService.clearRecentPathsList(); this.updateMenu(); } })); } } @@ -455,7 +400,7 @@ export class VSCodeMenu { label: unMnemonicLabel(path), click: () => { const success = !!this.windowsService.open({ cli: this.envService.cliArgs, pathsToOpen: [path] }); if (!success) { - this.removeFromOpenedPathsList(path); + this.windowsService.removeFromRecentPathsList(path); this.updateMenu(); } } diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 4460c6a6dd343..a01c8e6e72bb9 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -57,7 +57,7 @@ interface IWindowsState { openedFolders: IWindowState[]; } -export interface IOpenedPathsList { +export interface IRecentPathsList { folders: string[]; files: string[]; } @@ -109,14 +109,18 @@ export interface IWindowsService { getWindowById(windowId: number): VSCodeWindow; getWindows(): VSCodeWindow[]; getWindowCount(): number; + getRecentPathsList(): IRecentPathsList; + removeFromRecentPathsList(path: string); + clearRecentPathsList(): void; } export class WindowsManager implements IWindowsService { _serviceBrand: any; - public static openedPathsListStorageKey = 'openedPathsList'; - + private static MAX_TOTAL_RECENT_ENTRIES = 100; + + private static recentPathsListStorageKey = 'openedPathsList'; private static workingDirPickerStorageKey = 'pickerWorkingDir'; private static windowsStateStorageKey = 'windowsState'; @@ -331,7 +335,7 @@ export class WindowsManager implements IWindowsService { const vscodeWindow = this.getWindowById(windowId); if (vscodeWindow) { - const recents = this.getRecentlyOpenedPaths(vscodeWindow.config.workspacePath, vscodeWindow.config.filesToOpen); + const recents = this.getRecentPathsList(vscodeWindow.config.workspacePath, vscodeWindow.config.filesToOpen); vscodeWindow.send('vscode:openRecent', recents.files, recents.folders); } @@ -495,7 +499,7 @@ export class WindowsManager implements IWindowsService { public reload(win: VSCodeWindow, cli?: ICommandLineArguments): void { // Only reload when the window has not vetoed this - this.lifecycleService.unload(win).done((veto) => { + this.lifecycleService.unload(win).done(veto => { if (!veto) { win.reload(cli); } @@ -508,7 +512,7 @@ export class WindowsManager implements IWindowsService { // Find paths from provided paths if any if (openConfig.pathsToOpen && openConfig.pathsToOpen.length > 0) { - iPathsToOpen = openConfig.pathsToOpen.map((pathToOpen) => { + iPathsToOpen = openConfig.pathsToOpen.map(pathToOpen => { const iPath = this.toIPath(pathToOpen, false, openConfig.cli && openConfig.cli.goto); // Warn if the requested path to open does not exist @@ -554,13 +558,13 @@ export class WindowsManager implements IWindowsService { let filesToOpen: IPath[] = []; let filesToDiff: IPath[] = []; - let foldersToOpen = iPathsToOpen.filter((iPath) => iPath.workspacePath && !iPath.filePath && !iPath.installExtensionPath); - let emptyToOpen = iPathsToOpen.filter((iPath) => !iPath.workspacePath && !iPath.filePath && !iPath.installExtensionPath); - let extensionsToInstall = iPathsToOpen.filter((iPath) => iPath.installExtensionPath).map(ipath => ipath.filePath); - let filesToCreate = iPathsToOpen.filter((iPath) => !!iPath.filePath && iPath.createFilePath && !iPath.installExtensionPath); + let foldersToOpen = iPathsToOpen.filter(iPath => iPath.workspacePath && !iPath.filePath && !iPath.installExtensionPath); + let emptyToOpen = iPathsToOpen.filter(iPath => !iPath.workspacePath && !iPath.filePath && !iPath.installExtensionPath); + let extensionsToInstall = iPathsToOpen.filter(iPath => iPath.installExtensionPath).map(ipath => ipath.filePath); + let filesToCreate = iPathsToOpen.filter(iPath => !!iPath.filePath && iPath.createFilePath && !iPath.installExtensionPath); // Diff mode needs special care - const candidates = iPathsToOpen.filter((iPath) => !!iPath.filePath && !iPath.createFilePath && !iPath.installExtensionPath); + const candidates = iPathsToOpen.filter(iPath => !!iPath.filePath && !iPath.createFilePath && !iPath.installExtensionPath); if (openConfig.diffMode) { if (candidates.length === 2) { filesToDiff = candidates; @@ -597,7 +601,7 @@ export class WindowsManager implements IWindowsService { const lastActiveWindow = this.getLastActiveWindow(); if (!openFilesInNewWindow && lastActiveWindow) { lastActiveWindow.focus(); - lastActiveWindow.ready().then((readyWindow) => { + lastActiveWindow.ready().then(readyWindow => { readyWindow.send('vscode:openFiles', { filesToOpen: filesToOpen, filesToCreate: filesToCreate, @@ -627,11 +631,11 @@ export class WindowsManager implements IWindowsService { if (foldersToOpen.length > 0) { // Check for existing instances - const windowsOnWorkspacePath = arrays.coalesce(foldersToOpen.map((iPath) => this.findWindow(iPath.workspacePath))); + const windowsOnWorkspacePath = arrays.coalesce(foldersToOpen.map(iPath => this.findWindow(iPath.workspacePath))); if (windowsOnWorkspacePath.length > 0) { const browserWindow = windowsOnWorkspacePath[0]; browserWindow.focus(); // just focus one of them - browserWindow.ready().then((readyWindow) => { + browserWindow.ready().then(readyWindow => { readyWindow.send('vscode:openFiles', { filesToOpen: filesToOpen, filesToCreate: filesToCreate, @@ -655,8 +659,8 @@ export class WindowsManager implements IWindowsService { } // Open remaining ones - foldersToOpen.forEach((folderToOpen) => { - if (windowsOnWorkspacePath.some((win) => this.isPathEqual(win.openedWorkspacePath, folderToOpen.workspacePath))) { + foldersToOpen.forEach(folderToOpen => { + if (windowsOnWorkspacePath.some(win => this.isPathEqual(win.openedWorkspacePath, folderToOpen.workspacePath))) { return; // ignore folders that are already open } @@ -685,19 +689,95 @@ export class WindowsManager implements IWindowsService { }); } - // Remember in recent document list - iPathsToOpen.forEach((iPath) => { - if (iPath.filePath || iPath.workspacePath) { - app.addRecentDocument(iPath.filePath || iPath.workspacePath); - } - }); + // Remember in recent document list (unless this opens for extension development) + if (!openConfig.cli.extensionDevelopmentPath) { + iPathsToOpen.forEach(iPath => { + if (iPath.filePath || iPath.workspacePath) { + app.addRecentDocument(iPath.filePath || iPath.workspacePath); + this.addToRecentPathsList(iPath.filePath || iPath.workspacePath, !!iPath.filePath); + } + }); + } // Emit events - iPathsToOpen.forEach((iPath) => this.eventEmitter.emit(EventTypes.OPEN, iPath)); + iPathsToOpen.forEach(iPath => this.eventEmitter.emit(EventTypes.OPEN, iPath)); return arrays.distinct(usedWindows); } + private addToRecentPathsList(path?: string, isFile?: boolean): void { + if (!path) { + return; + } + + const mru = this.getRecentPathsList(); + if (isFile) { + mru.files.unshift(path); + mru.files = arrays.distinct(mru.files, (f) => platform.isLinux ? f : f.toLowerCase()); + } else { + mru.folders.unshift(path); + mru.folders = arrays.distinct(mru.folders, (f) => platform.isLinux ? f : f.toLowerCase()); + } + + // Make sure its bounded + mru.folders = mru.folders.slice(0, WindowsManager.MAX_TOTAL_RECENT_ENTRIES); + mru.files = mru.files.slice(0, WindowsManager.MAX_TOTAL_RECENT_ENTRIES); + + this.storageService.setItem(WindowsManager.recentPathsListStorageKey, mru); + } + + public removeFromRecentPathsList(path: string): void { + const mru = this.getRecentPathsList(); + + let index = mru.files.indexOf(path); + if (index >= 0) { + mru.files.splice(index, 1); + } + + index = mru.folders.indexOf(path); + if (index >= 0) { + mru.folders.splice(index, 1); + } + + this.storageService.setItem(WindowsManager.recentPathsListStorageKey, mru); + } + + public clearRecentPathsList(): void { + this.storageService.setItem(WindowsManager.recentPathsListStorageKey, { folders: [], files: [] }); + app.clearRecentDocuments(); + } + + public getRecentPathsList(workspacePath?: string, filesToOpen?: IPath[]): IRecentPathsList { + let files: string[]; + let folders: string[]; + + // Get from storage + const storedRecents = this.storageService.getItem(WindowsManager.recentPathsListStorageKey); + if (storedRecents) { + files = storedRecents.files || []; + folders = storedRecents.folders || []; + } else { + files = []; + folders = []; + } + + // Add currently files to open to the beginning if any + if (filesToOpen) { + files.unshift(...filesToOpen.map(f => f.filePath)); + } + + // Add current workspace path to beginning if set + if (workspacePath) { + folders.unshift(workspacePath); + } + + // Clear those dupes + files = arrays.distinct(files); + folders = arrays.distinct(folders); + + return { files, folders }; + } + private getWindowUserEnv(openConfig: IOpenConfiguration): IProcessEnvironment { return assign({}, this.initialUserEnv, openConfig.userEnv || {}); } @@ -707,7 +787,7 @@ export class WindowsManager implements IWindowsService { // Reload an existing plugin development host window on the same path // We currently do not allow more than one extension development window // on the same plugin path. - let res = WindowsManager.WINDOWS.filter((w) => w.config && this.isPathEqual(w.config.extensionDevelopmentPath, openConfig.cli.extensionDevelopmentPath)); + let res = WindowsManager.WINDOWS.filter(w => w.config && this.isPathEqual(w.config.extensionDevelopmentPath, openConfig.cli.extensionDevelopmentPath)); if (res && res.length === 1) { this.reload(res[0], openConfig.cli); res[0].focus(); // make sure it gets focus and is restored @@ -725,7 +805,7 @@ export class WindowsManager implements IWindowsService { // Make sure we are not asked to open a path that is already opened if (openConfig.cli.paths.length > 0) { - res = WindowsManager.WINDOWS.filter((w) => w.openedWorkspacePath && openConfig.cli.paths.indexOf(w.openedWorkspacePath) >= 0); + res = WindowsManager.WINDOWS.filter(w => w.openedWorkspacePath && openConfig.cli.paths.indexOf(w.openedWorkspacePath) >= 0); if (res.length) { openConfig.cli.paths = []; } @@ -749,37 +829,6 @@ export class WindowsManager implements IWindowsService { return configuration; } - private getRecentlyOpenedPaths(workspacePath?: string, filesToOpen?: IPath[]): IOpenedPathsList { - let files: string[]; - let folders: string[]; - - // Get from storage - const storedRecents = this.storageService.getItem(WindowsManager.openedPathsListStorageKey); - if (storedRecents) { - files = storedRecents.files || []; - folders = storedRecents.folders || []; - } else { - files = []; - folders = []; - } - - // Add currently files to open to the beginning if any - if (filesToOpen) { - files.unshift(...filesToOpen.map(f => f.filePath)); - } - - // Add current workspace path to beginning if set - if (workspacePath) { - folders.unshift(workspacePath); - } - - // Clear those dupes - files = arrays.distinct(files); - folders = arrays.distinct(folders); - - return { files, folders }; - } - private toIPath(anyPath: string, ignoreFileNotFound?: boolean, gotoLineMode?: boolean): IPath { if (!anyPath) { return null; @@ -852,7 +901,7 @@ export class WindowsManager implements IWindowsService { } } - const iPaths = candidates.map((candidate) => this.toIPath(candidate, ignoreFileNotFound, cli.goto)).filter((path) => !!path); + const iPaths = candidates.map(candidate => this.toIPath(candidate, ignoreFileNotFound, cli.goto)).filter(path => !!path); if (iPaths.length > 0) { return iPaths; } @@ -912,7 +961,7 @@ export class WindowsManager implements IWindowsService { } // Only load when the window has not vetoed this - this.lifecycleService.unload(vscodeWindow).done((veto) => { + this.lifecycleService.unload(vscodeWindow).done(veto => { if (!veto) { // Load it @@ -989,8 +1038,8 @@ export class WindowsManager implements IWindowsService { return state; } - const existingWindowBounds = WindowsManager.WINDOWS.map((win) => win.getBounds()); - while (existingWindowBounds.some((b) => b.x === state.x || b.y === state.y)) { + const existingWindowBounds = WindowsManager.WINDOWS.map(win => win.getBounds()); + while (existingWindowBounds.some(b => b.x === state.x || b.y === state.y)) { state.x += 30; state.y += 30; } @@ -1032,7 +1081,7 @@ export class WindowsManager implements IWindowsService { dialog.showOpenDialog(focussedWindow && focussedWindow.win, { defaultPath: workingDir, properties: pickerProperties - }, (paths) => { + }, paths => { if (paths && paths.length > 0) { // Remember path in storage for next time @@ -1063,8 +1112,8 @@ export class WindowsManager implements IWindowsService { public getLastActiveWindow(): VSCodeWindow { if (WindowsManager.WINDOWS.length) { - const lastFocussedDate = Math.max.apply(Math, WindowsManager.WINDOWS.map((w) => w.lastFocusTime)); - const res = WindowsManager.WINDOWS.filter((w) => w.lastFocusTime === lastFocussedDate); + const lastFocussedDate = Math.max.apply(Math, WindowsManager.WINDOWS.map(w => w.lastFocusTime)); + const res = WindowsManager.WINDOWS.filter(w => w.lastFocusTime === lastFocussedDate); if (res && res.length) { return res[0]; } @@ -1085,7 +1134,7 @@ export class WindowsManager implements IWindowsService { } // Find it - const res = windowsToTest.filter((w) => { + const res = windowsToTest.filter(w => { // match on workspace if (typeof w.openedWorkspacePath === 'string' && (this.isPathEqual(w.openedWorkspacePath, workspacePath))) { @@ -1131,7 +1180,7 @@ export class WindowsManager implements IWindowsService { } public sendToAll(channel: string, payload: any, windowIdsToIgnore?: number[]): void { - WindowsManager.WINDOWS.forEach((w) => { + WindowsManager.WINDOWS.forEach(w => { if (windowIdsToIgnore && windowIdsToIgnore.indexOf(w.id) >= 0) { return; // do not send if we are instructed to ignore it } @@ -1150,7 +1199,7 @@ export class WindowsManager implements IWindowsService { } public getWindowById(windowId: number): VSCodeWindow { - const res = WindowsManager.WINDOWS.filter((w) => w.id === windowId); + const res = WindowsManager.WINDOWS.filter(w => w.id === windowId); if (res && res.length === 1) { return res[0]; } @@ -1178,7 +1227,7 @@ export class WindowsManager implements IWindowsService { message: nls.localize('appStalled', "The window is no longer responding"), detail: nls.localize('appStalledDetail', "You can reopen or close the window or keep waiting."), noLink: true - }, (result) => { + }, result => { if (result === 0) { vscodeWindow.reload(); } else if (result === 2) { @@ -1197,7 +1246,7 @@ export class WindowsManager implements IWindowsService { message: nls.localize('appCrashed', "The window has crashed"), detail: nls.localize('appCrashedDetail', "We are sorry for the inconvenience! You can reopen the window to continue where you left off."), noLink: true - }, (result) => { + }, result => { if (result === 0) { vscodeWindow.reload(); } else if (result === 1) {