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

implement modal message API

上级 968bd571
......@@ -1411,6 +1411,21 @@ declare module 'vscode' {
isCloseAffordance?: boolean;
}
/**
* Options to configure the behavior of the message.
*
* @see [showInformationMessage](#window.showInformationMessage)
* @see [showWarningMessage](#window.showWarningMessage)
* @see [showErrorMessage](#window.showErrorMessage)
*/
export interface MessageOptions {
/**
* Indicates that this message should be modal.
*/
modal?: boolean;
}
/**
* Options to configure the behavior of the input box UI.
*/
......@@ -3567,6 +3582,7 @@ declare module 'vscode' {
* @return A thenable that resolves to the selected item or `undefined` when being dismissed.
*/
export function showInformationMessage(message: string, ...items: string[]): Thenable<string | undefined>;
export function showInformationMessage(message: string, options: MessageOptions, ...items: string[]): Thenable<string | undefined>;
/**
* Show an information message.
......@@ -3578,6 +3594,7 @@ declare module 'vscode' {
* @return A thenable that resolves to the selected item or `undefined` when being dismissed.
*/
export function showInformationMessage<T extends MessageItem>(message: string, ...items: T[]): Thenable<T | undefined>;
export function showInformationMessage<T extends MessageItem>(message: string, options: MessageOptions, ...items: T[]): Thenable<T | undefined>;
/**
* Show a warning message.
......@@ -3589,6 +3606,7 @@ declare module 'vscode' {
* @return A thenable that resolves to the selected item or `undefined` when being dismissed.
*/
export function showWarningMessage(message: string, ...items: string[]): Thenable<string | undefined>;
export function showWarningMessage(message: string, options: MessageOptions, ...items: string[]): Thenable<string | undefined>;
/**
* Show a warning message.
......@@ -3600,6 +3618,7 @@ declare module 'vscode' {
* @return A thenable that resolves to the selected item or `undefined` when being dismissed.
*/
export function showWarningMessage<T extends MessageItem>(message: string, ...items: T[]): Thenable<T | undefined>;
export function showWarningMessage<T extends MessageItem>(message: string, options: MessageOptions, ...items: T[]): Thenable<T | undefined>;
/**
* Show an error message.
......@@ -3611,6 +3630,7 @@ declare module 'vscode' {
* @return A thenable that resolves to the selected item or `undefined` when being dismissed.
*/
export function showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined>;
export function showErrorMessage(message: string, options: MessageOptions, ...items: string[]): Thenable<string | undefined>;
/**
* Show an error message.
......@@ -3622,6 +3642,7 @@ declare module 'vscode' {
* @return A thenable that resolves to the selected item or `undefined` when being dismissed.
*/
export function showErrorMessage<T extends MessageItem>(message: string, ...items: T[]): Thenable<T | undefined>;
export function showErrorMessage<T extends MessageItem>(message: string, options: MessageOptions, ...items: T[]): Thenable<T | undefined>;
/**
* Shows a selection list.
......
......@@ -255,6 +255,18 @@ export function createApiFactory(initData: IInitData, threadService: IThreadServ
}
};
const emptyMessageOptions: vscode.MessageOptions = Object.create(null);
function parseMessageArguments(args: any[]): { options: vscode.MessageOptions; items: any[]; } {
const [first, ...rest] = args;
if (first && (typeof first === 'string' || first.title)) {
return { options: emptyMessageOptions, items: args };
} else {
return { options: first || emptyMessageOptions, items: rest };
}
}
// namespace: window
const window: typeof vscode.window = {
get activeTextEditor() {
......@@ -287,14 +299,17 @@ export function createApiFactory(initData: IInitData, threadService: IThreadServ
onDidCloseTerminal(listener, thisArg?, disposables?) {
return extHostTerminalService.onDidCloseTerminal(listener, thisArg, disposables);
},
showInformationMessage(message, ...items) {
return extHostMessageService.showMessage(Severity.Info, message, items);
showInformationMessage(message, ...args) {
const { options, items } = parseMessageArguments(args);
return extHostMessageService.showMessage(Severity.Info, message, options, items);
},
showWarningMessage(message, ...items) {
return extHostMessageService.showMessage(Severity.Warning, message, items);
showWarningMessage(message, ...args) {
const { options, items } = parseMessageArguments(args);
return extHostMessageService.showMessage(Severity.Warning, message, options, items);
},
showErrorMessage(message, ...items) {
return extHostMessageService.showMessage(Severity.Error, message, items);
showErrorMessage(message, ...args) {
const { options, items } = parseMessageArguments(args);
return extHostMessageService.showMessage(Severity.Error, message, options, items);
},
showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken) {
return extHostQuickOpen.showQuickPick(items, options, token);
......@@ -325,7 +340,7 @@ export function createApiFactory(initData: IInitData, threadService: IThreadServ
},
// proposed API
sampleFunction: proposedApiFunction(extension, () => {
return extHostMessageService.showMessage(Severity.Info, 'Hello Proposed Api!', []);
return extHostMessageService.showMessage(Severity.Info, 'Hello Proposed Api!', {}, []);
}),
registerTreeExplorerNodeProvider: proposedApiFunction(extension, (providerId: string, provider: vscode.TreeExplorerNodeProvider<any>) => {
return extHostExplorers.registerTreeExplorerNodeProvider(providerId, provider);
......
......@@ -176,7 +176,7 @@ export abstract class MainThreadLanguagesShape {
}
export abstract class MainThreadMessageServiceShape {
$showMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Thenable<number> { throw ni(); }
$showMessage(severity: Severity, message: string, options: vscode.MessageOptions, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Thenable<number> { throw ni(); }
}
export abstract class MainThreadOutputServiceShape {
......
......@@ -17,7 +17,7 @@ export class ExtHostMessageService {
this._proxy = threadService.get(MainContext.MainThreadMessageService);
}
showMessage(severity: Severity, message: string, commands: (string | vscode.MessageItem)[]): Thenable<string | vscode.MessageItem> {
showMessage(severity: Severity, message: string, options: vscode.MessageOptions, commands: (string | vscode.MessageItem)[]): Thenable<string | vscode.MessageItem> {
const items: { title: string; isCloseAffordance: boolean; handle: number; }[] = [];
......@@ -33,7 +33,7 @@ export class ExtHostMessageService {
}
}
return this._proxy.$showMessage(severity, message, items).then(handle => {
return this._proxy.$showMessage(severity, message, options, items).then(handle => {
if (typeof handle === 'number') {
return commands[handle];
}
......
......@@ -5,22 +5,31 @@
'use strict';
import nls = require('vs/nls');
import { IMessageService } from 'vs/platform/message/common/message';
import { IMessageService, IChoiceService } from 'vs/platform/message/common/message';
import Severity from 'vs/base/common/severity';
import { Action } from 'vs/base/common/actions';
import { TPromise as Promise } from 'vs/base/common/winjs.base';
import { MainThreadMessageServiceShape } from './extHost.protocol';
import * as vscode from 'vscode';
export class MainThreadMessageService extends MainThreadMessageServiceShape {
private _messageService: IMessageService;
constructor( @IMessageService messageService: IMessageService) {
constructor(
@IMessageService private _messageService: IMessageService,
@IChoiceService private _choiceService: IChoiceService
) {
super();
this._messageService = messageService;
}
$showMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Thenable<number> {
$showMessage(severity: Severity, message: string, options: vscode.MessageOptions, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Thenable<number> {
if (options.modal) {
return this.showModalMessage(severity, message, commands);
} else {
return this.showMessage(severity, message, commands);
}
}
private showMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Thenable<number> {
return new Promise<number>(resolve => {
......@@ -58,4 +67,27 @@ export class MainThreadMessageService extends MainThreadMessageServiceShape {
});
});
}
private showModalMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Thenable<number> {
let closeAffordanceIndex = -1;
const options = commands.map((command, index) => {
if (command.isCloseAffordance === true) {
closeAffordanceIndex = index;
}
return command.title;
});
if (closeAffordanceIndex === -1) {
if (options.length > 0) {
options.push(nls.localize('cancel', "Cancel"));
} else {
options.push(nls.localize('ok', "OK"));
}
}
return this._choiceService.choose(severity, message, options, true)
.then(result => result === commands.length ? undefined : commands[result].handle);
}
}
......@@ -8,8 +8,9 @@
import * as assert from 'assert';
import { Action } from 'vs/base/common/actions';
import { MainThreadMessageService } from 'vs/workbench/api/node/mainThreadMessageService';
import { TPromise as Promise } from 'vs/base/common/winjs.base';
suite('ExtHostMessageService', function () {
suite('`ExtHostMessageService`', function () {
test('propagte handle on select', function () {
......@@ -19,9 +20,13 @@ suite('ExtHostMessageService', function () {
setImmediate(() => m.actions[0].run());
return () => { };
}
}, <any>{
choose() {
throw new Error('not implemented');
}
});
return service.$showMessage(1, 'h', [{ handle: 42, title: 'a thing', isCloseAffordance: true }]).then(handle => {
return service.$showMessage(1, 'h', {}, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]).then(handle => {
assert.equal(handle, 42);
});
});
......@@ -33,17 +38,21 @@ suite('ExtHostMessageService', function () {
show(sev: number, m: { message; actions: Action[] }) {
actions = m.actions;
}
}, <any>{
choose() {
throw new Error('not implemented');
}
});
// default close action
service.$showMessage(1, '', [{ title: 'a thing', isCloseAffordance: false, handle: 0 }]);
service.$showMessage(1, '', {}, [{ title: 'a thing', isCloseAffordance: false, handle: 0 }]);
assert.equal(actions.length, 2);
let [first, second] = actions;
assert.equal(first.label, 'a thing');
assert.equal(second.label, 'Close');
// override close action
service.$showMessage(1, '', [{ title: 'a thing', isCloseAffordance: true, handle: 0 }]);
service.$showMessage(1, '', {}, [{ title: 'a thing', isCloseAffordance: true, handle: 0 }]);
assert.equal(actions.length, 1);
first = actions[0];
assert.equal(first.label, 'a thing');
......@@ -61,12 +70,71 @@ suite('ExtHostMessageService', function () {
c += 1;
};
}
}, <any>{
choose() {
throw new Error('not implemented');
}
});
service.$showMessage(1, '', [{ title: 'a thing', isCloseAffordance: true, handle: 0 }]);
service.$showMessage(1, '', {}, [{ title: 'a thing', isCloseAffordance: true, handle: 0 }]);
assert.equal(actions.length, 1);
actions[0].run();
assert.equal(c, 1);
});
suite('modal', () => {
test('calls choice service', () => {
const service = new MainThreadMessageService(<any>{
show(sev: number, m: { message; actions: Action[] }) {
throw new Error('not implemented');
}
}, <any>{
choose(severity, message, options, modal) {
assert.equal(severity, 1);
assert.equal(message, 'h');
assert.equal(options.length, 2);
assert.equal(options[1], 'Cancel');
return Promise.as(0);
}
});
return service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]).then(handle => {
assert.equal(handle, 42);
});
});
test('returns undefined when cancelled', () => {
const service = new MainThreadMessageService(<any>{
show(sev: number, m: { message; actions: Action[] }) {
throw new Error('not implemented');
}
}, <any>{
choose(severity, message, options, modal) {
return Promise.as(1);
}
});
return service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]).then(handle => {
assert.equal(handle, undefined);
});
});
test('hides Cancel button when not needed', () => {
const service = new MainThreadMessageService(<any>{
show(sev: number, m: { message; actions: Action[] }) {
throw new Error('not implemented');
}
}, <any>{
choose(severity, message, options, modal) {
assert.equal(options.length, 1);
return Promise.as(0);
}
});
return service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]).then(handle => {
assert.equal(handle, 42);
});
});
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册