提交 c409f85c 编写于 作者: J Joao Moreno

Merge remote-tracking branch 'origin/master'

......@@ -17,10 +17,10 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
export const ILifecycleService = createDecorator<ILifecycleService>('lifecycleService');
export enum UnloadReason {
CLOSE,
QUIT,
RELOAD,
LOAD
CLOSE = 1,
QUIT = 2,
RELOAD = 3,
LOAD = 4
}
export interface ILifecycleService {
......@@ -264,4 +264,4 @@ export class LifecycleService implements ILifecycleService {
public isQuitRequested(): boolean {
return !!this.quitRequested;
}
}
\ No newline at end of file
}
......@@ -486,10 +486,11 @@ const editorConfiguration: IConfigurationNode = {
'default': EDITOR_DEFAULTS.contribInfo.folding,
'description': nls.localize('folding', "Controls whether the editor has code folding enabled")
},
'editor.hideFoldIcons': {
'type': 'boolean',
'default': EDITOR_DEFAULTS.contribInfo.hideFoldIcons,
'description': nls.localize('hideFoldIcons', "Controls whether the fold icons on the gutter are automatically hidden.")
'editor.showFoldingControls': {
'type': 'string',
'enum': ['always', 'mouseover'],
'default': EDITOR_DEFAULTS.contribInfo.showFoldingControls,
'description': nls.localize('showFoldingControls', "Controls whether the fold controls on the gutter are automatically hidden.")
},
'editor.matchBrackets': {
'type': 'boolean',
......
......@@ -420,10 +420,10 @@ export interface IEditorOptions {
*/
folding?: boolean;
/**
* Enable automatic hiding of non-collapsed fold icons in the gutter.
* Defaults to true.
* Controls whether the fold actions in the gutter stay always visible or hide unless the mouse is over the gutter.
* Defaults to 'mouseover'.
*/
hideFoldIcons?: boolean;
showFoldingControls?: 'always' | 'mouseover';
/**
* Enable highlighting of matching brackets.
* Defaults to true.
......@@ -736,7 +736,7 @@ export interface EditorContribOptions {
readonly occurrencesHighlight: boolean;
readonly codeLens: boolean;
readonly folding: boolean;
readonly hideFoldIcons: boolean;
readonly showFoldingControls: 'always' | 'mouseover';
readonly matchBrackets: boolean;
}
......@@ -1045,7 +1045,7 @@ export class InternalEditorOptions {
&& a.occurrencesHighlight === b.occurrencesHighlight
&& a.codeLens === b.codeLens
&& a.folding === b.folding
&& a.hideFoldIcons === b.hideFoldIcons
&& a.showFoldingControls === b.showFoldingControls
&& a.matchBrackets === b.matchBrackets
);
}
......@@ -1542,7 +1542,7 @@ export class EditorOptionsValidator {
occurrencesHighlight: _boolean(opts.occurrencesHighlight, defaults.occurrencesHighlight),
codeLens: _boolean(opts.codeLens, defaults.codeLens) && _boolean(opts.referenceInfos, true),
folding: _boolean(opts.folding, defaults.folding),
hideFoldIcons: _boolean(opts.hideFoldIcons, defaults.hideFoldIcons),
showFoldingControls: _stringSet<'always' | 'mouseover'>(opts.showFoldingControls, defaults.showFoldingControls, ['always', 'mouseover']),
matchBrackets: _boolean(opts.matchBrackets, defaults.matchBrackets),
};
}
......@@ -1949,7 +1949,7 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = {
occurrencesHighlight: true,
codeLens: true,
folding: true,
hideFoldIcons: true,
showFoldingControls: 'mouseover',
matchBrackets: true,
},
};
......@@ -36,7 +36,7 @@ export class FoldingController implements IFoldingController {
private editor: ICodeEditor;
private _isEnabled: boolean;
private _hideFoldIcons: boolean;
private _showFoldingControls: 'always' | 'mouseover';
private globalToDispose: IDisposable[];
private computeToken: number;
......@@ -49,7 +49,7 @@ export class FoldingController implements IFoldingController {
constructor(editor: ICodeEditor) {
this.editor = editor;
this._isEnabled = this.editor.getConfiguration().contribInfo.folding;
this._hideFoldIcons = this.editor.getConfiguration().contribInfo.hideFoldIcons;
this._showFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls;
this.globalToDispose = [];
this.localToDispose = [];
......@@ -63,9 +63,9 @@ export class FoldingController implements IFoldingController {
if (oldIsEnabled !== this._isEnabled) {
this.onModelChanged();
}
let oldHideFoldIcons = this._hideFoldIcons;
this._hideFoldIcons = this.editor.getConfiguration().contribInfo.hideFoldIcons;
if (oldHideFoldIcons !== this._hideFoldIcons) {
let oldShowFoldingControls = this._showFoldingControls;
this._showFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls;
if (oldShowFoldingControls !== this._showFoldingControls) {
this.updateHideFoldIconClass();
}
}));
......@@ -85,7 +85,7 @@ export class FoldingController implements IFoldingController {
private updateHideFoldIconClass(): void {
let domNode = this.editor.getDomNode();
if (domNode) {
dom.toggleClass(domNode, 'alwaysShowFoldIcons', this._hideFoldIcons === false);
dom.toggleClass(domNode, 'alwaysShowFoldIcons', this._showFoldingControls === 'always');
}
}
......
......@@ -57,21 +57,24 @@ export class SnippetController2 {
overwriteBefore: number = 0, overwriteAfter: number = 0,
undoStopBefore: boolean = true, undoStopAfter: boolean = true
): void {
if (this._snippet) {
this.cancel();
}
this._snippet = new SnippetSession(this._editor, template, overwriteBefore, overwriteAfter);
if (undoStopBefore) {
this._editor.getModel().pushStackElement();
}
this._snippet.insert();
if (!this._snippet) {
// insert with new session
this._snippet = new SnippetSession(this._editor, template, overwriteBefore, overwriteAfter);
this._snippet.insert();
this._snippetListener = [
this._editor.onDidChangeModel(() => this.cancel()),
this._editor.onDidChangeCursorSelection(() => this._updateState())
];
} else {
// insert nested
this._snippet.insertNested(template, overwriteBefore, overwriteAfter);
}
if (undoStopAfter) {
this._editor.getModel().pushStackElement();
}
this._snippetListener = [
this._editor.onDidChangeModel(() => this.cancel()),
this._editor.onDidChangeCursorSelection(() => this._updateState())
];
this._updateState();
}
......
......@@ -291,6 +291,18 @@ export class SnippetSession {
this._editor.setSelections(newSelections);
}
insertNested(template: string, overwriteBefore: number = 0, overwriteAfter: number = 0): void {
const { edits } = SnippetSession.makeInsertEditsAndSnippets(
this._editor, template, overwriteBefore, overwriteAfter
);
const model = this._editor.getModel();
const selections = this._editor.getSelections();
const newSelections = model.pushEditOperations(selections, edits, () => {
return this._move(true);
});
this._editor.setSelections(newSelections);
}
next(): void {
const newSelections = this._move(true);
this._editor.setSelections(newSelections);
......
......@@ -2978,10 +2978,10 @@ declare module monaco.editor {
*/
folding?: boolean;
/**
* Enable automatic hiding of non-collapsed fold icons in the gutter.
* Defaults to true.
* Controls whether the fold actions in the gutter stay always visible or hide unless the mouse is over the gutter.
* Defaults to 'mouseover'.
*/
hideFoldIcons?: boolean;
showFoldingControls?: 'always' | 'mouseover';
/**
* Enable highlighting of matching brackets.
* Defaults to true.
......@@ -3239,7 +3239,7 @@ declare module monaco.editor {
readonly occurrencesHighlight: boolean;
readonly codeLens: boolean;
readonly folding: boolean;
readonly hideFoldIcons: boolean;
readonly showFoldingControls: 'always' | 'mouseover';
readonly matchBrackets: boolean;
}
......
......@@ -26,16 +26,22 @@ export interface ShutdownEvent {
export enum ShutdownReason {
/** Window is closed */
CLOSE,
CLOSE = 1,
/** Application is quit */
QUIT,
QUIT = 2,
/** Window is reloaded */
RELOAD,
RELOAD = 3,
/** Other configuration loaded into window */
LOAD
LOAD = 4
}
export enum StartupKind {
NewWindow = 1,
ReloadedWindow = 3,
ReopenedWindow = 4,
}
/**
......@@ -46,17 +52,22 @@ export interface ILifecycleService {
_serviceBrand: any;
/**
* Value indicates how this window got loaded.
*/
readonly startupKind: StartupKind;
/**
* A flag indicating if the application is in the process of shutting down. This will be true
* before the onWillShutdown event is fired and false if the shutdown is being vetoed.
*/
willShutdown: boolean;
readonly willShutdown: boolean;
/**
* Fired before shutdown happens. Allows listeners to veto against the
* shutdown.
*/
onWillShutdown: Event<ShutdownEvent>;
readonly onWillShutdown: Event<ShutdownEvent>;
/**
* Fired when no client is preventing the shutdown from happening. Can be used to dispose heavy resources
......@@ -64,12 +75,13 @@ export interface ILifecycleService {
*
* The event carries a shutdown reason that indicates how the shutdown was triggered.
*/
onShutdown: Event<ShutdownReason>;
readonly onShutdown: Event<ShutdownReason>;
}
export const NullLifecycleService: ILifecycleService = {
_serviceBrand: null,
startupKind: StartupKind.NewWindow,
willShutdown: false,
onWillShutdown: () => ({ dispose() { } }),
onShutdown: (reason) => ({ dispose() { } })
};
\ No newline at end of file
};
......@@ -177,6 +177,7 @@ export class UpdateService implements IUpdateService {
this._availableUpdate = data;
this._onUpdateAvailable.fire({ url: update.url, version: update.version });
this.state = State.UpdateAvailable;
this.telemetryService.publicLog('update:available', { explicit, version: update.version, currentVersion: product.commit });
} else {
const data: IUpdate = {
......
......@@ -132,6 +132,7 @@ export class WorkbenchShell {
private windowIPCService: IWindowIPCService;
private timerService: ITimerService;
private themeService: WorkbenchThemeService;
private lifecycleService: ILifecycleService;
private container: HTMLElement;
private toUnbind: IDisposable[];
......@@ -235,7 +236,10 @@ export class WorkbenchShell {
theme: this.themeService.getColorTheme().id,
language: platform.language,
experiments: this.telemetryService.getExperiments(),
pinnedViewlets: info.pinnedViewlets
pinnedViewlets: info.pinnedViewlets,
restoredViewlet: info.restoredViewlet,
restoredEditors: info.restoredEditors.length,
startupKind: this.lifecycleService.startupKind
});
// Telemetry: startup metrics
......@@ -355,6 +359,7 @@ export class WorkbenchShell {
this.toUnbind.push(lifecycleService.onShutdown(reason => saveFontInfo(this.storageService)));
serviceCollection.set(ILifecycleService, lifecycleService);
disposables.add(lifecycleTelemetry(this.telemetryService, lifecycleService));
this.lifecycleService = lifecycleService;
const extensionManagementChannel = getDelayedChannel<IExtensionManagementChannel>(sharedProcess.then(c => c.getChannel('extensions')));
serviceCollection.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementChannelClient, extensionManagementChannel));
......
......@@ -120,6 +120,8 @@ export interface IWorkbenchStartedInfo {
restoreViewletDuration: number;
restoreEditorsDuration: number;
pinnedViewlets: string[];
restoredViewlet: string;
restoredEditors: string[];
}
export interface IWorkbenchCallbacks {
......@@ -294,8 +296,8 @@ export class Workbench implements IPartService {
// Restore last opened viewlet
let viewletRestoreStopWatch: StopWatch;
let viewletIdToRestore: string;
if (!this.sideBarHidden) {
let viewletIdToRestore: string;
if (this.shouldRestoreLastOpenedViewlet()) {
viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE);
......@@ -321,6 +323,7 @@ export class Workbench implements IPartService {
// Load Editors
const editorRestoreStopWatch = StopWatch.create();
const restoredEditors: string[] = [];
compositeAndEditorPromises.push(this.resolveEditorsToOpen().then(inputs => {
let editorOpenPromise: TPromise<IEditor[]>;
if (inputs.length) {
......@@ -329,9 +332,16 @@ export class Workbench implements IPartService {
editorOpenPromise = this.editorPart.restoreEditors();
}
return editorOpenPromise.then(() => {
return editorOpenPromise.then(editors => {
this.onEditorsChanged(); // make sure we show the proper background in the editor area
editorRestoreStopWatch.stop();
for (const editor of editors) {
if (editor.input) {
restoredEditors.push(editor.input.getName());
} else {
restoredEditors.push(`other:${editor.getId()}`);
}
}
});
}));
......@@ -350,6 +360,8 @@ export class Workbench implements IPartService {
restoreViewletDuration: viewletRestoreStopWatch ? Math.round(viewletRestoreStopWatch.elapsed()) : 0,
restoreEditorsDuration: Math.round(editorRestoreStopWatch.elapsed()),
pinnedViewlets: this.activitybarPart.getPinned(),
restoredViewlet: viewletIdToRestore,
restoredEditors
});
}
......
......@@ -17,6 +17,7 @@ import { VIEWLET_ID } from 'vs/workbench/parts/scm/common/scm';
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actionRegistry';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/parts/extensions/common/extensions';
import { ISCMService } from 'vs/workbench/services/scm/common/scm';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
......@@ -41,7 +42,8 @@ export class SwitchProvider extends Action {
id = SwitchProvider.ID,
label = SwitchProvider.LABEL,
@ISCMService private scmService: ISCMService,
@IQuickOpenService private quickOpenService: IQuickOpenService
@IQuickOpenService private quickOpenService: IQuickOpenService,
@IViewletService private viewletService: IViewletService
) {
super('scm.switchprovider', 'Switch SCM Provider', '', true);
}
......@@ -51,6 +53,16 @@ export class SwitchProvider extends Action {
label: provider.label,
run: () => this.scmService.activeProvider = provider
}));
picks.push({
label: localize('installAdditionalSCMProviders', "Install Additional SCM Providers..."), run: () => {
this.viewletService.openViewlet(EXTENSIONS_VIEWLET_ID, true).then(viewlet => viewlet as IExtensionsViewlet)
.then(viewlet => {
viewlet.search('category:"SCM Providers" @sort:installs');
viewlet.focus();
});
return this.scmService.activeProvider;
}
});
return this.quickOpenService.pick(picks);
}
......
......@@ -16,6 +16,8 @@ import { IAction, Action } from 'vs/base/common/actions';
import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem';
import { ContextSubMenu } from 'vs/platform/contextview/browser/contextView';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/parts/extensions/common/extensions';
import { ISCMService, ISCMProvider, ISCMResource, ISCMResourceGroup } from 'vs/workbench/services/scm/common/scm';
import { getSCMResourceContextKey } from './scmUtil';
......@@ -38,6 +40,21 @@ class SwitchProviderAction extends Action {
}
}
class InstallAdditionalSCMProviders extends Action {
constructor(private viewletService: IViewletService) {
super('scm.installAdditionalSCMProviders', localize('installAdditionalSCMProviders', "Install Additional SCM Providers..."), '', true);
}
run(): TPromise<void> {
return this.viewletService.openViewlet(EXTENSIONS_VIEWLET_ID, true).then(viewlet => viewlet as IExtensionsViewlet)
.then(viewlet => {
viewlet.search('category:"SCM Providers" @sort:installs');
viewlet.focus();
});
}
}
export class SCMMenus implements IDisposable {
private disposables: IDisposable[] = [];
......@@ -52,7 +69,8 @@ export class SCMMenus implements IDisposable {
constructor(
@IContextKeyService private contextKeyService: IContextKeyService,
@ISCMService private scmService: ISCMService,
@IMenuService private menuService: IMenuService
@IMenuService private menuService: IMenuService,
@IViewletService private viewletService: IViewletService
) {
this.setActiveProvider(this.scmService.activeProvider);
this.scmService.onDidChangeProvider(this.setActiveProvider, this, this.disposables);
......@@ -92,7 +110,7 @@ export class SCMMenus implements IDisposable {
}
getTitleSecondaryActions(): IAction[] {
const providerSwitchActions = this.scmService.providers
const providerSwitchActions: IAction[] = this.scmService.providers
.map(p => new SwitchProviderAction(p, this.scmService));
let result = [];
......@@ -100,14 +118,16 @@ export class SCMMenus implements IDisposable {
if (this.titleSecondaryActions.length > 0) {
result = result.concat(this.titleSecondaryActions);
}
if (providerSwitchActions.length > 0) {
providerSwitchActions.push(new Separator());
}
providerSwitchActions.push(new InstallAdditionalSCMProviders(this.viewletService));
if (result.length > 0 && providerSwitchActions.length > 0) {
if (result.length > 0) {
result.push(new Separator());
}
if (providerSwitchActions.length > 0) {
result.push(new ContextSubMenu(localize('switch provider', "Switch SCM Provider..."), providerSwitchActions));
}
result.push(new ContextSubMenu(localize('switch provider', "Switch SCM Provider..."), providerSwitchActions));
return result;
}
......
......@@ -7,26 +7,46 @@
import { TPromise } from 'vs/base/common/winjs.base';
import Severity from 'vs/base/common/severity';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { ILifecycleService, ShutdownEvent, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
import { ILifecycleService, ShutdownEvent, ShutdownReason, StartupKind } from 'vs/platform/lifecycle/common/lifecycle';
import { IMessageService } from 'vs/platform/message/common/message';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IWindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService';
import { ipcRenderer as ipc } from 'electron';
import Event, { Emitter } from 'vs/base/common/event';
export class LifecycleService implements ILifecycleService {
private static readonly _lastShutdownReasonKey = 'lifecyle.lastShutdownReason';
public _serviceBrand: any;
private _onWillShutdown = new Emitter<ShutdownEvent>();
private _onShutdown = new Emitter<ShutdownReason>();
private readonly _onWillShutdown = new Emitter<ShutdownEvent>();
private readonly _onShutdown = new Emitter<ShutdownReason>();
private readonly _startupKind: StartupKind;
private _willShutdown: boolean;
constructor(
@IMessageService private messageService: IMessageService,
@IWindowIPCService private windowService: IWindowIPCService
@IMessageService private _messageService: IMessageService,
@IWindowIPCService private _windowService: IWindowIPCService,
@IStorageService private _storageService: IStorageService
) {
this.registerListeners();
this._registerListeners();
const lastShutdownReason = this._storageService.getInteger(LifecycleService._lastShutdownReasonKey, StorageScope.WORKSPACE);
this._storageService.remove(LifecycleService._lastShutdownReasonKey, StorageScope.WORKSPACE);
if (lastShutdownReason === ShutdownReason.RELOAD) {
this._startupKind = StartupKind.ReloadedWindow;
} else if (lastShutdownReason === ShutdownReason.LOAD) {
this._startupKind = StartupKind.ReopenedWindow;
} else {
this._startupKind = StartupKind.NewWindow;
}
console.log(this.startupKind);
}
public get startupKind(): StartupKind {
return this._startupKind;
}
public get willShutdown(): boolean {
......@@ -41,16 +61,18 @@ export class LifecycleService implements ILifecycleService {
return this._onShutdown.event;
}
private registerListeners(): void {
const windowId = this.windowService.getWindowId();
private _registerListeners(): void {
const windowId = this._windowService.getWindowId();
// Main side indicates that window is about to unload, check for vetos
ipc.on('vscode:beforeUnload', (event, reply: { okChannel: string, cancelChannel: string, reason: ShutdownReason }) => {
this._willShutdown = true;
this._storageService.store(LifecycleService._lastShutdownReasonKey, JSON.stringify(reply.reason), StorageScope.WORKSPACE);
// trigger onWillShutdown events and veto collecting
this.onBeforeUnload(reply.reason).done(veto => {
if (veto) {
this._storageService.remove(LifecycleService._lastShutdownReasonKey, StorageScope.WORKSPACE);
this._willShutdown = false; // reset this flag since the shutdown has been vetoed!
ipc.send(reply.cancelChannel, windowId);
} else {
......@@ -92,11 +114,11 @@ export class LifecycleService implements ILifecycleService {
}
}, err => {
// error, treated like a veto, done
this.messageService.show(Severity.Error, toErrorMessage(err));
this._messageService.show(Severity.Error, toErrorMessage(err));
lazyValue = true;
}));
}
}
return TPromise.join(promises).then(() => lazyValue);
}
}
\ No newline at end of file
}
......@@ -28,7 +28,7 @@ import { IEditorInput, IEditorOptions, Position, Direction, IEditor, IResourceIn
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IMessageService, IConfirmation } from 'vs/platform/message/common/message';
import { IWorkspace, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ILifecycleService, ShutdownEvent, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
import { ILifecycleService, ShutdownEvent, ShutdownReason, StartupKind } from 'vs/platform/lifecycle/common/lifecycle';
import { EditorStacksModel } from 'vs/workbench/common/editor/editorStacksModel';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
......@@ -855,6 +855,7 @@ export class TestLifecycleService implements ILifecycleService {
public _serviceBrand: any;
public willShutdown: boolean;
public startupKind: StartupKind;
private _onWillShutdown = new Emitter<ShutdownEvent>();
private _onShutdown = new Emitter<ShutdownReason>();
......@@ -1023,4 +1024,4 @@ export class TestThemeService implements IThemeService {
onThemeChange(participant: IThemingParticipant): IDisposable {
return { dispose: () => { } };
}
}
\ No newline at end of file
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册