提交 daeac8e6 编写于 作者: B Benjamin Pasero

Merge branch 'master' into fix-21692

......@@ -278,6 +278,7 @@ export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocumen
const startAngle = '<';
const endAngle = '>';
const escape = '\\';
const question = '?';
const currentHtmlNode = <HtmlNode>currentNode;
let start = new vscode.Position(0, 0);
......@@ -324,6 +325,10 @@ export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocumen
foundSpace = true;
continue;
}
if (char === question && textToBackTrack[i] === startAngle) {
i--;
continue;
}
if (char !== startAngle && char !== endAngle) {
continue;
}
......
......@@ -7,7 +7,7 @@ import * as interfaces from './interfaces';
import { loadMessageBundle } from 'vscode-nls';
const localize = loadMessageBundle();
export default class MergeDectorator implements vscode.Disposable {
export default class MergeDecorator implements vscode.Disposable {
private decorations: { [key: string]: vscode.TextEditorDecorationType } = {};
......@@ -249,4 +249,4 @@ export default class MergeDectorator implements vscode.Disposable {
}
});
}
}
\ No newline at end of file
}
......@@ -3,7 +3,7 @@
"version": "0.0.1",
"description": "Dependencies shared by all extensions",
"dependencies": {
"typescript": "2.7.0-insiders.20171214"
"typescript": "2.7.0-insiders.20180108"
},
"scripts": {
"postinstall": "node ./postinstall"
......
......@@ -8,6 +8,7 @@ import * as Proto from '../protocol';
import { ITypeScriptServiceClient } from '../typescriptService';
import { tsTextSpanToVsRange } from '../utils/convert';
import { escapeRegExp } from '../utils/regexp';
export class ReferencesCodeLens extends CodeLens {
constructor(
......@@ -138,7 +139,7 @@ export abstract class TypeScriptBaseCodeLensProvider implements CodeLensProvider
const range = tsTextSpanToVsRange(span);
const text = document.getText(range);
const identifierMatch = new RegExp(`^(.*?(\\b|\\W))${(item.text || '').replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}(\\b|\\W)`, 'gm');
const identifierMatch = new RegExp(`^(.*?(\\b|\\W))${escapeRegExp(item.text || '')}(\\b|\\W)`, 'gm');
const match = identifierMatch.exec(text);
const prefixLength = match ? match.index + match[1].length : 0;
const startOffset = document.offsetAt(new Position(range.start.line, range.start.character)) + prefixLength;
......
......@@ -21,38 +21,53 @@ import { CommandManager, Command } from '../utils/commandManager';
const localize = nls.loadMessageBundle();
class MyCompletionItem extends CompletionItem {
public readonly source: string | undefined;
public readonly useCodeSnippet: boolean;
constructor(
public readonly position: Position,
public readonly document: TextDocument,
entry: Proto.CompletionEntry,
public readonly tsEntry: Proto.CompletionEntry,
enableDotCompletions: boolean,
useCodeSnippetsOnMethodSuggest: boolean
) {
super(entry.name);
this.source = entry.source;
super(tsEntry.name);
if (entry.isRecommended) {
if (tsEntry.isRecommended) {
// Make sure isRecommended property always comes first
// https://github.com/Microsoft/vscode/issues/40325
this.sortText = '\0' + entry.sortText;
} else if (entry.source) {
this.sortText = '\0' + tsEntry.sortText;
} else if (tsEntry.source) {
// De-prioritze auto-imports
// https://github.com/Microsoft/vscode/issues/40311
this.sortText = '\uffff' + entry.sortText;
this.sortText = '\uffff' + tsEntry.sortText;
} else {
this.sortText = entry.sortText;
this.sortText = tsEntry.sortText;
}
this.kind = MyCompletionItem.convertKind(entry.kind);
this.kind = MyCompletionItem.convertKind(tsEntry.kind);
this.position = position;
this.commitCharacters = MyCompletionItem.getCommitCharacters(enableDotCompletions, !useCodeSnippetsOnMethodSuggest, entry.kind);
this.commitCharacters = MyCompletionItem.getCommitCharacters(enableDotCompletions, !useCodeSnippetsOnMethodSuggest, tsEntry.kind);
this.useCodeSnippet = useCodeSnippetsOnMethodSuggest && (this.kind === CompletionItemKind.Function || this.kind === CompletionItemKind.Method);
if (entry.replacementSpan) {
this.range = tsTextSpanToVsRange(entry.replacementSpan);
if (tsEntry.replacementSpan) {
this.range = tsTextSpanToVsRange(tsEntry.replacementSpan);
}
if (typeof (tsEntry as any).insertText === 'string') {
this.insertText = (tsEntry as any).insertText as string;
if (tsEntry.replacementSpan) {
this.range = tsTextSpanToVsRange(tsEntry.replacementSpan);
if (this.insertText[0] === '[') { // o.x -> o['x']
this.filterText = '.' + this.label;
}
}
}
if (tsEntry.kindModifiers.match(/\boptional\b/)) {
this.insertText = this.label;
this.filterText = this.label;
this.label += '?';
}
}
......@@ -271,8 +286,9 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
try {
const args: Proto.CompletionsRequestArgs = {
...vsPositionToTsFileLocation(file, position),
includeExternalModuleExports: config.autoImportSuggestions
};
includeExternalModuleExports: config.autoImportSuggestions,
includeInsertTextCompletions: true
} as Proto.CompletionsRequestArgs;
const msg = await this.client.execute('completions', args, token);
// This info has to come from the tsserver. See https://github.com/Microsoft/TypeScript/issues/2831
// let isMemberCompletion = false;
......@@ -342,7 +358,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
const args: Proto.CompletionDetailsRequestArgs = {
...vsPositionToTsFileLocation(filepath, item.position),
entryNames: [
item.source ? { name: item.label, source: item.source } : item.label
item.tsEntry.source ? { name: item.tsEntry.name, source: item.tsEntry.source } : item.tsEntry.name
]
};
......@@ -398,7 +414,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
if (detail && item.useCodeSnippet) {
const shouldCompleteFunction = await this.isValidFunctionCompletionContext(filepath, item.position);
if (shouldCompleteFunction) {
item.insertText = this.snippetForFunctionCall(detail);
item.insertText = this.snippetForFunctionCall(item, detail);
}
return item;
}
......@@ -426,12 +442,15 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
}
}
private snippetForFunctionCall(detail: Proto.CompletionEntryDetails): SnippetString {
private snippetForFunctionCall(
item: CompletionItem,
detail: Proto.CompletionEntryDetails
): SnippetString {
let hasOptionalParameters = false;
let hasAddedParameters = false;
const snippet = new SnippetString();
snippet.appendText(detail.name);
snippet.appendText(item.label || item.insertText as string);
snippet.appendText('(');
let parenCount = 0;
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export function escapeRegExp(text: string) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
\ No newline at end of file
......@@ -2,6 +2,6 @@
# yarn lockfile v1
typescript@2.7.0-insiders.20171214:
version "2.7.0-insiders.20171214"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.0-insiders.20171214.tgz#841344ddae5f498a97c0435fcd12860480050e71"
typescript@2.7.0-insiders.20180108:
version "2.7.0-insiders.20180108"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.0-insiders.20180108.tgz#b9230ca5a0020e92133f63e6a4272f8c1b301bdb"
......@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
.monaco-list {
position: relative;
height: 100%;
width: 100%;
white-space: nowrap;
......
......@@ -341,6 +341,22 @@ export function matchesFuzzy(word: string, wordToMatchAgainst: string, enableSep
return enableSeparateSubstringMatching ? fuzzySeparateFilter(word, wordToMatchAgainst) : fuzzyContiguousFilter(word, wordToMatchAgainst);
}
export function skipScore(pattern: string, word: string, patternMaxWhitespaceIgnore?: number): [number, number[]] {
pattern = pattern.toLowerCase();
word = word.toLowerCase();
const matches: number[] = [];
let idx = 0;
for (let pos = 0; pos < pattern.length; ++pos) {
const thisIdx = word.indexOf(pattern.charAt(pos), idx);
if (thisIdx >= 0) {
matches.push(thisIdx);
idx = thisIdx + 1;
}
}
return [matches.length, matches];
}
//#region --- fuzzyScore ---
export function createMatches(position: number[]): IMatch[] {
......
......@@ -233,7 +233,7 @@ export function listProcesses(rootPid: number): Promise<ProcessItem> {
});
} else { // OS X & Linux
const CMD = 'ps -ax -o pid=,ppid=,pcpu=,pmem=,command=';
const CMD = '/bin/ps -ax -o pid=,ppid=,pcpu=,pmem=,command=';
const PID_CMD = /^\s*([0-9]+)\s+([0-9]+)\s+([0-9]+\.[0-9]+)\s+([0-9]+\.[0-9]+)\s+(.+)$/;
exec(CMD, { maxBuffer: 1000 * 1024 }, (err, stdout, stderr) => {
......
......@@ -82,14 +82,6 @@ suite('History Navigator', () => {
assert.deepEqual(['4', '5'], toArray(testObject));
});
test('adding existing element changes the position', function () {
let testObject = new HistoryNavigator(['1', '2', '3', '4'], 2);
testObject.add('2');
assert.deepEqual(['4', '2'], toArray(testObject));
});
test('add resets the navigator to last', function () {
let testObject = new HistoryNavigator(['1', '2', '3', '4'], 3);
......
......@@ -148,7 +148,9 @@ function formatProcessList(info: IMainProcessInfo, rootProcess: ProcessItem): st
output.push('CPU %\tMem MB\t PID\tProcess');
formatProcessItem(mapPidToWindowTitle, output, rootProcess, 0);
if (rootProcess) {
formatProcessItem(mapPidToWindowTitle, output, rootProcess, 0);
}
return output.join('\n');
}
......
......@@ -161,7 +161,7 @@ class FormatOnType implements editorCommon.IEditorContribution {
return;
}
EditOperationsCommand.execute(this.editor, edits);
EditOperationsCommand.execute(this.editor, edits, true);
alertFormattingEdits(edits);
}, (err) => {
......@@ -244,7 +244,7 @@ class FormatOnPaste implements editorCommon.IEditorContribution {
if (!state.validate(this.editor) || isFalsyOrEmpty(edits)) {
return;
}
EditOperationsCommand.execute(this.editor, edits);
EditOperationsCommand.execute(this.editor, edits, false);
alertFormattingEdits(edits);
});
}
......@@ -280,7 +280,7 @@ export abstract class AbstractFormatAction extends EditorAction {
return;
}
EditOperationsCommand.execute(editor, edits);
EditOperationsCommand.execute(editor, edits, false);
alertFormattingEdits(edits);
editor.focus();
}, err => {
......
......@@ -11,16 +11,21 @@ import * as editorCommon from 'vs/editor/common/editorCommon';
import { Selection } from 'vs/editor/common/core/selection';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ITextModel, EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model';
import { EditOperation } from 'vs/editor/common/core/editOperation';
export class EditOperationsCommand implements editorCommon.ICommand {
static execute(editor: ICodeEditor, edits: TextEdit[]) {
static execute(editor: ICodeEditor, edits: TextEdit[], asCommand: boolean) {
const cmd = new EditOperationsCommand(edits, editor.getSelection());
if (typeof cmd._newEol === 'number') {
editor.getModel().setEOL(cmd._newEol);
}
editor.pushUndoStop();
editor.executeCommand('formatEditsCommand', cmd);
if (!asCommand) {
editor.executeEdits('formatEditsCommand', cmd._edits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text)));
} else {
editor.executeCommand('formatEditsCommand', cmd);
}
editor.pushUndoStop();
}
......
......@@ -396,9 +396,14 @@ class OpenLinkAction extends EditorAction {
return;
}
let link = linkDetector.getLinkOccurrence(editor.getPosition());
if (link) {
linkDetector.openLinkOccurrence(link, false);
let selections = editor.getSelections();
for (let sel of selections) {
let link = linkDetector.getLinkOccurrence(sel.getEndPosition());
if (link) {
linkDetector.openLinkOccurrence(link, false);
}
}
}
}
......
......@@ -19,19 +19,20 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { ReferencesModel, OneReference } from './referencesModel';
import { ReferencesModel } from './referencesModel';
import { ReferenceWidget, LayoutData } from './referencesWidget';
import { Range } from 'vs/editor/common/core/range';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { Position } from 'vs/editor/common/core/position';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { Location } from 'vs/editor/common/modes';
export const ctxReferenceSearchVisible = new RawContextKey<boolean>('referenceSearchVisible', false);
export interface RequestOptions {
getMetaTitle(model: ReferencesModel): string;
onGoto?: (reference: OneReference) => TPromise<any>;
onGoto?: (reference: Location) => TPromise<any>;
}
export class ReferencesController implements editorCommon.IEditorContribution {
......@@ -189,7 +190,7 @@ export class ReferencesController implements editorCommon.IEditorContribution {
this._requestIdPool += 1; // Cancel pending requests
}
private _gotoReference(ref: OneReference): void {
private _gotoReference(ref: Location): void {
this._widget.hide();
this._ignoreModelChangeEvent = true;
......@@ -222,7 +223,7 @@ export class ReferencesController implements editorCommon.IEditorContribution {
});
}
public openReference(ref: OneReference, sideBySide: boolean): void {
public openReference(ref: Location, sideBySide: boolean): void {
const { uri, range } = ref;
this._editorService.openEditor({
resource: uri,
......
......@@ -43,6 +43,7 @@ import URI from 'vs/base/common/uri';
import { TrackedRangeStickiness, IModelDeltaDecoration } from 'vs/editor/common/model';
import { WorkbenchTree } from 'vs/platform/list/browser/listService';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { Location } from 'vs/editor/common/modes';
class DecorationsManager implements IDisposable {
......@@ -500,7 +501,7 @@ export interface LayoutData {
export interface SelectionEvent {
kind: 'goto' | 'show' | 'side' | 'open';
source: 'editor' | 'tree' | 'title';
element: OneReference;
element: Location;
}
export const ctxReferenceWidgetSearchTreeFocused = new RawContextKey<boolean>('referenceSearchTreeFocused', true);
......@@ -731,11 +732,12 @@ export class ReferenceWidget extends PeekViewWidget {
this._disposeOnNewModel.push(this._model.onDidChangeReferenceRange(reference => this._tree.refresh(reference)));
// listen on editor
this._disposeOnNewModel.push(this._preview.onMouseDown((e) => {
if (e.event.detail === 2) {
this._disposeOnNewModel.push(this._preview.onMouseDown(e => {
const { event, target } = e;
if (event.detail === 2) {
this._onDidSelectReference.fire({
element: this._getFocusedReference(),
kind: (e.event.ctrlKey || e.event.metaKey) ? 'side' : 'open',
element: { uri: this._getFocusedReference().uri, range: target.range },
kind: (event.ctrlKey || event.metaKey) ? 'side' : 'open',
source: 'editor'
});
}
......
......@@ -5,7 +5,7 @@
'use strict';
import { fuzzyScore, fuzzyScoreGracefulAggressive } from 'vs/base/common/filters';
import { fuzzyScore, fuzzyScoreGracefulAggressive, skipScore } from 'vs/base/common/filters';
import { ISuggestSupport, ISuggestResult } from 'vs/editor/common/modes';
import { ISuggestionItem, SnippetConfig } from './suggest';
import { isDisposable } from 'vs/base/common/lifecycle';
......@@ -185,11 +185,8 @@ export class CompletionModel {
continue;
}
item.score = match[0];
item.matches = [];
match = scoreFn(word, suggestion.label, suggestion.overwriteBefore);
if (match) {
item.matches = match[1];
}
item.matches = skipScore(word, suggestion.label)[1];
} else {
// by default match `word` against the `label`
let match = scoreFn(word, suggestion.label, suggestion.overwriteBefore);
......
......@@ -15,19 +15,23 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { domEvent } from 'vs/base/browser/event';
import { Emitter } from 'vs/base/common/event';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { memoize } from 'vs/base/common/decorators';
const _altKey = new class extends Emitter<boolean> {
class AltKeyEmitter extends Emitter<boolean> {
private _subscriptions: IDisposable[] = [];
private _isPressed: boolean;
constructor() {
private constructor(contextMenuService: IContextMenuService) {
super();
this._subscriptions.push(domEvent(document.body, 'keydown')(e => this.isPressed = e.altKey));
this._subscriptions.push(domEvent(document.body, 'keyup')(e => this.isPressed = false));
this._subscriptions.push(domEvent(document.body, 'mouseleave')(e => this.isPressed = false));
this._subscriptions.push(domEvent(document.body, 'blur')(e => this.isPressed = false));
// Workaround since we do not get any events while a context menu is shown
this._subscriptions.push(contextMenuService.onDidContextMenu(() => this.isPressed = false));
}
get isPressed(): boolean {
......@@ -39,21 +43,27 @@ const _altKey = new class extends Emitter<boolean> {
this.fire(this._isPressed);
}
@memoize
static getInstance(contextMenuService: IContextMenuService) {
return new AltKeyEmitter(contextMenuService);
}
dispose() {
super.dispose();
this._subscriptions = dispose(this._subscriptions);
}
};
}
export function fillInActions(menu: IMenu, options: IMenuActionOptions, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, isPrimaryGroup: (group: string) => boolean = group => group === 'navigation'): void {
export function fillInActions(menu: IMenu, options: IMenuActionOptions, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, contextMenuService: IContextMenuService, isPrimaryGroup: (group: string) => boolean = group => group === 'navigation'): void {
const groups = menu.getActions(options);
if (groups.length === 0) {
return;
}
const altKey = AltKeyEmitter.getInstance(contextMenuService);
for (let tuple of groups) {
let [group, actions] = tuple;
if (_altKey.isPressed) {
if (altKey.isPressed) {
actions = actions.map(a => !!a.alt ? a.alt : a);
}
......@@ -97,9 +107,9 @@ export function fillInActions(menu: IMenu, options: IMenuActionOptions, target:
}
export function createActionItem(action: IAction, keybindingService: IKeybindingService, messageService: IMessageService): ActionItem {
export function createActionItem(action: IAction, keybindingService: IKeybindingService, messageService: IMessageService, contextMenuService: IContextMenuService): ActionItem {
if (action instanceof MenuItemAction) {
return new MenuItemActionItem(action, keybindingService, messageService);
return new MenuItemActionItem(action, keybindingService, messageService, contextMenuService);
}
return undefined;
}
......@@ -111,7 +121,8 @@ export class MenuItemActionItem extends ActionItem {
constructor(
action: MenuItemAction,
@IKeybindingService private _keybindingService: IKeybindingService,
@IMessageService protected _messageService: IMessageService
@IMessageService protected _messageService: IMessageService,
@IContextMenuService private _contextMenuService: IContextMenuService
) {
super(undefined, action, { icon: !!action.class, label: !action.class });
}
......@@ -144,7 +155,7 @@ export class MenuItemActionItem extends ActionItem {
}
};
this._callOnDispose.push(_altKey.event(value => {
this._callOnDispose.push(AltKeyEmitter.getInstance(this._contextMenuService).event(value => {
altDown = value;
updateAltState();
}));
......
......@@ -25,6 +25,7 @@ export interface ICommandAction {
category?: string | ILocalizedString;
iconClass?: string;
iconPath?: string;
precondition?: ContextKeyExpr;
}
export interface IMenuItem {
......@@ -175,15 +176,16 @@ export class MenuItemAction extends ExecuteCommandAction {
item: ICommandAction,
alt: ICommandAction,
options: IMenuActionOptions,
@IContextKeyService contextKeyService: IContextKeyService,
@ICommandService commandService: ICommandService
) {
typeof item.title === 'string' ? super(item.id, item.title, commandService) : super(item.id, item.title.value, commandService);
this._cssClass = item.iconClass;
this._enabled = true;
this._enabled = !item.precondition || contextKeyService.contextMatchesRules(item.precondition);
this._options = options || {};
this.item = item;
this.alt = alt ? new MenuItemAction(alt, undefined, this._options, commandService) : undefined;
this.alt = alt ? new MenuItemAction(alt, undefined, this._options, contextKeyService, commandService) : undefined;
}
run(...args: any[]): TPromise<any> {
......
......@@ -73,7 +73,7 @@ export class Menu implements IMenu {
const activeActions: MenuItemAction[] = [];
for (const item of items) {
if (this._contextKeyService.contextMatchesRules(item.when)) {
const action = new MenuItemAction(item.command, item.alt, options, this._commandService);
const action = new MenuItemAction(item.command, item.alt, options, this._contextKeyService, this._commandService);
action.order = item.order; //TODO@Ben order is menu item property, not an action property
activeActions.push(action);
}
......
......@@ -10,7 +10,6 @@ import { ICommandService, ICommandEvent, CommandsRegistry } from 'vs/platform/co
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import Event, { Emitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ILogService } from 'vs/platform/log/common/log';
export class CommandService extends Disposable implements ICommandService {
......@@ -25,7 +24,6 @@ export class CommandService extends Disposable implements ICommandService {
constructor(
@IInstantiationService private _instantiationService: IInstantiationService,
@IExtensionService private _extensionService: IExtensionService,
@IContextKeyService private _contextKeyService: IContextKeyService,
@ILogService private _logService: ILogService
) {
super();
......@@ -53,12 +51,6 @@ export class CommandService extends Disposable implements ICommandService {
if (!command) {
return TPromise.wrapError(new Error(`command '${id}' not found`));
}
if (command.precondition && !this._contextKeyService.contextMatchesRules(command.precondition)) {
// not enabled
return TPromise.wrapError(new Error('NOT_ENABLED'));
}
try {
this._onWillExecuteCommand.fire({ commandId: id });
const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler].concat(args));
......
......@@ -9,7 +9,6 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { TypeConstraint, validateConstraints } from 'vs/base/common/types';
import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation';
import Event from 'vs/base/common/event';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { LinkedList } from 'vs/base/common/linkedList';
export const ICommandService = createDecorator<ICommandService>('commandService');
......@@ -35,7 +34,6 @@ export interface ICommandHandler {
export interface ICommand {
id: string;
handler: ICommandHandler;
precondition?: ContextKeyExpr;
description?: ICommandHandlerDescription;
}
......
......@@ -12,9 +12,6 @@ import { CommandService } from 'vs/platform/commands/common/commandService';
import { IExtensionService, ExtensionPointContribution, IExtensionDescription, IExtensionHostInformation, ProfileSession } from 'vs/platform/extensions/common/extensions';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IExtensionPoint } from 'vs/platform/extensions/common/extensionsRegistry';
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
import { SimpleConfigurationService } from 'vs/editor/standalone/browser/simpleServices';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import Event, { Emitter } from 'vs/base/common/event';
import { NullLogService } from 'vs/platform/log/common/log';
......@@ -75,7 +72,7 @@ suite('CommandService', function () {
lastEvent = activationEvent;
return super.activateByEvent(activationEvent);
}
}, new ContextKeyService(new SimpleConfigurationService()), new NullLogService());
}, new NullLogService());
return service.executeCommand('foo').then(() => {
assert.ok(lastEvent, 'onCommand:foo');
......@@ -93,7 +90,7 @@ suite('CommandService', function () {
activateByEvent(activationEvent: string): TPromise<void> {
return TPromise.wrapError<void>(new Error('bad_activate'));
}
}, new ContextKeyService(new SimpleConfigurationService()), new NullLogService());
}, new NullLogService());
return service.executeCommand('foo').then(() => assert.ok(false), err => {
assert.equal(err.message, 'bad_activate');
......@@ -109,7 +106,7 @@ suite('CommandService', function () {
whenInstalledExtensionsRegistered() {
return new TPromise<boolean>(_resolve => { /*ignore*/ });
}
}, new ContextKeyService(new SimpleConfigurationService()), new NullLogService());
}, new NullLogService());
service.executeCommand('bar');
assert.equal(callCounter, 1);
......@@ -126,7 +123,7 @@ suite('CommandService', function () {
whenInstalledExtensionsRegistered() {
return new TPromise<boolean>(_resolve => { resolveFunc = _resolve; });
}
}, new ContextKeyService(new SimpleConfigurationService()), new NullLogService());
}, new NullLogService());
let r = service.executeCommand('bar');
assert.equal(callCounter, 0);
......@@ -139,32 +136,4 @@ suite('CommandService', function () {
assert.equal(callCounter, 1);
});
});
test('honor command-precondition', function () {
let contextKeyService = new ContextKeyService(new SimpleConfigurationService());
let commandService = new CommandService(
new InstantiationService(),
new SimpleExtensionService(),
contextKeyService,
new NullLogService()
);
let counter = 0;
let reg = CommandsRegistry.registerCommand({
id: 'bar',
handler: () => { counter += 1; },
precondition: ContextKeyExpr.has('foocontext')
});
return commandService.executeCommand('bar').then(() => {
assert.throws(() => { });
}, () => {
contextKeyService.setContext('foocontext', true);
return commandService.executeCommand('bar');
}).then(() => {
assert.equal(counter, 1);
reg.dispose();
});
});
});
......@@ -6,7 +6,6 @@
import * as assert from 'assert';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
suite('Command Tests', function () {
......@@ -77,21 +76,4 @@ suite('Command Tests', function () {
assert.equal(CommandsRegistry.getCommands()['test3'].handler.apply(undefined, [undefined, 1]), true);
});
test('CommandsRegistry with precondition', function () {
let r1 = CommandsRegistry.registerCommand('foo', () => { });
const precondition = new RawContextKey<boolean>('ddd', false);
let r2 = CommandsRegistry.registerCommand({
id: 'bar',
handler: () => { },
precondition
});
assert.ok(CommandsRegistry.getCommand('bar').precondition === precondition);
assert.equal(CommandsRegistry.getCommand('foo').precondition, undefined);
r1.dispose();
r2.dispose();
});
});
......@@ -8,11 +8,14 @@ import { ContextMenuHandler } from './contextMenuHandler';
import { IContextViewService, IContextMenuService, IContextMenuDelegate } from './contextView';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IMessageService } from 'vs/platform/message/common/message';
import Event, { Emitter } from 'vs/base/common/event';
export class ContextMenuService implements IContextMenuService {
public _serviceBrand: any;
private contextMenuHandler: ContextMenuHandler;
private _onDidContextMenu = new Emitter<void>();
constructor(container: HTMLElement, telemetryService: ITelemetryService, messageService: IMessageService, contextViewService: IContextViewService) {
this.contextMenuHandler = new ContextMenuHandler(container, contextViewService, telemetryService, messageService);
......@@ -30,5 +33,10 @@ export class ContextMenuService implements IContextMenuService {
public showContextMenu(delegate: IContextMenuDelegate): void {
this.contextMenuHandler.showContextMenu(delegate);
this._onDidContextMenu.fire();
}
public get onDidContextMenu(): Event<void> {
return this._onDidContextMenu.event;
}
}
\ No newline at end of file
}
......@@ -8,6 +8,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { IAction, IActionRunner, Action } from 'vs/base/common/actions';
import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { TPromise } from 'vs/base/common/winjs.base';
import Event from 'vs/base/common/event';
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
......@@ -24,7 +25,7 @@ export interface IContextViewDelegate {
getAnchor(): HTMLElement | { x: number; y: number; };
render(container: HTMLElement): IDisposable;
canRelayout?: boolean; // Default: true
onDOMEvent?(e: Event, activeElement: HTMLElement): void;
onDOMEvent?(e: any, activeElement: HTMLElement): void;
onHide?(data?: any): void;
}
......@@ -33,6 +34,8 @@ export const IContextMenuService = createDecorator<IContextMenuService>('context
export interface IContextMenuService {
_serviceBrand: any;
showContextMenu(delegate: IContextMenuDelegate): void;
// TODO@isidor these event should be removed once we get async context menus
onDidContextMenu: Event<void>;
}
export interface IEvent {
......
......@@ -155,7 +155,12 @@ export class ExtensionManagementService implements IExtensionManagementService {
.then(
metadata => this.installFromZipPath(identifier, zipPath, metadata, manifest),
error => this.installFromZipPath(identifier, zipPath, null, manifest))
.then(() => this.logService.info('Successfully installed the extension:', identifier.id), e => this.logService.error('Failed to install the extension:', identifier.id, e.message));
.then(
() => this.logService.info('Successfully installed the extension:', identifier.id),
e => {
this.logService.error('Failed to install the extension:', identifier.id, e.message);
return TPromise.wrapError(e);
});
}
return null;
}),
......@@ -208,7 +213,7 @@ export class ExtensionManagementService implements IExtensionManagementService {
.then(dependenciesToInstall => this.downloadAndInstallExtensions(metadata ? dependenciesToInstall.filter(d => d.identifier.uuid !== metadata.id) : dependenciesToInstall))
.then(() => local, error => {
this.uninstallExtension(local);
return TPromise.wrapError(error);
return TPromise.wrapError(new Error(nls.localize('errorInstallingDependencies', "Error while installing dependencies. {0}", error instanceof Error ? error.message : error)));
});
}
return local;
......@@ -321,14 +326,18 @@ export class ExtensionManagementService implements IExtensionManagementService {
private getDependenciesToInstall(dependencies: string[]): TPromise<IGalleryExtension[]> {
if (dependencies.length) {
return this.galleryService.loadAllDependencies(dependencies.map(id => (<IExtensionIdentifier>{ id })))
.then(allDependencies => this.getInstalled()
.then(local => {
return allDependencies.filter(d => {
const extensionId = getLocalExtensionIdFromGallery(d, d.version);
return local.every(({ identifier }) => identifier.id !== extensionId);
});
}));
return this.getInstalled()
.then(installed => {
const uninstalledDeps = dependencies.filter(d => installed.every(i => getGalleryExtensionId(i.manifest.publisher, i.manifest.name) !== d));
if (uninstalledDeps.length) {
return this.galleryService.loadAllDependencies(uninstalledDeps.map(id => (<IExtensionIdentifier>{ id })))
.then(allDependencies => allDependencies.filter(d => {
const extensionId = getLocalExtensionIdFromGallery(d, d.version);
return installed.every(({ identifier }) => identifier.id !== extensionId);
}));
}
return [];
});
}
return TPromise.as([]);
}
......
......@@ -14,7 +14,6 @@ import { IDelegate, IRenderer } from 'vs/base/browser/ui/list/list';
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
import { attachListStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import Event, { Emitter } from 'vs/base/common/event';
import { InputFocusedContextKey } from 'vs/platform/workbench/common/contextkeys';
export type ListWidget = List<any> | PagedList<any> | ITree;
......@@ -149,9 +148,6 @@ export class WorkbenchPagedList<T> extends PagedList<T> {
export class WorkbenchTree extends Tree {
private _onFocusChange = new Emitter<boolean>();
readonly onFocusChange: Event<boolean> = this._onFocusChange.event;
readonly contextKeyService: IContextKeyService;
private disposables: IDisposable[] = [];
......
......@@ -220,7 +220,7 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
}
private _editsWithEditor(editor: ICodeEditor, edits: ISingleEditOperation[]): void {
EditOperationsCommand.execute(editor, edits);
EditOperationsCommand.execute(editor, edits, false);
}
private _editWithModel(model: ITextModel, edits: ISingleEditOperation[]): void {
......
......@@ -94,7 +94,7 @@ export class NoTabsTitleControl extends TitleControl {
// - click on toolbar: should trigger actions within
// - mouse click: do not focus group if there are more than one as it otherwise makes group DND funky
// - touch: always focus
else if ((this.stacks.groups.length === 1 || !(e instanceof MouseEvent)) && !DOM.isAncestor((e.target || e.srcElement) as HTMLElement, this.editorActionsToolbar.getContainer().getHTMLElement())) {
else if ((this.stacks.groups.length === 1 || !(e instanceof MouseEvent)) && !DOM.isAncestor(((e as GestureEvent).initialTarget || e.target || e.srcElement) as HTMLElement, this.editorActionsToolbar.getContainer().getHTMLElement())) {
this.editorGroupService.focusGroup(group);
}
}
......
......@@ -642,7 +642,7 @@ export class TabsTitleControl extends TitleControl {
}
const { editor, position } = this.toTabContext(index);
if (!this.isTabActionBar((e.target || e.srcElement) as HTMLElement)) {
if (!this.isTabActionBar(((e as GestureEvent).initialTarget || e.target || e.srcElement) as HTMLElement)) {
setTimeout(() => this.editorService.openEditor(editor, null, position).done(null, errors.onUnexpectedError)); // timeout to keep focus in editor after mouse up
}
......
......@@ -270,7 +270,7 @@ export abstract class TitleControl extends Themable implements ITitleAreaControl
// Check extensions
if (!actionItem) {
actionItem = createActionItem(action, this.keybindingService, this.messageService);
actionItem = createActionItem(action, this.keybindingService, this.messageService, this.contextMenuService);
}
return actionItem;
......@@ -310,7 +310,7 @@ export abstract class TitleControl extends Themable implements ITitleAreaControl
const titleBarMenu = this.menuService.createMenu(MenuId.EditorTitle, scopedContextKeyService);
this.disposeOnEditorActions.push(titleBarMenu, titleBarMenu.onDidChange(_ => this.update()));
fillInActions(titleBarMenu, { arg: this.resourceContext.get() }, { primary, secondary });
fillInActions(titleBarMenu, { arg: this.resourceContext.get() }, { primary, secondary }, this.contextMenuService);
}
return { primary, secondary };
......@@ -386,7 +386,7 @@ export abstract class TitleControl extends Themable implements ITitleAreaControl
// Fill in contributed actions
const actions: IAction[] = [];
fillInActions(this.contextMenu, { shouldForwardArgs: true, arg: this.resourceContext.get() }, actions);
fillInActions(this.contextMenu, { shouldForwardArgs: true, arg: this.resourceContext.get() }, actions, this.contextMenuService);
// Show it
this.contextMenuService.showContextMenu({
......
......@@ -111,7 +111,7 @@ export class TreeView extends TreeViewsViewletPanel {
}
getActionItem(action: IAction): IActionItem {
return createActionItem(action, this.keybindingService, this.messageService);
return createActionItem(action, this.keybindingService, this.messageService, this.contextMenuService);
}
private setInput(): TPromise<void> {
......@@ -400,7 +400,8 @@ class Menus implements IDisposable {
constructor(
private id: string,
@IContextKeyService private contextKeyService: IContextKeyService,
@IMenuService private menuService: IMenuService
@IMenuService private menuService: IMenuService,
@IContextMenuService private contextMenuService: IContextMenuService
) {
if (this.titleDisposable) {
this.titleDisposable.dispose();
......@@ -414,7 +415,7 @@ class Menus implements IDisposable {
const updateActions = () => {
this.titleActions = [];
this.titleSecondaryActions = [];
fillInActions(titleMenu, null, { primary: this.titleActions, secondary: this.titleSecondaryActions });
fillInActions(titleMenu, null, { primary: this.titleActions, secondary: this.titleSecondaryActions }, this.contextMenuService);
this._onDidChangeTitle.fire();
};
......@@ -451,7 +452,7 @@ class Menus implements IDisposable {
const primary: IAction[] = [];
const secondary: IAction[] = [];
const result = { primary, secondary };
fillInActions(menu, { shouldForwardArgs: true }, result);
fillInActions(menu, { shouldForwardArgs: true }, result, this.contextMenuService);
menu.dispose();
contextKeyService.dispose();
......@@ -462,4 +463,4 @@ class Menus implements IDisposable {
dispose(): void {
this.disposables = dispose(this.disposables);
}
}
\ No newline at end of file
}
......@@ -376,7 +376,7 @@ export class ElectronWindow extends Themable {
const actions: (MenuItemAction | Separator)[] = [];
// Fill actions into groups respecting order
fillInActions(this.touchBarMenu, void 0, actions);
fillInActions(this.touchBarMenu, void 0, actions, this.contextMenuService);
// Convert into command action multi array
const items: ICommandAction[][] = [];
......
......@@ -224,7 +224,7 @@ export class BaseDebugController extends DefaultController {
this.contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => this.actionProvider.getSecondaryActions(tree, element).then(actions => {
fillInActions(this.contributedContextMenu, { arg: this.getContext(element) }, actions);
fillInActions(this.contributedContextMenu, { arg: this.getContext(element) }, actions, this.contextMenuService);
return actions;
}),
onHide: (wasCancelled?: boolean) => {
......
......@@ -91,7 +91,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
// Try workspace path first
const root = historyService.getLastActiveWorkspaceRoot('file');
return !resource ? TPromise.as(root && root.fsPath) : fileService.resolveFile(resource).then(stat => {
return !uri.isUri(resource) ? TPromise.as(root && root.fsPath) : fileService.resolveFile(resource).then(stat => {
return stat.isDirectory ? stat.resource.fsPath : paths.dirname(stat.resource.fsPath);
}).then(directoryToOpen => {
......
......@@ -197,7 +197,7 @@ export class FeedbackDropdown extends Dropdown {
const $buttons = $('div.form-buttons').appendTo($form);
const $hideButtonContainer = $('div.hide-button').appendTo($buttons);
const $hideButtonContainer = $('div.hide-button-container').appendTo($buttons);
this.hideButton = $('input.hide-button').type('checkbox').attr('checked', '').id('hide-button').appendTo($hideButtonContainer).getHTMLElement() as HTMLInputElement;
......
......@@ -160,7 +160,12 @@
display: flex;
}
.monaco-shell .feedback-form .form-buttons .hide-button {
.monaco-shell .feedback-form .form-buttons .hide-button-container {
display: flex;
}
.monaco-shell .feedback-form .form-buttons .hide-button-container input,
.monaco-shell .feedback-form .form-buttons .hide-button-container label {
align-self: center;
}
......
......@@ -29,7 +29,7 @@ import { IListService } from 'vs/platform/list/browser/listService';
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IResourceInput, Position } from 'vs/platform/editor/common/editor';
import { IResourceInput, Position, IEditorInput } from 'vs/platform/editor/common/editor';
import { IFileService } from 'vs/platform/files/common/files';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IEditorViewState } from 'vs/editor/common/editorCommon';
......@@ -38,6 +38,7 @@ import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRe
import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';
import { isWindows, isMacintosh } from 'vs/base/common/platform';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { FileStat, OpenEditor } from 'vs/workbench/parts/files/common/explorerModel';
// Commands
......@@ -244,7 +245,7 @@ CommandsRegistry.registerCommand({
const textFileService = accessor.get(ITextFileService);
const messageService = accessor.get(IMessageService);
if (!resource) {
if (!URI.isUri(resource)) {
resource = toResource(editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' });
}
......@@ -259,7 +260,7 @@ CommandsRegistry.registerCommand({
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(50),
when: ExplorerFocusCondition,
primary: KeyMod.CtrlCmd | KeyCode.Enter,
mac: {
......@@ -269,18 +270,32 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
const editorService = accessor.get(IWorkbenchEditorService);
const listService = accessor.get(IListService);
const tree = listService.lastFocusedList;
let resourceOrEditor: URI | IEditorInput;
if (URI.isUri(resource)) {
resourceOrEditor = resource;
} else {
const focus = tree.getFocus();
if (focus instanceof FileStat && !focus.isDirectory) {
resourceOrEditor = focus.resource;
} else if (focus instanceof OpenEditor) {
resourceOrEditor = focus.editorInput;
}
}
// Remove highlight
if (tree instanceof Tree) {
tree.clearHighlight();
}
// Set side input
return editorService.openEditor({
resource,
options: {
preserveFocus: false
}
}, true);
if (URI.isUri(resourceOrEditor)) {
return editorService.openEditor({ resource: resourceOrEditor, options: { preserveFocus: false } }, true);
} else if (resourceOrEditor) {
return editorService.openEditor(resourceOrEditor, { preserveFocus: false }, true);
}
return TPromise.as(true);
}
});
......@@ -300,7 +315,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
}
const editorService = accessor.get(IWorkbenchEditorService);
if (!resource) {
if (!URI.isUri(resource)) {
resource = toResource(editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' });
}
......@@ -356,7 +371,7 @@ CommandsRegistry.registerCommand({
const revealInOSHandler = (accessor: ServicesAccessor, resource: URI) => {
// Without resource, try to look at the active editor
if (!resource) {
if (!URI.isUri(resource)) {
const editorService = accessor.get(IWorkbenchEditorService);
resource = toResource(editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' });
}
......@@ -396,7 +411,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
id: COPY_PATH_COMMAND_ID,
handler: (accessor, resource: URI) => {
// Without resource, try to look at the active editor
if (!resource) {
if (!URI.isUri(resource)) {
const editorGroupService = accessor.get(IEditorGroupService);
const editorService = accessor.get(IWorkbenchEditorService);
const activeEditor = editorService.getActiveEditor();
......
......@@ -421,14 +421,8 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView
}, this.contextKeyService, this.listService, this.themeService);
// Bind context keys
const filesExplorerFocusedContextKey = FilesExplorerFocusedContext.bindTo(this.explorerViewer.contextKeyService);
const explorerFocusedContextKey = ExplorerFocusedContext.bindTo(this.explorerViewer.contextKeyService);
// Update context keys
this.disposables.push(this.explorerViewer.onFocusChange(focused => {
filesExplorerFocusedContextKey.set(focused);
explorerFocusedContextKey.set(focused);
}));
FilesExplorerFocusedContext.bindTo(this.explorerViewer.contextKeyService);
ExplorerFocusedContext.bindTo(this.explorerViewer.contextKeyService);
// Update Viewer based on File Change Events
this.disposables.push(this.fileService.onAfterOperation(e => this.onFileOperation(e)));
......
......@@ -424,7 +424,7 @@ export class FileController extends DefaultController implements IDisposable {
getAnchor: () => anchor,
getActions: () => {
const actions = [];
fillInActions(this.contributedContextMenu, { arg: stat instanceof FileStat ? stat.resource : undefined, shouldForwardArgs: true }, actions);
fillInActions(this.contributedContextMenu, { arg: stat instanceof FileStat ? stat.resource : undefined, shouldForwardArgs: true }, actions, this.contextMenuService);
return TPromise.as(actions);
},
onHide: (wasCancelled?: boolean) => {
......
......@@ -290,7 +290,7 @@ export class OpenEditorsView extends ViewsViewletPanel {
getAnchor: () => e.anchor,
getActions: () => {
const actions = [];
fillInActions(this.contributedContextMenu, { shouldForwardArgs: true, arg: element instanceof OpenEditor ? element.editorInput.getResource() : undefined }, actions);
fillInActions(this.contributedContextMenu, { shouldForwardArgs: true, arg: element instanceof OpenEditor ? element.editorInput.getResource() : undefined }, actions, this.contextMenuService);
return TPromise.as(actions);
},
getActionsContext: () => element instanceof OpenEditor ? { group: element.editorGroup, editor: element.editorInput } : { group: element }
......
......@@ -158,7 +158,7 @@ export class MarkersPanel extends Panel {
selection: marker.range,
preserveFocus,
pinned,
revealIfVisible: true
revealIfVisible: !sideByside
},
}, sideByside).done(editor => {
if (editor && preserveFocus) {
......
......@@ -21,7 +21,7 @@ export function registerContributions(): void {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: Constants.MARKER_OPEN_SIDE_ACTION_ID,
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(50),
when: ContextKeyExpr.and(Constants.MarkerFocusContextKey),
primary: KeyMod.CtrlCmd | KeyCode.Enter,
mac: {
......
......@@ -52,6 +52,7 @@ import { sortedDiff, firstIndex } from 'vs/base/common/arrays';
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { ISplice } from 'vs/base/common/sequence';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
// TODO@Joao
// Need to subclass MenuItemActionItem in order to respect
......@@ -197,7 +198,8 @@ class DirtyDiffWidget extends PeekViewWidget {
@IMenuService menuService: IMenuService,
@IKeybindingService private keybindingService: IKeybindingService,
@IMessageService private messageService: IMessageService,
@IContextKeyService contextKeyService: IContextKeyService
@IContextKeyService contextKeyService: IContextKeyService,
@IContextMenuService private contextMenuService: IContextMenuService
) {
super(editor, { isResizeable: true, frameWidth: 1, keepEditorSelection: true });
......@@ -271,7 +273,7 @@ class DirtyDiffWidget extends PeekViewWidget {
this._actionbarWidget.push([previous, next], { label: false, icon: true });
const actions: IAction[] = [];
fillInActions(this.menu, { shouldForwardArgs: true }, actions);
fillInActions(this.menu, { shouldForwardArgs: true }, actions, this.contextMenuService);
this._actionbarWidget.push(actions, { label: false, icon: true });
}
......@@ -288,7 +290,7 @@ class DirtyDiffWidget extends PeekViewWidget {
return undefined;
}
return new DiffMenuItemActionItem(action, this.keybindingService, this.messageService);
return new DiffMenuItemActionItem(action, this.keybindingService, this.messageService, this.contextMenuService);
}
protected _fillBody(container: HTMLElement): void {
......
......@@ -14,6 +14,7 @@ import { IAction } from 'vs/base/common/actions';
import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem';
import { ISCMProvider, ISCMResource, ISCMResourceGroup } from 'vs/workbench/services/scm/common/scm';
import { getSCMResourceContextKey } from './scmUtil';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
export class SCMMenus implements IDisposable {
......@@ -30,7 +31,8 @@ export class SCMMenus implements IDisposable {
constructor(
provider: ISCMProvider | undefined,
@IContextKeyService contextKeyService: IContextKeyService,
@IMenuService private menuService: IMenuService
@IMenuService private menuService: IMenuService,
@IContextMenuService private contextMenuService: IContextMenuService
) {
this.contextKeyService = contextKeyService.createScoped();
const scmProviderKey = this.contextKeyService.createKey<string | undefined>('scmProvider', void 0);
......@@ -52,7 +54,7 @@ export class SCMMenus implements IDisposable {
this.titleActions = [];
this.titleSecondaryActions = [];
// TODO@joao: second arg used to be null
fillInActions(this.titleMenu, { shouldForwardArgs: true }, { primary: this.titleActions, secondary: this.titleSecondaryActions });
fillInActions(this.titleMenu, { shouldForwardArgs: true }, { primary: this.titleActions, secondary: this.titleSecondaryActions }, this.contextMenuService);
this._onDidChangeTitle.fire();
}
......@@ -88,7 +90,7 @@ export class SCMMenus implements IDisposable {
const primary: IAction[] = [];
const secondary: IAction[] = [];
const result = { primary, secondary };
fillInActions(menu, { shouldForwardArgs: true }, result, g => /^inline/.test(g));
fillInActions(menu, { shouldForwardArgs: true }, result, this.contextMenuService, g => /^inline/.test(g));
menu.dispose();
contextKeyService.dispose();
......@@ -99,4 +101,4 @@ export class SCMMenus implements IDisposable {
dispose(): void {
this.disposables = dispose(this.disposables);
}
}
\ No newline at end of file
}
......@@ -323,7 +323,7 @@ class MainPanel extends ViewletPanel {
const secondary: IAction[] = [];
const result = { primary, secondary };
fillInActions(menu, { shouldForwardArgs: true }, result, g => g === 'inline');
fillInActions(menu, { shouldForwardArgs: true }, result, this.contextMenuService, g => g === 'inline');
menu.dispose();
contextKeyService.dispose();
......@@ -912,7 +912,7 @@ export class RepositoryPanel extends ViewletPanel {
return undefined;
}
return new SCMMenuItemActionItem(action, this.keybindingService, this.messageService);
return new SCMMenuItemActionItem(action, this.keybindingService, this.messageService, this.contextMenuService);
}
getActionsContext(): any {
......@@ -1028,7 +1028,7 @@ export class SCMViewlet extends PanelViewlet implements IViewModel {
@IContextKeyService contextKeyService: IContextKeyService,
@IKeybindingService protected keybindingService: IKeybindingService,
@IMessageService protected messageService: IMessageService,
@IContextMenuService contextMenuService: IContextMenuService,
@IContextMenuService private contextMenuService: IContextMenuService,
@IThemeService protected themeService: IThemeService,
@ICommandService protected commandService: ICommandService,
@IEditorGroupService protected editorGroupService: IEditorGroupService,
......@@ -1036,7 +1036,7 @@ export class SCMViewlet extends PanelViewlet implements IViewModel {
@IWorkspaceContextService contextService: IWorkspaceContextService,
@IStorageService storageService: IStorageService,
@IExtensionService extensionService: IExtensionService,
@IConfigurationService private configurationService: IConfigurationService
@IConfigurationService private configurationService: IConfigurationService,
) {
super(VIEWLET_ID, { showHeaderInTitleWhenSingleView: true }, telemetryService, themeService);
......@@ -1176,7 +1176,7 @@ export class SCMViewlet extends PanelViewlet implements IViewModel {
return undefined;
}
return new SCMMenuItemActionItem(action, this.keybindingService, this.messageService);
return new SCMMenuItemActionItem(action, this.keybindingService, this.messageService, this.contextMenuService);
}
layout(dimension: Dimension): void {
......
......@@ -17,7 +17,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { join, basename, extname } from 'path';
import { mkdirp, readdir } from 'vs/base/node/pfs';
import { mkdirp, readdir, exists } from 'vs/base/node/pfs';
import { watch } from 'fs';
import { SnippetFile, Snippet } from 'vs/workbench/parts/snippets/electron-browser/snippetsFile';
import { ISnippetsService } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution';
......@@ -218,19 +218,19 @@ class SnippetsService implements ISnippetsService {
return;
}
const filepath = join(userSnippetsFolder, filename);
if (type === 'change') {
// `changed` file
if (this._files.has(filepath)) {
this._files.get(filepath).reset();
}
} else if (type === 'rename') {
// `created` or `deleted` file
if (!this._files.has(filepath)) {
addUserSnippet(filepath);
exists(filepath).then(value => {
if (value) {
// file created or changed
if (this._files.has(filepath)) {
this._files.get(filepath).reset();
} else {
addUserSnippet(filepath);
}
} else {
// file not found
this._files.delete(filepath);
}
}
});
});
}).then(undefined, err => {
this._logService.error('Failed to load user snippets', err);
......
......@@ -17,10 +17,12 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { remote, webFrame } from 'electron';
import { unmnemonicLabel } from 'vs/base/common/labels';
import Event, { Emitter } from 'vs/base/common/event';
export class ContextMenuService implements IContextMenuService {
public _serviceBrand: any;
private _onDidContextMenu = new Emitter<void>();
constructor(
@IMessageService private messageService: IMessageService,
......@@ -29,6 +31,10 @@ export class ContextMenuService implements IContextMenuService {
) {
}
public get onDidContextMenu(): Event<void> {
return this._onDidContextMenu.event;
}
public showContextMenu(delegate: IContextMenuDelegate): void {
delegate.getActions().then(actions => {
if (!actions.length) {
......@@ -56,6 +62,7 @@ export class ContextMenuService implements IContextMenuService {
y *= zoom;
menu.popup(remote.getCurrentWindow(), { x: Math.floor(x), y: Math.floor(y), positioningItem: delegate.autoSelectFirstItem ? 0 : void 0 });
this._onDidContextMenu.fire();
if (delegate.onHide) {
delegate.onHide(undefined);
}
......
......@@ -5808,9 +5808,9 @@ vscode-textmate@^3.2.0:
fast-plist "^0.1.2"
oniguruma "^6.0.1"
vscode-xterm@3.1.0-beta1:
version "3.1.0-beta1"
resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.1.0-beta1.tgz#fe7d83687583444ec1726488e986e1828543c20c"
vscode-xterm@3.1.0-beta2:
version "3.1.0-beta2"
resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.1.0-beta2.tgz#74adae19283738fab15f0ef145797f2eff5cc608"
vso-node-api@^6.1.2-preview:
version "6.1.2-preview"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册