main - extract service for handling recent paths and jumplist
This commit is contained in:
parent
4541e70733
commit
2a580b4d68
|
@ -45,6 +45,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
|||
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
|
||||
import { TPromise } from "vs/base/common/winjs.base";
|
||||
import { IWindowsMainService } from "vs/platform/windows/electron-main/windows";
|
||||
import { IHistoryMainService } from "vs/platform/history/electron-main/historyMainService";
|
||||
|
||||
export class CodeApplication {
|
||||
private toDispose: IDisposable[];
|
||||
|
@ -63,7 +64,8 @@ export class CodeApplication {
|
|||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
@ILifecycleService private lifecycleService: ILifecycleService,
|
||||
@IConfigurationService private configurationService: ConfigurationService<any>,
|
||||
@IStorageService private storageService: IStorageService
|
||||
@IStorageService private storageService: IStorageService,
|
||||
@IHistoryMainService private historyService: IHistoryMainService
|
||||
) {
|
||||
this.toDispose = [mainIpcServer, configurationService];
|
||||
|
||||
|
@ -258,8 +260,8 @@ export class CodeApplication {
|
|||
appInstantiationService.createInstance(CodeMenu);
|
||||
|
||||
// Jump List
|
||||
this.windowsMainService.updateWindowsJumpList();
|
||||
this.windowsMainService.onRecentPathsChange(() => this.windowsMainService.updateWindowsJumpList());
|
||||
this.historyService.updateWindowsJumpList();
|
||||
this.historyService.onRecentPathsChange(() => this.historyService.updateWindowsJumpList());
|
||||
|
||||
// Start shared process here
|
||||
this.sharedProcess.spawn();
|
||||
|
|
|
@ -19,7 +19,7 @@ import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiati
|
|||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { ILogService, MainLogService } from 'vs/platform/log/common/log';
|
||||
import { ILogService, LogMainService } from 'vs/platform/log/common/log';
|
||||
import { IStorageService, StorageService } from 'vs/platform/storage/node/storage';
|
||||
import { IBackupMainService } from 'vs/platform/backup/common/backup';
|
||||
import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService';
|
||||
|
@ -33,12 +33,14 @@ import { IURLService } from 'vs/platform/url/common/url';
|
|||
import { URLService } from 'vs/platform/url/electron-main/urlService';
|
||||
import * as fs from 'original-fs';
|
||||
import { CodeApplication } from "vs/code/electron-main/app";
|
||||
import { HistoryMainService, IHistoryMainService } from "vs/platform/history/electron-main/historyMainService";
|
||||
|
||||
function createServices(args: ParsedArgs): IInstantiationService {
|
||||
const services = new ServiceCollection();
|
||||
|
||||
services.set(IEnvironmentService, new SyncDescriptor(EnvironmentService, args, process.execPath));
|
||||
services.set(ILogService, new SyncDescriptor(MainLogService));
|
||||
services.set(ILogService, new SyncDescriptor(LogMainService));
|
||||
services.set(IHistoryMainService, new SyncDescriptor(HistoryMainService));
|
||||
services.set(ILifecycleService, new SyncDescriptor(LifecycleService));
|
||||
services.set(IStorageService, new SyncDescriptor(StorageService));
|
||||
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService));
|
||||
|
|
|
@ -21,6 +21,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
|||
import { tildify } from 'vs/base/common/labels';
|
||||
import { KeybindingsResolver } from "vs/code/electron-main/keyboard";
|
||||
import { IWindowsMainService } from "vs/platform/windows/electron-main/windows";
|
||||
import { IHistoryMainService } from "vs/platform/history/electron-main/historyMainService";
|
||||
|
||||
interface IExtensionViewlet {
|
||||
id: string;
|
||||
|
@ -75,7 +76,8 @@ export class CodeMenu {
|
|||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IWindowsMainService private windowsService: IWindowsMainService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService
|
||||
@ITelemetryService private telemetryService: ITelemetryService,
|
||||
@IHistoryMainService private historyService: IHistoryMainService
|
||||
) {
|
||||
this.extensionViewlets = [];
|
||||
|
||||
|
@ -98,7 +100,7 @@ export class CodeMenu {
|
|||
|
||||
// Listen to some events from window service
|
||||
this.windowsService.onPathsOpen(paths => this.updateMenu());
|
||||
this.windowsService.onRecentPathsChange(paths => this.updateMenu());
|
||||
this.historyService.onRecentPathsChange(paths => this.updateMenu());
|
||||
this.windowsService.onWindowClose(_ => this.onClose(this.windowsService.getWindowCount()));
|
||||
|
||||
// Listen to extension viewlets
|
||||
|
@ -414,7 +416,7 @@ export class CodeMenu {
|
|||
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.windowsService.getRecentPathsList();
|
||||
const { folders, files } = this.historyService.getRecentPathsList();
|
||||
|
||||
// Folders
|
||||
if (folders.length > 0) {
|
||||
|
@ -448,7 +450,7 @@ export class CodeMenu {
|
|||
const openInNewWindow = this.isOptionClick(event);
|
||||
const success = !!this.windowsService.open({ context: OpenContext.MENU, cli: this.environmentService.args, pathsToOpen: [path], forceNewWindow: openInNewWindow });
|
||||
if (!success) {
|
||||
this.windowsService.removeFromRecentPathsList(path);
|
||||
this.historyService.removeFromRecentPathsList(path);
|
||||
}
|
||||
}
|
||||
}, false));
|
||||
|
|
|
@ -13,7 +13,6 @@ import * as types from 'vs/base/common/types';
|
|||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { assign, mixin } from 'vs/base/common/objects';
|
||||
import { IBackupMainService } from 'vs/platform/backup/common/backup';
|
||||
import { trim } from 'vs/base/common/strings';
|
||||
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import { IStorageService } from 'vs/platform/storage/node/storage';
|
||||
import { CodeWindow, IWindowState as ISingleWindowState, defaultWindowState, WindowMode } from 'vs/code/electron-main/window';
|
||||
|
@ -22,7 +21,6 @@ import { IPathWithLineAndColumn, parseLineAndColumnAware } from 'vs/code/node/pa
|
|||
import { ILifecycleService, UnloadReason } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { getPathLabel } from 'vs/base/common/labels';
|
||||
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration } from 'vs/platform/windows/common/windows';
|
||||
import { getLastActiveWindow, findBestWindowOrFolder } from 'vs/code/node/windowsUtils';
|
||||
import CommonEvent, { Emitter } from 'vs/base/common/event';
|
||||
|
@ -30,7 +28,8 @@ import product from 'vs/platform/node/product';
|
|||
import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { isParent, isEqual, isEqualOrParent } from 'vs/platform/files/common/files';
|
||||
import { KeyboardLayoutMonitor } from 'vs/code/electron-main/keyboard';
|
||||
import { IWindowsMainService, IOpenConfiguration, IRecentPathsList } from "vs/platform/windows/electron-main/windows";
|
||||
import { IWindowsMainService, IOpenConfiguration } from "vs/platform/windows/electron-main/windows";
|
||||
import { IHistoryMainService } from "vs/platform/history/electron-main/historyMainService";
|
||||
|
||||
enum WindowError {
|
||||
UNRESPONSIVE,
|
||||
|
@ -70,9 +69,6 @@ export class WindowsManager implements IWindowsMainService {
|
|||
|
||||
_serviceBrand: any;
|
||||
|
||||
private static MAX_TOTAL_RECENT_ENTRIES = 100;
|
||||
|
||||
private static recentPathsListStorageKey = 'openedPathsList';
|
||||
private static workingDirPickerStorageKey = 'pickerWorkingDir';
|
||||
private static windowsStateStorageKey = 'windowsState';
|
||||
|
||||
|
@ -83,9 +79,6 @@ export class WindowsManager implements IWindowsMainService {
|
|||
private windowsState: IWindowsState;
|
||||
private lastClosedWindowState: IWindowState;
|
||||
|
||||
private _onRecentPathsChange = new Emitter<void>();
|
||||
onRecentPathsChange: CommonEvent<void> = this._onRecentPathsChange.event;
|
||||
|
||||
private _onWindowReady = new Emitter<CodeWindow>();
|
||||
onWindowReady: CommonEvent<CodeWindow> = this._onWindowReady.event;
|
||||
|
||||
|
@ -105,7 +98,8 @@ export class WindowsManager implements IWindowsMainService {
|
|||
@ILifecycleService private lifecycleService: ILifecycleService,
|
||||
@IBackupMainService private backupService: IBackupMainService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService,
|
||||
@IConfigurationService private configurationService: IConfigurationService
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IHistoryMainService private historyService: IHistoryMainService
|
||||
) { }
|
||||
|
||||
public ready(initialUserEnv: platform.IProcessEnvironment): void {
|
||||
|
@ -521,7 +515,7 @@ export class WindowsManager implements IWindowsMainService {
|
|||
});
|
||||
|
||||
if (recentPaths.length) {
|
||||
this.addToRecentPathsList(recentPaths);
|
||||
this.historyService.addToRecentPathsList(recentPaths);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -531,103 +525,7 @@ export class WindowsManager implements IWindowsMainService {
|
|||
return arrays.distinct(usedWindows);
|
||||
}
|
||||
|
||||
public addToRecentPathsList(paths: { path: string; isFile?: boolean; }[]): void {
|
||||
if (!paths || !paths.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mru = this.getRecentPathsList();
|
||||
paths.forEach(p => {
|
||||
const { path, isFile } = p;
|
||||
|
||||
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);
|
||||
this._onRecentPathsChange.fire();
|
||||
}
|
||||
|
||||
public removeFromRecentPathsList(path: string): void;
|
||||
public removeFromRecentPathsList(paths: string[]): void;
|
||||
public removeFromRecentPathsList(arg1: any): void {
|
||||
let paths: string[];
|
||||
if (Array.isArray(arg1)) {
|
||||
paths = arg1;
|
||||
} else {
|
||||
paths = [arg1];
|
||||
}
|
||||
|
||||
const mru = this.getRecentPathsList();
|
||||
let update = false;
|
||||
|
||||
paths.forEach(path => {
|
||||
let index = mru.files.indexOf(path);
|
||||
if (index >= 0) {
|
||||
mru.files.splice(index, 1);
|
||||
update = true;
|
||||
}
|
||||
|
||||
index = mru.folders.indexOf(path);
|
||||
if (index >= 0) {
|
||||
mru.folders.splice(index, 1);
|
||||
update = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (update) {
|
||||
this.storageService.setItem(WindowsManager.recentPathsListStorageKey, mru);
|
||||
this._onRecentPathsChange.fire();
|
||||
}
|
||||
}
|
||||
|
||||
public clearRecentPathsList(): void {
|
||||
this.storageService.setItem(WindowsManager.recentPathsListStorageKey, { folders: [], files: [] });
|
||||
app.clearRecentDocuments();
|
||||
|
||||
// Event
|
||||
this._onRecentPathsChange.fire();
|
||||
}
|
||||
|
||||
public getRecentPathsList(workspacePath?: string, filesToOpen?: IPath[]): IRecentPathsList {
|
||||
let files: string[];
|
||||
let folders: string[];
|
||||
|
||||
// Get from storage
|
||||
const storedRecents = this.storageService.getItem<IRecentPathsList>(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): platform.IProcessEnvironment {
|
||||
return assign({}, this.initialUserEnv, openConfig.userEnv || {});
|
||||
|
@ -705,7 +603,7 @@ export class WindowsManager implements IWindowsMainService {
|
|||
{ workspacePath: candidate };
|
||||
}
|
||||
} catch (error) {
|
||||
this.removeFromRecentPathsList(candidate); // since file does not seem to exist anymore, remove from recent
|
||||
this.historyService.removeFromRecentPathsList(candidate); // since file does not seem to exist anymore, remove from recent
|
||||
|
||||
if (ignoreFileNotFound) {
|
||||
return { filePath: candidate, createFilePath: true }; // assume this is a file that does not yet exist
|
||||
|
@ -1182,68 +1080,6 @@ export class WindowsManager implements IWindowsMainService {
|
|||
this._onWindowClose.fire(win.id);
|
||||
}
|
||||
|
||||
public updateWindowsJumpList(): void {
|
||||
if (!platform.isWindows) {
|
||||
return; // only on windows
|
||||
}
|
||||
|
||||
const jumpList: Electron.JumpListCategory[] = [];
|
||||
|
||||
// Tasks
|
||||
jumpList.push({
|
||||
type: 'tasks',
|
||||
items: [
|
||||
{
|
||||
type: 'task',
|
||||
title: nls.localize('newWindow', "New Window"),
|
||||
description: nls.localize('newWindowDesc', "Opens a new window"),
|
||||
program: process.execPath,
|
||||
args: '-n', // force new window
|
||||
iconPath: process.execPath,
|
||||
iconIndex: 0
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// Recent Folders
|
||||
if (this.getRecentPathsList().folders.length > 0) {
|
||||
|
||||
// The user might have meanwhile removed items from the jump list and we have to respect that
|
||||
// so we need to update our list of recent paths with the choice of the user to not add them again
|
||||
// Also: Windows will not show our custom category at all if there is any entry which was removed
|
||||
// by the user! See https://github.com/Microsoft/vscode/issues/15052
|
||||
this.removeFromRecentPathsList(app.getJumpListSettings().removedItems.map(r => trim(r.args, '"')));
|
||||
|
||||
// Add entries
|
||||
jumpList.push({
|
||||
type: 'custom',
|
||||
name: nls.localize('recentFolders', "Recent Folders"),
|
||||
items: this.getRecentPathsList().folders.slice(0, 7 /* limit number of entries here */).map(folder => {
|
||||
return <Electron.JumpListItem>{
|
||||
type: 'task',
|
||||
title: path.basename(folder) || folder, // use the base name to show shorter entries in the list
|
||||
description: nls.localize('folderDesc', "{0} {1}", path.basename(folder), getPathLabel(path.dirname(folder))),
|
||||
program: process.execPath,
|
||||
args: `"${folder}"`, // open folder (use quotes to support paths with whitespaces)
|
||||
iconPath: 'explorer.exe', // simulate folder icon
|
||||
iconIndex: 0
|
||||
};
|
||||
}).filter(i => !!i)
|
||||
});
|
||||
}
|
||||
|
||||
// Recent
|
||||
jumpList.push({
|
||||
type: 'recent' // this enables to show files in the "recent" category
|
||||
});
|
||||
|
||||
try {
|
||||
app.setJumpList(jumpList);
|
||||
} catch (error) {
|
||||
this.logService.log('#setJumpList', error); // since setJumpList is relatively new API, make sure to guard for errors
|
||||
}
|
||||
}
|
||||
|
||||
public quit(): void {
|
||||
|
||||
// If the user selected to exit from an extension development host window, do not quit, but just
|
||||
|
|
220
src/vs/platform/history/electron-main/historyMainService.ts
Normal file
220
src/vs/platform/history/electron-main/historyMainService.ts
Normal file
|
@ -0,0 +1,220 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as path from 'path';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { trim } from 'vs/base/common/strings';
|
||||
import { IStorageService } from 'vs/platform/storage/node/storage';
|
||||
import { app } from 'electron';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { getPathLabel } from 'vs/base/common/labels';
|
||||
import { IPath } from 'vs/platform/windows/common/windows';
|
||||
import CommonEvent, { Emitter } from 'vs/base/common/event';
|
||||
import { createDecorator } from "vs/platform/instantiation/common/instantiation";
|
||||
|
||||
export const IHistoryMainService = createDecorator<IHistoryMainService>('historyMainService');
|
||||
|
||||
export interface IRecentPathsList {
|
||||
folders: string[];
|
||||
files: string[];
|
||||
}
|
||||
|
||||
export interface IHistoryMainService {
|
||||
_serviceBrand: any;
|
||||
|
||||
// events
|
||||
onRecentPathsChange: CommonEvent<void>;
|
||||
|
||||
// methods
|
||||
|
||||
addToRecentPathsList(paths: { path: string; isFile?: boolean; }[]): void;
|
||||
getRecentPathsList(workspacePath?: string, filesToOpen?: IPath[]): IRecentPathsList;
|
||||
removeFromRecentPathsList(path: string): void;
|
||||
removeFromRecentPathsList(paths: string[]): void;
|
||||
clearRecentPathsList(): void;
|
||||
updateWindowsJumpList(): void;
|
||||
}
|
||||
|
||||
export class HistoryMainService implements IHistoryMainService {
|
||||
|
||||
private static MAX_TOTAL_RECENT_ENTRIES = 100;
|
||||
|
||||
private static recentPathsListStorageKey = 'openedPathsList';
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
private _onRecentPathsChange = new Emitter<void>();
|
||||
onRecentPathsChange: CommonEvent<void> = this._onRecentPathsChange.event;
|
||||
|
||||
constructor(
|
||||
@IStorageService private storageService: IStorageService,
|
||||
@ILogService private logService: ILogService
|
||||
) {
|
||||
}
|
||||
|
||||
public addToRecentPathsList(paths: { path: string; isFile?: boolean; }[]): void {
|
||||
if (!paths || !paths.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mru = this.getRecentPathsList();
|
||||
paths.forEach(p => {
|
||||
const { path, isFile } = p;
|
||||
|
||||
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, HistoryMainService.MAX_TOTAL_RECENT_ENTRIES);
|
||||
mru.files = mru.files.slice(0, HistoryMainService.MAX_TOTAL_RECENT_ENTRIES);
|
||||
});
|
||||
|
||||
this.storageService.setItem(HistoryMainService.recentPathsListStorageKey, mru);
|
||||
this._onRecentPathsChange.fire();
|
||||
}
|
||||
|
||||
public removeFromRecentPathsList(path: string): void;
|
||||
public removeFromRecentPathsList(paths: string[]): void;
|
||||
public removeFromRecentPathsList(arg1: any): void {
|
||||
let paths: string[];
|
||||
if (Array.isArray(arg1)) {
|
||||
paths = arg1;
|
||||
} else {
|
||||
paths = [arg1];
|
||||
}
|
||||
|
||||
const mru = this.getRecentPathsList();
|
||||
let update = false;
|
||||
|
||||
paths.forEach(path => {
|
||||
let index = mru.files.indexOf(path);
|
||||
if (index >= 0) {
|
||||
mru.files.splice(index, 1);
|
||||
update = true;
|
||||
}
|
||||
|
||||
index = mru.folders.indexOf(path);
|
||||
if (index >= 0) {
|
||||
mru.folders.splice(index, 1);
|
||||
update = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (update) {
|
||||
this.storageService.setItem(HistoryMainService.recentPathsListStorageKey, mru);
|
||||
this._onRecentPathsChange.fire();
|
||||
}
|
||||
}
|
||||
|
||||
public clearRecentPathsList(): void {
|
||||
this.storageService.setItem(HistoryMainService.recentPathsListStorageKey, { folders: [], files: [] });
|
||||
app.clearRecentDocuments();
|
||||
|
||||
// Event
|
||||
this._onRecentPathsChange.fire();
|
||||
}
|
||||
|
||||
public getRecentPathsList(workspacePath?: string, filesToOpen?: IPath[]): IRecentPathsList {
|
||||
let files: string[];
|
||||
let folders: string[];
|
||||
|
||||
// Get from storage
|
||||
const storedRecents = this.storageService.getItem<IRecentPathsList>(HistoryMainService.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 };
|
||||
}
|
||||
|
||||
public updateWindowsJumpList(): void {
|
||||
if (!platform.isWindows) {
|
||||
return; // only on windows
|
||||
}
|
||||
|
||||
const jumpList: Electron.JumpListCategory[] = [];
|
||||
|
||||
// Tasks
|
||||
jumpList.push({
|
||||
type: 'tasks',
|
||||
items: [
|
||||
{
|
||||
type: 'task',
|
||||
title: nls.localize('newWindow', "New Window"),
|
||||
description: nls.localize('newWindowDesc', "Opens a new window"),
|
||||
program: process.execPath,
|
||||
args: '-n', // force new window
|
||||
iconPath: process.execPath,
|
||||
iconIndex: 0
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// Recent Folders
|
||||
if (this.getRecentPathsList().folders.length > 0) {
|
||||
|
||||
// The user might have meanwhile removed items from the jump list and we have to respect that
|
||||
// so we need to update our list of recent paths with the choice of the user to not add them again
|
||||
// Also: Windows will not show our custom category at all if there is any entry which was removed
|
||||
// by the user! See https://github.com/Microsoft/vscode/issues/15052
|
||||
this.removeFromRecentPathsList(app.getJumpListSettings().removedItems.map(r => trim(r.args, '"')));
|
||||
|
||||
// Add entries
|
||||
jumpList.push({
|
||||
type: 'custom',
|
||||
name: nls.localize('recentFolders', "Recent Folders"),
|
||||
items: this.getRecentPathsList().folders.slice(0, 7 /* limit number of entries here */).map(folder => {
|
||||
return <Electron.JumpListItem>{
|
||||
type: 'task',
|
||||
title: path.basename(folder) || folder, // use the base name to show shorter entries in the list
|
||||
description: nls.localize('folderDesc', "{0} {1}", path.basename(folder), getPathLabel(path.dirname(folder))),
|
||||
program: process.execPath,
|
||||
args: `"${folder}"`, // open folder (use quotes to support paths with whitespaces)
|
||||
iconPath: 'explorer.exe', // simulate folder icon
|
||||
iconIndex: 0
|
||||
};
|
||||
}).filter(i => !!i)
|
||||
});
|
||||
}
|
||||
|
||||
// Recent
|
||||
jumpList.push({
|
||||
type: 'recent' // this enables to show files in the "recent" category
|
||||
});
|
||||
|
||||
try {
|
||||
app.setJumpList(jumpList);
|
||||
} catch (error) {
|
||||
this.logService.log('#setJumpList', error); // since setJumpList is relatively new API, make sure to guard for errors
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ export interface ILogService {
|
|||
log(...args: any[]): void;
|
||||
}
|
||||
|
||||
export class MainLogService implements ILogService {
|
||||
export class LogMainService implements ILogService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@ export interface IWindowsMainService {
|
|||
onWindowClose: Event<number>;
|
||||
onWindowReload: Event<number>;
|
||||
onPathsOpen: Event<IPath[]>;
|
||||
onRecentPathsChange: Event<void>;
|
||||
|
||||
// methods
|
||||
ready(initialUserEnv: IProcessEnvironment): void;
|
||||
|
@ -63,12 +62,6 @@ export interface IWindowsMainService {
|
|||
getWindowById(windowId: number): ICodeWindow;
|
||||
getWindows(): ICodeWindow[];
|
||||
getWindowCount(): number;
|
||||
addToRecentPathsList(paths: { path: string; isFile?: boolean; }[]): void;
|
||||
getRecentPathsList(workspacePath?: string, filesToOpen?: IPath[]): IRecentPathsList;
|
||||
removeFromRecentPathsList(path: string): void;
|
||||
removeFromRecentPathsList(paths: string[]): void;
|
||||
clearRecentPathsList(): void;
|
||||
updateWindowsJumpList(): void;
|
||||
quit(): void;
|
||||
}
|
||||
|
||||
|
@ -86,11 +79,6 @@ export interface IOpenConfiguration {
|
|||
initialStartup?: boolean;
|
||||
}
|
||||
|
||||
export interface IRecentPathsList {
|
||||
folders: string[];
|
||||
files: string[];
|
||||
}
|
||||
|
||||
export interface ISharedProcess {
|
||||
whenReady(): TPromise<void>;
|
||||
toggle(): void;
|
||||
|
|
|
@ -18,6 +18,7 @@ import { IURLService } from 'vs/platform/url/common/url';
|
|||
import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ILifecycleService } from "vs/platform/lifecycle/electron-main/lifecycleMain";
|
||||
import { IWindowsMainService, ISharedProcess } from "vs/platform/windows/electron-main/windows";
|
||||
import { IHistoryMainService } from "vs/platform/history/electron-main/historyMainService";
|
||||
|
||||
export class WindowsService implements IWindowsService, IDisposable {
|
||||
|
||||
|
@ -33,7 +34,8 @@ export class WindowsService implements IWindowsService, IDisposable {
|
|||
@IWindowsMainService private windowsMainService: IWindowsMainService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
@IURLService urlService: IURLService,
|
||||
@ILifecycleService private lifecycleService: ILifecycleService
|
||||
@ILifecycleService private lifecycleService: ILifecycleService,
|
||||
@IHistoryMainService private historyService: IHistoryMainService
|
||||
) {
|
||||
chain(urlService.onOpenURL)
|
||||
.filter(uri => uri.authority === 'file' && !!uri.path)
|
||||
|
@ -124,19 +126,19 @@ export class WindowsService implements IWindowsService, IDisposable {
|
|||
}
|
||||
|
||||
addToRecentlyOpen(paths: { path: string, isFile?: boolean }[]): TPromise<void> {
|
||||
this.windowsMainService.addToRecentPathsList(paths);
|
||||
this.historyService.addToRecentPathsList(paths);
|
||||
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
removeFromRecentlyOpen(paths: string[]): TPromise<void> {
|
||||
this.windowsMainService.removeFromRecentPathsList(paths);
|
||||
this.historyService.removeFromRecentPathsList(paths);
|
||||
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
clearRecentPathsList(): TPromise<void> {
|
||||
this.windowsMainService.clearRecentPathsList();
|
||||
this.historyService.clearRecentPathsList();
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
|
@ -144,7 +146,7 @@ export class WindowsService implements IWindowsService, IDisposable {
|
|||
const codeWindow = this.windowsMainService.getWindowById(windowId);
|
||||
|
||||
if (codeWindow) {
|
||||
const { files, folders } = this.windowsMainService.getRecentPathsList(codeWindow.config.workspacePath, codeWindow.config.filesToOpen);
|
||||
const { files, folders } = this.historyService.getRecentPathsList(codeWindow.config.workspacePath, codeWindow.config.filesToOpen);
|
||||
return TPromise.as({ files, folders });
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue