Revert "Revert "Merge from vscode ada4bddb8edc69eea6ebaaa0e88c5f903cbd43d8 (#5529)" (#5553)" (#5562)

This reverts commit c9a4f8f664.
This commit is contained in:
Anthony Dresser
2019-05-21 14:19:32 -07:00
committed by GitHub
parent 7670104e4d
commit 81ae86ff79
325 changed files with 4497 additions and 3328 deletions

View File

@@ -66,10 +66,7 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu
if (!this.configuredAutoSaveAfterDelay) {
const model = this.textFileService.models.get(event.resource);
if (model) {
const snapshot = model.createSnapshot();
if (snapshot) {
this.backupFileService.backupResource(model.getResource(), snapshot, model.getVersionId());
}
model.backup();
}
}
}
@@ -77,12 +74,7 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu
private onUntitledModelChanged(resource: Uri): void {
if (this.untitledEditorService.isDirty(resource)) {
this.untitledEditorService.loadOrCreate({ resource }).then(model => {
const snapshot = model.createSnapshot();
if (snapshot) {
this.backupFileService.backupResource(resource, snapshot, model.getVersionId());
}
});
this.untitledEditorService.loadOrCreate({ resource }).then(model => model.backup());
} else {
this.discardBackup(resource);
}

View File

@@ -78,10 +78,10 @@ export class BackupRestorer implements IWorkbenchContribution {
private resolveInput(resource: URI, index: number, hasOpenedEditors: boolean): IResourceInput | IUntitledResourceInput {
const options = { pinned: true, preserveFocus: true, inactive: index > 0 || hasOpenedEditors };
// {{SQL CARBON EDIT}}
if (resource.scheme === Schemas.untitled
&& !BackupRestorer.UNTITLED_REGEX.test(resource.fsPath)
&& !BackupRestorer.SQLQUERY_REGEX.test(resource.fsPath)) {
// this is a (weak) strategy to find out if the untitled input had
// an associated file path or not by just looking at the path. and
// if so, we must ensure to restore the local resource it had.
if (resource.scheme === Schemas.untitled && !BackupRestorer.UNTITLED_REGEX.test(resource.path) && BackupRestorer.SQLQUERY_REGEX.test(resource.path)) { // {{SQL CARBON EDIT}} @anthonydresser add sql regex test
return { resource: toLocalResource(resource, this.environmentService.configuration.remoteAuthority), options, forceUntitled: true };
}

View File

@@ -282,7 +282,7 @@ class ShowAccessibilityHelpAction extends EditorAction {
id: 'editor.action.showAccessibilityHelp',
label: nls.localize('ShowAccessibilityHelpAction', "Show Accessibility Help"),
alias: 'Show Accessibility Help',
precondition: null,
precondition: undefined,
kbOpts: {
kbExpr: EditorContextKeys.focus,
primary: KeyMod.Alt | KeyCode.F1,

View File

@@ -17,7 +17,7 @@ class InspectKeyMap extends EditorAction {
id: 'workbench.action.inspectKeyMappings',
label: nls.localize('workbench.action.inspectKeyMap', "Developer: Inspect Key Mappings"),
alias: 'Developer: Inspect Key Mappings',
precondition: null
precondition: undefined
});
}

View File

@@ -102,7 +102,7 @@ class InspectTMScopes extends EditorAction {
id: 'editor.action.inspectTMScopes',
label: nls.localize('inspectTMScopes', "Developer: Inspect TM Scopes"),
alias: 'Developer: Inspect TM Scopes',
precondition: null
precondition: undefined
});
}

View File

@@ -121,7 +121,7 @@ class ToggleWordWrapAction extends EditorAction {
id: TOGGLE_WORD_WRAP_ID,
label: nls.localize('toggle.wordwrap', "View: Toggle Word Wrap"),
alias: 'View: Toggle Word Wrap',
precondition: null,
precondition: undefined,
kbOpts: {
kbExpr: null,
primary: KeyMod.Alt | KeyCode.KEY_Z,

View File

@@ -3,43 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .codelens-decoration {
overflow: hidden;
display: inline-block;
text-overflow: ellipsis;
}
.monaco-editor .codelens-decoration > span,
.monaco-editor .codelens-decoration > a {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
white-space: nowrap;
vertical-align: sub;
}
.monaco-editor .codelens-decoration > a {
text-decoration: none;
}
.monaco-editor .codelens-decoration > a:hover {
text-decoration: underline;
cursor: pointer;
}
.monaco-editor .codelens-decoration.invisible-cl {
opacity: 0;
}
@keyframes fadein { 0% { opacity:0; visibility:visible;} 100% { opacity:1; } }
@-moz-keyframes fadein { 0% { opacity:0; visibility:visible;} 100% { opacity:1; } }
@-o-keyframes fadein { 0% { opacity:0; visibility:visible;} 100% { opacity:1; } }
@-webkit-keyframes fadein { 0% { opacity:0; visibility:visible;} 100% { opacity:1; } }
.monaco-editor .codelens-decoration.fadein {
-webkit-animation: fadein 0.5s linear;
-moz-animation: fadein 0.5s linear;
-o-animation: fadein 0.5s linear;
animation: fadein 0.5s linear;
.monaco-editor .code-inset {
z-index: 10;
}

View File

@@ -155,6 +155,7 @@ export class CodeInsetWidget {
}
const div = document.createElement('div');
div.className = 'code-inset';
webview.mountTo(div);
webview.onMessage((e: { type: string, payload: any }) => {
// The webview contents can use a "size-info" message to report its size.

View File

@@ -6,7 +6,7 @@
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import * as modes from 'vs/editor/common/modes';
import { ActionsOrientation, ActionItem, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionsOrientation, ActionViewItem, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Button } from 'vs/base/browser/ui/button/button';
import { Action, IActionRunner } from 'vs/base/common/actions';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
@@ -29,9 +29,9 @@ import { assign } from 'vs/base/common/objects';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { DropdownMenuActionItem } from 'vs/base/browser/ui/dropdown/dropdown';
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { ToggleReactionsAction, ReactionAction, ReactionActionItem } from './reactionsAction';
import { ToggleReactionsAction, ReactionAction, ReactionActionViewItem } from './reactionsAction';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget';
@@ -165,14 +165,14 @@ export class CommentNode extends Disposable {
if (actions.length) {
this.toolbar = new ToolBar(this._actionsToolbarContainer, this.contextMenuService, {
actionItemProvider: action => {
actionViewItemProvider: action => {
if (action.id === ToggleReactionsAction.ID) {
return new DropdownMenuActionItem(
return new DropdownMenuActionViewItem(
action,
(<ToggleReactionsAction>action).menuActions,
this.contextMenuService,
action => {
return this.actionItemProvider(action as Action);
return this.actionViewItemProvider(action as Action);
},
this.actionRunner!,
undefined,
@@ -180,7 +180,7 @@ export class CommentNode extends Disposable {
() => { return AnchorAlignment.RIGHT; }
);
}
return this.actionItemProvider(action as Action);
return this.actionViewItemProvider(action as Action);
},
orientation: ActionsOrientation.HORIZONTAL
});
@@ -191,7 +191,7 @@ export class CommentNode extends Disposable {
}
}
actionItemProvider(action: Action) {
actionViewItemProvider(action: Action) {
let options = {};
if (action.id === 'comment.delete' || action.id === 'comment.edit' || action.id === ToggleReactionsAction.ID) {
options = { label: false, icon: true };
@@ -200,19 +200,19 @@ export class CommentNode extends Disposable {
}
if (action.id === ReactionAction.ID) {
let item = new ReactionActionItem(action);
let item = new ReactionActionViewItem(action);
return item;
} else {
let item = new ActionItem({}, action, options);
let item = new ActionViewItem({}, action, options);
return item;
}
}
private createReactionPicker2(): ToggleReactionsAction {
let toggleReactionActionItem: DropdownMenuActionItem;
let toggleReactionActionViewItem: DropdownMenuActionViewItem;
let toggleReactionAction = this._register(new ToggleReactionsAction(() => {
if (toggleReactionActionItem) {
toggleReactionActionItem.show();
if (toggleReactionActionViewItem) {
toggleReactionActionViewItem.show();
}
}, nls.localize('commentToggleReaction', "Toggle Reaction")));
@@ -235,15 +235,15 @@ export class CommentNode extends Disposable {
toggleReactionAction.menuActions = reactionMenuActions;
toggleReactionActionItem = new DropdownMenuActionItem(
toggleReactionActionViewItem = new DropdownMenuActionViewItem(
toggleReactionAction,
(<ToggleReactionsAction>toggleReactionAction).menuActions,
this.contextMenuService,
action => {
if (action.id === ToggleReactionsAction.ID) {
return toggleReactionActionItem;
return toggleReactionActionViewItem;
}
return this.actionItemProvider(action as Action);
return this.actionViewItemProvider(action as Action);
},
this.actionRunner!,
undefined,
@@ -255,10 +255,10 @@ export class CommentNode extends Disposable {
}
private createReactionPicker(): ToggleReactionsAction {
let toggleReactionActionItem: DropdownMenuActionItem;
let toggleReactionActionViewItem: DropdownMenuActionViewItem;
let toggleReactionAction = this._register(new ToggleReactionsAction(() => {
if (toggleReactionActionItem) {
toggleReactionActionItem.show();
if (toggleReactionActionViewItem) {
toggleReactionActionViewItem.show();
}
}, nls.localize('commentAddReaction', "Add Reaction")));
@@ -281,15 +281,15 @@ export class CommentNode extends Disposable {
toggleReactionAction.menuActions = reactionMenuActions;
toggleReactionActionItem = new DropdownMenuActionItem(
toggleReactionActionViewItem = new DropdownMenuActionViewItem(
toggleReactionAction,
(<ToggleReactionsAction>toggleReactionAction).menuActions,
this.contextMenuService,
action => {
if (action.id === ToggleReactionsAction.ID) {
return toggleReactionActionItem;
return toggleReactionActionViewItem;
}
return this.actionItemProvider(action as Action);
return this.actionViewItemProvider(action as Action);
},
this.actionRunner!,
undefined,
@@ -303,14 +303,14 @@ export class CommentNode extends Disposable {
private createReactionsContainer(commentDetailsContainer: HTMLElement): void {
this._reactionActionsContainer = dom.append(commentDetailsContainer, dom.$('div.comment-reactions'));
this._reactionsActionBar = new ActionBar(this._reactionActionsContainer, {
actionItemProvider: action => {
actionViewItemProvider: action => {
if (action.id === ToggleReactionsAction.ID) {
return new DropdownMenuActionItem(
return new DropdownMenuActionViewItem(
action,
(<ToggleReactionsAction>action).menuActions,
this.contextMenuService,
action => {
return this.actionItemProvider(action as Action);
return this.actionViewItemProvider(action as Action);
},
this.actionRunner!,
undefined,
@@ -318,7 +318,7 @@ export class CommentNode extends Disposable {
() => { return AnchorAlignment.RIGHT; }
);
}
return this.actionItemProvider(action as Action);
return this.actionViewItemProvider(action as Action);
}
});
this._toDispose.push(this._reactionsActionBar);

View File

@@ -840,7 +840,7 @@ export class NextCommentThreadAction extends EditorAction {
id: 'editor.action.nextCommentThreadAction',
label: nls.localize('nextCommentThreadAction', "Go to Next Comment Thread"),
alias: 'Go to Next Comment Thread',
precondition: null,
precondition: undefined,
});
}

View File

@@ -5,7 +5,7 @@
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import { ActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action, IAction } from 'vs/base/common/actions';
import { URI, UriComponents } from 'vs/base/common/uri';
@@ -29,7 +29,7 @@ export class ToggleReactionsAction extends Action {
this._menuActions = actions;
}
}
export class ReactionActionItem extends ActionItem {
export class ReactionActionViewItem extends ActionViewItem {
constructor(action: ReactionAction) {
super(null, action, {});
}

View File

@@ -21,7 +21,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c
import { IViewletPanelOptions, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet';
import { ILabelService } from 'vs/platform/label/common/label';
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem';
import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { ITreeRenderer, ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
import { TreeResourceNavigator2, WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';

View File

@@ -9,7 +9,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
import * as dom from 'vs/base/browser/dom';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { SelectBox, ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox';
import { SelectActionItem, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { SelectActionViewItem, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IDebugService, IDebugSession, IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug';
@@ -23,7 +23,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
const $ = dom.$;
export class StartDebugActionItem implements IActionItem {
export class StartDebugActionViewItem implements IActionViewItem {
private static readonly SEPARATOR = '─────────';
@@ -171,7 +171,7 @@ export class StartDebugActionItem implements IActionItem {
if (this.options.length === 0) {
this.options.push({ label: nls.localize('noConfigurations', "No Configurations"), handler: () => false });
} else {
this.options.push({ label: StartDebugActionItem.SEPARATOR, handler: undefined });
this.options.push({ label: StartDebugActionViewItem.SEPARATOR, handler: undefined });
}
const disabledIdx = this.options.length - 1;
@@ -189,7 +189,7 @@ export class StartDebugActionItem implements IActionItem {
}
}
export class FocusSessionActionItem extends SelectActionItem {
export class FocusSessionActionViewItem extends SelectActionViewItem {
constructor(
action: IAction,
@IDebugService protected readonly debugService: IDebugService,

View File

@@ -26,7 +26,7 @@ class ToggleBreakpointAction extends EditorAction {
id: TOGGLE_BREAKPOINT_ID,
label: nls.localize('toggleBreakpointAction', "Debug: Toggle Breakpoint"),
alias: 'Debug: Toggle Breakpoint',
precondition: null,
precondition: undefined,
kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus,
primary: KeyCode.F9,
@@ -63,7 +63,7 @@ class ConditionalBreakpointAction extends EditorAction {
id: TOGGLE_CONDITIONAL_BREAKPOINT_ID,
label: nls.localize('conditionalBreakpointEditorAction', "Debug: Add Conditional Breakpoint..."),
alias: 'Debug: Add Conditional Breakpoint...',
precondition: null
precondition: undefined
});
}
@@ -85,7 +85,7 @@ class LogPointAction extends EditorAction {
id: TOGGLE_LOG_POINT_ID,
label: nls.localize('logPointEditorAction', "Debug: Add Logpoint..."),
alias: 'Debug: Add Logpoint...',
precondition: null
precondition: undefined
});
}
@@ -288,7 +288,7 @@ class GoToNextBreakpointAction extends GoToBreakpointAction {
id: 'editor.debug.action.goToNextBreakpoint',
label: nls.localize('goToNextBreakpoint', "Debug: Go To Next Breakpoint"),
alias: 'Debug: Go To Next Breakpoint',
precondition: null
precondition: undefined
});
}
}
@@ -299,7 +299,7 @@ class GoToPreviousBreakpointAction extends GoToBreakpointAction {
id: 'editor.debug.action.goToPreviousBreakpoint',
label: nls.localize('goToPreviousBreakpoint', "Debug: Go To Previous Breakpoint"),
alias: 'Debug: Go To Previous Breakpoint',
precondition: null
precondition: undefined
});
}
}

View File

@@ -14,7 +14,7 @@ import { ActionBar, ActionsOrientation, Separator } from 'vs/base/browser/ui/act
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IDebugConfiguration, IDebugService, State } from 'vs/workbench/contrib/debug/common/debug';
import { FocusSessionActionItem } from 'vs/workbench/contrib/debug/browser/debugActionItems';
import { FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems';
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@@ -27,7 +27,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { INotificationService } from 'vs/platform/notification/common/notification';
import { RunOnceScheduler } from 'vs/base/common/async';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { fillInActionBarActions, MenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem';
import { fillInActionBarActions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenu, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { FocusSessionAction } from 'vs/workbench/contrib/debug/browser/debugActions';
@@ -86,12 +86,12 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
this.activeActions = [];
this.actionBar = this._register(new ActionBar(actionBarContainer, {
orientation: ActionsOrientation.HORIZONTAL,
actionItemProvider: (action: IAction) => {
actionViewItemProvider: (action: IAction) => {
if (action.id === FocusSessionAction.ID) {
return this.instantiationService.createInstance(FocusSessionActionItem, action);
return this.instantiationService.createInstance(FocusSessionActionViewItem, action);
}
if (action instanceof MenuItemAction) {
return new MenuItemActionItem(action, this.keybindingService, this.notificationService, contextMenuService);
return new MenuEntryActionViewItem(action, this.keybindingService, this.notificationService, contextMenuService);
}
return undefined;

View File

@@ -7,11 +7,11 @@ import 'vs/css!./media/debugViewlet';
import * as nls from 'vs/nls';
import { IAction } from 'vs/base/common/actions';
import * as DOM from 'vs/base/browser/dom';
import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { IDebugService, VIEWLET_ID, State, BREAKPOINTS_VIEW_ID, IDebugConfiguration, REPL_ID } from 'vs/workbench/contrib/debug/common/debug';
import { StartAction, ConfigureAction, SelectAndStartAction, FocusSessionAction } from 'vs/workbench/contrib/debug/browser/debugActions';
import { StartDebugActionItem, FocusSessionActionItem } from 'vs/workbench/contrib/debug/browser/debugActionItems';
import { StartDebugActionViewItem, FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress';
@@ -29,14 +29,14 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet';
import { IMenu, MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { MenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem';
import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { TogglePanelAction } from 'vs/workbench/browser/panel';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
export class DebugViewlet extends ViewContainerViewlet {
private startDebugActionItem: StartDebugActionItem;
private startDebugActionViewItem: StartDebugActionViewItem;
private progressRunner: IProgressRunner;
private breakpointView: ViewletPanel;
private panelListeners = new Map<string, IDisposable>();
@@ -80,8 +80,8 @@ export class DebugViewlet extends ViewContainerViewlet {
focus(): void {
super.focus();
if (this.startDebugActionItem) {
this.startDebugActionItem.focus();
if (this.startDebugActionViewItem) {
this.startDebugActionViewItem.focus();
}
}
@@ -130,16 +130,16 @@ export class DebugViewlet extends ViewContainerViewlet {
return [this.selectAndStartAction, this.configureAction, this.toggleReplAction];
}
getActionItem(action: IAction): IActionItem | undefined {
getActionViewItem(action: IAction): IActionViewItem | undefined {
if (action.id === StartAction.ID) {
this.startDebugActionItem = this.instantiationService.createInstance(StartDebugActionItem, null, action);
return this.startDebugActionItem;
this.startDebugActionViewItem = this.instantiationService.createInstance(StartDebugActionViewItem, null, action);
return this.startDebugActionViewItem;
}
if (action.id === FocusSessionAction.ID) {
return new FocusSessionActionItem(action, this.debugService, this.themeService, this.contextViewService, this.configurationService);
return new FocusSessionActionViewItem(action, this.debugService, this.themeService, this.contextViewService, this.configurationService);
}
if (action instanceof MenuItemAction) {
return new MenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
return new MenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
}
return undefined;

View File

@@ -7,7 +7,7 @@ import 'vs/css!vs/workbench/contrib/debug/browser/media/repl';
import * as nls from 'vs/nls';
import { URI as uri } from 'vs/base/common/uri';
import * as errors from 'vs/base/common/errors';
import { IAction, IActionItem, Action } from 'vs/base/common/actions';
import { IAction, IActionViewItem, Action } from 'vs/base/common/actions';
import * as dom from 'vs/base/browser/dom';
import * as aria from 'vs/base/browser/ui/aria/aria';
import { CancellationToken } from 'vs/base/common/cancellation';
@@ -39,7 +39,7 @@ import { getSimpleEditorOptions, getSimpleCodeEditorWidgetOptions } from 'vs/wor
import { IDecorationOptions } from 'vs/editor/common/editorCommon';
import { transparent, editorForeground } from 'vs/platform/theme/common/colorRegistry';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { FocusSessionActionItem } from 'vs/workbench/contrib/debug/browser/debugActionItems';
import { FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems';
import { CompletionContext, CompletionList, CompletionProviderRegistry } from 'vs/editor/common/modes';
import { first } from 'vs/base/common/arrays';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
@@ -309,9 +309,9 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
this.replInput.focus();
}
getActionItem(action: IAction): IActionItem | undefined {
getActionViewItem(action: IAction): IActionViewItem | undefined {
if (action.id === SelectReplAction.ID) {
return this.instantiationService.createInstance(SelectReplActionItem, this.selectReplAction);
return this.instantiationService.createInstance(SelectReplActionViewItem, this.selectReplAction);
}
return undefined;
@@ -852,7 +852,7 @@ class ReplCopyAllAction extends EditorAction {
registerEditorAction(AcceptReplInputAction);
registerEditorAction(ReplCopyAllAction);
class SelectReplActionItem extends FocusSessionActionItem {
class SelectReplActionViewItem extends FocusSessionActionViewItem {
protected getActionContext(_: string, index: number): any {
return this.debugService.getModel().getSessions(true)[index];

View File

@@ -392,7 +392,7 @@ export class DebugService implements IDebugService {
return this.showError(err.message).then(() => false);
}
if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
return this.showError(nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved on disk and that you have a debug extension installed for that file type."))
return this.showError(nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved and that you have a debug extension installed for that file type."))
.then(() => false);
}
@@ -719,7 +719,7 @@ export class DebugService implements IDebugService {
// If a task is missing the problem matcher the promise will never complete, so we need to have a workaround #35340
let taskStarted = false;
const promise = this.taskService.getActiveTasks().then(tasks => {
const promise: Promise<ITaskSummary | null> = this.taskService.getActiveTasks().then(tasks => {
if (tasks.filter(t => t._id === task._id).length) {
// task is already running - nothing to do.
return Promise.resolve(null);
@@ -733,7 +733,7 @@ export class DebugService implements IDebugService {
if (task.configurationProperties.isBackground) {
return new Promise((c, e) => once(e => e.kind === TaskEventKind.Inactive && e.taskId === task._id, this.taskService.onDidStateChange)(() => {
taskStarted = true;
c(undefined);
c(null);
}));
}

View File

@@ -253,9 +253,9 @@ export class ExtensionEditor extends BaseEditor {
const extensionActions = append(details, $('.actions'));
this.extensionActionBar = new ActionBar(extensionActions, {
animated: false,
actionItemProvider: (action: Action) => {
actionViewItemProvider: (action: Action) => {
if (action instanceof ExtensionEditorDropDownAction) {
return action.createActionItem();
return action.createActionViewItem();
}
return undefined;
}
@@ -565,7 +565,7 @@ export class ExtensionEditor extends BaseEditor {
this.contentDisposables.push(webviewElement.onDidFocus(() => this.fireOnDidFocus()));
const removeLayoutParticipant = arrays.insert(this.layoutParticipants, webviewElement);
this.contentDisposables.push(toDisposable(removeLayoutParticipant));
webviewElement.contents = body;
webviewElement.html = body;
this.contentDisposables.push(webviewElement.onDidClickLink(link => {
if (!link) {

View File

@@ -10,7 +10,7 @@ import { Delayer } from 'vs/base/common/async';
import * as DOM from 'vs/base/browser/dom';
import { Event } from 'vs/base/common/event';
import * as json from 'vs/base/common/json';
import { ActionItem, Separator, IActionItemOptions } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionViewItem, Separator, IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
// {{SQL CARBON EDIT}}
@@ -650,15 +650,15 @@ export class UpdateAction extends ExtensionAction {
}
}
interface IExtensionActionItemOptions extends IActionItemOptions {
interface IExtensionActionViewItemOptions extends IActionViewItemOptions {
tabOnlyOnFocus?: boolean;
}
export class ExtensionActionItem extends ActionItem {
export class ExtensionActionViewItem extends ActionViewItem {
protected options: IExtensionActionItemOptions;
protected options: IExtensionActionViewItemOptions;
constructor(context: any, action: IAction, options: IExtensionActionItemOptions = {}) {
constructor(context: any, action: IAction, options: IExtensionActionViewItemOptions = {}) {
super(context, action, options);
}
@@ -701,15 +701,15 @@ export abstract class ExtensionDropDownAction extends ExtensionAction {
super(id, label, cssClass, enabled);
}
private _actionItem: DropDownMenuActionItem;
createActionItem(): DropDownMenuActionItem {
this._actionItem = this.instantiationService.createInstance(DropDownMenuActionItem, this, this.tabOnlyOnFocus);
return this._actionItem;
private _actionViewItem: DropDownMenuActionViewItem;
createActionViewItem(): DropDownMenuActionViewItem {
this._actionViewItem = this.instantiationService.createInstance(DropDownMenuActionViewItem, this, this.tabOnlyOnFocus);
return this._actionViewItem;
}
public run({ actionGroups, disposeActionsOnHide }: { actionGroups: IAction[][], disposeActionsOnHide: boolean }): Promise<any> {
if (this._actionItem) {
this._actionItem.showMenu(actionGroups, disposeActionsOnHide);
if (this._actionViewItem) {
this._actionViewItem.showMenu(actionGroups, disposeActionsOnHide);
}
return Promise.resolve();
}
@@ -720,7 +720,7 @@ export abstract class ExtensionDropDownAction extends ExtensionAction {
}
}
export class DropDownMenuActionItem extends ExtensionActionItem {
export class DropDownMenuActionViewItem extends ExtensionActionViewItem {
private disposables: IDisposable[] = [];

View File

@@ -13,7 +13,7 @@ import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
import { Event } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionViewItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, TooltipWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
@@ -81,11 +81,11 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
const author = append(footer, $('.author.ellipsis'));
const actionbar = new ActionBar(footer, {
animated: false,
actionItemProvider: (action: Action) => {
actionViewItemProvider: (action: Action) => {
if (action.id === ManageExtensionAction.ID) {
return (<ManageExtensionAction>action).createActionItem();
return (<ManageExtensionAction>action).createActionViewItem();
}
return new ExtensionActionItem(null, action, actionOptions);
return new ExtensionActionViewItem(null, action, actionOptions);
}
});
actionbar.onDidRun(({ error }) => error && this.notificationService.error(error));
@@ -192,13 +192,13 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
this.extensionViewState.onFocus(e => {
if (areSameExtensions(extension.identifier, e.identifier)) {
data.actionbar.items.forEach(item => (<ExtensionActionItem>item).setFocus(true));
data.actionbar.viewItems.forEach(item => (<ExtensionActionViewItem>item).setFocus(true));
}
}, this, data.extensionDisposables);
this.extensionViewState.onBlur(e => {
if (areSameExtensions(extension.identifier, e.identifier)) {
data.actionbar.items.forEach(item => (<ExtensionActionItem>item).setFocus(false));
data.actionbar.viewItems.forEach(item => (<ExtensionActionViewItem>item).setFocus(false));
}
}, this, data.extensionDisposables);
}

View File

@@ -54,7 +54,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { Registry } from 'vs/platform/registry/common/platform';
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { RemoteAuthorityContext } from 'vs/workbench/common/contextkeys';
import { RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { ILabelService } from 'vs/platform/label/common/label';

View File

@@ -23,7 +23,7 @@ import { ResourceContextKey } from 'vs/workbench/common/resources';
import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService';
import { URI } from 'vs/base/common/uri';
import { Schemas } from 'vs/base/common/network';
import { SupportsWorkspacesContext } from 'vs/workbench/common/contextkeys';
import { SupportsWorkspacesContext } from 'vs/workbench/browser/contextkeys';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
// Contribute Global Actions
@@ -160,11 +160,11 @@ function appendEditorTitleContextMenuItem(id: string, title: string, when: Conte
}
// Editor Title Menu for Conflict Resolution
appendSaveConflictEditorTitleAction('workbench.files.action.acceptLocalChanges', nls.localize('acceptLocalChanges', "Use your changes and overwrite disk contents"), {
appendSaveConflictEditorTitleAction('workbench.files.action.acceptLocalChanges', nls.localize('acceptLocalChanges', "Use your changes and overwrite file contents"), {
light: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/check.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/check-inverse.svg`))
}, -10, acceptLocalChangesCommand);
appendSaveConflictEditorTitleAction('workbench.files.action.revertLocalChanges', nls.localize('revertLocalChanges', "Discard your changes and revert to content on disk"), {
appendSaveConflictEditorTitleAction('workbench.files.action.revertLocalChanges', nls.localize('revertLocalChanges', "Discard your changes and revert to file contents"), {
light: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/undo.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/undo-inverse.svg`))
}, -9, revertLocalChangesCommand);

View File

@@ -871,7 +871,7 @@ class ClipboardContentProvider implements ITextModelContentProvider {
) { }
provideTextContent(resource: URI): Promise<ITextModel> {
const model = this.modelService.createModel(this.clipboardService.readText(), this.modeService.create('text/plain'), resource);
const model = this.modelService.createModel(this.clipboardService.readText(), this.modeService.createByFilepathOrFirstLine(resource.path), resource);
return Promise.resolve(model);
}

View File

@@ -11,7 +11,7 @@ import { IWindowsService, IWindowService, IURIToOpen, IOpenSettings, INewWindowO
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ExplorerFocusCondition, FileOnDiskContentProvider, VIEWLET_ID, IExplorerService, resourceToFileOnDisk } from 'vs/workbench/contrib/files/common/files';
import { ExplorerFocusCondition, TextFileContentProvider, VIEWLET_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files';
import { ExplorerViewlet } from 'vs/workbench/contrib/files/browser/explorerViewlet';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ITextFileService, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles';
@@ -44,6 +44,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { UNTITLED_WORKSPACE_NAME } from 'vs/platform/workspaces/common/workspaces';
import { withUndefinedAsNull } from 'vs/base/common/types';
// {{SQL CARBON EDIT}}
import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService';
@@ -348,7 +349,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
if (providerDisposables.length === 0) {
registerEditorListener = true;
const provider = instantiationService.createInstance(FileOnDiskContentProvider);
const provider = instantiationService.createInstance(TextFileContentProvider);
providerDisposables.push(provider);
providerDisposables.push(textModelService.registerTextModelContentProvider(COMPARE_WITH_SAVED_SCHEMA, provider));
}
@@ -357,9 +358,9 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
const uri = getResourceForCommand(resource, accessor.get(IListService), editorService);
if (uri && fileService.canHandleResource(uri)) {
const name = basename(uri);
const editorLabel = nls.localize('modifiedLabel', "{0} (on disk) ↔ {1}", name, name);
const editorLabel = nls.localize('modifiedLabel', "{0} (in file) ↔ {1}", name, name);
editorService.openEditor({ leftResource: resourceToFileOnDisk(COMPARE_WITH_SAVED_SCHEMA, uri), rightResource: uri, label: editorLabel }).then(() => {
TextFileContentProvider.open(uri, COMPARE_WITH_SAVED_SCHEMA, editorLabel, editorService).then(() => {
// Dispose once no more diff editor is opened with the scheme
if (registerEditorListener) {
@@ -378,7 +379,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
}
});
let globalResourceToCompare: URI | null;
let globalResourceToCompare: URI | undefined;
let resourceSelectedForCompareContext: IContextKey<boolean>;
CommandsRegistry.registerCommand({
id: SELECT_FOR_COMPARE_COMMAND_ID,
@@ -553,9 +554,9 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
const editorService = accessor.get(IEditorService);
let resource: URI | null = null;
if (resourceOrObject && 'from' in resourceOrObject && resourceOrObject.from === 'menu') {
resource = toResource(editorService.activeEditor);
resource = withUndefinedAsNull(toResource(editorService.activeEditor));
} else {
resource = getResourceForCommand(resourceOrObject, accessor.get(IListService), editorService);
resource = withUndefinedAsNull(getResourceForCommand(resourceOrObject, accessor.get(IListService), editorService));
}
// {{SQL CARBON EDIT}}

View File

@@ -42,8 +42,8 @@ import { Schemas } from 'vs/base/common/network';
// Viewlet Action
export class OpenExplorerViewletAction extends ShowViewletAction {
public static readonly ID = VIEWLET_ID;
public static readonly LABEL = nls.localize('showExplorerViewlet', "Show Explorer");
static readonly ID = VIEWLET_ID;
static readonly LABEL = nls.localize('showExplorerViewlet', "Show Explorer");
constructor(
id: string,
@@ -126,8 +126,8 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
// Register default file input factory
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).registerFileInputFactory({
createFileInput: (resource, encoding, instantiationService): IFileEditorInput => {
return instantiationService.createInstance(FileEditorInput, resource, encoding);
createFileInput: (resource, encoding, mode, instantiationService): IFileEditorInput => {
return instantiationService.createInstance(FileEditorInput, resource, encoding, mode);
},
isFileInput: (obj): obj is IFileEditorInput => {
@@ -139,6 +139,7 @@ interface ISerializedFileInput {
resource: string;
resourceJSON: object;
encoding?: string;
modeId?: string;
}
// Register Editor Input Factory
@@ -146,25 +147,27 @@ class FileEditorInputFactory implements IEditorInputFactory {
constructor() { }
public serialize(editorInput: EditorInput): string {
serialize(editorInput: EditorInput): string {
const fileEditorInput = <FileEditorInput>editorInput;
const resource = fileEditorInput.getResource();
const fileInput: ISerializedFileInput = {
resource: resource.toString(), // Keep for backwards compatibility
resourceJSON: resource.toJSON(),
encoding: fileEditorInput.getEncoding()
encoding: fileEditorInput.getEncoding(),
modeId: fileEditorInput.getPreferredMode() // only using the preferred user associated mode here if available to not store redundant data
};
return JSON.stringify(fileInput);
}
public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileEditorInput {
deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileEditorInput {
return instantiationService.invokeFunction<FileEditorInput>(accessor => {
const fileInput: ISerializedFileInput = JSON.parse(serializedEditorInput);
const resource = !!fileInput.resourceJSON ? URI.revive(<UriComponents>fileInput.resourceJSON) : URI.parse(fileInput.resource);
const encoding = fileInput.encoding;
const mode = fileInput.modeId;
return accessor.get(IEditorService).createInput({ resource, encoding, forceFile: true }) as FileEditorInput;
return accessor.get(IEditorService).createInput({ resource, encoding, mode, forceFile: true }) as FileEditorInput;
});
}
}
@@ -326,6 +329,11 @@ configurationRegistry.registerConfiguration({
'type': 'number',
'default': 4096,
'markdownDescription': nls.localize('maxMemoryForLargeFilesMB', "Controls the memory available to VS Code after restart when trying to open large files. Same effect as specifying `--max-memory=NEWSIZE` on the command line.")
},
'files.simpleDialog.enable': {
'type': 'boolean',
'description': nls.localize('files.simpleDialog.enable', "Enables the simple file dialog. The simple file dialog replaces the system file dialog when enabled."),
'default': false,
}
}
});

View File

@@ -14,7 +14,7 @@ import { coalesce } from 'vs/base/common/arrays';
// Commands can get exeucted from a command pallete, from a context menu or from some list using a keybinding
// To cover all these cases we need to properly compute the resource on which the command is being executed
export function getResourceForCommand(resource: URI | object | undefined, listService: IListService, editorService: IEditorService): URI | null {
export function getResourceForCommand(resource: URI | object | undefined, listService: IListService, editorService: IEditorService): URI | undefined {
if (URI.isUri(resource)) {
return resource;
}
@@ -41,7 +41,7 @@ export function getResourceForCommand(resource: URI | object | undefined, listSe
}
}
return editorService.activeEditor ? toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : null;
return editorService.activeEditor ? toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : undefined;
}
export function getMultiSelectedResources(resource: URI | object | undefined, listService: IListService, editorService: IEditorService): Array<URI> {

View File

@@ -19,7 +19,7 @@ import { ResourceMap } from 'vs/base/common/map';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { FileOnDiskContentProvider, resourceToFileOnDisk } from 'vs/workbench/contrib/files/common/files';
import { TextFileContentProvider } from 'vs/workbench/contrib/files/common/files';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
import { IModelService } from 'vs/editor/common/services/modelService';
import { SAVE_FILE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL } from 'vs/workbench/contrib/files/browser/fileCommands';
@@ -39,7 +39,7 @@ export const CONFLICT_RESOLUTION_SCHEME = 'conflictResolution';
const LEARN_MORE_DIRTY_WRITE_IGNORE_KEY = 'learnMoreDirtyWriteError';
const conflictEditorHelp = nls.localize('userGuide', "Use the actions in the editor tool bar to either undo your changes or overwrite the content on disk with your changes.");
const conflictEditorHelp = nls.localize('userGuide', "Use the actions in the editor tool bar to either undo your changes or overwrite the content of the file with your changes.");
// A handler for save error happening with conflict resolution actions
export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, IWorkbenchContribution {
@@ -61,7 +61,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I
this.messages = new ResourceMap<INotificationHandle>();
this.conflictResolutionContext = new RawContextKey<boolean>(CONFLICT_RESOLUTION_CONTEXT, false).bindTo(contextKeyService);
const provider = this._register(instantiationService.createInstance(FileOnDiskContentProvider));
const provider = this._register(instantiationService.createInstance(TextFileContentProvider));
this._register(textModelService.registerTextModelContentProvider(CONFLICT_RESOLUTION_SCHEME, provider));
// Hook into model
@@ -125,7 +125,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I
// Otherwise show the message that will lead the user into the save conflict editor.
else {
message = nls.localize('staleSaveError', "Failed to save '{0}': The content on disk is newer. Please compare your version with the one on disk.", basename(resource));
message = nls.localize('staleSaveError', "Failed to save '{0}': The content of the file is newer. Please compare your version with the file contents.", basename(resource));
actions.primary!.push(this.instantiationService.createInstance(ResolveSaveConflictAction, model));
}
@@ -244,16 +244,9 @@ class ResolveSaveConflictAction extends Action {
if (!this.model.isDisposed()) {
const resource = this.model.getResource();
const name = basename(resource);
const editorLabel = nls.localize('saveConflictDiffLabel', "{0} (on disk) ↔ {1} (in {2}) - Resolve save conflict", name, name, this.environmentService.appNameLong);
const editorLabel = nls.localize('saveConflictDiffLabel', "{0} (in file) ↔ {1} (in {2}) - Resolve save conflict", name, name, this.environmentService.appNameLong);
return this.editorService.openEditor(
{
leftResource: resourceToFileOnDisk(CONFLICT_RESOLUTION_SCHEME, resource),
rightResource: resource,
label: editorLabel,
options: { pinned: true }
}
).then(() => {
return TextFileContentProvider.open(resource, CONFLICT_RESOLUTION_SCHEME, editorLabel, this.editorService, { pinned: true }).then(() => {
if (this.storageService.getBoolean(LEARN_MORE_DIRTY_WRITE_IGNORE_KEY, StorageScope.GLOBAL)) {
return; // return if this message is ignored
}

View File

@@ -35,7 +35,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree';
import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions';
import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem';
import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel';
import { onUnexpectedError } from 'vs/base/common/errors';

View File

@@ -30,7 +30,7 @@ import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem';
import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions';
import { DirtyEditorContext, OpenEditorsGroupContext } from 'vs/workbench/contrib/files/browser/fileCommands';
import { ResourceContextKey } from 'vs/workbench/common/resources';
@@ -41,7 +41,7 @@ import { IDragAndDropData, DataTransfers } from 'vs/base/browser/dnd';
import { memoize } from 'vs/base/common/decorators';
import { ElementsDragAndDropData, DesktopDragAndDropData } from 'vs/base/browser/ui/list/listView';
import { URI } from 'vs/base/common/uri';
import { withNullAsUndefined } from 'vs/base/common/types';
import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types';
const $ = dom.$;
@@ -245,7 +245,7 @@ export class OpenEditorsView extends ViewletPanel {
const element = e.elements.length ? e.elements[0] : undefined;
if (element instanceof OpenEditor) {
this.dirtyEditorFocusedContext.set(this.textFileService.isDirty(withNullAsUndefined(element.getResource())));
this.resourceContext.set(element.getResource());
this.resourceContext.set(withUndefinedAsNull(element.getResource()));
} else if (!!element) {
this.groupFocusedContext.set(true);
}

View File

@@ -24,8 +24,11 @@ import { ILabelService } from 'vs/platform/label/common/label';
*/
export class FileEditorInput extends EditorInput implements IFileEditorInput {
private preferredEncoding: string;
private preferredMode: string;
private forceOpenAsBinary: boolean;
private forceOpenAsText: boolean;
private textModelReference: Promise<IReference<ITextEditorModel>> | null;
private name: string;
@@ -35,6 +38,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
constructor(
private resource: URI,
preferredEncoding: string | undefined,
preferredMode: string | undefined,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ITextFileService private readonly textFileService: ITextFileService,
@ITextModelService private readonly textModelResolverService: ITextModelService,
@@ -46,6 +50,10 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
this.setPreferredEncoding(preferredEncoding);
}
if (preferredMode) {
this.setPreferredMode(preferredMode);
}
this.registerListeners();
}
@@ -89,7 +97,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
}
setEncoding(encoding: string, mode: EncodingMode): void {
this.preferredEncoding = encoding;
this.setPreferredEncoding(encoding);
const textModel = this.textFileService.models.get(this.resource);
if (textModel) {
@@ -102,6 +110,24 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
this.forceOpenAsText = true; // encoding is a good hint to open the file as text
}
getPreferredMode(): string | undefined {
return this.preferredMode;
}
setMode(mode: string): void {
this.setPreferredMode(mode);
const textModel = this.textFileService.models.get(this.resource);
if (textModel) {
textModel.setMode(mode);
}
}
setPreferredMode(mode: string): void {
this.preferredMode = mode;
this.forceOpenAsText = true; // mode is a good hint to open the file as text
}
setForceOpenAsText(): void {
this.forceOpenAsText = true;
this.forceOpenAsBinary = false;
@@ -193,7 +219,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
private decorateLabel(label: string): string {
const model = this.textFileService.models.get(this.resource);
if (model && model.hasState(ModelState.ORPHAN)) {
return localize('orphanedFile', "{0} (deleted from disk)", label);
return localize('orphanedFile', "{0} (deleted)", label);
}
if (model && model.isReadonly()) {
@@ -251,6 +277,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
// Resolve as text
return this.textFileService.models.loadOrCreate(this.resource, {
mode: this.preferredMode,
encoding: this.preferredEncoding,
reload: { async: true }, // trigger a reload of the model if it exists already but do not wait to show the model
allowBinary: this.forceOpenAsText,

View File

@@ -23,6 +23,8 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel';
import { once } from 'vs/base/common/functional';
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
/**
* Explorer viewlet id.
@@ -58,8 +60,8 @@ export interface IExplorerService {
isCut(stat: ExplorerItem): boolean;
/**
* Selects and reveal the file element provided by the given resource if its found in the explorer. Will try to
* resolve the path from the disk in case the explorer is not yet expanded to the file yet.
* Selects and reveal the file element provided by the given resource if its found in the explorer.
* Will try to resolve the path in case the explorer is not yet expanded to the file yet.
*/
select(resource: URI, reveal?: boolean): Promise<void>;
}
@@ -131,15 +133,7 @@ export const SortOrderConfiguration = {
export type SortOrder = 'default' | 'mixed' | 'filesFirst' | 'type' | 'modified';
export function resourceToFileOnDisk(scheme: string, resource: URI): URI {
return resource.with({ scheme, query: JSON.stringify({ scheme: resource.scheme }) });
}
export function fileOnDiskToResource(resource: URI): URI {
return resource.with({ scheme: JSON.parse(resource.query)['scheme'], query: null });
}
export class FileOnDiskContentProvider implements ITextModelContentProvider {
export class TextFileContentProvider implements ITextModelContentProvider {
private fileWatcherDisposable: IDisposable | undefined;
constructor(
@@ -147,16 +141,34 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider {
@IFileService private readonly fileService: IFileService,
@IModeService private readonly modeService: IModeService,
@IModelService private readonly modelService: IModelService
) {
) { }
static open(resource: URI, scheme: string, label: string, editorService: IEditorService, options?: ITextEditorOptions): Promise<void> {
return editorService.openEditor(
{
leftResource: TextFileContentProvider.resourceToTextFile(scheme, resource),
rightResource: resource,
label,
options
}
).then();
}
private static resourceToTextFile(scheme: string, resource: URI): URI {
return resource.with({ scheme, query: JSON.stringify({ scheme: resource.scheme }) });
}
private static textFileToResource(resource: URI): URI {
return resource.with({ scheme: JSON.parse(resource.query)['scheme'], query: null });
}
provideTextContent(resource: URI): Promise<ITextModel> {
const savedFileResource = fileOnDiskToResource(resource);
const savedFileResource = TextFileContentProvider.textFileToResource(resource);
// Make sure our file from disk is resolved up to date
// Make sure our text file is resolved up to date
return this.resolveEditorModel(resource).then(codeEditorModel => {
// Make sure to keep contents on disk up to date when it changes
// Make sure to keep contents up to date when it changes
if (!this.fileWatcherDisposable) {
this.fileWatcherDisposable = this.fileService.onFileChanges(changes => {
if (changes.contains(savedFileResource, FileChangeType.UPDATED)) {
@@ -179,20 +191,20 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider {
private resolveEditorModel(resource: URI, createAsNeeded?: true): Promise<ITextModel>;
private resolveEditorModel(resource: URI, createAsNeeded?: boolean): Promise<ITextModel | null>;
private resolveEditorModel(resource: URI, createAsNeeded: boolean = true): Promise<ITextModel | null> {
const savedFileResource = fileOnDiskToResource(resource);
const savedFileResource = TextFileContentProvider.textFileToResource(resource);
return this.textFileService.readStream(savedFileResource).then(content => {
let codeEditorModel = this.modelService.getModel(resource);
if (codeEditorModel) {
this.modelService.updateModel(codeEditorModel, content.value);
} else if (createAsNeeded) {
const fileOnDiskModel = this.modelService.getModel(savedFileResource);
const textFileModel = this.modelService.getModel(savedFileResource);
let languageSelector: ILanguageSelection;
if (fileOnDiskModel) {
languageSelector = this.modeService.create(fileOnDiskModel.getModeId());
if (textFileModel) {
languageSelector = this.modeService.create(textFileModel.getModeId());
} else {
languageSelector = this.modeService.createByFilepathOrFirstLine(savedFileResource.fsPath);
languageSelector = this.modeService.createByFilepathOrFirstLine(savedFileResource.path);
}
codeEditorModel = this.modelService.createModel(content.value, languageSelector, resource);
@@ -246,7 +258,7 @@ export class OpenEditor implements IEditorIdentifier {
return this.editor.isDirty();
}
public getResource(): URI | null {
public getResource(): URI | undefined {
return toResource(this.editor, { supportSideBySide: SideBySideEditor.MASTER });
}
}

View File

@@ -16,6 +16,7 @@ import { FileOperationResult, FileOperationError } from 'vs/platform/files/commo
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
import { IModelService } from 'vs/editor/common/services/modelService';
import { timeout } from 'vs/base/common/async';
import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
class ServiceAccessor {
constructor(
@@ -36,10 +37,10 @@ suite('Files - FileEditorInput', () => {
accessor = instantiationService.createInstance(ServiceAccessor);
});
test('Basics', function () {
let input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined);
const otherInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, 'foo/bar/otherfile.js'), undefined);
const otherInputSame = instantiationService.createInstance(FileEditorInput, toResource.call(this, 'foo/bar/file.js'), undefined);
test('Basics', async function () {
let input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined, undefined);
const otherInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, 'foo/bar/otherfile.js'), undefined, undefined);
const otherInputSame = instantiationService.createInstance(FileEditorInput, toResource.call(this, 'foo/bar/file.js'), undefined, undefined);
assert(input.matches(input));
assert(input.matches(otherInputSame));
@@ -54,52 +55,65 @@ suite('Files - FileEditorInput', () => {
assert.strictEqual(toResource.call(this, '/foo/bar/file.js').fsPath, input.getResource().fsPath);
assert(input.getResource() instanceof URI);
input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar.html'), undefined);
input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar.html'), undefined, undefined);
const inputToResolve: FileEditorInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined);
const sameOtherInput: FileEditorInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined);
const inputToResolve: FileEditorInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined, undefined);
const sameOtherInput: FileEditorInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined, undefined);
return inputToResolve.resolve().then(resolved => {
assert.ok(inputToResolve.isResolved());
let resolved = await inputToResolve.resolve();
assert.ok(inputToResolve.isResolved());
const resolvedModelA = resolved;
return inputToResolve.resolve().then(resolved => {
assert(resolvedModelA === resolved); // OK: Resolved Model cached globally per input
const resolvedModelA = resolved;
resolved = await inputToResolve.resolve();
assert(resolvedModelA === resolved); // OK: Resolved Model cached globally per input
return sameOtherInput.resolve().then(otherResolved => {
assert(otherResolved === resolvedModelA); // OK: Resolved Model cached globally per input
const otherResolved = await sameOtherInput.resolve();
assert(otherResolved === resolvedModelA); // OK: Resolved Model cached globally per input
inputToResolve.dispose();
inputToResolve.dispose();
resolved = await inputToResolve.resolve();
assert(resolvedModelA === resolved); // Model is still the same because we had 2 clients
inputToResolve.dispose();
sameOtherInput.dispose();
resolvedModelA.dispose();
return inputToResolve.resolve().then(resolved => {
assert(resolvedModelA === resolved); // Model is still the same because we had 2 clients
resolved = await inputToResolve.resolve();
assert(resolvedModelA !== resolved); // Different instance, because input got disposed
inputToResolve.dispose();
sameOtherInput.dispose();
const stat = (resolved as TextFileEditorModel).getStat();
resolved = await inputToResolve.resolve();
await timeout(0);
assert(stat !== (resolved as TextFileEditorModel).getStat()); // Different stat, because resolve always goes to the server for refresh
});
resolvedModelA.dispose();
return inputToResolve.resolve().then(resolved => {
assert(resolvedModelA !== resolved); // Different instance, because input got disposed
let stat = (resolved as TextFileEditorModel).getStat();
return inputToResolve.resolve().then(resolved => {
return timeout(0).then(() => { // due to file editor input using `reload: { async: true }`
assert(stat !== (resolved as TextFileEditorModel).getStat()); // Different stat, because resolve always goes to the server for refresh
});
});
});
});
});
});
test('preferred mode', async function () {
const mode = 'file-input-test';
ModesRegistry.registerLanguage({
id: mode,
});
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined, mode);
assert.equal(input.getPreferredMode(), mode);
const model = await input.resolve() as TextFileEditorModel;
assert.equal(model.textEditorModel!.getModeId(), mode);
input.setMode('text');
assert.equal(input.getPreferredMode(), 'text');
assert.equal(model.textEditorModel!.getModeId(), PLAINTEXT_MODE_ID);
const input2 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined, undefined);
input2.setPreferredMode(mode);
const model2 = await input2.resolve() as TextFileEditorModel;
assert.equal(model2.textEditorModel!.getModeId(), mode);
});
test('matches', function () {
const input1 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined);
const input2 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined);
const input3 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/other.js'), undefined);
const input2Upper = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/UPDATEFILE.js'), undefined);
const input1 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined);
const input2 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined);
const input3 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/other.js'), undefined, undefined);
const input2Upper = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/UPDATEFILE.js'), undefined, undefined);
assert.strictEqual(input1.matches(null), false);
assert.strictEqual(input1.matches(input1), true);
@@ -109,70 +123,58 @@ suite('Files - FileEditorInput', () => {
assert.strictEqual(input1.matches(input2Upper), false);
});
test('getEncoding/setEncoding', function () {
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined);
test('getEncoding/setEncoding', async function () {
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined);
input.setEncoding('utf16', EncodingMode.Encode);
assert.equal(input.getEncoding(), 'utf16');
return input.resolve().then((resolved: TextFileEditorModel) => {
assert.equal(input.getEncoding(), resolved.getEncoding());
resolved.dispose();
});
const resolved = await input.resolve() as TextFileEditorModel;
assert.equal(input.getEncoding(), resolved.getEncoding());
resolved.dispose();
});
test('save', function () {
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined);
test('save', async function () {
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined);
return input.resolve().then((resolved: TextFileEditorModel) => {
resolved.textEditorModel!.setValue('changed');
assert.ok(input.isDirty());
const resolved = await input.resolve() as TextFileEditorModel;
resolved.textEditorModel!.setValue('changed');
assert.ok(input.isDirty());
return input.save().then(() => {
assert.ok(!input.isDirty());
resolved.dispose();
});
});
await input.save();
assert.ok(!input.isDirty());
resolved.dispose();
});
test('revert', function () {
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined);
test('revert', async function () {
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined);
return input.resolve().then((resolved: TextFileEditorModel) => {
resolved.textEditorModel!.setValue('changed');
assert.ok(input.isDirty());
const resolved = await input.resolve() as TextFileEditorModel;
resolved.textEditorModel!.setValue('changed');
assert.ok(input.isDirty());
return input.revert().then(() => {
assert.ok(!input.isDirty());
resolved.dispose();
});
});
await input.revert();
assert.ok(!input.isDirty());
resolved.dispose();
});
test('resolve handles binary files', function () {
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined);
test('resolve handles binary files', async function () {
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined);
accessor.textFileService.setResolveTextContentErrorOnce(new TextFileOperationError('error', TextFileOperationResult.FILE_IS_BINARY));
return input.resolve().then(resolved => {
assert.ok(resolved);
resolved.dispose();
});
const resolved = await input.resolve();
assert.ok(resolved);
resolved.dispose();
});
test('resolve handles too large files', function () {
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined);
test('resolve handles too large files', async function () {
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined);
accessor.textFileService.setResolveTextContentErrorOnce(new FileOperationError('error', FileOperationResult.FILE_TOO_LARGE));
return input.resolve().then(resolved => {
assert.ok(resolved);
resolved.dispose();
});
const resolved = await input.resolve();
assert.ok(resolved);
resolved.dispose();
});
});

View File

@@ -7,7 +7,7 @@ import * as assert from 'assert';
import { URI } from 'vs/base/common/uri';
import { workbenchInstantiationService, TestFileService } from 'vs/workbench/test/workbenchTestServices';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { FileOnDiskContentProvider, resourceToFileOnDisk } from 'vs/workbench/contrib/files/common/files';
import { TextFileContentProvider } from 'vs/workbench/contrib/files/common/files';
import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles';
import { IFileService } from 'vs/platform/files/common/files';
@@ -29,10 +29,10 @@ suite('Files - FileOnDiskContentProvider', () => {
});
test('provideTextContent', async () => {
const provider = instantiationService.createInstance(FileOnDiskContentProvider);
const provider = instantiationService.createInstance(TextFileContentProvider);
const uri = URI.parse('testFileOnDiskContentProvider://foo');
const content = await provider.provideTextContent(resourceToFileOnDisk('conflictResolution', uri));
const content = await provider.provideTextContent(uri.with({ scheme: 'conflictResolution', query: JSON.stringify({ scheme: uri.scheme }) }));
assert.equal(snapshotToString(content.createSnapshot()), 'Hello Html');
assert.equal(accessor.fileService.getLastReadFileUri().toString(), uri.toString());

View File

@@ -201,19 +201,34 @@ async function showFormatterPick(accessor: ServicesAccessor, model: ITextModel,
const overrides = { resource: model.uri, overrideIdentifier: model.getModeId() };
const defaultFormatter = configService.getValue<string>(DefaultFormatter.configName, overrides);
let defaultFormatterPick: IIndexedPick | undefined;
const picks = formatters.map((provider, index) => {
return <IIndexedPick>{
const isDefault = ExtensionIdentifier.equals(provider.extensionId, defaultFormatter);
const pick = <IIndexedPick>{
index,
label: provider.displayName || '',
description: ExtensionIdentifier.equals(provider.extensionId, defaultFormatter) ? nls.localize('def', "(default)") : undefined,
description: isDefault ? nls.localize('def', "(default)") : undefined,
};
if (isDefault) {
// autofocus default pick
defaultFormatterPick = pick;
}
return pick;
});
const configurePick: IQuickPickItem = {
label: nls.localize('config', "Configure Default Formatter...")
};
const pick = await quickPickService.pick([...picks, { type: 'separator' }, configurePick], { placeHolder: nls.localize('format.placeHolder', "Select a formatter") });
const pick = await quickPickService.pick([...picks, { type: 'separator' }, configurePick],
{
placeHolder: nls.localize('format.placeHolder', "Select a formatter"),
activeItem: defaultFormatterPick
}
);
if (!pick) {
// dismissed
return undefined;

View File

@@ -7,14 +7,14 @@ import 'vs/css!./media/markers';
import { URI } from 'vs/base/common/uri';
import * as dom from 'vs/base/browser/dom';
import { IAction, IActionItem, Action } from 'vs/base/common/actions';
import { IAction, IActionViewItem, Action } from 'vs/base/common/actions';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { Panel } from 'vs/workbench/browser/panel';
import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import Constants from 'vs/workbench/contrib/markers/browser/constants';
import { Marker, ResourceMarkers, RelatedInformation, MarkersModel } from 'vs/workbench/contrib/markers/browser/markersModel';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { MarkersFilterActionItem, MarkersFilterAction, IMarkersFilterActionChangeEvent, IMarkerFilterController } from 'vs/workbench/contrib/markers/browser/markersPanelActions';
import { MarkersFilterActionViewItem, MarkersFilterAction, IMarkersFilterActionChangeEvent, IMarkerFilterController } from 'vs/workbench/contrib/markers/browser/markersPanelActions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import Messages from 'vs/workbench/contrib/markers/browser/messages';
import { RangeHighlightDecorations } from 'vs/workbench/browser/parts/editor/rangeDecorations';
@@ -34,7 +34,7 @@ import { deepClone } from 'vs/base/common/objects';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { FilterData, Filter, VirtualDelegate, ResourceMarkersRenderer, MarkerRenderer, RelatedInformationRenderer, TreeElement, MarkersTreeAccessibilityProvider, MarkersViewModel, ResourceDragAndDrop } from 'vs/workbench/contrib/markers/browser/markersTreeViewer';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { Separator, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { Separator, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
@@ -74,7 +74,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
private actions: IAction[];
private collapseAllAction: IAction;
private filterAction: MarkersFilterAction;
private filterInputActionItem: MarkersFilterActionItem;
private filterInputActionViewItem: MarkersFilterActionViewItem;
private treeContainer: HTMLElement;
private messageBoxContainer: HTMLElement;
@@ -152,8 +152,8 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
public layout(dimension: dom.Dimension): void {
this.treeContainer.style.height = `${dimension.height}px`;
this.tree.layout(dimension.height, dimension.width);
if (this.filterInputActionItem) {
this.filterInputActionItem.toggleLayout(dimension.width < 1200);
if (this.filterInputActionViewItem) {
this.filterInputActionViewItem.toggleLayout(dimension.width < 1200);
}
}
@@ -166,8 +166,8 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
}
public focusFilter(): void {
if (this.filterInputActionItem) {
this.filterInputActionItem.focus();
if (this.filterInputActionViewItem) {
this.filterInputActionViewItem.focus();
}
}
@@ -358,8 +358,8 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
// move focus to input, whenever a key is pressed in the panel container
this._register(domEvent(parent, 'keydown')(e => {
if (this.filterInputActionItem && this.keybindingService.mightProducePrintableCharacter(new StandardKeyboardEvent(e))) {
this.filterInputActionItem.focus();
if (this.filterInputActionViewItem && this.keybindingService.mightProducePrintableCharacter(new StandardKeyboardEvent(e))) {
this.filterInputActionViewItem.focus();
}
}));
@@ -624,10 +624,10 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
this.contextMenuService.showContextMenu({
getAnchor: () => e.anchor!,
getActions: () => this.getMenuActions(element),
getActionItem: (action) => {
getActionViewItem: (action) => {
const keybinding = this.keybindingService.lookupKeybinding(action.id);
if (keybinding) {
return new ActionItem(action, action, { label: true, keybinding: keybinding.getLabel() });
return new ActionViewItem(action, action, { label: true, keybinding: keybinding.getLabel() });
}
return undefined;
},
@@ -671,12 +671,12 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
return this.tree.getFocus()[0];
}
public getActionItem(action: IAction): IActionItem | undefined {
public getActionViewItem(action: IAction): IActionViewItem | undefined {
if (action.id === MarkersFilterAction.ID) {
this.filterInputActionItem = this.instantiationService.createInstance(MarkersFilterActionItem, this.filterAction, this);
return this.filterInputActionItem;
this.filterInputActionViewItem = this.instantiationService.createInstance(MarkersFilterActionViewItem, this.filterAction, this);
return this.filterInputActionViewItem;
}
return super.getActionItem(action);
return super.getActionViewItem(action);
}
getFilterOptions(): FilterOptions {

View File

@@ -19,7 +19,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachInputBoxStyler, attachStylerCallback, attachCheckboxStyler } from 'vs/platform/theme/common/styler';
import { IMarkersWorkbenchService } from 'vs/workbench/contrib/markers/browser/markers';
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import { BaseActionItem, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { BaseActionViewItem, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { badgeBackground, badgeForeground, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { localize } from 'vs/nls';
import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
@@ -115,7 +115,7 @@ export interface IMarkerFilterController {
getFilterStats(): { total: number, filtered: number };
}
export class MarkersFilterActionItem extends BaseActionItem {
export class MarkersFilterActionViewItem extends BaseActionViewItem {
private delayedFilterUpdate: Delayer<void>;
private container: HTMLElement;
@@ -331,7 +331,7 @@ export class QuickFixAction extends Action {
}
}
export class QuickFixActionItem extends ActionItem {
export class QuickFixActionViewItem extends ActionViewItem {
constructor(action: QuickFixAction,
@IContextMenuService private readonly contextMenuService: IContextMenuService,

View File

@@ -17,7 +17,7 @@ import { attachBadgeStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IDisposable, dispose, Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { QuickFixAction, QuickFixActionItem } from 'vs/workbench/contrib/markers/browser/markersPanelActions';
import { QuickFixAction, QuickFixActionViewItem } from 'vs/workbench/contrib/markers/browser/markersPanelActions';
import { ILabelService } from 'vs/platform/label/common/label';
import { dirname, basename, isEqual } from 'vs/base/common/resources';
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
@@ -253,7 +253,7 @@ class MarkerWidget extends Disposable {
) {
super();
this.actionBar = this._register(new ActionBar(dom.append(parent, dom.$('.actions')), {
actionItemProvider: (action) => action.id === QuickFixAction.ID ? instantiationService.createInstance(QuickFixActionItem, action) : undefined
actionViewItemProvider: (action) => action.id === QuickFixAction.ID ? instantiationService.createInstance(QuickFixActionViewItem, action) : undefined
}));
this.icon = dom.append(parent, dom.$('.icon'));
this.multilineActionbar = this._register(new ActionBar(dom.append(parent, dom.$('.multiline-actions'))));
@@ -290,9 +290,9 @@ class MarkerWidget extends Disposable {
}
}, this, this.disposables);
quickFixAction.onShowQuickFixes(() => {
const quickFixActionItem = <QuickFixActionItem>this.actionBar.items[0];
if (quickFixActionItem) {
quickFixActionItem.showQuickFixes();
const quickFixActionViewItem = <QuickFixActionViewItem>this.actionBar.viewItems[0];
if (quickFixActionViewItem) {
quickFixActionViewItem.showQuickFixes();
}
}, this, this.disposables);
}

View File

@@ -28,7 +28,7 @@ export class LogViewerInput extends ResourceEditorInput {
constructor(private outputChannelDescriptor: IFileOutputChannelDescriptor,
@ITextModelService textModelResolverService: ITextModelService
) {
super(basename(outputChannelDescriptor.file.path), dirname(outputChannelDescriptor.file.path), URI.from({ scheme: LOG_SCHEME, path: outputChannelDescriptor.id }), textModelResolverService);
super(basename(outputChannelDescriptor.file.path), dirname(outputChannelDescriptor.file.path), URI.from({ scheme: LOG_SCHEME, path: outputChannelDescriptor.id }), undefined, textModelResolverService);
}
public getTypeId(): string {

View File

@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
import * as aria from 'vs/base/browser/ui/aria/aria';
import { IAction, Action } from 'vs/base/common/actions';
import { IOutputService, OUTPUT_PANEL_ID, IOutputChannelRegistry, Extensions as OutputExt, IOutputChannelDescriptor, IFileOutputChannelDescriptor } from 'vs/workbench/contrib/output/common/output';
import { SelectActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { TogglePanelAction } from 'vs/workbench/browser/panel';
@@ -125,7 +125,7 @@ export class SwitchOutputAction extends Action {
}
}
export class SwitchOutputActionItem extends SelectActionItem {
export class SwitchOutputActionViewItem extends SelectActionViewItem {
private static readonly SEPARATOR = '─────────';
@@ -168,7 +168,7 @@ export class SwitchOutputActionItem extends SelectActionItem {
this.logChannels = groups[1] || [];
const showSeparator = this.outputChannels.length && this.logChannels.length;
const separatorIndex = showSeparator ? this.outputChannels.length : -1;
const options: string[] = [...this.outputChannels.map(c => c.label), ...(showSeparator ? [SwitchOutputActionItem.SEPARATOR] : []), ...this.logChannels.map(c => nls.localize('logChannel', "Log ({0})", c.label))];
const options: string[] = [...this.outputChannels.map(c => c.label), ...(showSeparator ? [SwitchOutputActionViewItem.SEPARATOR] : []), ...this.logChannels.map(c => nls.localize('logChannel', "Log ({0})", c.label))];
let selected = 0;
const activeChannel = this.outputService.getActiveChannel();
if (activeChannel) {

View File

@@ -6,7 +6,7 @@
import 'vs/css!./media/output';
import * as nls from 'vs/nls';
import { Action, IAction } from 'vs/base/common/actions';
import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@@ -18,7 +18,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { EditorInput, EditorOptions } from 'vs/workbench/common/editor';
import { AbstractTextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor';
import { OUTPUT_PANEL_ID, IOutputService, CONTEXT_IN_OUTPUT } from 'vs/workbench/contrib/output/common/output';
import { SwitchOutputAction, SwitchOutputActionItem, ClearOutputAction, ToggleOrSetOutputScrollLockAction, OpenLogOutputFile } from 'vs/workbench/contrib/output/browser/outputActions';
import { SwitchOutputAction, SwitchOutputActionViewItem, ClearOutputAction, ToggleOrSetOutputScrollLockAction, OpenLogOutputFile } from 'vs/workbench/contrib/output/browser/outputActions';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -75,12 +75,12 @@ export class OutputPanel extends AbstractTextResourceEditor {
return this.actions;
}
public getActionItem(action: Action): IActionItem | undefined {
public getActionViewItem(action: Action): IActionViewItem | undefined {
if (action.id === SwitchOutputAction.ID) {
return this.instantiationService.createInstance(SwitchOutputActionItem, action);
return this.instantiationService.createInstance(SwitchOutputActionViewItem, action);
}
return super.getActionItem(action);
return super.getActionViewItem(action);
}
protected getConfigurationOverrides(): IEditorOptions {
@@ -95,7 +95,7 @@ export class OutputPanel extends AbstractTextResourceEditor {
options.renderLineHighlight = 'none';
options.minimap = { enabled: false };
const outputConfig = this.baseConfigurationService.getValue('[Log]');
const outputConfig = this.baseConfigurationService.getValue<{}>('[Log]');
if (outputConfig) {
if (outputConfig['editor.minimap.enabled']) {
options.minimap = { enabled: true };

View File

@@ -244,7 +244,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo
private createInput(channel: IOutputChannel): ResourceEditorInput {
const resource = URI.from({ scheme: OUTPUT_SCHEME, path: channel.id });
return this.instantiationService.createInstance(ResourceEditorInput, nls.localize('output', "{0} - Output", channel.label), nls.localize('channel', "Output channel for '{0}'", channel.label), resource);
return this.instantiationService.createInstance(ResourceEditorInput, nls.localize('output', "{0} - Output", channel.label), nls.localize('channel', "Output channel for '{0}'", channel.label), resource, undefined);
}
private saveState(): void {

View File

@@ -52,6 +52,7 @@ export class PerfviewInput extends ResourceEditorInput {
localize('name', "Startup Performance"),
null,
PerfviewInput.Uri,
undefined,
textModelResolverService
);
}

View File

@@ -9,7 +9,7 @@ import { Delayer } from 'vs/base/common/async';
import * as DOM from 'vs/base/browser/dom';
import { OS } from 'vs/base/common/platform';
import { dispose, Disposable, toDisposable, IDisposable } from 'vs/base/common/lifecycle';
import { CheckboxActionItem } from 'vs/base/browser/ui/checkbox/checkbox';
import { CheckboxActionViewItem } from 'vs/base/browser/ui/checkbox/checkbox';
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';
import { IAction, Action } from 'vs/base/common/actions';
@@ -372,12 +372,12 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
this.actionBar = this._register(new ActionBar(this.actionsContainer, {
animated: false,
actionItemProvider: (action: Action) => {
actionViewItemProvider: (action: Action) => {
if (action.id === this.sortByPrecedenceAction.id) {
return new CheckboxActionItem(null, action);
return new CheckboxActionViewItem(null, action);
}
if (action.id === this.recordKeysAction.id) {
return new CheckboxActionItem(null, action);
return new CheckboxActionViewItem(null, action);
}
return undefined;
}

View File

@@ -154,14 +154,14 @@ export class PreferencesEditor extends BaseEditor {
this.preferencesRenderers.editFocusedPreference();
}
setInput(newInput: PreferencesEditorInput, options: SettingsEditorOptions, token: CancellationToken): Promise<void> {
setInput(newInput: EditorInput, options: SettingsEditorOptions, token: CancellationToken): Promise<void> {
this.defaultSettingsEditorContextKey.set(true);
this.defaultSettingsJSONEditorContextKey.set(true);
if (options && options.query) {
this.focusSearch(options.query);
}
return super.setInput(newInput, options, token).then(() => this.updateInput(newInput, options, token));
return super.setInput(newInput, options, token).then(() => this.updateInput(newInput as PreferencesEditorInput, options, token));
}
layout(dimension: DOM.Dimension): void {

View File

@@ -5,7 +5,7 @@
import * as DOM from 'vs/base/browser/dom';
import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { ActionBar, ActionsOrientation, BaseActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionBar, ActionsOrientation, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IInputOptions, InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
import { Widget } from 'vs/base/browser/ui/widget';
import { Action, IAction } from 'vs/base/common/actions';
@@ -291,7 +291,7 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone {
}
}
export class FolderSettingsActionItem extends BaseActionItem {
export class FolderSettingsActionViewItem extends BaseActionViewItem {
private _folder: IWorkspaceFolder | null;
private _folderSettingCounts = new Map<string, number>();
@@ -427,7 +427,7 @@ export class FolderSettingsActionItem extends BaseActionItem {
this.contextMenuService.showContextMenu({
getAnchor: () => this.container,
getActions: () => this.getDropdownMenuActions(),
getActionItem: () => undefined,
getActionViewItem: () => undefined,
onHide: () => {
this.anchorElement.blur();
}
@@ -479,7 +479,7 @@ export class SettingsTargetsWidget extends Widget {
private userLocalSettings: Action;
private userRemoteSettings: Action;
private workspaceSettings: Action;
private folderSettings: FolderSettingsActionItem;
private folderSettings: FolderSettingsActionViewItem;
private options: ISettingsTargetsWidgetOptions;
private _settingsTarget: SettingsTarget;
@@ -508,7 +508,7 @@ export class SettingsTargetsWidget extends Widget {
orientation: ActionsOrientation.HORIZONTAL,
ariaLabel: localize('settingsSwitcherBarAriaLabel', "Settings Switcher"),
animated: false,
actionItemProvider: (action: Action) => action.id === 'folderSettings' ? this.folderSettings : undefined
actionViewItemProvider: (action: Action) => action.id === 'folderSettings' ? this.folderSettings : undefined
}));
this.userLocalSettings = new Action('userSettings', localize('userSettings', "User"), '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_LOCAL));
@@ -525,7 +525,7 @@ export class SettingsTargetsWidget extends Widget {
this.workspaceSettings.tooltip = this.workspaceSettings.label;
const folderSettingsAction = new Action('folderSettings', localize('folderSettings', "Folder"), '.settings-tab', false, (folder: IWorkspaceFolder) => this.updateTarget(folder.uri));
this.folderSettings = this.instantiationService.createInstance(FolderSettingsActionItem, folderSettingsAction);
this.folderSettings = this.instantiationService.createInstance(FolderSettingsActionViewItem, folderSettingsAction);
this.update();

View File

@@ -405,10 +405,10 @@ export function settingKeyToDisplayFormat(key: string, groupId = ''): { category
function wordifyKey(key: string): string {
return key
.replace(/\.([a-z])/g, (match, p1) => ` ${p1.toUpperCase()}`)
.replace(/([a-z])([A-Z])/g, '$1 $2') // fooBar => foo Bar
.replace(/^[a-z]/g, match => match.toUpperCase()) // foo => Foo
.replace(/\b\w+\b/g, match => {
.replace(/\.([a-z0-9])/g, (match, p1) => ` ${p1.toUpperCase()}`) // Replace dot with spaced '>'
.replace(/([a-z0-9])([A-Z])/g, '$1 $2') // Camel case to spacing, fooBar => foo Bar
.replace(/^[a-z]/g, match => match.toUpperCase()) // Upper casing all first letters, foo => Foo
.replace(/\b\w+\b/g, match => { // Upper casing known acronyms
return knownAcronyms.has(match.toLowerCase()) ?
match.toUpperCase() :
match;

View File

@@ -13,7 +13,7 @@ import * as nls from 'vs/nls';
import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { WorkbenchStateContext, RemoteAuthorityContext } from 'vs/workbench/common/contextkeys';
import { WorkbenchStateContext, RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';

View File

@@ -101,6 +101,20 @@ suite('SettingsTree', () => {
category: 'Something Else',
label: 'Etc'
});
assert.deepEqual(
settingKeyToDisplayFormat('foo.1leading.number'),
{
category: 'Foo 1leading',
label: 'Number'
});
assert.deepEqual(
settingKeyToDisplayFormat('foo.1Leading.number'),
{
category: 'Foo 1 Leading',
label: 'Number'
});
});
test('parseQuery', () => {

View File

@@ -192,7 +192,7 @@ class CommandPaletteEditorAction extends EditorAction {
id: ShowAllCommandsAction.ID,
label: nls.localize('showCommands.label', "Command Palette..."),
alias: 'Command Palette',
precondition: null,
precondition: undefined,
menuOpts: {
group: 'z_commands',
order: 1

View File

@@ -139,8 +139,8 @@ class GotoLineEntry extends EditorQuickOpenEntry {
return this.runPreview();
}
getInput(): IEditorInput | null {
return types.withUndefinedAsNull(this.editorService.activeEditor);
getInput(): IEditorInput | undefined {
return this.editorService.activeEditor;
}
getOptions(pinned?: boolean): ITextEditorOptions {

View File

@@ -288,8 +288,8 @@ class SymbolEntry extends EditorQuickOpenEntryGroup {
return this.range;
}
getInput(): IEditorInput | null {
return types.withUndefinedAsNull(this.editorService.activeEditor);
getInput(): IEditorInput | undefined {
return this.editorService.activeEditor;
}
getOptions(pinned?: boolean): ITextEditorOptions {

View File

@@ -35,11 +35,11 @@ import { peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekV
import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions';
import { Action, IAction, ActionRunner } from 'vs/base/common/actions';
import { IActionBarOptions, ActionsOrientation, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IActionBarOptions, ActionsOrientation, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { basename } from 'vs/base/common/resources';
import { MenuId, IMenuService, IMenu, MenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions';
import { MenuItemActionItem, fillInActionBarActions } from 'vs/platform/actions/browser/menuItemActionItem';
import { fillInActionBarActions, ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IChange, IEditorModel, ScrollType, IEditorContribution, IDiffEditorModel } from 'vs/editor/common/editorCommon';
import { OverviewRulerLane, ITextModel, IModelDecorationOptions } from 'vs/editor/common/model';
import { sortedDiff, firstIndex } from 'vs/base/common/arrays';
@@ -50,21 +50,6 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { INotificationService } from 'vs/platform/notification/common/notification';
import { createStyleSheet } from 'vs/base/browser/dom';
// TODO@Joao
// Need to subclass MenuItemActionItem in order to respect
// the action context coming from any action bar, without breaking
// existing users
class DiffMenuItemActionItem extends MenuItemActionItem {
onClick(event: MouseEvent): void {
event.preventDefault();
event.stopPropagation();
this.actionRunner.run(this._commandAction, this._context)
.then(undefined, err => this._notificationService.error(err));
}
}
class DiffActionRunner extends ActionRunner {
runAction(action: IAction, context: any): Promise<any> {
@@ -289,17 +274,17 @@ class DirtyDiffWidget extends PeekViewWidget {
return {
actionRunner,
actionItemProvider: action => this.getActionItem(action),
actionViewItemProvider: action => this.getActionViewItem(action),
orientation: ActionsOrientation.HORIZONTAL_REVERSE
};
}
getActionItem(action: IAction): IActionItem | undefined {
getActionViewItem(action: IAction): IActionViewItem | undefined {
if (!(action instanceof MenuItemAction)) {
return undefined;
}
return new DiffMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
return new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
}
protected _fillBody(container: HTMLElement): void {
@@ -382,7 +367,7 @@ export class ShowPreviousChangeAction extends EditorAction {
id: 'editor.action.dirtydiff.previous',
label: nls.localize('show previous change', "Show Previous Change"),
alias: 'Show Previous Change',
precondition: null,
precondition: undefined,
kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.F3, weight: KeybindingWeight.EditorContrib }
});
}
@@ -416,7 +401,7 @@ export class ShowNextChangeAction extends EditorAction {
id: 'editor.action.dirtydiff.next',
label: nls.localize('show next change', "Show Next Change"),
alias: 'Show Next Change',
precondition: null,
precondition: undefined,
kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Alt | KeyCode.F3, weight: KeybindingWeight.EditorContrib }
});
}
@@ -469,7 +454,7 @@ export class MoveToPreviousChangeAction extends EditorAction {
id: 'workbench.action.editor.previousChange',
label: nls.localize('move to previous change', "Move to Previous Change"),
alias: 'Move to Previous Change',
precondition: null,
precondition: undefined,
kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.F5, weight: KeybindingWeight.EditorContrib }
});
}
@@ -511,7 +496,7 @@ export class MoveToNextChangeAction extends EditorAction {
id: 'workbench.action.editor.nextChange',
label: nls.localize('move to next change', "Move to Next Change"),
alias: 'Move to Next Change',
precondition: null,
precondition: undefined,
kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Alt | KeyCode.F5, weight: KeybindingWeight.EditorContrib }
});
}

View File

@@ -9,7 +9,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions';
import { IAction } from 'vs/base/common/actions';
import { fillInContextMenuActions, fillInActionBarActions } from 'vs/platform/actions/browser/menuItemActionItem';
import { fillInContextMenuActions, fillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { ISCMProvider, ISCMResource, ISCMResourceGroup } from 'vs/workbench/contrib/scm/common/scm';
import { isSCMResource } from './scmUtil';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';

View File

@@ -24,10 +24,10 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { MenuItemAction, IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions';
import { IAction, Action, IActionItem, ActionRunner } from 'vs/base/common/actions';
import { fillInContextMenuActions, ContextAwareMenuItemActionItem, fillInActionBarActions } from 'vs/platform/actions/browser/menuItemActionItem';
import { IAction, Action, IActionViewItem, ActionRunner } from 'vs/base/common/actions';
import { fillInContextMenuActions, ContextAwareMenuEntryActionViewItem, fillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { SCMMenus } from './scmMenus';
import { ActionBar, IActionItemProvider, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IThemeService, LIGHT } from 'vs/platform/theme/common/themeService';
import { isSCMResource } from './scmUtil';
import { attachBadgeStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler';
@@ -94,7 +94,7 @@ class StatusBarAction extends Action {
}
}
class StatusBarActionItem extends ActionItem {
class StatusBarActionViewItem extends ActionViewItem {
constructor(action: StatusBarAction) {
super(null, action, {});
@@ -160,7 +160,7 @@ class ProviderRenderer implements IListRenderer<ISCMRepository, RepositoryTempla
const countContainer = append(provider, $('.count'));
const count = new CountBadge(countContainer);
const badgeStyler = attachBadgeStyler(count, this.themeService);
const actionBar = new ActionBar(provider, { actionItemProvider: a => new StatusBarActionItem(a as StatusBarAction) });
const actionBar = new ActionBar(provider, { actionViewItemProvider: a => new StatusBarActionViewItem(a as StatusBarAction) });
const disposable = Disposable.None;
const templateDisposable = combinedDisposable([actionBar, badgeStyler]);
@@ -366,7 +366,7 @@ class ResourceGroupRenderer implements IListRenderer<ISCMResourceGroup, Resource
get templateId(): string { return ResourceGroupRenderer.TEMPLATE_ID; }
constructor(
private actionItemProvider: IActionItemProvider,
private actionViewItemProvider: IActionViewItemProvider,
private themeService: IThemeService,
private menus: SCMMenus
) { }
@@ -375,7 +375,7 @@ class ResourceGroupRenderer implements IListRenderer<ISCMResourceGroup, Resource
const element = append(container, $('.resource-group'));
const name = append(element, $('.name'));
const actionsContainer = append(element, $('.actions'));
const actionBar = new ActionBar(actionsContainer, { actionItemProvider: this.actionItemProvider });
const actionBar = new ActionBar(actionsContainer, { actionViewItemProvider: this.actionViewItemProvider });
const countContainer = append(element, $('.count'));
const count = new CountBadge(countContainer);
const styler = attachBadgeStyler(count, this.themeService);
@@ -454,7 +454,7 @@ class ResourceRenderer implements IListRenderer<ISCMResource, ResourceTemplate>
constructor(
private labels: ResourceLabels,
private actionItemProvider: IActionItemProvider,
private actionViewItemProvider: IActionViewItemProvider,
private getSelectedResources: () => ISCMResource[],
private themeService: IThemeService,
private menus: SCMMenus
@@ -466,7 +466,7 @@ class ResourceRenderer implements IListRenderer<ISCMResource, ResourceTemplate>
const fileLabel = this.labels.create(name);
const actionsContainer = append(fileLabel.element, $('.actions'));
const actionBar = new ActionBar(actionsContainer, {
actionItemProvider: this.actionItemProvider,
actionViewItemProvider: this.actionViewItemProvider,
actionRunner: new MultipleSelectionActionRunner(this.getSelectedResources)
});
@@ -827,14 +827,14 @@ export class RepositoryPanel extends ViewletPanel {
const delegate = new ProviderListDelegate();
const actionItemProvider = (action: IAction) => this.getActionItem(action);
const actionViewItemProvider = (action: IAction) => this.getActionViewItem(action);
this.listLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility });
this.disposables.push(this.listLabels);
const renderers = [
new ResourceGroupRenderer(actionItemProvider, this.themeService, this.menus),
new ResourceRenderer(this.listLabels, actionItemProvider, () => this.getSelectedResources(), this.themeService, this.menus)
new ResourceGroupRenderer(actionViewItemProvider, this.themeService, this.menus),
new ResourceRenderer(this.listLabels, actionViewItemProvider, () => this.getSelectedResources(), this.themeService, this.menus)
];
this.list = this.instantiationService.createInstance(WorkbenchList, this.listContainer, delegate, renderers, {
@@ -918,12 +918,12 @@ export class RepositoryPanel extends ViewletPanel {
return this.menus.getTitleSecondaryActions();
}
getActionItem(action: IAction): IActionItem | undefined {
getActionViewItem(action: IAction): IActionViewItem | undefined {
if (!(action instanceof MenuItemAction)) {
return undefined;
}
return new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
return new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
}
getActionsContext(): any {
@@ -1227,12 +1227,12 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel {
}
}
getActionItem(action: IAction): IActionItem | undefined {
getActionViewItem(action: IAction): IActionViewItem | undefined {
if (!(action instanceof MenuItemAction)) {
return undefined;
}
return new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
return new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
}
getActions(): IAction[] {

View File

@@ -203,7 +203,7 @@ export class OpenFileHandler extends QuickOpenHandler {
const queryOptions: IFileQueryBuilderOptions = {
_reason: 'openFileHandler',
extraFileResources: getOutOfWorkspaceEditorResources(this.editorService, this.contextService),
filePattern: query.value,
filePattern: query.original,
cacheKey
};

View File

@@ -25,7 +25,6 @@ import { ILabelService } from 'vs/platform/label/common/label';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Schemas } from 'vs/base/common/network';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { withUndefinedAsNull } from 'vs/base/common/types';
class SymbolEntry extends EditorQuickOpenEntry {
private bearingResolve: Promise<this | undefined>;
@@ -49,7 +48,7 @@ class SymbolEntry extends EditorQuickOpenEntry {
return nls.localize('entryAriaLabel', "{0}, symbols picker", this.getLabel());
}
getDescription(): string | null {
getDescription(): string | undefined {
const containerName = this.bearing.containerName;
if (this.bearing.location.uri) {
if (containerName) {
@@ -59,7 +58,7 @@ class SymbolEntry extends EditorQuickOpenEntry {
return this.labelService.getUriLabel(this.bearing.location.uri, { relative: true });
}
return withUndefinedAsNull(containerName);
return containerName;
}
getIcon(): string {

View File

@@ -23,7 +23,7 @@ import 'vs/css!./media/searchview';
import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import * as nls from 'vs/nls';
import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem';
import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
@@ -682,11 +682,7 @@ export class SearchView extends ViewletPanel {
}));
}
private onContextMenu(e: ITreeContextMenuEvent<RenderableMatch>): void {
if (!e.element) {
return;
}
private onContextMenu(e: ITreeContextMenuEvent<RenderableMatch | null>): void {
if (!this.contextMenu) {
this.contextMenu = this._register(this.menuService.createMenu(MenuId.SearchContext, this.contextKeyService));
}
@@ -1327,8 +1323,6 @@ export class SearchView extends ViewletPanel {
// Indicate as status to ARIA
aria.status(message);
dom.hide(this.resultsElement);
const messageEl = this.clearMessage();
const p = dom.append(messageEl, $('p', undefined, message));
@@ -1363,6 +1357,7 @@ export class SearchView extends ViewletPanel {
if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
this.showSearchWithoutFolderMessage();
}
this.reLayout();
} else {
this.viewModel.searchResult.toggleHighlights(this.isVisible()); // show highlights

View File

@@ -7,10 +7,8 @@ import * as nls from 'vs/nls';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { join, basename, dirname, extname } from 'vs/base/common/path';
import { join, basename, extname } from 'vs/base/common/path';
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { timeout } from 'vs/base/common/async';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { URI } from 'vs/base/common/uri';
import { ISnippetsService } from 'vs/workbench/contrib/snippets/browser/snippets.contribution';
@@ -19,8 +17,9 @@ import { IQuickPickItem, IQuickInputService, QuickPickInput } from 'vs/platform/
import { SnippetSource } from 'vs/workbench/contrib/snippets/browser/snippetsFile';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IFileService } from 'vs/platform/files/common/files';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { isValidBasename } from 'vs/base/common/extpath';
import { joinPath } from 'vs/base/common/resources';
const id = 'workbench.action.openSnippets';
@@ -121,24 +120,39 @@ async function computePicks(snippetService: ISnippetsService, envService: IEnvir
return { existing, future };
}
async function createSnippetFile(scope: string, defaultPath: URI, windowService: IWindowService, notificationService: INotificationService, fileService: IFileService, textFileService: ITextFileService, opener: IOpenerService) {
async function createSnippetFile(scope: string, defaultPath: URI, quickInputService: IQuickInputService, fileService: IFileService, textFileService: ITextFileService, opener: IOpenerService) {
function createSnippetUri(input: string) {
const filename = extname(input) !== '.code-snippets'
? `${input}.code-snippets`
: input;
return joinPath(defaultPath, filename);
}
await fileService.createFolder(defaultPath);
await timeout(100); // ensure quick pick closes...
const path = await windowService.showSaveDialog({
defaultPath: defaultPath.fsPath,
filters: [{ name: 'Code Snippets', extensions: ['code-snippets'] }]
const input = await quickInputService.input({
placeHolder: nls.localize('name', "Type snippet file name"),
async validateInput(input) {
if (!input) {
return nls.localize('bad_name1', "Invalid file name");
}
if (!isValidBasename(input)) {
return nls.localize('bad_name2', "'{0}' is not a valid file name", input);
}
if (await fileService.exists(createSnippetUri(input))) {
return nls.localize('bad_name3', "'{0}' already exists", input);
}
return undefined;
}
});
if (!path) {
return undefined;
}
const resource = URI.file(path);
if (dirname(resource.fsPath) !== defaultPath.fsPath) {
notificationService.error(nls.localize('badPath', "Snippets must be inside this folder: '{0}'. ", defaultPath.fsPath));
if (!input) {
return undefined;
}
const resource = createSnippetUri(input);
await textFileService.write(resource, [
'{',
'\t// Place your ' + scope + ' snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and ',
@@ -193,10 +207,8 @@ CommandsRegistry.registerCommand(id, async (accessor): Promise<any> => {
const snippetService = accessor.get(ISnippetsService);
const quickInputService = accessor.get(IQuickInputService);
const opener = accessor.get(IOpenerService);
const windowService = accessor.get(IWindowService);
const modeService = accessor.get(IModeService);
const envService = accessor.get(IEnvironmentService);
const notificationService = accessor.get(INotificationService);
const workspaceService = accessor.get(IWorkspaceContextService);
const fileService = accessor.get(IFileService);
const textFileService = accessor.get(ITextFileService);
@@ -233,9 +245,9 @@ CommandsRegistry.registerCommand(id, async (accessor): Promise<any> => {
});
if (globalSnippetPicks.indexOf(pick as SnippetPick) >= 0) {
return createSnippetFile((pick as SnippetPick).scope, (pick as SnippetPick).uri, windowService, notificationService, fileService, textFileService, opener);
return createSnippetFile((pick as SnippetPick).scope, (pick as SnippetPick).uri, quickInputService, fileService, textFileService, opener);
} else if (workspaceSnippetPicks.indexOf(pick as SnippetPick) >= 0) {
return createSnippetFile((pick as SnippetPick).scope, (pick as SnippetPick).uri, windowService, notificationService, fileService, textFileService, opener);
return createSnippetFile((pick as SnippetPick).scope, (pick as SnippetPick).uri, quickInputService, fileService, textFileService, opener);
} else if (ISnippetPick.is(pick)) {
if (pick.hint) {
await createLanguageSnippetFile(pick, fileService, textFileService);

View File

@@ -28,13 +28,13 @@ export class TaskEntry extends Model.QuickOpenEntry {
return this.task._label;
}
public getDescription(): string | null {
public getDescription(): string | undefined {
if (!this.taskService.needsFolderQualification()) {
return null;
return undefined;
}
let workspaceFolder = this.task.getWorkspaceFolder();
if (!workspaceFolder) {
return null;
return undefined;
}
return `${workspaceFolder.name}`;
}

View File

@@ -265,7 +265,7 @@ abstract class AbstractLineMatcher implements ILineMatcher {
if (trim) {
value = Strings.trim(value)!;
}
data[property] += endOfLine + value;
(data as any)[property] += endOfLine + value;
}
}
@@ -277,7 +277,7 @@ abstract class AbstractLineMatcher implements ILineMatcher {
if (trim) {
value = Strings.trim(value)!;
}
data[property] = value;
(data as any)[property] = value;
}
}
}
@@ -894,9 +894,9 @@ export class ProblemPatternParser extends Parser {
}
function copyProperty(result: ProblemPattern, source: Config.ProblemPattern, resultKey: keyof ProblemPattern, sourceKey: keyof Config.ProblemPattern) {
let value = source[sourceKey];
const value = source[sourceKey];
if (typeof value === 'number') {
result[resultKey] = value;
(result as any)[resultKey] = value;
}
}
copyProperty(result, value, 'file', 'file');

View File

@@ -1360,7 +1360,6 @@ class TaskService extends Disposable implements ITaskService {
this.modelService, this.configurationResolverService, this.telemetryService,
this.contextService, this._environmentService,
TaskService.OutputChannelId,
this.configurationService,
(workspaceFolder: IWorkspaceFolder) => {
if (!workspaceFolder) {
return undefined;
@@ -1974,7 +1973,7 @@ class TaskService extends Disposable implements ITaskService {
}
private showQuickPick(tasks: Promise<Task[]> | Task[], placeHolder: string, defaultEntry?: TaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: TaskQuickPickEntry, additionalEntries?: TaskQuickPickEntry[]): Promise<TaskQuickPickEntry | undefined | null> {
let _createEntries = (): Promise<TaskQuickPickEntry[]> => {
let _createEntries = (): Promise<QuickPickInput<TaskQuickPickEntry>[]> => {
if (Array.isArray(tasks)) {
return Promise.resolve(this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry));
} else {
@@ -1984,8 +1983,8 @@ class TaskService extends Disposable implements ITaskService {
return this.quickInputService.pick(_createEntries().then((entries) => {
if ((entries.length === 0) && defaultEntry) {
entries.push(defaultEntry);
}
else if (entries.length > 1 && additionalEntries && additionalEntries.length > 0) {
} else if (entries.length > 1 && additionalEntries && additionalEntries.length > 0) {
entries.push({ type: 'separator', label: '' });
entries.push(additionalEntries[0]);
}
return entries;
@@ -2013,7 +2012,7 @@ class TaskService extends Disposable implements ITaskService {
Severity.Info,
nls.localize('TaskService.ignoredFolder', 'The following workspace folders are ignored since they use task version 0.1.0: {0}', this.ignoredWorkspaceFolders.map(f => f.name).join(', ')),
[{
label: nls.localize('TaskService.notAgain', 'Don\'t Show Again'),
label: nls.localize('TaskService.notAgain', "Don't Show Again"),
isSecondary: true,
run: () => {
this.storageService.store(TaskService.IgnoreTask010DonotShowAgain_key, true, StorageScope.WORKSPACE);
@@ -2219,7 +2218,7 @@ class TaskService extends Disposable implements ITaskService {
}
let runQuickPick = (promise?: Promise<Task[]>) => {
this.showQuickPick(promise || this.getActiveTasks(),
nls.localize('TaskService.taskToTerminate', 'Select task to terminate'),
nls.localize('TaskService.taskToTerminate', 'Select a task to terminate'),
{
label: nls.localize('TaskService.noTaskRunning', 'No task is currently running'),
task: undefined
@@ -2227,7 +2226,7 @@ class TaskService extends Disposable implements ITaskService {
false, true,
undefined,
[{
label: nls.localize('TaskService.terminateAllRunningTasks', 'All running tasks'),
label: nls.localize('TaskService.terminateAllRunningTasks', 'All Running Tasks'),
id: 'terminateAll',
task: undefined
}]

View File

@@ -44,7 +44,6 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
import { Schemas } from 'vs/base/common/network';
import { getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/terminal';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
interface TerminalData {
terminal: ITerminalInstance;
@@ -172,7 +171,6 @@ export class TerminalTaskSystem implements ITaskSystem {
private contextService: IWorkspaceContextService,
private environmentService: IWorkbenchEnvironmentService,
private outputChannelId: string,
private readonly configurationService: IConfigurationService,
taskSystemInfoResolver: TaskSystemInfoResovler,
) {
@@ -756,7 +754,7 @@ export class TerminalTaskSystem implements ITaskSystem {
let originalCommand = task.command.name;
if (isShellCommand) {
shellLaunchConfig = { name: terminalName, executable: undefined, args: undefined, waitOnExit };
this.terminalService.configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig, platform);
this.terminalService.configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig, this.terminalService.getDefaultShell(platform), platform);
let shellSpecified: boolean = false;
let shellOptions: ShellConfiguration | undefined = task.command.options && task.command.options.shell;
if (shellOptions) {
@@ -879,9 +877,6 @@ export class TerminalTaskSystem implements ITaskSystem {
if (options.env) {
shellLaunchConfig.env = options.env;
}
// Conpty doesn't do linefeeds in an expected way. Force winpty unless the user has requested otherwise.
shellLaunchConfig.forceWinpty = !this.configurationService.getValue('tasks.terminal.windowsAllowConpty');
return shellLaunchConfig;
}

View File

@@ -502,7 +502,7 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, Fi
const sendSequenceTerminalCommand = new SendSequenceTerminalCommand({
id: SendSequenceTerminalCommand.ID,
precondition: null,
precondition: undefined,
description: {
description: `Send Custom Sequence To Terminal`,
args: [{

View File

@@ -6,7 +6,7 @@
import { Terminal as XTermTerminal } from 'vscode-xterm';
import { ITerminalInstance, IWindowsShellHelper, ITerminalProcessManager, ITerminalConfigHelper, ITerminalChildProcess, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { IProcessEnvironment, Platform } from 'vs/base/common/platform';
export const ITerminalInstanceService = createDecorator<ITerminalInstanceService>('terminalInstanceService');
@@ -17,6 +17,7 @@ export interface ITerminalInstanceService {
createWindowsShellHelper(shellProcessId: number, instance: ITerminalInstance, xterm: XTermTerminal): IWindowsShellHelper;
createTerminalProcessManager(id: number, configHelper: ITerminalConfigHelper): ITerminalProcessManager;
createTerminalProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean): ITerminalChildProcess;
getDefaultShell(p: Platform): string;
}
export interface IBrowserTerminalConfigHelper extends ITerminalConfigHelper {

View File

@@ -8,7 +8,7 @@ import { Action, IAction } from 'vs/base/common/actions';
import { EndOfLinePreference } from 'vs/editor/common/model';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, Direction, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal';
import { SelectActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { TogglePanelAction } from 'vs/workbench/browser/panel';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
@@ -726,7 +726,7 @@ export class SwitchTerminalAction extends Action {
}
}
export class SwitchTerminalActionItem extends SelectActionItem {
export class SwitchTerminalActionViewItem extends SelectActionViewItem {
constructor(
action: IAction,

View File

@@ -30,7 +30,7 @@ export class TerminalCommandTracker implements ITerminalCommandTracker, IDisposa
constructor(
private _xterm: Terminal
) {
this._xterm.on('key', key => this._onKey(key));
this._xterm.onKey(e => this._onKey(e.key));
}
public dispose(): void {
@@ -48,7 +48,7 @@ export class TerminalCommandTracker implements ITerminalCommandTracker, IDisposa
}
private _onEnter(): void {
if (this._xterm._core.buffer.x >= MINIMUM_PROMPT_LENGTH) {
if (this._xterm.buffer.cursorX >= MINIMUM_PROMPT_LENGTH) {
this._xterm.addMarker(0);
}
}
@@ -175,7 +175,7 @@ export class TerminalCommandTracker implements ITerminalCommandTracker, IDisposa
private _getLine(marker: IMarker | Boundary): number {
// Use the _second last_ row as the last row is likely the prompt
if (marker === Boundary.Bottom) {
return this._xterm._core.buffer.ybase + this._xterm.rows - 1;
return this._xterm.buffer.baseY + this._xterm.rows - 1;
}
if (marker === Boundary.Top) {
@@ -235,10 +235,10 @@ export class TerminalCommandTracker implements ITerminalCommandTracker, IDisposa
if (this._currentMarker === Boundary.Bottom) {
return 0;
} else if (this._currentMarker === Boundary.Top) {
return 0 - (this._xterm._core.buffer.ybase + this._xterm._core.buffer.y);
return 0 - (this._xterm.buffer.baseY + this._xterm.buffer.cursorY);
} else {
let offset = this._getLine(this._currentMarker);
offset -= this._xterm._core.buffer.ybase + this._xterm._core.buffer.y;
offset -= this._xterm.buffer.baseY + this._xterm.buffer.cursorY;
return offset;
}
}

View File

@@ -227,9 +227,9 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper {
return !!isWorkspaceShellAllowed;
}
public mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, platformOverride: platform.Platform = platform.platform): void {
public mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, defaultShell: string, platformOverride: platform.Platform = platform.platform): void {
const isWorkspaceShellAllowed = this.checkWorkspaceShellPermissions(platformOverride === platform.Platform.Windows ? platform.OperatingSystem.Windows : (platformOverride === platform.Platform.Mac ? platform.OperatingSystem.Macintosh : platform.OperatingSystem.Linux));
mergeDefaultShellPathAndArgs(shell, (key) => this._workspaceConfigurationService.inspect(key), isWorkspaceShellAllowed, platformOverride);
mergeDefaultShellPathAndArgs(shell, (key) => this._workspaceConfigurationService.inspect(key), isWorkspaceShellAllowed, defaultShell, platformOverride);
}
private _toInteger(source: any, minimum: number, maximum: number, fallback: number): number {

View File

@@ -25,14 +25,14 @@ import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderB
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { PANEL_BACKGROUND } from 'vs/workbench/common/theme';
import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager';
import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper } from 'vs/workbench/contrib/terminal/common/terminal';
import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE } from 'vs/workbench/contrib/terminal/common/terminal';
import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands';
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler';
import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/browser/terminalCommandTracker';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { ISearchOptions, Terminal as XTermTerminal } from 'vscode-xterm';
import { ISearchOptions, Terminal as XTermTerminal, IBuffer } from 'vscode-xterm';
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
@@ -371,7 +371,7 @@ export class TerminalInstance implements ITerminalInstance {
// it gets removed and then added back to the DOM (resetting scrollTop to 0).
// Upstream issue: https://github.com/sourcelair/xterm.js/issues/291
if (this._xterm) {
this._xterm.emit('scroll', this._xterm._core.buffer.ydisp);
this._xterm._core._onScroll.fire(this._xterm.buffer.viewportY);
}
}
@@ -416,18 +416,17 @@ export class TerminalInstance implements ITerminalInstance {
// TODO: Guess whether to use canvas or dom better
rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType,
// TODO: Remove this once the setting is removed upstream
experimentalCharAtlas: 'dynamic',
experimentalBufferLineImpl: 'TypedArray'
experimentalCharAtlas: 'dynamic'
});
if (this._shellLaunchConfig.initialText) {
this._xterm.writeln(this._shellLaunchConfig.initialText);
}
this._xterm.on('linefeed', () => this._onLineFeed());
this._xterm.on('key', (key, ev) => this._onKey(key, ev));
this._xterm.onLineFeed(() => this._onLineFeed());
this._xterm.onKey(e => this._onKey(e.key, e.domEvent));
if (this._processManager) {
this._processManager.onProcessData(data => this._onProcessData(data));
this._xterm.on('data', data => this._processManager!.write(data));
this._xterm.onData(data => this._processManager!.write(data));
// TODO: How does the cwd work on detached processes?
this.processReady.then(async () => {
this._linkHandler.processCwd = await this._processManager!.getInitialCwd();
@@ -439,18 +438,24 @@ export class TerminalInstance implements ITerminalInstance {
return;
}
if (this._processManager.os === platform.OperatingSystem.Windows) {
this._xterm.winptyCompatInit();
this._xterm.setOption('windowsMode', true);
// Force line data to be sent when the cursor is moved, the main purpose for
// this is because ConPTY will often not do a line feed but instead move the
// cursor, in which case we still want to send the current line's data to tasks.
this._xterm.addCsiHandler('H', () => {
this._onCursorMove();
return false;
});
}
this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, this._xterm, platform.platform, this._processManager);
});
} else if (this.shellLaunchConfig.isRendererOnly) {
this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, this._xterm, undefined, undefined);
}
this._xterm.on('focus', () => this._onFocus.fire(this));
// Register listener to trigger the onInput ext API if the terminal is a renderer only
if (this._shellLaunchConfig.isRendererOnly) {
this._xterm.on('data', (data) => this._sendRendererInput(data));
this._xterm.onData(data => this._sendRendererInput(data));
}
this._commandTracker = new TerminalCommandTracker(this._xterm);
@@ -508,6 +513,7 @@ export class TerminalInstance implements ITerminalInstance {
(<any>this._wrapperElement).xterm = this._xterm;
this._xterm.open(this._xtermElement);
this._xterm.textarea.addEventListener('focus', () => this._onFocus.fire(this));
this._xterm.attachCustomKeyEventHandler((event: KeyboardEvent): boolean => {
// Disable all input if the terminal is exiting
if (this._isExiting) {
@@ -745,8 +751,8 @@ export class TerminalInstance implements ITerminalInstance {
}
}
if (this._xterm) {
const buffer = (<any>this._xterm._core.buffer);
this._sendLineData(buffer, buffer.ybase + buffer.y);
const buffer = this._xterm.buffer;
this._sendLineData(buffer, buffer.baseY + buffer.cursorY);
this._xterm.dispose();
}
@@ -859,7 +865,7 @@ export class TerminalInstance implements ITerminalInstance {
// necessary if the number of rows in the terminal has decreased while it was in the
// background since scrollTop changes take no effect but the terminal's position does
// change since the number of visible rows decreases.
this._xterm.emit('scroll', this._xterm._core.buffer.ydisp);
this._xterm._core._onScroll.fire(this._xterm.buffer.viewportY);
if (this._container && this._container.parentElement) {
// Force a layout when the instance becomes invisible. This is particularly important
// for ensuring that terminals that are created in the background by an extension will
@@ -970,10 +976,32 @@ export class TerminalInstance implements ITerminalInstance {
}
this._isExiting = true;
let exitCodeMessage: string;
let exitCodeMessage: string | undefined;
// Create exit code message
if (exitCode) {
exitCodeMessage = nls.localize('terminal.integrated.exitedWithCode', 'The terminal process terminated with exit code: {0}', exitCode);
if (exitCode === SHELL_PATH_INVALID_EXIT_CODE) {
exitCodeMessage = nls.localize('terminal.integrated.exitedWithInvalidPath', 'The terminal shell path does not exist: {0}', this._shellLaunchConfig.executable);
} else if (this._processManager && this._processManager.processState === ProcessState.KILLED_DURING_LAUNCH) {
let args = '';
if (typeof this._shellLaunchConfig.args === 'string') {
args = ` ${this._shellLaunchConfig.args}`;
} else if (this._shellLaunchConfig.args && this._shellLaunchConfig.args.length) {
args = ' ' + this._shellLaunchConfig.args.map(a => {
if (typeof a === 'string' && a.indexOf(' ') !== -1) {
return `'${a}'`;
}
return a;
}).join(' ');
}
if (this._shellLaunchConfig.executable) {
exitCodeMessage = nls.localize('terminal.integrated.launchFailed', 'The terminal process command \'{0}{1}\' failed to launch (exit code: {2})', this._shellLaunchConfig.executable, args, exitCode);
} else {
exitCodeMessage = nls.localize('terminal.integrated.launchFailedExtHost', 'The terminal process failed to launch (exit code: {0})', exitCode);
}
} else {
exitCodeMessage = nls.localize('terminal.integrated.exitedWithCode', 'The terminal process terminated with exit code: {0}', exitCode);
}
}
this._logService.debug(`Terminal process exit (id: ${this.id})${this._processManager ? ' state ' + this._processManager.processState : ''}`);
@@ -981,8 +1009,8 @@ export class TerminalInstance implements ITerminalInstance {
// Only trigger wait on exit when the exit was *not* triggered by the
// user (via the `workbench.action.terminal.kill` command).
if (this._shellLaunchConfig.waitOnExit && (!this._processManager || this._processManager.processState !== ProcessState.KILLED_BY_USER)) {
if (exitCode) {
this._xterm.writeln(exitCodeMessage!);
if (exitCodeMessage) {
this._xterm.writeln(exitCodeMessage);
}
if (typeof this._shellLaunchConfig.waitOnExit === 'string') {
let message = this._shellLaunchConfig.waitOnExit;
@@ -997,29 +1025,14 @@ export class TerminalInstance implements ITerminalInstance {
}
} else {
this.dispose();
if (exitCode) {
if (exitCodeMessage) {
if (this._processManager && this._processManager.processState === ProcessState.KILLED_DURING_LAUNCH) {
let args = '';
if (typeof this._shellLaunchConfig.args === 'string') {
args = this._shellLaunchConfig.args;
} else if (this._shellLaunchConfig.args && this._shellLaunchConfig.args.length) {
args = ' ' + this._shellLaunchConfig.args.map(a => {
if (typeof a === 'string' && a.indexOf(' ') !== -1) {
return `'${a}'`;
}
return a;
}).join(' ');
}
if (this._shellLaunchConfig.executable) {
this._notificationService.error(nls.localize('terminal.integrated.launchFailed', 'The terminal process command \'{0}{1}\' failed to launch (exit code: {2})', this._shellLaunchConfig.executable, args, exitCode));
} else {
this._notificationService.error(nls.localize('terminal.integrated.launchFailedExtHost', 'The terminal process failed to launch (exit code: {0})', exitCode));
}
this._notificationService.error(exitCodeMessage);
} else {
if (this._configHelper.config.showExitAlert) {
this._notificationService.error(exitCodeMessage!);
this._notificationService.error(exitCodeMessage);
} else {
console.warn(exitCodeMessage!);
console.warn(exitCodeMessage);
}
}
}
@@ -1101,17 +1114,22 @@ export class TerminalInstance implements ITerminalInstance {
}
private _onLineFeed(): void {
const buffer = (<any>this._xterm._core.buffer);
const newLine = buffer.lines.get(buffer.ybase + buffer.y);
if (!newLine.isWrapped) {
this._sendLineData(buffer, buffer.ybase + buffer.y - 1);
const buffer = this._xterm.buffer;
const newLine = buffer.getLine(buffer.baseY + buffer.cursorY);
if (newLine && !newLine.isWrapped) {
this._sendLineData(buffer, buffer.baseY + buffer.cursorY - 1);
}
}
private _sendLineData(buffer: any, lineIndex: number): void {
let lineData = buffer.translateBufferLineToString(lineIndex, true);
while (lineIndex >= 0 && buffer.lines.get(lineIndex--).isWrapped) {
lineData = buffer.translateBufferLineToString(lineIndex, false) + lineData;
private _onCursorMove(): void {
const buffer = this._xterm.buffer;
this._sendLineData(buffer, buffer.baseY + buffer.cursorY);
}
private _sendLineData(buffer: IBuffer, lineIndex: number): void {
let lineData = buffer.getLine(lineIndex)!.translateToString(true);
while (lineIndex >= 0 && buffer.getLine(lineIndex--)!.isWrapped) {
lineData = buffer.getLine(lineIndex)!.translateToString(false) + lineData;
}
this._onLineData.fire(lineData);
}

View File

@@ -7,7 +7,7 @@ import * as dom from 'vs/base/browser/dom';
import * as nls from 'vs/nls';
import * as platform from 'vs/base/common/platform';
import { Action, IAction } from 'vs/base/common/actions';
import { IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IActionViewItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -16,7 +16,7 @@ import { ITerminalService, TERMINAL_PANEL_ID } from 'vs/workbench/contrib/termin
import { IThemeService, ITheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget';
import { editorHoverBackground, editorHoverBorder, editorForeground } from 'vs/platform/theme/common/colorRegistry';
import { KillTerminalAction, SwitchTerminalAction, SwitchTerminalActionItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction, CreateNewTerminalAction, SplitTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions';
import { KillTerminalAction, SwitchTerminalAction, SwitchTerminalActionViewItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction, CreateNewTerminalAction, SplitTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions';
import { Panel } from 'vs/workbench/browser/panel';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { URI } from 'vs/base/common/uri';
@@ -161,12 +161,12 @@ export class TerminalPanel extends Panel {
return this._contextMenuActions;
}
public getActionItem(action: Action): IActionItem | undefined {
public getActionViewItem(action: Action): IActionViewItem | undefined {
if (action.id === SwitchTerminalAction.ID) {
return this._instantiationService.createInstance(SwitchTerminalActionItem, action);
return this._instantiationService.createInstance(SwitchTerminalActionViewItem, action);
}
return super.getActionItem(action);
return super.getActionViewItem(action);
}
public focus(): void {

View File

@@ -169,7 +169,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
private _launchProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number): ITerminalChildProcess {
if (!shellLaunchConfig.executable) {
this._configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig);
this._configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig, this._terminalInstanceService.getDefaultShell(platform.platform));
}
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file);
@@ -181,8 +181,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
const isWorkspaceShellAllowed = this._configHelper.checkWorkspaceShellPermissions();
const env = terminalEnvironment.createTerminalEnvironment(shellLaunchConfig, lastActiveWorkspace, envFromConfigValue, this._configurationResolverService, isWorkspaceShellAllowed, this._productService.version, this._configHelper.config.setLocaleVariables);
this._logService.debug(`Terminal process launching`, shellLaunchConfig, initialCwd, cols, rows, env);
const useConpty = (shellLaunchConfig.forceWinpty !== true) && this._configHelper.config.windowsEnableConpty;
const useConpty = this._configHelper.config.windowsEnableConpty;
return this._terminalInstanceService.createTerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, useConpty);
}

View File

@@ -44,7 +44,7 @@ export abstract class TerminalService extends CommonTerminalService implements I
super(contextKeyService, panelService, lifecycleService, storageService, notificationService, dialogService, extensionService, fileService, remoteAgentService);
}
protected abstract _getDefaultShell(p: platform.Platform): string;
public abstract getDefaultShell(p: platform.Platform): string;
public createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance {
const instance = this._instantiationService.createInstance(TerminalInstance, terminalFocusContextKey, configHelper, container, shellLaunchConfig);
@@ -101,7 +101,7 @@ export abstract class TerminalService extends CommonTerminalService implements I
}
// Never suggest if the setting is non-default already (ie. they set the setting manually)
if (this.configHelper.config.shell.windows !== this._getDefaultShell(platform.Platform.Windows)) {
if (this.configHelper.config.shell.windows !== this.getDefaultShell(platform.Platform.Windows)) {
this._storageService.store(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, true, StorageScope.GLOBAL);
return;
}

View File

@@ -58,6 +58,7 @@ export const TERMINAL_CONFIG_SECTION = 'terminal.integrated';
export const DEFAULT_LETTER_SPACING = 0;
export const MINIMUM_LETTER_SPACING = -5;
export const DEFAULT_LINE_HEIGHT = 1;
export const SHELL_PATH_INVALID_EXIT_CODE = -1;
export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';
@@ -112,7 +113,7 @@ export interface ITerminalConfigHelper {
/**
* Merges the default shell path and args into the provided launch configuration
*/
mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, platformOverride?: platform.Platform): void;
mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, defaultShell: string, platformOverride?: platform.Platform): void;
/** Sets whether a workspace shell configuration is allowed or not */
setWorkspaceShellAllowed(isAllowed: boolean): void;
checkWorkspaceShellPermissions(osOverride?: platform.OperatingSystem): boolean;
@@ -192,12 +193,6 @@ export interface IShellLaunchConfig {
* provided as nothing will be inherited from the process or any configuration.
*/
strictEnv?: boolean;
/**
* Moving forward, conpty will be the default. However, there are cases where conpty is not ready
* to be the default. This property will force winpty to be used, even when conpty would normally be used.
*/
forceWinpty?: boolean;
}
export interface ITerminalService {
@@ -259,6 +254,7 @@ export interface ITerminalService {
findPrevious(): void;
setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
getDefaultShell(p: platform.Platform): string;
selectDefaultWindowsShell(): Promise<string | undefined>;
setWorkspaceShellAllowed(isAllowed: boolean): void;
@@ -694,7 +690,6 @@ export const enum ProcessState {
KILLED_BY_PROCESS
}
export interface ITerminalProcessExtHostProxy extends IDisposable {
readonly terminalId: number;

View File

@@ -164,15 +164,14 @@ export function mergeDefaultShellPathAndArgs(
shell: IShellLaunchConfig,
fetchSetting: (key: string) => { user: string | string[] | undefined, value: string | string[] | undefined, default: string | string[] | undefined },
isWorkspaceShellAllowed: boolean,
defaultShell: string,
platformOverride: platform.Platform = platform.platform
): void {
const platformKey = platformOverride === platform.Platform.Windows ? 'windows' : platformOverride === platform.Platform.Mac ? 'osx' : 'linux';
const shellConfigValue = fetchSetting(`terminal.integrated.shell.${platformKey}`);
// const shellConfigValue = this._workspaceConfigurationService.inspect<string>(`terminal.integrated.shell.${platformKey}`);
const shellArgsConfigValue = fetchSetting(`terminal.integrated.shellArgs.${platformKey}`);
// const shellArgsConfigValue = this._workspaceConfigurationService.inspect<string[]>(`terminal.integrated.shellArgs.${platformKey}`);
shell.executable = (isWorkspaceShellAllowed ? <string>shellConfigValue.value : <string>shellConfigValue.user) || <string>shellConfigValue.default;
shell.executable = (isWorkspaceShellAllowed ? <string>shellConfigValue.value : <string>shellConfigValue.user) || (<string | null>shellConfigValue.default || defaultShell);
shell.args = (isWorkspaceShellAllowed ? <string[]>shellArgsConfigValue.value : <string[]>shellArgsConfigValue.user) || <string[]>shellArgsConfigValue.default;
// Change Sysnative to System32 if the OS is Windows but NOT WoW64. It's

View File

@@ -17,7 +17,7 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { isWindows } from 'vs/base/common/platform';
import { isWindows, Platform } from 'vs/base/common/platform';
import { basename } from 'vs/base/common/path';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { timeout } from 'vs/base/common/async';
@@ -106,6 +106,7 @@ export abstract class TerminalService implements ITerminalService {
public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance;
public abstract createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance;
public abstract getDefaultShell(platform: Platform): string;
public abstract selectDefaultWindowsShell(): Promise<string | undefined>;
public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
@@ -426,6 +427,9 @@ export abstract class TerminalService implements ITerminalService {
return Promise.resolve(null);
}
const current = potentialPaths.shift();
if (current! === '') {
return this._validateShellPaths(label, potentialPaths);
}
return this._fileService.exists(URI.file(current!)).then(exists => {
if (!exists) {
return this._validateShellPaths(label, potentialPaths);

View File

@@ -22,19 +22,19 @@ configurationRegistry.registerConfiguration({
type: 'object',
properties: {
'terminal.integrated.shell.linux': {
markdownDescription: nls.localize('terminal.integrated.shell.linux', "The path of the shell that the terminal uses on Linux. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."),
type: 'string',
default: getDefaultShell(platform.Platform.Linux)
markdownDescription: nls.localize('terminal.integrated.shell.linux', "The path of the shell that the terminal uses on Linux (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(platform.Platform.Linux)),
type: ['string', 'null'],
default: null
},
'terminal.integrated.shell.osx': {
markdownDescription: nls.localize('terminal.integrated.shell.osx', "The path of the shell that the terminal uses on macOS. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."),
type: 'string',
default: getDefaultShell(platform.Platform.Mac)
markdownDescription: nls.localize('terminal.integrated.shell.osx', "The path of the shell that the terminal uses on macOS (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(platform.Platform.Mac)),
type: ['string', 'null'],
default: null
},
'terminal.integrated.shell.windows': {
markdownDescription: nls.localize('terminal.integrated.shell.windows', "The path of the shell that the terminal uses on Windows. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."),
type: 'string',
default: getDefaultShell(platform.Platform.Windows)
markdownDescription: nls.localize('terminal.integrated.shell.windows', "The path of the shell that the terminal uses on Windows (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(platform.Platform.Windows)),
type: ['string', 'null'],
default: null
}
}
});

View File

@@ -10,9 +10,10 @@ import { ITerminalInstance, IWindowsShellHelper, ITerminalConfigHelper, ITermina
import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsShellHelper';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { IProcessEnvironment, Platform } from 'vs/base/common/platform';
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
import * as typeAheadAddon from 'vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon';
import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal';
let Terminal: typeof XTermTerminal;
@@ -35,7 +36,6 @@ export class TerminalInstanceService implements ITerminalInstanceService {
// Enable xterm.js addons
Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/search/search'));
Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/webLinks/webLinks'));
Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/winptyCompat/winptyCompat'));
Terminal.applyAddon(typeAheadAddon);
// Localize strings
Terminal.strings.blankLine = nls.localize('terminal.integrated.a11yBlankLine', 'Blank line');
@@ -54,6 +54,10 @@ export class TerminalInstanceService implements ITerminalInstanceService {
}
public createTerminalProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean): ITerminalChildProcess {
return new TerminalProcess(shellLaunchConfig, cwd, cols, rows, env, windowsEnableConpty);
return this._instantiationService.createInstance(TerminalProcess, shellLaunchConfig, cwd, cols, rows, env, windowsEnableConpty);
}
}
public getDefaultShell(p: Platform): string {
return getDefaultShell(p);
}
}

View File

@@ -98,7 +98,7 @@ export class TerminalService extends BrowserTerminalService implements ITerminal
});
}
protected _getDefaultShell(p: platform.Platform): string {
public getDefaultShell(p: platform.Platform): string {
return getDefaultShell(p);
}
@@ -117,7 +117,28 @@ export class TerminalService extends BrowserTerminalService implements ITerminal
});
}
private _detectWindowsShells(): Promise<IQuickPickItem[]> {
/**
* Get the executable file path of shell from registry.
* @param shellName The shell name to get the executable file path
* @returns `[]` or `[ 'path' ]`
*/
private async _getShellPathFromRegistry(shellName: string): Promise<string[]> {
const Registry = await import('vscode-windows-registry');
try {
const shellPath = Registry.GetStringRegKey('HKEY_LOCAL_MACHINE', `SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${shellName}.exe`, '');
if (shellPath === undefined) {
return [];
}
return [shellPath];
} catch (error) {
return [];
}
}
private async _detectWindowsShells(): Promise<IQuickPickItem[]> {
// Determine the correct System32 path. We want to point to Sysnative
// when the 32-bit version of VS Code is running on a 64-bit machine.
// The reason for this is because PowerShell's important PSReadline
@@ -134,6 +155,7 @@ export class TerminalService extends BrowserTerminalService implements ITerminal
const expectedLocations = {
'Command Prompt': [`${system32Path}\\cmd.exe`],
PowerShell: [`${system32Path}\\WindowsPowerShell\\v1.0\\powershell.exe`],
'PowerShell Core': await this._getShellPathFromRegistry('pwsh'),
'WSL Bash': [`${system32Path}\\${useWSLexe ? 'wsl.exe' : 'bash.exe'}`],
'Git Bash': [
`${process.env['ProgramW6432']}\\Git\\bin\\bash.exe`,

View File

@@ -13,11 +13,12 @@ import { getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/termin
import { IDisposable } from 'vs/base/common/lifecycle';
import { IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal';
import { exec } from 'child_process';
import { ILogService } from 'vs/platform/log/common/log';
export class TerminalProcess implements ITerminalChildProcess, IDisposable {
private _exitCode: number;
private _closeTimeout: any;
private _ptyProcess: pty.IPty;
private _ptyProcess: pty.IPty | undefined;
private _currentTitle: string = '';
private _processStartupComplete: Promise<void>;
private _isDisposed: boolean = false;
@@ -39,7 +40,8 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
cols: number,
rows: number,
env: platform.IProcessEnvironment,
windowsEnableConpty: boolean
windowsEnableConpty: boolean,
@ILogService private readonly _logService: ILogService
) {
let shellName: string;
if (os.platform() === 'win32') {
@@ -69,37 +71,42 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
experimentalUseConpty: useConpty
};
try {
this._ptyProcess = pty.spawn(shellLaunchConfig.executable!, shellLaunchConfig.args || [], options);
this._processStartupComplete = new Promise<void>(c => {
this.onProcessIdReady((pid) => {
c();
});
});
} catch (error) {
// The only time this is expected to happen is when the file specified to launch with does not exist.
this._exitCode = 2;
this._queueProcessExit();
this._processStartupComplete = Promise.resolve(undefined);
return;
}
this._ptyProcess.on('data', (data) => {
// TODO: Need to verify whether executable is on $PATH, otherwise things like cmd.exe will break
// fs.stat(shellLaunchConfig.executable!, (err) => {
// if (err && err.code === 'ENOENT') {
// this._exitCode = SHELL_PATH_INVALID_EXIT_CODE;
// this._queueProcessExit();
// this._processStartupComplete = Promise.resolve(undefined);
// return;
// }
this.setupPtyProcess(shellLaunchConfig, options);
// });
}
private setupPtyProcess(shellLaunchConfig: IShellLaunchConfig, options: pty.IPtyForkOptions): void {
const args = shellLaunchConfig.args || [];
this._logService.trace('IPty#spawn', shellLaunchConfig.executable, args, options);
const ptyProcess = pty.spawn(shellLaunchConfig.executable!, args, options);
this._ptyProcess = ptyProcess;
this._processStartupComplete = new Promise<void>(c => {
this.onProcessIdReady(() => c());
});
ptyProcess.on('data', (data) => {
this._onProcessData.fire(data);
if (this._closeTimeout) {
clearTimeout(this._closeTimeout);
this._queueProcessExit();
}
});
this._ptyProcess.on('exit', (code) => {
ptyProcess.on('exit', (code) => {
this._exitCode = code;
this._queueProcessExit();
});
this._setupTitlePolling(ptyProcess);
// TODO: We should no longer need to delay this since pty.spawn is sync
setTimeout(() => {
this._sendProcessId();
this._sendProcessId(ptyProcess);
}, 500);
this._setupTitlePolling();
}
public dispose(): void {
@@ -114,15 +121,15 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
this._onProcessTitleChanged.dispose();
}
private _setupTitlePolling() {
private _setupTitlePolling(ptyProcess: pty.IPty) {
// Send initial timeout async to give event listeners a chance to init
setTimeout(() => {
this._sendProcessTitle();
this._sendProcessTitle(ptyProcess);
}, 0);
// Setup polling
this._titleInterval = setInterval(() => {
if (this._currentTitle !== this._ptyProcess.process) {
this._sendProcessTitle();
if (this._currentTitle !== ptyProcess.process) {
this._sendProcessTitle(ptyProcess);
}
}, 200);
}
@@ -146,7 +153,10 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
// Attempt to kill the pty, it may have already been killed at this
// point but we want to make sure
try {
this._ptyProcess.kill();
if (this._ptyProcess) {
this._logService.trace('IPty#kill');
this._ptyProcess.kill();
}
} catch (ex) {
// Swallow, the pty has already been killed
}
@@ -155,15 +165,15 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
});
}
private _sendProcessId() {
this._onProcessIdReady.fire(this._ptyProcess.pid);
private _sendProcessId(ptyProcess: pty.IPty) {
this._onProcessIdReady.fire(ptyProcess.pid);
}
private _sendProcessTitle(): void {
private _sendProcessTitle(ptyProcess: pty.IPty): void {
if (this._isDisposed) {
return;
}
this._currentTitle = this._ptyProcess.process;
this._currentTitle = ptyProcess.process;
this._onProcessTitleChanged.fire(this._currentTitle);
}
@@ -176,9 +186,10 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
}
public input(data: string): void {
if (this._isDisposed) {
if (this._isDisposed || !this._ptyProcess) {
return;
}
this._logService.trace('IPty#write', data);
this._ptyProcess.write(data);
}
@@ -188,7 +199,12 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
}
// Ensure that cols and rows are always >= 1, this prevents a native
// exception in winpty.
this._ptyProcess.resize(Math.max(cols, 1), Math.max(rows, 1));
if (this._ptyProcess) {
cols = Math.max(cols, 1);
rows = Math.max(rows, 1);
this._logService.trace('IPty#resize', cols, rows);
this._ptyProcess.resize(cols, rows);
}
}
public getInitialCwd(): Promise<string> {
@@ -198,6 +214,11 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
public getCwd(): Promise<string> {
if (platform.isMacintosh) {
return new Promise<string>(resolve => {
if (!this._ptyProcess) {
resolve(this._initialCwd);
return;
}
this._logService.trace('IPty#pid');
exec('lsof -p ' + this._ptyProcess.pid + ' | grep cwd', (error, stdout, stderr) => {
if (stdout !== '') {
resolve(stdout.substring(stdout.indexOf('/'), stdout.length - 1));
@@ -208,6 +229,11 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
if (platform.isLinux) {
return new Promise<string>(resolve => {
if (!this._ptyProcess) {
resolve(this._initialCwd);
return;
}
this._logService.trace('IPty#pid');
fs.readlink('/proc/' + this._ptyProcess.pid + '/cwd', (err, linkedstr) => {
if (err) {
resolve(this._initialCwd);

View File

@@ -61,15 +61,15 @@ export class WindowsShellHelper implements IWindowsShellHelper {
// If this is done on every linefeed, parsing ends up taking
// significantly longer due to resetting timers. Note that this is
// private API.
this._xterm.on('linefeed', () => this._newLineFeed = true);
this._xterm.on('cursormove', () => {
this._xterm.onLineFeed(() => this._newLineFeed = true);
this._xterm.onCursorMove(() => {
if (this._newLineFeed) {
this._onCheckShell.fire(undefined);
}
});
// Fire a new check for the shell when any key is pressed.
this._xterm.on('keypress', () => this._onCheckShell.fire(undefined));
this._xterm.onKey(() => this._onCheckShell.fire(undefined));
});
}

View File

@@ -238,7 +238,7 @@ class GenerateColorThemeAction extends Action {
}, null, '\t');
contents = contents.replace(/\"__/g, '//"');
return this.editorService.openEditor({ contents, language: 'jsonc' });
return this.editorService.openEditor({ contents, mode: 'jsonc' });
}
}

View File

@@ -153,7 +153,7 @@ module.exports = function createWebviewManager(host) {
scrollTarget.scrollIntoView();
}
} else {
host.postMessage('did-click-link', node.href);
host.postMessage('did-click-link', node.href.baseVal || node.href);
}
event.preventDefault();
break;

View File

@@ -170,7 +170,7 @@ export class WebviewEditorInput extends EditorInput {
this._html = value;
if (this._webview) {
this._webview.contents = value;
this._webview.html = value;
this._currentWebviewHtml = value;
}
}

View File

@@ -47,7 +47,7 @@ export interface WebviewContentOptions {
export interface Webview {
contents: string;
html: string;
options: WebviewContentOptions;
initialScrollProgress: number;
state: string | undefined;

View File

@@ -354,6 +354,11 @@ class WebviewKeyboardHandler extends Disposable {
}
}
interface WebviewContent {
readonly html: string;
readonly options: WebviewContentOptions;
readonly state: string | undefined;
}
export class WebviewElement extends Disposable implements Webview {
private _webview: Electron.WebviewTag;
@@ -361,8 +366,8 @@ export class WebviewElement extends Disposable implements Webview {
private _webviewFindWidget: WebviewFindWidget;
private _findStarted: boolean = false;
private _contents: string = '';
private _state: string | undefined = undefined;
private content: WebviewContent;
private _focused = false;
private readonly _onDidFocus = this._register(new Emitter<void>());
@@ -370,7 +375,7 @@ export class WebviewElement extends Disposable implements Webview {
constructor(
private readonly _options: WebviewOptions,
private _contentOptions: WebviewContentOptions,
contentOptions: WebviewContentOptions,
@IInstantiationService instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IEnvironmentService environmentService: IEnvironmentService,
@@ -380,9 +385,14 @@ export class WebviewElement extends Disposable implements Webview {
@IConfigurationService private readonly _configurationService: IConfigurationService,
) {
super();
this.content = {
html: '',
options: contentOptions,
state: undefined
};
this._webview = document.createElement('webview');
this._webview.setAttribute('partition', `webview${Date.now()}`);
this._webview.setAttribute('webpreferences', 'contextIsolation=yes');
this._webview.style.flex = '0 1';
@@ -410,21 +420,21 @@ export class WebviewElement extends Disposable implements Webview {
this._register(new WebviewProtocolProvider(
this._webview,
this._options.extension ? this._options.extension.location : undefined,
() => (this._contentOptions.localResourceRoots || []),
() => (this.content.options.localResourceRoots || []),
environmentService,
textFileService));
this._register(new WebviewPortMappingProvider(
session,
_options.extension ? _options.extension.location : undefined,
() => (this._contentOptions.portMappings || []),
() => (this.content.options.portMappings || []),
tunnelService,
_options.extension ? _options.extension.id : undefined,
telemetryService
));
if (!this._options.allowSvgs) {
const svgBlocker = this._register(new SvgBlocker(session, this._contentOptions));
const svgBlocker = this._register(new SvgBlocker(session, this.content.options));
svgBlocker.onDidBlockSvg(() => this.onDidBlockSvg());
}
@@ -476,8 +486,9 @@ export class WebviewElement extends Disposable implements Webview {
return;
case 'do-update-state':
this._state = event.args[0];
this._onDidUpdateState.fire(this._state);
const state = event.args[0];
this.state = state;
this._onDidUpdateState.fire(state);
return;
case 'did-focus':
@@ -542,42 +553,53 @@ export class WebviewElement extends Disposable implements Webview {
this._send('initial-scroll-position', value);
}
public set state(value: string | undefined) {
this._state = value;
public set state(state: string | undefined) {
this.content = {
html: this.content.html,
options: this.content.options,
state,
};
}
public set options(value: WebviewContentOptions) {
if (this._contentOptions && areWebviewInputOptionsEqual(value, this._contentOptions)) {
public set options(options: WebviewContentOptions) {
if (areWebviewInputOptionsEqual(options, this.content.options)) {
return;
}
this._contentOptions = value;
this._send('content', {
contents: this._contents,
options: this._contentOptions,
state: this._state
});
this.content = {
html: this.content.html,
options: options,
state: this.content.state,
};
this.doUpdateContent();
}
public set contents(value: string) {
this._contents = value;
this._send('content', {
contents: value,
options: this._contentOptions,
state: this._state
});
public set html(value: string) {
this.content = {
html: value,
options: this.content.options,
state: this.content.state,
};
this.doUpdateContent();
}
public update(value: string, options: WebviewContentOptions, retainContextWhenHidden: boolean) {
if (retainContextWhenHidden && value === this._contents && this._contentOptions && areWebviewInputOptionsEqual(options, this._contentOptions)) {
public update(html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean) {
if (retainContextWhenHidden && html === this.content.html && areWebviewInputOptionsEqual(options, this.content.options)) {
return;
}
this._contents = value;
this._contentOptions = options;
this.content = {
html: html,
options: options,
state: this.content.state,
};
this.doUpdateContent();
}
private doUpdateContent() {
this._send('content', {
contents: this._contents,
options: this._contentOptions,
state: this._state
contents: this.content.html,
options: this.content.options,
state: this.content.state
});
}
@@ -620,7 +642,6 @@ export class WebviewElement extends Disposable implements Webview {
return colors;
}, {} as { [key: string]: string });
const styles = {
'vscode-font-family': '-apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif',
'vscode-font-weight': 'normal',
@@ -717,7 +738,7 @@ export class WebviewElement extends Disposable implements Webview {
}
public reload() {
this.contents = this._contents;
this.doUpdateContent();
}
public selectAll() {

View File

@@ -80,7 +80,7 @@ export class WalkThroughInput extends EditorInput {
return this.options.telemetryFrom;
}
getTelemetryDescriptor(): object {
getTelemetryDescriptor(): { [key: string]: unknown } {
const descriptor = super.getTelemetryDescriptor();
descriptor['target'] = this.getTelemetryFrom();
/* __GDPR__FRAGMENT__